diff --git a/hyperdbg/hprdbgctrl/code/debugger/commands/meta-commands/process.cpp b/hyperdbg/hprdbgctrl/code/debugger/commands/meta-commands/process.cpp index bab3926f..561238cb 100644 --- a/hyperdbg/hprdbgctrl/code/debugger/commands/meta-commands/process.cpp +++ b/hyperdbg/hprdbgctrl/code/debugger/commands/meta-commands/process.cpp @@ -41,10 +41,12 @@ CommandProcessHelp() VOID CommandProcess(vector SplittedCommand, string Command) { - UINT32 TargetProcessId = 0; - UINT64 TargetProcess = 0; + UINT32 TargetProcessId = 0; + UINT64 TargetProcess = 0; + DWORD32 OffsetOfActiveProcessLinks = 0; + BOOLEAN ResultOfGettingOffsets = FALSE; - if (SplittedCommand.size() != 3 && SplittedCommand.size() != 1) + if (SplittedCommand.size() >= 4) { ShowMessages("incorrect use of '.process'\n\n"); CommandProcessHelp(); @@ -69,6 +71,42 @@ CommandProcess(vector SplittedCommand, string Command) NULL, NULL); } + else if (SplittedCommand.size() == 2) + { + if (!SplittedCommand.at(1).compare("list")) + { + // + // Query for ActiveProcessLinks offset from the top of nt!_EPROCESS + // + ResultOfGettingOffsets = ScriptEngineGetFieldOffsetWrapper((CHAR *)"nt!_EPROCESS", + (CHAR *)"ActiveProcessLinks", + &OffsetOfActiveProcessLinks); + + // + // Check if we find the nt!_EPROCESS.ActiveProcessLinks or not, otherwise, + // it means that the PDB for ntoskrnl.exe is not available + // + if (ResultOfGettingOffsets) + { + ShowMessages("Offset : %x\n", OffsetOfActiveProcessLinks); + } + else + { + ShowMessages("err, the need offset to iterate over processes not found, " + "make sure to load ntoskrnl.exe's PDB file. use '.help .sym' for " + "more information\n"); + return; + } + } + else + { + ShowMessages( + "err, unknown parameter at '%s'\n\n", + SplittedCommand.at(1).c_str()); + CommandProcessHelp(); + return; + } + } else if (SplittedCommand.size() == 3) { if (!SplittedCommand.at(1).compare("pid")) diff --git a/hyperdbg/hprdbgctrl/code/debugger/script-engine-wrapper/script-engine-wrapper.cpp b/hyperdbg/hprdbgctrl/code/debugger/script-engine-wrapper/script-engine-wrapper.cpp index 7d7005b6..fd28f584 100644 --- a/hyperdbg/hprdbgctrl/code/debugger/script-engine-wrapper/script-engine-wrapper.cpp +++ b/hyperdbg/hprdbgctrl/code/debugger/script-engine-wrapper/script-engine-wrapper.cpp @@ -106,6 +106,22 @@ ScriptEngineSearchSymbolForMaskWrapper(const char * SearchMask) return ScriptEngineSearchSymbolForMask(SearchMask); } +/** + * @brief ScriptEngineGetFieldOffset wrapper + * + * @param TypeName + * @param FieldName + * @param FieldOffset + * + * @return BOOLEAN + */ +BOOLEAN +ScriptEngineGetFieldOffsetWrapper(CHAR * TypeName, CHAR * FieldName, DWORD32 * FieldOffset) + +{ + return ScriptEngineGetFieldOffset(TypeName, FieldName, FieldOffset); +} + /** * @brief ScriptEngineCreateSymbolTableForDisassembler wrapper * diff --git a/hyperdbg/hprdbgctrl/header/script-engine.h b/hyperdbg/hprdbgctrl/header/script-engine.h index bcfaa9f2..b096eacb 100644 --- a/hyperdbg/hprdbgctrl/header/script-engine.h +++ b/hyperdbg/hprdbgctrl/header/script-engine.h @@ -32,6 +32,9 @@ ScriptEngineUnloadModuleSymbolWrapper(char * ModuleName); UINT32 ScriptEngineSearchSymbolForMaskWrapper(const char * SearchMask); +BOOLEAN +ScriptEngineGetFieldOffsetWrapper(CHAR * TypeName, CHAR * FieldName, DWORD32 * FieldOffset); + BOOLEAN ScriptEngineCreateSymbolTableForDisassemblerWrapper(void * CallbackFunction); diff --git a/hyperdbg/hprdbghv/code/common/Logging.c b/hyperdbg/hprdbghv/code/common/Logging.c index 75a1295a..eaf01a91 100644 --- a/hyperdbg/hprdbghv/code/common/Logging.c +++ b/hyperdbg/hprdbghv/code/common/Logging.c @@ -207,7 +207,7 @@ LogSendBuffer(UINT32 OperationCode, PVOID Buffer, UINT32 BufferLength) if (MessageBufferInformation[Index].CurrentIndexToWrite > MaximumPacketsCapacity - 1) { // - // start from the begining + // start from the beginning // MessageBufferInformation[Index].CurrentIndexToWrite = 0; } @@ -717,7 +717,7 @@ LogPrepareAndSendMessageToQueue(UINT32 OperationCode, BOOLEAN IsImmediateMessage // Append time with previous message // SprintfResult = sprintf_s(LogMessage, PacketChunkSize - 1, "(%s - core : %d - vmx-root? %s)\t %s", TimeBuffer, KeGetCurrentProcessorNumberEx(0), IsVmxRootMode ? "yes" : "no", TempMessage); - + // // Check if the buffer passed the limit // diff --git a/hyperdbg/include/ScriptEngineEval.h b/hyperdbg/include/ScriptEngineEval.h index 1251f2e1..d3eff2fa 100644 --- a/hyperdbg/include/ScriptEngineEval.h +++ b/hyperdbg/include/ScriptEngineEval.h @@ -214,6 +214,8 @@ __declspec(dllimport) UINT32 ScriptEngineUnloadModuleSymbol(char * ModuleName); __declspec(dllimport) UINT32 ScriptEngineSearchSymbolForMask(const char * SearchMask); +__declspec(dllimport) BOOLEAN + ScriptEngineGetFieldOffset(CHAR * TypeName, CHAR * FieldName, DWORD32 * FieldOffset); __declspec(dllimport) BOOLEAN ScriptEngineCreateSymbolTableForDisassembler(void * CallbackFunction); __declspec(dllimport) BOOLEAN diff --git a/hyperdbg/script-engine/script-engine.c b/hyperdbg/script-engine/script-engine.c index e2e89a8f..b9dae9cd 100644 --- a/hyperdbg/script-engine/script-engine.c +++ b/hyperdbg/script-engine/script-engine.c @@ -79,6 +79,15 @@ ScriptEngineSearchSymbolForMask(const char * SearchMask) return SymSearchSymbolForMask(SearchMask); } +BOOLEAN +ScriptEngineGetFieldOffset(CHAR * TypeName, CHAR * FieldName, DWORD32 * FieldOffset) +{ + // + // A wrapper for search for fields in the structure + // + return SymGetFieldOffset(TypeName, FieldName, FieldOffset); +} + BOOLEAN ScriptEngineCreateSymbolTableForDisassembler(void * CallbackFunction) { diff --git a/hyperdbg/script-engine/script-engine.h b/hyperdbg/script-engine/script-engine.h index e5cb94dc..630b9c95 100644 --- a/hyperdbg/script-engine/script-engine.h +++ b/hyperdbg/script-engine/script-engine.h @@ -23,6 +23,8 @@ __declspec(dllimport) UINT32 SymLoadFileSymbol(UINT64 BaseAddress, const char * __declspec(dllimport) UINT32 SymUnloadAllSymbols(); __declspec(dllimport) UINT32 SymUnloadModuleSymbol(char * ModuleName); __declspec(dllimport) UINT32 SymSearchSymbolForMask(const char * SearchMask); +__declspec(dllimport) BOOLEAN ScriptEngineGetFieldOffset(CHAR * TypeName, CHAR * FieldName, DWORD32 * FieldOffset); +__declspec(dllimport) BOOLEAN SymGetFieldOffset(CHAR * TypeName, CHAR * FieldName, DWORD32 * FieldOffset); __declspec(dllimport) BOOLEAN SymCreateSymbolTableForDisassembler(void * CallbackFunction); __declspec(dllimport) BOOLEAN SymConvertFileToPdbPath(const char * LocalFilePath, char * ResultPath); __declspec(dllimport) BOOLEAN SymConvertFileToPdbFileAndGuidAndAgeDetails(const char * LocalFilePath, char * PdbFilePath, char * GuidAndAgeDetails); @@ -42,6 +44,8 @@ __declspec(dllexport) UINT32 ScriptEngineUnloadModuleSymbol(char * ModuleName); __declspec(dllexport) UINT32 ScriptEngineSearchSymbolForMask(const char * SearchMask); +__declspec(dllexport) BOOLEAN + ScriptEngineGetFieldOffset(CHAR * TypeName, CHAR * FieldName, DWORD32 * FieldOffset); __declspec(dllexport) BOOLEAN ScriptEngineCreateSymbolTableForDisassembler(void * CallbackFunction); __declspec(dllexport) BOOLEAN diff --git a/hyperdbg/symbol-parser/code/symbol-parser.cpp b/hyperdbg/symbol-parser/code/symbol-parser.cpp index a1516d57..85e48897 100644 --- a/hyperdbg/symbol-parser/code/symbol-parser.cpp +++ b/hyperdbg/symbol-parser/code/symbol-parser.cpp @@ -182,6 +182,136 @@ SymGetModuleBaseFromSearchMask(const char * SearchMask, BOOLEAN SetModuleNameGlo return NULL; } +/** + * @brief Get the offset of a field from the top of a structure + * @param Base + * @param TypeName + * @param FieldName + * @param FieldOffset + * @details This function is derived from: https://github.com/0vercl0k/sic/blob/master/src/sic/sym.cc + * + * @return BOOLEAN Whether the module is found successfully or not + */ +BOOLEAN +SymGetFieldOffsetFromModule(DWORD64 Base, WCHAR * TypeName, WCHAR * FieldName, DWORD32 * FieldOffset) +{ + BOOLEAN Found = FALSE; + + // + // Allocate a buffer to back the SYMBOL_INFO structure + // + const DWORD SizeOfStruct = + sizeof(SYMBOL_INFOW) + ((MAX_SYM_NAME - 1) * sizeof(wchar_t)); + uint8_t SymbolInfoBuffer[SizeOfStruct]; + auto SymbolInfo = PSYMBOL_INFOW(SymbolInfoBuffer); + + // + // Initialize the fields that need initialization + // + SymbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW); + SymbolInfo->MaxNameLen = MAX_SYM_NAME; + + // + // Retrieve a type index for the type we're after + // + if (!SymGetTypeFromNameW(GetCurrentProcess(), Base, TypeName, SymbolInfo)) + { + // ShowMessages("err, SymGetTypeFromName failed (%x)\n", + // GetLastError()); + return FALSE; + } + + // + // Now that we have a type, we need to enumerate its children to find the + // field we're after. First step is to get the number of children + // + const ULONG TypeIndex = SymbolInfo->TypeIndex; + DWORD ChildrenCount = 0; + if (!SymGetTypeInfo(GetCurrentProcess(), Base, TypeIndex, TI_GET_CHILDRENCOUNT, &ChildrenCount)) + { + // ShowMessages("err, SymGetTypeInfo failed (%x)\n", + // GetLastError()); + return FALSE; + } + + // + // Allocate enough memory to receive the children ids + // + auto FindChildrenParamsBacking = std::make_unique( + sizeof(_TI_FINDCHILDREN_PARAMS) + ((ChildrenCount - 1) * sizeof(ULONG))); + auto FindChildrenParams = + (_TI_FINDCHILDREN_PARAMS *)FindChildrenParamsBacking.get(); + + // + // Initialize the structure with the children count + // + FindChildrenParams->Count = ChildrenCount; + + // + // Get all the children ids + // + if (!SymGetTypeInfo(GetCurrentProcess(), Base, TypeIndex, TI_FINDCHILDREN, FindChildrenParams)) + { + // ShowMessages("err, SymGetTypeInfo failed (%x)\n", + // GetLastError()); + return FALSE; + } + + // + // Now that we have all the ids, we can walk them and find the one that + // matches the field we're looking for + // + + for (DWORD ChildIdx = 0; ChildIdx < ChildrenCount; ChildIdx++) + { + // + // Grab the child name + // + const ULONG ChildId = FindChildrenParams->ChildId[ChildIdx]; + WCHAR * ChildName = nullptr; + SymGetTypeInfo(GetCurrentProcess(), Base, ChildId, TI_GET_SYMNAME, &ChildName); + + // + // Grab the child size - this is useful to know if a field is a bit or a + // normal field + // + ULONG64 ChildSize = 0; + SymGetTypeInfo(GetCurrentProcess(), Base, ChildId, TI_GET_LENGTH, &ChildSize); + + // + // Does this child's name match the field we're looking for? + // + Found = FALSE; + if (wcscmp(ChildName, FieldName) == 0) + { + // + // If we have found the field, now we need to find its offset if + // it's a normal field, or its bit position if it is a bit + // + const IMAGEHLP_SYMBOL_TYPE_INFO Info = + (ChildSize == 1) ? TI_GET_BITPOSITION : TI_GET_OFFSET; + SymGetTypeInfo(GetCurrentProcess(), Base, ChildId, Info, FieldOffset); + Found = TRUE; + } + + // + // Even if we have found a match, we need to clean up the memory + // + LocalFree(ChildName); + ChildName = nullptr; + + // + // We can now break out of the loop if we have what we came looking for + // + if (Found) + { + break; + } + } + + return Found; +} + /** * @brief load symbol based on a file name and GUID * @@ -324,8 +454,10 @@ SymLoadFileSymbol(UINT64 BaseAddress, const char * PdbFileName) if (ModuleDetails->ModuleBase == NULL) { + // //ShowMessages("err, loading symbols failed (%x)\n", // GetLastError()); + // free(ModuleDetails); return -1; @@ -547,6 +679,72 @@ SymConvertNameToAddress(const char * FunctionOrVariableName, PBOOLEAN WasFound) * @brief Search and show symbols * @details mainly used by the 'x' command * + * @param TypeName + * @param FieldName + * @param FieldOffset + * + * @return BOOLEAN Whether the module is found successfully or not + */ +BOOLEAN +SymGetFieldOffset(CHAR * TypeName, CHAR * FieldName, DWORD32 * FieldOffset) +{ + BOOL Ret = FALSE; + DWORD64 ModuleBase = NULL; + UINT32 Index = 0; + + // + // Find module base + // + ModuleBase = SymGetModuleBaseFromSearchMask(TypeName, TRUE); + + // + // Find the module name + // + if (ModuleBase == NULL) + { + // + // Module not found or there was an error + // + return FALSE; + } + + // + // Remove the *!Name from TypeName as it not supports module name + // at the beginning of a type name + // + while (TypeName[Index] != '\0') + { + if (TypeName[Index] == '!') + { + TypeName = (CHAR *)(TypeName + Index + 1); + break; + } + + Index++; + } + + // + // Convert FieldName to wide-char, it's because SymGetTypeInfo supports + // wide-char + // + const size_t TypeNameSize = strlen(TypeName) + 1; + WCHAR * TypeNameW = new wchar_t[TypeNameSize]; + mbstowcs(TypeNameW, TypeName, TypeNameSize); + + // + // Convert FieldName to wide-char, it's because SymGetTypeInfo supports + // wide-char + // + const size_t FieldNameSize = strlen(FieldName) + 1; + WCHAR * FieldNameW = new wchar_t[FieldNameSize]; + mbstowcs(FieldNameW, FieldName, FieldNameSize); + + return SymGetFieldOffsetFromModule(ModuleBase, TypeNameW, FieldNameW, FieldOffset); +} + +/** + * @brief Gets the offset from the symbol + * * @param SearchMask * * @return UINT32 diff --git a/hyperdbg/symbol-parser/header/symbol-parser.h b/hyperdbg/symbol-parser/header/symbol-parser.h index 9fb60f6d..13e8da81 100644 --- a/hyperdbg/symbol-parser/header/symbol-parser.h +++ b/hyperdbg/symbol-parser/header/symbol-parser.h @@ -42,6 +42,7 @@ __declspec(dllexport) UINT32 SymLoadFileSymbol(UINT64 BaseAddress, const char * __declspec(dllexport) UINT32 SymUnloadAllSymbols(); __declspec(dllexport) UINT32 SymUnloadModuleSymbol(char * ModuleName); __declspec(dllexport) UINT32 SymSearchSymbolForMask(const char * SearchMask); +__declspec(dllexport) BOOLEAN SymGetFieldOffset(CHAR * TypeName, CHAR * FieldName, DWORD32 * FieldOffset); __declspec(dllexport) BOOLEAN SymCreateSymbolTableForDisassembler(void * CallbackFunction); __declspec(dllexport) UINT64 SymConvertNameToAddress(const char * FunctionOrVariableName, PBOOLEAN WasFound); __declspec(dllexport) BOOLEAN SymConvertFileToPdbPath(const char * LocalFilePath, char * ResultPath);