29 typedef struct _PH_SYMBOL_MODULE
62 static HANDLE PhNextFakeHandle = (HANDLE)0;
65 #define PH_LOCK_SYMBOLS() PhAcquireFastLockExclusive(&PhSymMutex)
66 #define PH_UNLOCK_SYMBOLS() PhReleaseFastLockExclusive(&PhSymMutex)
105 _In_opt_ PVOID DbgHelpBase
108 HMODULE dbghelpHandle;
109 HMODULE symsrvHandle;
116 dbghelpHandle = DbgHelpBase;
118 dbghelpHandle = GetModuleHandle(L
"dbghelp.dll");
120 symsrvHandle = GetModuleHandle(L
"symsrv.dll");
122 SymInitialize_I = (PVOID)GetProcAddress(dbghelpHandle,
"SymInitialize");
123 SymCleanup_I = (PVOID)GetProcAddress(dbghelpHandle,
"SymCleanup");
124 if (!(
SymEnumSymbolsW_I = (PVOID)GetProcAddress(dbghelpHandle,
"SymEnumSymbolsW")))
126 if (!(
SymFromAddrW_I = (PVOID)GetProcAddress(dbghelpHandle,
"SymFromAddrW")))
127 SymFromAddr_I = (PVOID)GetProcAddress(dbghelpHandle,
"SymFromAddr");
128 if (!(
SymFromNameW_I = (PVOID)GetProcAddress(dbghelpHandle,
"SymFromNameW")))
129 SymFromName_I = (PVOID)GetProcAddress(dbghelpHandle,
"SymFromName");
134 SymGetOptions_I = (PVOID)GetProcAddress(dbghelpHandle,
"SymGetOptions");
135 SymSetOptions_I = (PVOID)GetProcAddress(dbghelpHandle,
"SymSetOptions");
144 StackWalk64_I = (PVOID)GetProcAddress(dbghelpHandle,
"StackWalk64");
169 static ACCESS_MASK accesses[] =
171 STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff,
181 for (i = 0; i <
sizeof(accesses) /
sizeof(ACCESS_MASK); i++)
198 symbolProvider->
ProcessHandle = (HANDLE)((ULONG_PTR)fakeHandle + 1);
201 return symbolProvider;
210 PLIST_ENTRY listEntry;
231 listEntry = listEntry->Flink;
250 return STATUS_SUCCESS;
254 _In_ HANDLE hProcess,
255 _In_ ULONG ActionCode,
256 _In_opt_ ULONG64 CallbackData,
257 _In_opt_ ULONG64 UserContext
262 PIMAGEHLP_DEFERRED_SYMBOL_LOADW64 callbackData;
276 data->
Type = ActionCode;
280 callbackData = (PIMAGEHLP_DEFERRED_SYMBOL_LOADW64)CallbackData;
282 data->
CheckSum = callbackData->CheckSum;
283 data->
TimeStamp = callbackData->TimeDateStamp;
322 SymbolProvider->IsRegistered =
TRUE;
346 return uint64cmp(symbolModule1->BaseAddress, symbolModule2->BaseAddress);
351 _In_ ULONG64 Address,
353 _Out_opt_ PULONG Displacement,
357 IMAGEHLP_LINEW64 line;
367 line.SizeOfStruct =
sizeof(IMAGEHLP_LINEW64);
374 SymbolProvider->ProcessHandle,
385 IMAGEHLP_LINE64 lineA;
387 lineA.SizeOfStruct =
sizeof(IMAGEHLP_LINE64);
390 SymbolProvider->ProcessHandle,
399 line.LineNumber = lineA.LineNumber;
400 line.Address = lineA.Address;
409 *FileName = fileName;
412 *Displacement = displacement;
416 Information->LineNumber = line.LineNumber;
417 Information->Address = line.Address;
425 _In_ ULONG64 Address,
434 ULONG64 foundBaseAddress;
437 foundFileName = NULL;
438 foundBaseAddress = 0;
442 lookupModule.BaseAddress = Address;
478 if (module && Address < module->BaseAddress + module->Size)
481 foundBaseAddress = module->BaseAddress;
490 *FileName = foundFileName;
498 return foundBaseAddress;
502 _Out_ PSYMBOL_INFOW SymbolInfoW,
503 _In_ PSYMBOL_INFO SymbolInfoA
506 SymbolInfoW->TypeIndex = SymbolInfoA->TypeIndex;
507 SymbolInfoW->Index = SymbolInfoA->Index;
508 SymbolInfoW->Size = SymbolInfoA->Size;
509 SymbolInfoW->ModBase = SymbolInfoA->ModBase;
510 SymbolInfoW->Flags = SymbolInfoA->Flags;
511 SymbolInfoW->Value = SymbolInfoA->Value;
512 SymbolInfoW->Address = SymbolInfoA->Address;
513 SymbolInfoW->Register = SymbolInfoA->Register;
514 SymbolInfoW->Scope = SymbolInfoA->Scope;
515 SymbolInfoW->Tag = SymbolInfoA->Tag;
516 SymbolInfoW->NameLen = 0;
518 if (SymbolInfoA->NameLen != 0 && SymbolInfoW->MaxNameLen != 0)
522 copyCount = min(SymbolInfoA->NameLen, SymbolInfoW->MaxNameLen - 1);
528 SymbolInfoW->MaxNameLen,
532 SymbolInfoW->NameLen = copyCount;
539 _In_ ULONG64 Address,
543 _Out_opt_ PULONG64 Displacement
546 PSYMBOL_INFOW symbolInfo;
550 ULONG64 displacement;
559 if (FileName) *FileName = NULL;
560 if (SymbolName) *SymbolName = NULL;
561 if (Displacement) *Displacement = 0;
572 memset(symbolInfo, 0,
sizeof(SYMBOL_INFOW));
573 symbolInfo->SizeOfStruct =
sizeof(SYMBOL_INFOW);
589 SymbolProvider->ProcessHandle,
594 nameLength = symbolInfo->NameLen;
599 symbolInfo = PhAllocate(FIELD_OFFSET(SYMBOL_INFOW, Name) + nameLength * 2 + 2);
600 memset(symbolInfo, 0,
sizeof(SYMBOL_INFOW));
601 symbolInfo->SizeOfStruct =
sizeof(SYMBOL_INFOW);
602 symbolInfo->MaxNameLen = nameLength + 1;
605 SymbolProvider->ProcessHandle,
614 PSYMBOL_INFO symbolInfoA;
617 memset(symbolInfoA, 0,
sizeof(SYMBOL_INFO));
618 symbolInfoA->SizeOfStruct =
sizeof(SYMBOL_INFO);
622 SymbolProvider->ProcessHandle,
627 nameLength = symbolInfoA->NameLen;
632 symbolInfoA = PhAllocate(FIELD_OFFSET(SYMBOL_INFO, Name) + nameLength + 1);
633 memset(symbolInfoA, 0,
sizeof(SYMBOL_INFO));
634 symbolInfoA->SizeOfStruct =
sizeof(SYMBOL_INFO);
635 symbolInfoA->MaxNameLen = nameLength + 1;
638 SymbolProvider->ProcessHandle,
646 symbolInfo = PhAllocate(FIELD_OFFSET(SYMBOL_INFOW, Name) + nameLength * 2 + 2);
647 memset(symbolInfo, 0,
sizeof(SYMBOL_INFOW));
648 symbolInfo->SizeOfStruct =
sizeof(SYMBOL_INFOW);
649 symbolInfo->MaxNameLen = nameLength + 1;
660 if (symbolInfo->ModBase == 0)
674 lookupSymbolModule.BaseAddress = symbolInfo->ModBase;
705 if (symbolInfo->NameLen == 0)
725 if (displacement == 0)
751 *ResolveLevel = resolveLevel;
757 *Displacement = displacement;
773 PSYMBOL_INFOW symbolInfo;
782 symbolInfo = (PSYMBOL_INFOW)symbolInfoBuffer;
783 memset(symbolInfo, 0,
sizeof(SYMBOL_INFOW));
784 symbolInfo->SizeOfStruct =
sizeof(SYMBOL_INFOW);
794 SymbolProvider->ProcessHandle,
802 PSYMBOL_INFO symbolInfoA;
805 symbolInfoA = (PSYMBOL_INFO)buffer;
806 memset(symbolInfoA, 0,
sizeof(SYMBOL_INFO));
807 symbolInfoA->SizeOfStruct =
sizeof(SYMBOL_INFO);
813 SymbolProvider->ProcessHandle,
833 Information->Address = symbolInfo->Address;
834 Information->ModuleBase = symbolInfo->ModBase;
835 Information->Index = symbolInfo->Index;
836 Information->Size = symbolInfo->Size;
844 _In_ ULONG64 BaseAddress,
862 lookupSymbolModule.BaseAddress = BaseAddress;
874 SymbolProvider->ProcessHandle,
890 SymbolProvider->ProcessHandle,
907 lookupSymbolModule.BaseAddress = BaseAddress;
913 symbolModule->BaseAddress = BaseAddress;
914 symbolModule->Size =
Size;
915 symbolModule->FileName =
PhGetFullPath(FileName, &symbolModule->BaseNameIndex);
918 assert(!existingLinks);
919 InsertTailList(&SymbolProvider->ModulesListHead, &symbolModule->ListEntry);
926 if (GetLastError() != ERROR_SUCCESS)
987 NTSTATUS PhpLookupDynamicFunctionTable(
988 _In_ HANDLE ProcessHandle,
989 _In_ ULONG64 Address,
990 _Out_opt_ PDYNAMIC_FUNCTION_TABLE *FunctionTableAddress,
991 _Out_opt_ PDYNAMIC_FUNCTION_TABLE FunctionTable,
992 _Out_writes_bytes_opt_(OutOfProcessCallbackDllBufferSize) PWCHAR OutOfProcessCallbackDllBuffer,
993 _In_ ULONG OutOfProcessCallbackDllBufferSize,
998 PLIST_ENTRY (NTAPI *rtlGetFunctionTableListHead)(
VOID);
999 PLIST_ENTRY tableListHead;
1000 LIST_ENTRY tableListHeadEntry;
1001 PLIST_ENTRY tableListEntry;
1002 PDYNAMIC_FUNCTION_TABLE functionTableAddress;
1003 DYNAMIC_FUNCTION_TABLE functionTable;
1005 SIZE_T numberOfBytesRead;
1011 if (!rtlGetFunctionTableListHead)
1012 return STATUS_PROCEDURE_NOT_FOUND;
1014 tableListHead = rtlGetFunctionTableListHead();
1021 &tableListHeadEntry,
1027 tableListEntry = tableListHeadEntry.Flink;
1032 functionTableAddress = CONTAINING_RECORD(tableListEntry, DYNAMIC_FUNCTION_TABLE, ListEntry);
1036 functionTableAddress,
1038 sizeof(DYNAMIC_FUNCTION_TABLE),
1043 if (Address >= functionTable.MinimumAddress && Address < functionTable.MaximumAddress)
1045 if (OutOfProcessCallbackDllBuffer)
1047 if (functionTable.OutOfProcessCallbackDll)
1052 memset(OutOfProcessCallbackDllBuffer, 0xff, OutOfProcessCallbackDllBufferSize);
1055 functionTable.OutOfProcessCallbackDll,
1056 OutOfProcessCallbackDllBuffer,
1057 OutOfProcessCallbackDllBufferSize,
1061 if (status != STATUS_PARTIAL_COPY && !
NT_SUCCESS(status))
1066 for (i = 0; i < OutOfProcessCallbackDllBufferSize /
sizeof(WCHAR); i++)
1068 if (OutOfProcessCallbackDllBuffer[i] == 0)
1072 if (OutOfProcessCallbackDllString)
1074 OutOfProcessCallbackDllString->Buffer = OutOfProcessCallbackDllBuffer;
1075 OutOfProcessCallbackDllString->Length = (USHORT)(i *
sizeof(WCHAR));
1076 OutOfProcessCallbackDllString->MaximumLength = OutOfProcessCallbackDllString->Length;
1086 return STATUS_BUFFER_OVERFLOW;
1090 OutOfProcessCallbackDllBuffer[0] = 0;
1092 if (OutOfProcessCallbackDllString)
1094 OutOfProcessCallbackDllString->Buffer = NULL;
1095 OutOfProcessCallbackDllString->Length = 0;
1096 OutOfProcessCallbackDllString->MaximumLength = 0;
1101 if (FunctionTableAddress)
1102 *FunctionTableAddress = functionTableAddress;
1105 *FunctionTable = functionTable;
1107 return STATUS_SUCCESS;
1110 tableListEntry = functionTable.ListEntry.Flink;
1114 return STATUS_NOT_FOUND;
1117 PRUNTIME_FUNCTION PhpLookupFunctionEntry(
1118 _In_ PRUNTIME_FUNCTION Functions,
1119 _In_ ULONG NumberOfFunctions,
1120 _In_ BOOLEAN Sorted,
1121 _In_ ULONG64 RelativeControlPc
1130 if (NumberOfFunctions == 0)
1134 high = NumberOfFunctions - 1;
1138 i = (low + high) / 2;
1140 if (RelativeControlPc < Functions[i].BeginAddress)
1142 else if (RelativeControlPc >= Functions[i].EndAddress)
1145 return &Functions[i];
1146 }
while (low <= high);
1150 for (i = 0; i < NumberOfFunctions; i++)
1152 if (RelativeControlPc >= Functions[i].BeginAddress && RelativeControlPc < Functions[i].EndAddress)
1153 return &Functions[i];
1160 NTSTATUS PhpAccessCallbackFunctionTable(
1161 _In_ HANDLE ProcessHandle,
1162 _In_ PVOID FunctionTableAddress,
1164 _Out_ PRUNTIME_FUNCTION *Functions,
1165 _Out_ PULONG NumberOfFunctions
1168 static PH_STRINGREF knownFunctionTableDllsKeyName =
PH_STRINGREF_INIT(L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\KnownFunctionTableDlls");
1174 ANSI_STRING outOfProcessFunctionTableCallbackName;
1175 POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK outOfProcessFunctionTableCallback;
1177 if (!OutOfProcessCallbackDllString->Buffer)
1178 return STATUS_INVALID_PARAMETER;
1186 &knownFunctionTableDllsKeyName,
1194 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1195 return STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT;
1197 status = LdrLoadDll(NULL, NULL, OutOfProcessCallbackDllString, &dllHandle);
1202 RtlInitAnsiString(&outOfProcessFunctionTableCallbackName, OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME);
1203 status = LdrGetProcedureAddress(dllHandle, &outOfProcessFunctionTableCallbackName, 0, (PVOID *)&outOfProcessFunctionTableCallback);
1207 status = outOfProcessFunctionTableCallback(
1209 FunctionTableAddress,
1215 LdrUnloadDll(dllHandle);
1220 NTSTATUS PhpAccessNormalFunctionTable(
1221 _In_ HANDLE ProcessHandle,
1222 _In_ PDYNAMIC_FUNCTION_TABLE FunctionTable,
1223 _Out_ PRUNTIME_FUNCTION *Functions,
1224 _Out_ PULONG NumberOfFunctions
1229 PRUNTIME_FUNCTION functions;
1232 if (FunctionTable->EntryCount > 0x100000)
1233 return STATUS_BUFFER_OVERFLOW;
1235 bufferSize = FunctionTable->EntryCount *
sizeof(RUNTIME_FUNCTION);
1239 return STATUS_NO_MEMORY;
1241 status =
PhReadVirtualMemory(ProcessHandle, FunctionTable->FunctionTable, functions, bufferSize, NULL);
1245 *Functions = functions;
1246 *NumberOfFunctions = FunctionTable->EntryCount;
1256 NTSTATUS PhAccessOutOfProcessFunctionEntry(
1257 _In_ HANDLE ProcessHandle,
1258 _In_ ULONG64 ControlPc,
1259 _Out_ PRUNTIME_FUNCTION Function
1263 PDYNAMIC_FUNCTION_TABLE functionTableAddress;
1264 DYNAMIC_FUNCTION_TABLE functionTable;
1265 WCHAR outOfProcessCallbackDll[512];
1267 PRUNTIME_FUNCTION functions;
1268 ULONG numberOfFunctions;
1269 PRUNTIME_FUNCTION
function;
1271 if (!
NT_SUCCESS(status = PhpLookupDynamicFunctionTable(
1274 &functionTableAddress,
1276 outOfProcessCallbackDll,
1277 sizeof(outOfProcessCallbackDll),
1278 &outOfProcessCallbackDllString
1284 if (functionTable.Type == RF_CALLBACK)
1286 if (!
NT_SUCCESS(status = PhpAccessCallbackFunctionTable(
1288 functionTableAddress,
1289 &outOfProcessCallbackDllString,
1297 function = PhpLookupFunctionEntry(functions, numberOfFunctions,
FALSE, ControlPc - functionTable.BaseAddress);
1300 *Function = *
function;
1302 status = STATUS_NOT_FOUND;
1308 if (!
NT_SUCCESS(status = PhpAccessNormalFunctionTable(
1318 function = PhpLookupFunctionEntry(functions, numberOfFunctions, functionTable.Type == RF_SORTED, ControlPc - functionTable.BaseAddress);
1321 *Function = *
function;
1323 status = STATUS_NOT_FOUND;
1334 _In_ HANDLE hProcess,
1340 DYNAMIC_FUNCTION_TABLE functionTable;
1344 if (
NT_SUCCESS(PhpLookupDynamicFunctionTable(
1354 base = functionTable.BaseAddress;
1371 _In_ HANDLE hProcess,
1372 _In_ DWORD64 AddrBase
1376 static RUNTIME_FUNCTION lastRuntimeFunction;
1382 if (
NT_SUCCESS(PhAccessOutOfProcessFunctionEntry(hProcess, AddrBase, &lastRuntimeFunction)))
1383 entry = &lastRuntimeFunction;
1397 _In_ ULONG MachineType,
1398 _In_ HANDLE ProcessHandle,
1399 _In_ HANDLE ThreadHandle,
1401 _Inout_ PVOID ContextRecord,
1416 if (!FunctionTableAccessRoutine)
1418 if (MachineType == IMAGE_FILE_MACHINE_AMD64)
1424 if (!GetModuleBaseRoutine)
1426 if (MachineType == IMAGE_FILE_MACHINE_AMD64)
1440 FunctionTableAccessRoutine,
1441 GetModuleBaseRoutine,
1450 _In_ HANDLE ProcessHandle,
1452 _In_ HANDLE FileHandle,
1463 SetLastError(ERROR_PROC_NOT_FOUND);
1489 _In_ STACKFRAME64 *StackFrame64,
1496 ThreadStackFrame->PcAddress = (PVOID)StackFrame64->AddrPC.Offset;
1497 ThreadStackFrame->ReturnAddress = (PVOID)StackFrame64->AddrReturn.Offset;
1498 ThreadStackFrame->FrameAddress = (PVOID)StackFrame64->AddrFrame.Offset;
1499 ThreadStackFrame->StackAddress = (PVOID)StackFrame64->AddrStack.Offset;
1500 ThreadStackFrame->BStoreAddress = (PVOID)StackFrame64->AddrBStore.Offset;
1502 for (i = 0; i < 4; i++)
1503 ThreadStackFrame->Params[i] = (PVOID)StackFrame64->Params[i];
1505 ThreadStackFrame->Flags = Flags;
1507 if (StackFrame64->FuncTableEntry)
1539 _In_ HANDLE ThreadHandle,
1540 _In_opt_ HANDLE ProcessHandle,
1545 _In_opt_ PVOID Context
1548 NTSTATUS status = STATUS_SUCCESS;
1549 BOOLEAN suspended =
FALSE;
1550 BOOLEAN processOpened =
FALSE;
1551 BOOLEAN isCurrentThread =
FALSE;
1552 BOOLEAN isSystemProcess =
FALSE;
1572 ClientId->UniqueProcess
1577 processOpened =
TRUE;
1583 if (ClientId->UniqueThread == NtCurrentTeb()->ClientId.UniqueThread)
1584 isCurrentThread =
TRUE;
1586 isSystemProcess =
TRUE;
1590 if (ThreadHandle == NtCurrentThread())
1592 isCurrentThread =
TRUE;
1597 isCurrentThread =
TRUE;
1599 isSystemProcess =
TRUE;
1605 if (!isCurrentThread && !isSystemProcess)
1607 if (
NT_SUCCESS(NtSuspendThread(ThreadHandle, NULL)))
1614 PVOID stack[62 - 1];
1615 ULONG capturedFrames;
1621 sizeof(stack) /
sizeof(PVOID),
1631 for (i = 0; i < capturedFrames; i++)
1636 if (!Callback(&threadStackFrame, Context))
1647 STACKFRAME64 stackFrame;
1651 context.ContextFlags = CONTEXT_ALL;
1657 goto SkipAmd64Stack;
1659 memset(&stackFrame, 0,
sizeof(STACKFRAME64));
1660 stackFrame.AddrPC.Mode = AddrModeFlat;
1661 stackFrame.AddrPC.Offset = context.Rip;
1662 stackFrame.AddrStack.Mode = AddrModeFlat;
1663 stackFrame.AddrStack.Offset = context.Rsp;
1664 stackFrame.AddrFrame.Mode = AddrModeFlat;
1665 stackFrame.AddrFrame.Offset = context.Rbp;
1670 IMAGE_FILE_MACHINE_AMD64,
1684 if (!stackFrame.AddrPC.Offset || stackFrame.AddrPC.Offset == -1)
1691 if (!Callback(&threadStackFrame, Context))
1702 STACKFRAME64 stackFrame;
1707 context.ContextFlags = CONTEXT_ALL;
1715 WOW64_CONTEXT context;
1717 context.ContextFlags = WOW64_CONTEXT_ALL;
1719 if (!
NT_SUCCESS(status = NtQueryInformationThread(
1723 sizeof(WOW64_CONTEXT),
1729 memset(&stackFrame, 0,
sizeof(STACKFRAME64));
1730 stackFrame.AddrPC.Mode = AddrModeFlat;
1731 stackFrame.AddrPC.Offset = context.Eip;
1732 stackFrame.AddrStack.Mode = AddrModeFlat;
1733 stackFrame.AddrStack.Offset = context.Esp;
1734 stackFrame.AddrFrame.Mode = AddrModeFlat;
1735 stackFrame.AddrFrame.Offset = context.Ebp;
1740 IMAGE_FILE_MACHINE_I386,
1754 if (!stackFrame.AddrPC.Offset || stackFrame.AddrPC.Offset == -1)
1761 if (!Callback(&threadStackFrame, Context))
1765 context.Eip = PtrToUlong(threadStackFrame.
PcAddress);
1766 stackFrame.AddrPC.Offset = PtrToUlong(threadStackFrame.
PcAddress);
1767 context.Ebp = PtrToUlong(threadStackFrame.
FrameAddress);
1768 stackFrame.AddrFrame.Offset = PtrToUlong(threadStackFrame.
FrameAddress);
1769 context.Esp = PtrToUlong(threadStackFrame.
StackAddress);
1770 stackFrame.AddrStack.Offset = PtrToUlong(threadStackFrame.
StackAddress);
1778 NtResumeThread(ThreadHandle, NULL);
1781 NtClose(ProcessHandle);