HyperDbg/hyperdbg/libhyperdbg/code/debugger/commands/debugging-commands/lm.cpp

501 lines
14 KiB
C++

/**
* @file lm.cpp
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief lm command
* @details
* @version 0.1
* @date 2020-07-13
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
using namespace std;
//
// Global Variables
//
extern ACTIVE_DEBUGGING_PROCESS g_ActiveProcessDebuggingState;
/**
* @brief help of the lm command
*
* @return VOID
*/
VOID
CommandLmHelp()
{
ShowMessages("lm : lists user/kernel modules' base address, size, name and path.\n\n");
ShowMessages("syntax : \tlm [m Name (string)] [pid ProcessId (hex)] [Filter (string)]\n");
ShowMessages("\n");
ShowMessages("\t\te.g : lm\n");
ShowMessages("\t\te.g : lm km\n");
ShowMessages("\t\te.g : lm um\n");
ShowMessages("\t\te.g : lm m nt\n");
ShowMessages("\t\te.g : lm km m ntos\n");
ShowMessages("\t\te.g : lm um m kernel32\n");
ShowMessages("\t\te.g : lm um m kernel32 pid 1240\n");
}
/**
* @brief Convert redirection of 32-bit compatibility path
*
* @param LocalFilePath
*
* @return wstring
*/
std::wstring
CommandLmConvertWow64CompatibilityPaths(const WCHAR * LocalFilePath)
{
std::wstring filePath(LocalFilePath);
// Convert the path to lowercase
std::transform(filePath.begin(), filePath.end(), filePath.begin(), ::tolower);
// Replace "\windows\system32" with "\windows\syswow64"
SIZE_T pos = filePath.find(L":\\windows\\system32");
if (pos != std::string::npos)
{
filePath.replace(pos, 18, L":\\Windows\\SysWOW64");
}
// Replace "\program files" with "\program files (x86)"
pos = filePath.find(L":\\program files");
if (pos != std::string::npos)
{
filePath.replace(pos, 15, L":\\Program Files (x86)");
}
return filePath;
}
/**
* @brief show modules for specified user mode process
* @param ProcessId
* @param SearchModule
*
* @return BOOLEAN
*/
BOOLEAN
CommandLmShowUserModeModule(UINT32 ProcessId, const CHAR * SearchModule)
{
BOOLEAN Status;
ULONG ReturnedLength;
UINT32 ModuleDetailsSize = 0;
UINT32 ModulesCount = 0;
PUSERMODE_LOADED_MODULE_DETAILS ModuleDetailsRequest = NULL;
PUSERMODE_LOADED_MODULE_SYMBOLS Modules = NULL;
USERMODE_LOADED_MODULE_DETAILS ModuleCountRequest = {0};
SIZE_T CharSize = 0;
WCHAR * WcharBuff = NULL;
wstring SearchModuleString;
//
// Check if debugger is loaded or not
//
AssertShowMessageReturnStmt(g_DeviceHandle, ASSERT_MESSAGE_DRIVER_NOT_LOADED, AssertReturnFalse);
//
// Set the module details to get the details
//
ModuleCountRequest.ProcessId = ProcessId;
ModuleCountRequest.OnlyCountModules = TRUE;
//
// Send the request to the kernel
//
Status = DeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_GET_USER_MODE_MODULE_DETAILS, // IO Control
// code
&ModuleCountRequest, // Input Buffer to driver.
sizeof(USERMODE_LOADED_MODULE_DETAILS), // Input buffer length
&ModuleCountRequest, // Output Buffer from driver.
sizeof(USERMODE_LOADED_MODULE_DETAILS), // Length of output
// buffer in bytes.
&ReturnedLength, // Bytes placed in buffer.
NULL // synchronous call
);
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
return FALSE;
}
//
// Check if counting modules was successful or not
//
if (ModuleCountRequest.Result == DEBUGGER_OPERATION_WAS_SUCCESSFUL)
{
ModulesCount = ModuleCountRequest.ModulesCount;
// ShowMessages("Count of modules : 0x%x\n", ModuleCountRequest.ModulesCount);
ModuleDetailsSize = sizeof(USERMODE_LOADED_MODULE_DETAILS) +
(ModuleCountRequest.ModulesCount * sizeof(USERMODE_LOADED_MODULE_SYMBOLS));
ModuleDetailsRequest = (PUSERMODE_LOADED_MODULE_DETAILS)malloc(ModuleDetailsSize);
if (ModuleDetailsRequest == NULL)
{
return FALSE;
}
RtlZeroMemory(ModuleDetailsRequest, ModuleDetailsSize);
//
// Set the module details to get the modules (not count)
//
ModuleDetailsRequest->ProcessId = ProcessId;
ModuleDetailsRequest->OnlyCountModules = FALSE;
//
// Send the request to the kernel
//
Status = DeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_GET_USER_MODE_MODULE_DETAILS, // IO Control
// code
ModuleDetailsRequest, // Input Buffer to driver.
sizeof(USERMODE_LOADED_MODULE_DETAILS), // Input buffer length
ModuleDetailsRequest, // Output Buffer from driver.
ModuleDetailsSize, // Length of output
// buffer in bytes.
&ReturnedLength, // Bytes placed in buffer.
NULL // synchronous call
);
if (!Status)
{
free(ModuleDetailsRequest);
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
return FALSE;
}
//
// Show modules list
//
if (ModuleCountRequest.Result == DEBUGGER_OPERATION_WAS_SUCCESSFUL)
{
Modules = (PUSERMODE_LOADED_MODULE_SYMBOLS)((UINT64)ModuleDetailsRequest +
sizeof(USERMODE_LOADED_MODULE_DETAILS));
ShowMessages("user mode\n");
ShowMessages("start\t\t\tentrypoint\t\tpath\n\n");
if (SearchModule != NULL)
{
CharSize = strlen(SearchModule) + 1;
WcharBuff = (WCHAR *)malloc(CharSize * 2);
if (WcharBuff == NULL)
{
return FALSE;
}
RtlZeroMemory(WcharBuff, CharSize);
mbstowcs(WcharBuff, SearchModule, CharSize);
SearchModuleString.assign(WcharBuff, wcslen(WcharBuff));
}
for (SIZE_T i = 0; i < ModulesCount; i++)
{
//
// Check if we need to search for the module or not
//
if (SearchModule != NULL)
{
//
// Convert FullPathName to string
//
std::wstring FullPathName((WCHAR *)Modules[i].FilePath);
if (FindCaseInsensitiveW(FullPathName, SearchModuleString, 0) == std::wstring::npos)
{
//
// not found
//
continue;
}
}
//
// Check if module is 32-bit or not
//
if (ModuleDetailsRequest->Is32Bit)
{
ShowMessages("%016llx\t%016llx\t%ws\n",
Modules[i].BaseAddress,
Modules[i].Entrypoint,
CommandLmConvertWow64CompatibilityPaths(Modules[i].FilePath).c_str());
}
else
{
ShowMessages("%016llx\t%016llx\t%ws\n",
Modules[i].BaseAddress,
Modules[i].Entrypoint,
Modules[i].FilePath);
}
}
if (SearchModule != NULL)
{
free(WcharBuff);
}
}
else
{
ShowErrorMessage(ModuleCountRequest.Result);
return FALSE;
}
free(ModuleDetailsRequest);
return TRUE;
}
else
{
ShowErrorMessage(ModuleCountRequest.Result);
return FALSE;
}
}
/**
* @brief show modules for kernel mode
* @param SearchModule
*
* @return BOOLEAN
*/
BOOLEAN
CommandLmShowKernelModeModule(const CHAR * SearchModule)
{
PRTL_PROCESS_MODULES ModulesInfo = NULL;
string SearchModuleString;
if (SymbolCheckAndAllocateModuleInformation(&ModulesInfo) == FALSE)
{
ShowMessages("err, unable get modules information\n");
return FALSE;
}
if (SearchModule != NULL)
{
SearchModuleString.assign(SearchModule, strlen(SearchModule));
}
ShowMessages("kernel mode\n");
ShowMessages("start\t\t\tsize\tname\t\t\t\tpath\n\n");
for (ULONG i = 0; i < ModulesInfo->NumberOfModules; i++)
{
RTL_PROCESS_MODULE_INFORMATION * CurrentModule = &ModulesInfo->Modules[i];
//
// Check if we need to search for the module or not
//
if (SearchModule != NULL)
{
//
// Convert FullPathName to string
//
std::string FullPathName((CHAR *)CurrentModule->FullPathName);
if (FindCaseInsensitive(FullPathName, SearchModuleString, 0) == std::string::npos)
{
//
// not found
//
continue;
}
}
ShowMessages("%s\t", SeparateTo64BitValue((UINT64)CurrentModule->ImageBase).c_str());
ShowMessages("%x\t", CurrentModule->ImageSize);
auto PathName = CurrentModule->FullPathName + CurrentModule->OffsetToFileName;
UINT32 PathNameLen = (UINT32)strlen((const CHAR *)PathName);
ShowMessages("%s\t", PathName);
if (PathNameLen >= 24)
{
}
else if (PathNameLen >= 16)
{
ShowMessages("\t");
}
else if (PathNameLen >= 8)
{
ShowMessages("\t\t");
}
else
{
ShowMessages("\t\t\t");
}
ShowMessages("%s\n", CurrentModule->FullPathName);
}
free(ModulesInfo);
return TRUE;
}
/**
* @brief handle lm command
*
* @param CommandTokens
* @param Command
*
* @return VOID
*/
VOID
CommandLm(vector<CommandToken> CommandTokens, string Command)
{
BOOLEAN SetPid = FALSE;
BOOLEAN SetSearchFilter = FALSE;
BOOLEAN SearchStringEntered = FALSE;
BOOLEAN OnlyShowKernelModules = FALSE;
BOOLEAN OnlyShowUserModules = FALSE;
UINT32 TargetPid = NULL;
CHAR Search[MAX_PATH] = {0};
CHAR * SearchString = NULL;
//
// Interpret command specific details (if any)
//
for (auto Section : CommandTokens)
{
if (CompareLowerCaseStrings(Section, "lm"))
{
continue;
}
else if (CompareLowerCaseStrings(Section, "pid") && !SetPid)
{
SetPid = TRUE;
}
else if (CompareLowerCaseStrings(Section, "m") && !SetSearchFilter)
{
SetSearchFilter = TRUE;
}
else if (SetPid)
{
if (!ConvertTokenToUInt32(Section, &TargetPid))
{
//
// couldn't resolve or unknown parameter
//
ShowMessages("err, couldn't resolve error at '%s'\n\n",
GetCaseSensitiveStringFromCommandToken(Section).c_str());
CommandLmHelp();
return;
}
SetPid = FALSE;
}
else if (SetSearchFilter)
{
if (GetCaseSensitiveStringFromCommandToken(Section).length() >= MAX_PATH)
{
ShowMessages("err, string is too large for search, please enter "
"smaller string\n");
return;
}
SearchStringEntered = TRUE;
strcpy(Search, GetLowerStringFromCommandToken(Section).c_str());
SetSearchFilter = FALSE;
}
else if (CompareLowerCaseStrings(Section, "km"))
{
if (OnlyShowUserModules)
{
ShowMessages("err, you cannot use both 'um', and 'km', by default "
"HyperDbg shows both user-mode and kernel-mode modules\n");
return;
}
OnlyShowKernelModules = TRUE;
}
else if (CompareLowerCaseStrings(Section, "um"))
{
if (OnlyShowKernelModules)
{
ShowMessages("err, you cannot use both 'um', and 'km', by default "
"HyperDbg shows both user-mode and kernel-mode modules\n");
return;
}
OnlyShowUserModules = TRUE;
}
else
{
//
// Unknown parameter
//
ShowMessages("err, couldn't resolve error at '%s'\n\n",
GetCaseSensitiveStringFromCommandToken(Section).c_str());
CommandLmHelp();
return;
}
}
if (SetPid)
{
ShowMessages("err, please enter a valid process id in hex format, "
"or if you want to use it in decimal format, add '0n' "
"prefix to the number\n");
return;
}
if (SetSearchFilter)
{
ShowMessages("err, please enter a valid string to search in modules\n");
return;
}
//
// Check if we have string to search
//
if (SearchStringEntered)
{
SearchString = Search;
}
//
// Show user mode modules
//
if (!OnlyShowKernelModules)
{
if (TargetPid != NULL)
{
CommandLmShowUserModeModule(TargetPid, SearchString);
}
else if (g_ActiveProcessDebuggingState.IsActive)
{
CommandLmShowUserModeModule(g_ActiveProcessDebuggingState.ProcessId, SearchString);
}
else
{
CommandLmShowUserModeModule(GetCurrentProcessId(), SearchString);
}
}
//
// Show kernel mode modules
//
if (!OnlyShowUserModules)
{
if (!OnlyShowKernelModules)
{
ShowMessages("\n==============================================================================\n\n");
}
CommandLmShowKernelModeModule(SearchString);
}
}