HyperDbg/hyperdbg/libhyperdbg/code/debugger/commands/meta-commands/dump.cpp

331 lines
8.9 KiB
C++

/**
* @file dump.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief .dump command implementation
* @details
* @version 0.6
* @date 2023-08-26
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
//
// Global Variables
//
extern BOOLEAN g_IsSerialConnectedToRemoteDebuggee;
extern ACTIVE_DEBUGGING_PROCESS g_ActiveProcessDebuggingState;
//
// Local global variables
//
/**
* @brief Holds the handle of the dump file
*
*/
HANDLE DumpFileHandle;
/**
* @brief help of the .dump command
*
* @return VOID
*/
VOID
CommandDumpHelp()
{
ShowMessages(".dump & !dump : saves memory context into a file.\n\n");
ShowMessages("syntax : \t.dump [FromAddress (hex)] [ToAddress (hex)] [pid ProcessId (hex)] [path Path (string)]\n");
ShowMessages("\nIf you want to dump physical memory then add '!' at the "
"start of the command\n\n");
ShowMessages("\n");
ShowMessages("\t\te.g : .dump 401000 40b000 path c:\\rev\\dump1.dmp\n");
ShowMessages("\t\te.g : .dump 401000 40b000 pid 1c0 path c:\\rev\\desktop\\dump2.dmp\n");
ShowMessages("\t\te.g : .dump fffff801deadb000 fffff801deade054 path c:\\rev\\dump3.dmp\n");
ShowMessages("\t\te.g : .dump fffff801deadb000 fffff801deade054 path c:\\rev\\dump4.dmp\n");
ShowMessages("\t\te.g : .dump 00007ff8349f2000 00007ff8349f8000 path c:\\rev\\dump5.dmp\n");
ShowMessages("\t\te.g : .dump @rax+@rcx @rax+@rcx+1000 path c:\\rev\\dump6.dmp\n");
ShowMessages("\t\te.g : !dump 1000 2100 path c:\\rev\\dump7.dmp\n");
}
/**
* @brief .dump command handler
*
* @param CommandTokens
* @param Command
* @return VOID
*/
VOID
CommandDump(vector<CommandToken> CommandTokens, string Command)
{
wstring Filepath;
UINT32 ActualLength;
UINT32 Iterator;
UINT32 Pid = 0;
UINT32 Length = 0;
UINT64 StartAddress = 0;
UINT64 EndAddress = 0;
BOOLEAN IsFirstCommand = TRUE;
BOOLEAN NextIsProcId = FALSE;
BOOLEAN NextIsPath = FALSE;
BOOLEAN IsTheFirstAddr = FALSE;
BOOLEAN IsTheSecondAddr = FALSE;
BOOLEAN IsDumpPathSpecified = FALSE;
string FirstCommand = GetLowerStringFromCommandToken(CommandTokens.front());
DEBUGGER_READ_MEMORY_TYPE MemoryType = DEBUGGER_READ_VIRTUAL_ADDRESS;
if (CommandTokens.size() <= 4)
{
ShowMessages("err, incorrect use of the '.dump' command\n\n");
CommandDumpHelp();
return;
}
//
// By default if the user-debugger is active, we use these commands
// on the memory layout of the debuggee process
//
if (g_ActiveProcessDebuggingState.IsActive)
{
Pid = g_ActiveProcessDebuggingState.ProcessId;
}
for (auto Section : CommandTokens)
{
if (IsFirstCommand == TRUE)
{
IsFirstCommand = FALSE;
continue;
}
else if (NextIsProcId)
{
if (!ConvertTokenToUInt32(Section, &Pid))
{
ShowMessages("please specify a correct hex value for process id\n\n");
CommandDumpHelp();
return;
}
NextIsProcId = FALSE;
continue;
}
else if (NextIsPath)
{
//
// Convert path to wstring
//
StringToWString(Filepath, GetCaseSensitiveStringFromCommandToken(Section));
IsDumpPathSpecified = TRUE;
NextIsPath = FALSE;
}
else if (CompareLowerCaseStrings(Section, "pid"))
{
NextIsProcId = TRUE;
continue;
}
else if (CompareLowerCaseStrings(Section, "path"))
{
NextIsPath = TRUE;
continue;
}
//
// Check the 'From' address
//
else if (!IsTheFirstAddr &&
SymbolConvertNameOrExprToAddress(GetCaseSensitiveStringFromCommandToken(Section), &StartAddress))
{
IsTheFirstAddr = TRUE;
}
//
// Check the 'To' address
//
else if (!IsTheSecondAddr &&
SymbolConvertNameOrExprToAddress(GetCaseSensitiveStringFromCommandToken(Section), &EndAddress))
{
IsTheSecondAddr = TRUE;
}
else
{
//
// invalid input
//
ShowMessages("err, couldn't resolve error at '%s'\n\n",
GetCaseSensitiveStringFromCommandToken(Section).c_str());
CommandDumpHelp();
return;
}
}
//
// Check if 'pid' is not specified
//
if (NextIsProcId)
{
ShowMessages("please specify a correct hex value for process id\n\n");
CommandDumpHelp();
return;
}
//
// Check if 'path' is either specified, not completely specified
//
if (NextIsPath || !IsDumpPathSpecified)
{
ShowMessages("please specify a correct path for saving the dump\n\n");
CommandDumpHelp();
return;
}
//
// Check if start address or end address is null
//
if (!IsTheFirstAddr || !IsTheSecondAddr)
{
ShowMessages("err, please specify the start and end address in hex format\n");
return;
}
//
// Check if end address is bigger than start address
//
if (StartAddress >= EndAddress)
{
ShowMessages("err, please note that the 'to' address should be greater than the 'from' address\n");
return;
}
//
// Check to prevent using process id in d* and u* commands
//
if (g_IsSerialConnectedToRemoteDebuggee && Pid != 0)
{
ShowMessages(ASSERT_MESSAGE_CANNOT_SPECIFY_PID);
return;
}
if (Pid == 0)
{
//
// Default process we read from current process
//
Pid = PlatformGetCurrentProcessId();
}
//
// Check whether it's physical or virtual address
//
if (!FirstCommand.compare("!dump"))
{
MemoryType = DEBUGGER_READ_PHYSICAL_ADDRESS;
}
//
// Create or open the file for writing the dump file
//
// TEMPORARY LINUX SHIM (same as in pe.cpp): std::wstring stores native
// wchar_t (4 bytes on Linux), but the HyperDbg WCHAR type is 2 bytes
// (UINT16) and PlatformOpenFileForWriting takes a const WCHAR *. On Linux
// the cast is a bogus 2-byte reinterpretation, acceptable only because
// Linux file I/O is still stubbed (the path is never opened). On Windows
// WCHAR == wchar_t, so it is a plain correct pointer. TODO(Linux): remove
// once real file I/O lands and convert wchar_t -> 2-byte WCHAR properly.
//
#ifdef __linux__
DumpFileHandle = PlatformOpenFileForWriting((const WCHAR *)Filepath.c_str());
#else
DumpFileHandle = PlatformOpenFileForWriting(Filepath.c_str());
#endif
if (DumpFileHandle == INVALID_HANDLE_VALUE)
{
ShowMessages("err, unable to create or open the file\n");
return;
}
//
// Compute the length
//
Length = (UINT32)(EndAddress - StartAddress);
ActualLength = NULL;
Iterator = Length / PAGE_SIZE;
for (SIZE_T i = 0; i <= Iterator; i++)
{
UINT64 Address = StartAddress + (i * PAGE_SIZE);
if (Length >= PAGE_SIZE)
{
ActualLength = PAGE_SIZE;
}
else
{
ActualLength = Length;
}
Length -= ActualLength;
if (ActualLength != 0)
{
// ShowMessages("address: 0x%llx | actual length: 0x%llx\n", Address, ActualLength);
HyperDbgShowMemoryOrDisassemble(
DEBUGGER_SHOW_COMMAND_DUMP,
Address,
MemoryType,
READ_FROM_KERNEL,
Pid,
ActualLength,
NULL);
}
}
//
// Close the file handle if it's not already closed
//
if (DumpFileHandle != NULL)
{
PlatformCloseFile(DumpFileHandle);
DumpFileHandle = NULL;
}
ShowMessages("the dump file is saved at: %ls\n", Filepath.c_str());
}
/**
* @brief Saves the received buffers into the files
*
* @param Buffer
* @param Length
*
* @return VOID
*/
VOID
CommandDumpSaveIntoFile(PVOID Buffer, UINT32 Length)
{
//
// Check if handle is valid
//
if (DumpFileHandle == NULL)
{
ShowMessages("err, invalid handle for saving the dump buffer is specified\n");
return;
}
//
// Write the buffer into the dump file
//
if (!PlatformWriteFile(DumpFileHandle, Buffer, Length))
{
ShowMessages("err, unable to write buffer into the dump\n");
PlatformCloseFile(DumpFileHandle);
DumpFileHandle = NULL;
return;
}
}