/* @implemented */ VOID NTAPI RtlFreeUserThreadStack(HANDLE ProcessHandle, HANDLE ThreadHandle) { NTSTATUS Status; THREAD_BASIC_INFORMATION ThreadBasicInfo; SIZE_T Dummy, Size = 0; PVOID StackLocation; /* Query the Basic Info */ Status = NtQueryInformationThread(ThreadHandle, ThreadBasicInformation, &ThreadBasicInfo, sizeof(THREAD_BASIC_INFORMATION), NULL); if (!NT_SUCCESS(Status) || !ThreadBasicInfo.TebBaseAddress) return; /* Get the deallocation stack */ Status = NtReadVirtualMemory(ProcessHandle, &((PTEB)ThreadBasicInfo.TebBaseAddress)-> DeallocationStack, &StackLocation, sizeof(PVOID), &Dummy); if (!NT_SUCCESS(Status) || !StackLocation) return; /* Free it */ NtFreeVirtualMemory(ProcessHandle, &StackLocation, &Size, MEM_RELEASE); }
void CheckProcessMemory() { UINT_PTR i,j,flag,addr; DWORD len; CLIENT_ID id; OBJECT_ATTRIBUTES oa={0}; HANDLE hProc; BYTE buffer[8]; AcquireLock(); id.UniqueThread=0; oa.uLength=sizeof(oa); for (i=0;i<count;i++) { id.UniqueProcess=(proc_record[i]&0xFFF)<<2; addr=proc_record[i]&~0xFFF; flag=0; if (NT_SUCCESS(NtOpenProcess(&hProc,PROCESS_VM_OPERATION|PROCESS_VM_READ,&oa,&id))) { if (NT_SUCCESS(NtReadVirtualMemory(hProc,(PVOID)addr,buffer,8,&len))) if (memcmp(buffer,normal_routine,4)==0) flag=1; NtClose(hProc); } if (flag==0) { for (j=i;j<count;j++) proc_record[j]=proc_record[j+1]; count--; i--; } } ReleaseLock(); }
VOID RtlFreeUserThreadStack( HANDLE hProcess, HANDLE hThread ) { NTSTATUS Status; PTEB Teb; THREAD_BASIC_INFORMATION ThreadInfo; PVOID StackDeallocationBase; SIZE_T Size; Status = NtQueryInformationThread (hThread, ThreadBasicInformation, &ThreadInfo, sizeof (ThreadInfo), NULL); Teb = ThreadInfo.TebBaseAddress; if (!NT_SUCCESS (Status) || !Teb) { return; } Status = NtReadVirtualMemory (hProcess, &Teb->DeallocationStack, &StackDeallocationBase, sizeof (StackDeallocationBase), NULL); if (!NT_SUCCESS (Status) || !StackDeallocationBase) { return; } Size = 0; NtFreeVirtualMemory (hProcess, &StackDeallocationBase, &Size, MEM_RELEASE); return; }
NTSTATUS WINAPI SafeNtReadVirtualMemory( HANDLE ProcessHandle, PVOID BaseAddress, PVOID Buffer, ULONG NumberOfBytesToRead, PULONG NumberOfBytesReaded ) { NTSTATUS rc; /*if (CheckOldFunction(&OldNtReadVirtualMemory)) rc=OldNtReadVirtualMemory(ProcessHandle,BaseAddress,Buffer,NumberOfBytesToRead,NumberOfBytesReaded); else*/ rc=NtReadVirtualMemory(ProcessHandle,BaseAddress,Buffer,NumberOfBytesToRead,NumberOfBytesReaded); return rc; }
NTSTATUS PhpGetProcessSystemDllInitBlock( _In_ HANDLE ProcessHandle, _Out_ PPS_SYSTEM_DLL_INIT_BLOCK *SystemDllInitBlock ) { NTSTATUS status; PPS_SYSTEM_DLL_INIT_BLOCK ldrInitBlock = NULL; PVOID ldrInitBlockBaseAddress = NULL; PPH_STRING ntdllFileName; ldrInitBlock = PhAllocate(sizeof(PS_SYSTEM_DLL_INIT_BLOCK)); memset(ldrInitBlock, 0, sizeof(PS_SYSTEM_DLL_INIT_BLOCK)); ntdllFileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\System32\\ntdll.dll"); status = PhGetProcedureAddressRemote( ProcessHandle, ntdllFileName->Buffer, "LdrSystemDllInitBlock", 0, &ldrInitBlockBaseAddress, NULL ); PhDereferenceObject(ntdllFileName); if (NT_SUCCESS(status) && ldrInitBlockBaseAddress) { status = NtReadVirtualMemory( ProcessHandle, ldrInitBlockBaseAddress, ldrInitBlock, sizeof(PS_SYSTEM_DLL_INIT_BLOCK), NULL ); } if (NT_SUCCESS(status)) { *SystemDllInitBlock = ldrInitBlock; } return status; }
NTSTATUS PhGetThreadServiceTag( _In_ HANDLE ThreadHandle, _In_opt_ HANDLE ProcessHandle, _Out_ PVOID *ServiceTag ) { NTSTATUS status; THREAD_BASIC_INFORMATION basicInfo; BOOLEAN openedProcessHandle = FALSE; if (!NT_SUCCESS(status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo))) return status; if (!ProcessHandle) { if (!NT_SUCCESS(status = PhOpenThreadProcess( ThreadHandle, PROCESS_VM_READ, &ProcessHandle ))) return status; openedProcessHandle = TRUE; } status = NtReadVirtualMemory( ProcessHandle, PTR_ADD_OFFSET(basicInfo.TebBaseAddress, FIELD_OFFSET(TEB, SubProcessTag)), ServiceTag, sizeof(PVOID), NULL ); if (openedProcessHandle) NtClose(ProcessHandle); return status; }
NTSTATUS NTAPI ConSrvConnect(IN PCSR_PROCESS CsrProcess, IN OUT PVOID ConnectionInfo, IN OUT PULONG ConnectionInfoLength) { /************************************************************************** * This function is called whenever a CUI new process is created. **************************************************************************/ NTSTATUS Status = STATUS_SUCCESS; PCONSRV_API_CONNECTINFO ConnectInfo = (PCONSRV_API_CONNECTINFO)ConnectionInfo; PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess); if ( ConnectionInfo == NULL || ConnectionInfoLength == NULL || *ConnectionInfoLength != sizeof(*ConnectInfo) ) { DPRINT1("CONSRV: Connection failed - ConnectionInfo = 0x%p ; ConnectionInfoLength = 0x%p (%lu), expected %lu\n", ConnectionInfo, ConnectionInfoLength, ConnectionInfoLength ? *ConnectionInfoLength : (ULONG)-1, sizeof(*ConnectInfo)); return STATUS_UNSUCCESSFUL; } /* If we don't need a console, then get out of here */ DPRINT("ConnectInfo->IsConsoleApp = %s\n", ConnectInfo->IsConsoleApp ? "True" : "False"); if (!ConnectInfo->IsConsoleApp) return STATUS_SUCCESS; /* If we don't inherit from an existing console, then create a new one... */ if (ConnectInfo->ConsoleStartInfo.ConsoleHandle == NULL) { CONSOLE_INIT_INFO ConsoleInitInfo; DPRINT("ConSrvConnect - Allocate a new console\n"); /* Initialize the console initialization info structure */ ConsoleInitInfo.ConsoleStartInfo = &ConnectInfo->ConsoleStartInfo; ConsoleInitInfo.IsWindowVisible = ConnectInfo->IsWindowVisible; ConsoleInitInfo.TitleLength = ConnectInfo->TitleLength; ConsoleInitInfo.ConsoleTitle = ConnectInfo->ConsoleTitle; ConsoleInitInfo.DesktopLength = 0; ConsoleInitInfo.Desktop = NULL; ConsoleInitInfo.AppNameLength = ConnectInfo->AppNameLength; ConsoleInitInfo.AppName = ConnectInfo->AppName; ConsoleInitInfo.CurDirLength = ConnectInfo->CurDirLength; ConsoleInitInfo.CurDir = ConnectInfo->CurDir; /* * Contrary to the case of SrvAllocConsole, the desktop string is * allocated in the process' heap, so we need to retrieve it by * using NtReadVirtualMemory. */ if (ConnectInfo->DesktopLength) { ConsoleInitInfo.DesktopLength = ConnectInfo->DesktopLength; ConsoleInitInfo.Desktop = ConsoleAllocHeap(HEAP_ZERO_MEMORY, ConsoleInitInfo.DesktopLength); if (ConsoleInitInfo.Desktop == NULL) return STATUS_NO_MEMORY; Status = NtReadVirtualMemory(ProcessData->Process->ProcessHandle, ConnectInfo->Desktop, ConsoleInitInfo.Desktop, ConsoleInitInfo.DesktopLength, NULL); if (!NT_SUCCESS(Status)) { ConsoleFreeHeap(ConsoleInitInfo.Desktop); return Status; } } /* * We are about to create a new console. However when ConSrvNewProcess * was called, we didn't know that we wanted to create a new console and * therefore, we by default inherited the handles table from our parent * process. It's only now that we notice that in fact we do not need * them, because we've created a new console and thus we must use it. * * ConSrvAllocateConsole will free our old handles table * and recreate a new valid one. */ /* Initialize a new Console owned by the Console Leader Process */ Status = ConSrvAllocateConsole(ProcessData, &ConnectInfo->ConsoleStartInfo.InputHandle, &ConnectInfo->ConsoleStartInfo.OutputHandle, &ConnectInfo->ConsoleStartInfo.ErrorHandle, &ConsoleInitInfo); /* Free our local desktop string if any */ if (ConsoleInitInfo.DesktopLength) ConsoleFreeHeap(ConsoleInitInfo.Desktop); /* Check for success */ if (!NT_SUCCESS(Status)) { DPRINT1("Console allocation failed\n"); return Status; } } else /* We inherit it from the parent */ { DPRINT("ConSrvConnect - Reuse current (parent's) console\n"); /* Reuse our current console */ Status = ConSrvInheritConsole(ProcessData, ConnectInfo->ConsoleStartInfo.ConsoleHandle, FALSE, NULL, // &ConnectInfo->ConsoleStartInfo.InputHandle, NULL, // &ConnectInfo->ConsoleStartInfo.OutputHandle, NULL, // &ConnectInfo->ConsoleStartInfo.ErrorHandle, &ConnectInfo->ConsoleStartInfo); if (!NT_SUCCESS(Status)) { DPRINT1("Console inheritance failed\n"); return Status; } } /* Set the Property-Dialog and Control-Dispatcher handlers */ ProcessData->PropRoutine = ConnectInfo->PropRoutine; ProcessData->CtrlRoutine = ConnectInfo->CtrlRoutine; return STATUS_SUCCESS; }
INT_PTR CALLBACK PhpProcessMemoryDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { LPPROPSHEETPAGE propSheetPage; PPH_PROCESS_PROPPAGECONTEXT propPageContext; PPH_PROCESS_ITEM processItem; PPH_MEMORY_CONTEXT memoryContext; HWND tnHandle; if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) { memoryContext = (PPH_MEMORY_CONTEXT)propPageContext->Context; if (memoryContext) tnHandle = memoryContext->ListContext.TreeNewHandle; } else { return FALSE; } switch (uMsg) { case WM_INITDIALOG: { memoryContext = propPageContext->Context = PhAllocate(PhEmGetObjectSize(EmMemoryContextType, sizeof(PH_MEMORY_CONTEXT))); memset(memoryContext, 0, sizeof(PH_MEMORY_CONTEXT)); memoryContext->ProcessId = processItem->ProcessId; // Initialize the list. tnHandle = GetDlgItem(hwndDlg, IDC_LIST); BringWindowToTop(tnHandle); PhInitializeMemoryList(hwndDlg, tnHandle, &memoryContext->ListContext); TreeNew_SetEmptyText(tnHandle, &PhpLoadingText, 0); memoryContext->LastRunStatus = -1; memoryContext->ErrorMessage = NULL; PhEmCallObjectOperation(EmMemoryContextType, memoryContext, EmObjectCreate); if (PhPluginsEnabled) { PH_PLUGIN_TREENEW_INFORMATION treeNewInfo; treeNewInfo.TreeNewHandle = tnHandle; treeNewInfo.CmData = &memoryContext->ListContext.Cm; treeNewInfo.SystemContext = memoryContext; PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMemoryTreeNewInitializing), &treeNewInfo); } PhLoadSettingsMemoryList(&memoryContext->ListContext); PhSetOptionsMemoryList(&memoryContext->ListContext, TRUE); Button_SetCheck(GetDlgItem(hwndDlg, IDC_HIDEFREEREGIONS), memoryContext->ListContext.HideFreeRegions ? BST_CHECKED : BST_UNCHECKED); PhpRefreshProcessMemoryList(hwndDlg, propPageContext); } break; case WM_DESTROY: { PhEmCallObjectOperation(EmMemoryContextType, memoryContext, EmObjectDelete); if (PhPluginsEnabled) { PH_PLUGIN_TREENEW_INFORMATION treeNewInfo; treeNewInfo.TreeNewHandle = tnHandle; treeNewInfo.CmData = &memoryContext->ListContext.Cm; PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMemoryTreeNewUninitializing), &treeNewInfo); } PhSaveSettingsMemoryList(&memoryContext->ListContext); PhDeleteMemoryList(&memoryContext->ListContext); if (memoryContext->MemoryItemListValid) PhDeleteMemoryItemList(&memoryContext->MemoryItemList); PhClearReference(&memoryContext->ErrorMessage); PhFree(memoryContext); PhpPropPageDlgProcDestroy(hwndDlg); } break; case WM_SHOWWINDOW: { if (!propPageContext->LayoutInitialized) { PPH_LAYOUT_ITEM dialogItem; dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_STRINGS), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_REFRESH), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddPropPageLayoutItem(hwndDlg, memoryContext->ListContext.TreeNewHandle, dialogItem, PH_ANCHOR_ALL); PhDoPropPageLayout(hwndDlg); propPageContext->LayoutInitialized = TRUE; } } break; case WM_COMMAND: { switch (LOWORD(wParam)) { case ID_SHOWCONTEXTMENU: { PhShowMemoryContextMenu(hwndDlg, processItem, memoryContext, (PPH_TREENEW_CONTEXT_MENU)lParam); } break; case ID_MEMORY_READWRITEMEMORY: { PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext); if (memoryNode && !memoryNode->IsAllocationBase) { if (memoryNode->MemoryItem->State & MEM_COMMIT) { PPH_SHOWMEMORYEDITOR showMemoryEditor = PhAllocate(sizeof(PH_SHOWMEMORYEDITOR)); memset(showMemoryEditor, 0, sizeof(PH_SHOWMEMORYEDITOR)); showMemoryEditor->ProcessId = processItem->ProcessId; showMemoryEditor->BaseAddress = memoryNode->MemoryItem->BaseAddress; showMemoryEditor->RegionSize = memoryNode->MemoryItem->RegionSize; showMemoryEditor->SelectOffset = -1; showMemoryEditor->SelectLength = 0; ProcessHacker_ShowMemoryEditor(PhMainWndHandle, showMemoryEditor); } else { PhShowError(hwndDlg, L"Unable to edit the memory region because it is not committed."); } } } break; case ID_MEMORY_SAVE: { NTSTATUS status; HANDLE processHandle; PPH_MEMORY_NODE *memoryNodes; ULONG numberOfMemoryNodes; if (!NT_SUCCESS(status = PhOpenProcess( &processHandle, PROCESS_VM_READ, processItem->ProcessId ))) { PhShowStatus(hwndDlg, L"Unable to open the process", status, 0); break; } PhGetSelectedMemoryNodes(&memoryContext->ListContext, &memoryNodes, &numberOfMemoryNodes); if (numberOfMemoryNodes != 0) { static PH_FILETYPE_FILTER filters[] = { { L"Binary files (*.bin)", L"*.bin" }, { L"All files (*.*)", L"*.*" } }; PVOID fileDialog; fileDialog = PhCreateSaveFileDialog(); PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); PhSetFileDialogFileName(fileDialog, PhaConcatStrings2(processItem->ProcessName->Buffer, L".bin")->Buffer); if (PhShowFileDialog(hwndDlg, fileDialog)) { PPH_STRING fileName; PPH_FILE_STREAM fileStream; PVOID buffer; ULONG i; ULONG_PTR offset; fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); if (NT_SUCCESS(status = PhCreateFileStream( &fileStream, fileName->Buffer, FILE_GENERIC_WRITE, FILE_SHARE_READ, FILE_OVERWRITE_IF, 0 ))) { buffer = PhAllocatePage(PAGE_SIZE, NULL); // Go through each selected memory item and append the region contents // to the file. for (i = 0; i < numberOfMemoryNodes; i++) { PPH_MEMORY_NODE memoryNode = memoryNodes[i]; PPH_MEMORY_ITEM memoryItem = memoryNode->MemoryItem; if (!memoryNode->IsAllocationBase && !(memoryItem->State & MEM_COMMIT)) continue; for (offset = 0; offset < memoryItem->RegionSize; offset += PAGE_SIZE) { if (NT_SUCCESS(NtReadVirtualMemory( processHandle, PTR_ADD_OFFSET(memoryItem->BaseAddress, offset), buffer, PAGE_SIZE, NULL ))) { PhWriteFileStream(fileStream, buffer, PAGE_SIZE); } } } PhFreePage(buffer); PhDereferenceObject(fileStream); } if (!NT_SUCCESS(status)) PhShowStatus(hwndDlg, L"Unable to create the file", status, 0); } PhFreeFileDialog(fileDialog); } PhFree(memoryNodes); NtClose(processHandle); } break; case ID_MEMORY_CHANGEPROTECTION: { PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext); if (memoryNode) { PhReferenceObject(memoryNode->MemoryItem); PhShowMemoryProtectDialog(hwndDlg, processItem, memoryNode->MemoryItem); PhUpdateMemoryNode(&memoryContext->ListContext, memoryNode); PhDereferenceObject(memoryNode->MemoryItem); } } break; case ID_MEMORY_FREE: { PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext); if (memoryNode) { PhReferenceObject(memoryNode->MemoryItem); PhUiFreeMemory(hwndDlg, processItem->ProcessId, memoryNode->MemoryItem, TRUE); PhDereferenceObject(memoryNode->MemoryItem); // TODO: somehow update the list } } break; case ID_MEMORY_DECOMMIT: { PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext); if (memoryNode) { PhReferenceObject(memoryNode->MemoryItem); PhUiFreeMemory(hwndDlg, processItem->ProcessId, memoryNode->MemoryItem, FALSE); PhDereferenceObject(memoryNode->MemoryItem); } } break; case ID_MEMORY_READWRITEADDRESS: { PPH_STRING selectedChoice = NULL; if (!memoryContext->MemoryItemListValid) break; while (PhaChoiceDialog( hwndDlg, L"Read/Write Address", L"Enter an address:", NULL, 0, NULL, PH_CHOICE_DIALOG_USER_CHOICE, &selectedChoice, NULL, L"MemoryReadWriteAddressChoices" )) { ULONG64 address64; PVOID address; if (selectedChoice->Length == 0) continue; if (PhStringToInteger64(&selectedChoice->sr, 0, &address64)) { PPH_MEMORY_ITEM memoryItem; address = (PVOID)address64; memoryItem = PhLookupMemoryItemList(&memoryContext->MemoryItemList, address); if (memoryItem) { PPH_SHOWMEMORYEDITOR showMemoryEditor = PhAllocate(sizeof(PH_SHOWMEMORYEDITOR)); memset(showMemoryEditor, 0, sizeof(PH_SHOWMEMORYEDITOR)); showMemoryEditor->ProcessId = processItem->ProcessId; showMemoryEditor->BaseAddress = memoryItem->BaseAddress; showMemoryEditor->RegionSize = memoryItem->RegionSize; showMemoryEditor->SelectOffset = (ULONG)((ULONG_PTR)address - (ULONG_PTR)memoryItem->BaseAddress); showMemoryEditor->SelectLength = 0; ProcessHacker_ShowMemoryEditor(PhMainWndHandle, showMemoryEditor); break; } else { PhShowError(hwndDlg, L"Unable to find the memory region for the selected address."); } } } } break; case ID_MEMORY_COPY: { PPH_STRING text; text = PhGetTreeNewText(tnHandle, 0); PhSetClipboardString(tnHandle, &text->sr); PhDereferenceObject(text); } break; case IDC_HIDEFREEREGIONS: { BOOLEAN hide; hide = Button_GetCheck(GetDlgItem(hwndDlg, IDC_HIDEFREEREGIONS)) == BST_CHECKED; PhSetOptionsMemoryList(&memoryContext->ListContext, hide); } break; case IDC_STRINGS: PhShowMemoryStringDialog(hwndDlg, processItem); break; case IDC_REFRESH: PhpRefreshProcessMemoryList(hwndDlg, propPageContext); break; } } break; } return FALSE; }
/* * Based on lib/epsapi/enum/modules.c by KJK::Hyperion. * */ NTSTATUS NTAPI RtlpQueryRemoteProcessModules(HANDLE ProcessHandle, IN PRTL_PROCESS_MODULES Modules OPTIONAL, IN ULONG Size OPTIONAL, OUT PULONG ReturnedSize) { PROCESS_BASIC_INFORMATION pbiInfo; PPEB_LDR_DATA ppldLdrData; LDR_DATA_TABLE_ENTRY lmModule; PLIST_ENTRY pleListHead; PLIST_ENTRY pleCurEntry; PRTL_PROCESS_MODULE_INFORMATION ModulePtr = NULL; NTSTATUS Status = STATUS_SUCCESS; ULONG UsedSize = sizeof(ULONG); ANSI_STRING AnsiString; PCHAR p; DPRINT("RtlpQueryRemoteProcessModules Start\n"); /* query the process basic information (includes the PEB address) */ Status = NtQueryInformationProcess(ProcessHandle, ProcessBasicInformation, &pbiInfo, sizeof(PROCESS_BASIC_INFORMATION), NULL); if (!NT_SUCCESS(Status)) { /* failure */ DPRINT("NtQueryInformationProcess 1 0x%lx \n", Status); return Status; } if (Modules == NULL || Size == 0) { Status = STATUS_INFO_LENGTH_MISMATCH; } else { Modules->NumberOfModules = 0; ModulePtr = &Modules->Modules[0]; Status = STATUS_SUCCESS; } /* get the address of the PE Loader data */ Status = NtReadVirtualMemory(ProcessHandle, &(pbiInfo.PebBaseAddress->Ldr), &ppldLdrData, sizeof(ppldLdrData), NULL); if (!NT_SUCCESS(Status)) { /* failure */ DPRINT("NtReadVirtualMemory 1 0x%lx \n", Status); return Status; } /* head of the module list: the last element in the list will point to this */ pleListHead = &ppldLdrData->InLoadOrderModuleList; /* get the address of the first element in the list */ Status = NtReadVirtualMemory(ProcessHandle, &(ppldLdrData->InLoadOrderModuleList.Flink), &pleCurEntry, sizeof(pleCurEntry), NULL); if (!NT_SUCCESS(Status)) { /* failure */ DPRINT("NtReadVirtualMemory 2 0x%lx \n", Status); return Status; } while(pleCurEntry != pleListHead) { UNICODE_STRING Unicode; WCHAR Buffer[256 * sizeof(WCHAR)]; /* read the current module */ Status = NtReadVirtualMemory(ProcessHandle, CONTAINING_RECORD(pleCurEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks), &lmModule, sizeof(LDR_DATA_TABLE_ENTRY), NULL); if (!NT_SUCCESS(Status)) { /* failure */ DPRINT( "NtReadVirtualMemory 3 0x%lx \n", Status); return Status; } /* Import module name from remote Process user space. */ Unicode.Length = lmModule.FullDllName.Length; Unicode.MaximumLength = lmModule.FullDllName.MaximumLength; Unicode.Buffer = Buffer; Status = NtReadVirtualMemory(ProcessHandle, lmModule.FullDllName.Buffer, Unicode.Buffer, Unicode.Length, NULL); if (!NT_SUCCESS(Status)) { /* failure */ DPRINT( "NtReadVirtualMemory 3 0x%lx \n", Status); return Status; } DPRINT(" Module %wZ\n", &Unicode); if (UsedSize > Size) { Status = STATUS_INFO_LENGTH_MISMATCH; } else if (Modules != NULL) { ModulePtr->Section = 0; ModulePtr->MappedBase = NULL; // FIXME: ?? ModulePtr->ImageBase = lmModule.DllBase; ModulePtr->ImageSize = lmModule.SizeOfImage; ModulePtr->Flags = lmModule.Flags; ModulePtr->LoadOrderIndex = 0; // FIXME: ?? ModulePtr->InitOrderIndex = 0; // FIXME: ?? ModulePtr->LoadCount = lmModule.LoadCount; AnsiString.Length = 0; AnsiString.MaximumLength = 256; AnsiString.Buffer = ModulePtr->FullPathName; RtlUnicodeStringToAnsiString(&AnsiString, &Unicode, FALSE); p = strrchr(ModulePtr->FullPathName, '\\'); if (p != NULL) ModulePtr->OffsetToFileName = (USHORT)(p - ModulePtr->FullPathName + 1); else ModulePtr->OffsetToFileName = 0; ModulePtr++; Modules->NumberOfModules++; } UsedSize += sizeof(RTL_PROCESS_MODULE_INFORMATION); /* address of the next module in the list */ pleCurEntry = lmModule.InLoadOrderLinks.Flink; } if (ReturnedSize != 0) *ReturnedSize = UsedSize; DPRINT("RtlpQueryRemoteProcessModules End\n"); /* success */ return (STATUS_SUCCESS); }
INT_PTR CALLBACK PhpMemoryEditorDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { PMEMORY_EDITOR_CONTEXT context; if (uMsg != WM_INITDIALOG) { context = GetProp(hwndDlg, PhMakeContextAtom()); } else { context = (PMEMORY_EDITOR_CONTEXT)lParam; SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); } if (!context) return FALSE; switch (uMsg) { case WM_INITDIALOG: { NTSTATUS status; SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); if (context->Title) { SetWindowText(hwndDlg, context->Title->Buffer); } else { PPH_PROCESS_ITEM processItem; if (processItem = PhReferenceProcessItem(context->ProcessId)) { SetWindowText(hwndDlg, PhaFormatString(L"%s (%u) (0x%Ix - 0x%Ix)", processItem->ProcessName->Buffer, HandleToUlong(context->ProcessId), context->BaseAddress, (ULONG_PTR)context->BaseAddress + context->RegionSize)->Buffer); PhDereferenceObject(processItem); } } PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); if (context->RegionSize > 1024 * 1024 * 1024) // 1 GB { PhShowError(context->OwnerHandle, L"Unable to edit the memory region because it is too large."); return TRUE; } if (!NT_SUCCESS(status = PhOpenProcess( &context->ProcessHandle, PROCESS_VM_READ, context->ProcessId ))) { PhShowStatus(context->OwnerHandle, L"Unable to open the process", status, 0); return TRUE; } context->Buffer = PhAllocatePage(context->RegionSize, NULL); if (!context->Buffer) { PhShowError(context->OwnerHandle, L"Unable to allocate memory for the buffer."); return TRUE; } if (!NT_SUCCESS(status = NtReadVirtualMemory( context->ProcessHandle, context->BaseAddress, context->Buffer, context->RegionSize, NULL ))) { PhShowStatus(context->OwnerHandle, L"Unable to read memory", status, 0); return TRUE; } PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_BYTESPERROW), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_GOTO), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_WRITE), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REREAD), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); if (MinimumSize.left == -1) { RECT rect; rect.left = 0; rect.top = 0; rect.right = 290; rect.bottom = 140; MapDialogRect(hwndDlg, &rect); MinimumSize = rect; MinimumSize.left = 0; } context->HexEditHandle = GetDlgItem(hwndDlg, IDC_MEMORY); PhAddLayoutItem(&context->LayoutManager, context->HexEditHandle, NULL, PH_ANCHOR_ALL); HexEdit_SetBuffer(context->HexEditHandle, context->Buffer, (ULONG)context->RegionSize); { PH_RECTANGLE windowRectangle; windowRectangle.Position = PhGetIntegerPairSetting(L"MemEditPosition"); windowRectangle.Size = PhGetScalableIntegerPairSetting(L"MemEditSize", TRUE).Pair; PhAdjustRectangleToWorkingArea(NULL, &windowRectangle); MoveWindow(hwndDlg, windowRectangle.Left, windowRectangle.Top, windowRectangle.Width, windowRectangle.Height, FALSE); // Implement cascading by saving an offsetted rectangle. windowRectangle.Left += 20; windowRectangle.Top += 20; PhSetIntegerPairSetting(L"MemEditPosition", windowRectangle.Position); PhSetScalableIntegerPairSetting2(L"MemEditSize", windowRectangle.Size); } { PWSTR bytesPerRowStrings[7]; ULONG i; ULONG bytesPerRow; for (i = 0; i < sizeof(bytesPerRowStrings) / sizeof(PWSTR); i++) bytesPerRowStrings[i] = PhaFormatString(L"%u bytes per row", 1 << (2 + i))->Buffer; PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_BYTESPERROW), bytesPerRowStrings, sizeof(bytesPerRowStrings) / sizeof(PWSTR)); bytesPerRow = PhGetIntegerSetting(L"MemEditBytesPerRow"); if (bytesPerRow >= 4) { HexEdit_SetBytesPerRow(context->HexEditHandle, bytesPerRow); PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_BYTESPERROW), PhaFormatString(L"%u bytes per row", bytesPerRow)->Buffer, FALSE); } } context->LoadCompleted = TRUE; } break; case WM_DESTROY: { if (context->LoadCompleted) { PhSaveWindowPlacementToSetting(L"MemEditPosition", L"MemEditSize", hwndDlg); PhRemoveElementAvlTree(&PhMemoryEditorSet, &context->Links); PhUnregisterDialog(hwndDlg); } RemoveProp(hwndDlg, PhMakeContextAtom()); PhDeleteLayoutManager(&context->LayoutManager); if (context->Buffer) PhFreePage(context->Buffer); if (context->ProcessHandle) NtClose(context->ProcessHandle); PhClearReference(&context->Title); if ((context->Flags & PH_MEMORY_EDITOR_UNMAP_VIEW_OF_SECTION) && context->ProcessId == NtCurrentProcessId()) NtUnmapViewOfSection(NtCurrentProcess(), context->BaseAddress); PhFree(context); } break; case WM_SHOWWINDOW: { SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->HexEditHandle, TRUE); } break; case WM_COMMAND: { switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: case IDOK: DestroyWindow(hwndDlg); break; case IDC_SAVE: { static PH_FILETYPE_FILTER filters[] = { { L"Binary files (*.bin)", L"*.bin" }, { L"All files (*.*)", L"*.*" } }; PVOID fileDialog; PPH_PROCESS_ITEM processItem; fileDialog = PhCreateSaveFileDialog(); PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); if (!context->Title && (processItem = PhReferenceProcessItem(context->ProcessId))) { PhSetFileDialogFileName(fileDialog, PhaFormatString(L"%s_0x%Ix-0x%Ix.bin", processItem->ProcessName->Buffer, context->BaseAddress, context->RegionSize)->Buffer); PhDereferenceObject(processItem); } else { PhSetFileDialogFileName(fileDialog, L"Memory.bin"); } if (PhShowFileDialog(hwndDlg, fileDialog)) { NTSTATUS status; PPH_STRING fileName; PPH_FILE_STREAM fileStream; fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); if (NT_SUCCESS(status = PhCreateFileStream( &fileStream, fileName->Buffer, FILE_GENERIC_WRITE, FILE_SHARE_READ, FILE_OVERWRITE_IF, 0 ))) { status = PhWriteFileStream(fileStream, context->Buffer, (ULONG)context->RegionSize); PhDereferenceObject(fileStream); } if (!NT_SUCCESS(status)) PhShowStatus(hwndDlg, L"Unable to create the file", status, 0); } PhFreeFileDialog(fileDialog); } break; case IDC_GOTO: { PPH_STRING selectedChoice = NULL; while (PhaChoiceDialog( hwndDlg, L"Go to Offset", L"Enter an offset:", NULL, 0, NULL, PH_CHOICE_DIALOG_USER_CHOICE, &selectedChoice, NULL, L"MemEditGotoChoices" )) { ULONG64 offset; if (selectedChoice->Length == 0) continue; if (PhStringToInteger64(&selectedChoice->sr, 0, &offset)) { if (offset >= context->RegionSize) { PhShowError(hwndDlg, L"The offset is too large."); continue; } SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->HexEditHandle, TRUE); HexEdit_SetSel(context->HexEditHandle, (LONG)offset, (LONG)offset); break; } } } break; case IDC_WRITE: { NTSTATUS status; if (!context->WriteAccess) { HANDLE processHandle; if (!NT_SUCCESS(status = PhOpenProcess( &processHandle, PROCESS_VM_READ | PROCESS_VM_WRITE, context->ProcessId ))) { PhShowStatus(hwndDlg, L"Unable to open the process", status, 0); break; } if (context->ProcessHandle) NtClose(context->ProcessHandle); context->ProcessHandle = processHandle; context->WriteAccess = TRUE; } if (!NT_SUCCESS(status = NtWriteVirtualMemory( context->ProcessHandle, context->BaseAddress, context->Buffer, context->RegionSize, NULL ))) { PhShowStatus(hwndDlg, L"Unable to write memory", status, 0); } } break; case IDC_REREAD: { NTSTATUS status; if (!NT_SUCCESS(status = NtReadVirtualMemory( context->ProcessHandle, context->BaseAddress, context->Buffer, context->RegionSize, NULL ))) { PhShowStatus(hwndDlg, L"Unable to read memory", status, 0); } InvalidateRect(context->HexEditHandle, NULL, TRUE); } break; case IDC_BYTESPERROW: if (HIWORD(wParam) == CBN_SELCHANGE) { PPH_STRING bytesPerRowString = PhaGetDlgItemText(hwndDlg, IDC_BYTESPERROW); PH_STRINGREF firstPart; PH_STRINGREF secondPart; ULONG64 bytesPerRow64; if (PhSplitStringRefAtChar(&bytesPerRowString->sr, ' ', &firstPart, &secondPart)) { if (PhStringToInteger64(&firstPart, 10, &bytesPerRow64)) { PhSetIntegerSetting(L"MemEditBytesPerRow", (ULONG)bytesPerRow64); HexEdit_SetBytesPerRow(context->HexEditHandle, (ULONG)bytesPerRow64); SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->HexEditHandle, TRUE); } } } break; } } break; case WM_SIZE: { PhLayoutManagerLayout(&context->LayoutManager); } break; case WM_SIZING: { PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); } break; case WM_PH_SELECT_OFFSET: { HexEdit_SetEditMode(context->HexEditHandle, EDIT_ASCII); HexEdit_SetSel(context->HexEditHandle, (ULONG)wParam, (ULONG)wParam + (ULONG)lParam); } break; } return FALSE; }
static VOID PhpGetWfmoInformation( _In_ HANDLE ProcessHandle, _In_ BOOLEAN IsWow64, _In_ ULONG NumberOfHandles, _In_ PHANDLE AddressOfHandles, _In_ WAIT_TYPE WaitType, _In_ BOOLEAN Alertable, _Inout_ PPH_STRING_BUILDER StringBuilder ) { NTSTATUS status; HANDLE handles[MAXIMUM_WAIT_OBJECTS]; ULONG i; status = STATUS_SUCCESS; if (NumberOfHandles <= MAXIMUM_WAIT_OBJECTS) { #ifdef _WIN64 if (IsWow64) { ULONG handles32[MAXIMUM_WAIT_OBJECTS]; if (NT_SUCCESS(status = NtReadVirtualMemory( ProcessHandle, AddressOfHandles, handles32, NumberOfHandles * sizeof(ULONG), NULL ))) { for (i = 0; i < NumberOfHandles; i++) handles[i] = UlongToHandle(handles32[i]); } } else { #endif status = NtReadVirtualMemory( ProcessHandle, AddressOfHandles, handles, NumberOfHandles * sizeof(HANDLE), NULL ); #ifdef _WIN64 } #endif if (NT_SUCCESS(status)) { PhAppendFormatStringBuilder( StringBuilder, L"Thread is waiting (%s, %s) for:\r\n", Alertable ? L"alertable" : L"non-alertable", WaitType == WaitAll ? L"wait all" : L"wait any" ); for (i = 0; i < NumberOfHandles; i++) { PhAppendStringBuilder( StringBuilder, &PhpaGetHandleString(ProcessHandle, handles[i])->sr ); PhAppendStringBuilder2( StringBuilder, L"\r\n" ); } } } if (!NT_SUCCESS(status) || NumberOfHandles > MAXIMUM_WAIT_OBJECTS) { PhAppendStringBuilder2( StringBuilder, L"Thread is waiting for multiple objects." ); } }
static NTSTATUS UserpCaptureStringParameters( OUT PULONG_PTR Parameters, OUT PULONG SizeOfAllUnicodeStrings, IN PHARDERROR_MSG HardErrorMessage, HANDLE hProcess) { ULONG nParam, Size = 0; NTSTATUS Status = STATUS_SUCCESS; UNICODE_STRING TempStringU, ParamStringU; ANSI_STRING TempStringA; if (SizeOfAllUnicodeStrings) *SizeOfAllUnicodeStrings = 0; /* Read all strings from client space */ for (nParam = 0; nParam < HardErrorMessage->NumberOfParameters; nParam++) { Parameters[nParam] = 0; /* Check if the current parameter is a unicode string */ if (HardErrorMessage->UnicodeStringParameterMask & (1 << nParam)) { /* Read the UNICODE_STRING from the process memory */ Status = NtReadVirtualMemory(hProcess, (PVOID)HardErrorMessage->Parameters[nParam], &ParamStringU, sizeof(ParamStringU), NULL); if (!NT_SUCCESS(Status)) break; /* Allocate a buffer for the string */ TempStringU.MaximumLength = ParamStringU.Length; TempStringU.Length = ParamStringU.Length; TempStringU.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, TempStringU.MaximumLength); if (!TempStringU.Buffer) { DPRINT1("Cannot allocate memory %u\n", TempStringU.MaximumLength); Status = STATUS_NO_MEMORY; } /* Read the string buffer from the process memory */ Status = NtReadVirtualMemory(hProcess, ParamStringU.Buffer, TempStringU.Buffer, ParamStringU.Length, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("NtReadVirtualMemory failed with code: %lx\n", Status); RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU.Buffer); break; } DPRINT("ParamString=\'%wZ\'\n", &TempStringU); /* Allocate a buffer for converted to ANSI string */ TempStringA.MaximumLength = RtlUnicodeStringToAnsiSize(&TempStringU); TempStringA.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, TempStringA.MaximumLength); if (!TempStringA.Buffer) { DPRINT1("Cannot allocate memory %u\n", TempStringA.MaximumLength); RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU.Buffer); Status = STATUS_NO_MEMORY; break; } /* Convert string to ANSI and free temporary buffer */ Status = RtlUnicodeStringToAnsiString(&TempStringA, &TempStringU, FALSE); RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU.Buffer); if (!NT_SUCCESS(Status)) { RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringA.Buffer); break; } /* Note: RtlUnicodeStringToAnsiString returns NULL terminated string */ Parameters[nParam] = (ULONG_PTR)TempStringA.Buffer; Size += TempStringU.Length; } else { /* It's not a unicode string */ Parameters[nParam] = HardErrorMessage->Parameters[nParam]; } } if (!NT_SUCCESS(Status)) { UserpFreeStringParameters(Parameters, HardErrorMessage); return Status; } if (SizeOfAllUnicodeStrings) *SizeOfAllUnicodeStrings = Size; return Status; }
/* * @implemented */ DWORD WINAPI GetProcessVersion(DWORD ProcessId) { DWORD Version = 0; PIMAGE_NT_HEADERS NtHeader = NULL; IMAGE_NT_HEADERS NtHeaders; IMAGE_DOS_HEADER DosHeader; PROCESS_BASIC_INFORMATION ProcessBasicInfo; PVOID BaseAddress = NULL; HANDLE ProcessHandle = NULL; NTSTATUS Status; SIZE_T Count; PEB Peb; _SEH2_TRY { if (0 == ProcessId || GetCurrentProcessId() == ProcessId) { /* Caller's */ BaseAddress = (PVOID) NtCurrentPeb()->ImageBaseAddress; NtHeader = RtlImageNtHeader(BaseAddress); Version = (NtHeader->OptionalHeader.MajorOperatingSystemVersion << 16) | (NtHeader->OptionalHeader.MinorOperatingSystemVersion); } else { /* Other process */ ProcessHandle = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, ProcessId); if (!ProcessHandle) return 0; Status = NtQueryInformationProcess(ProcessHandle, ProcessBasicInformation, &ProcessBasicInfo, sizeof(ProcessBasicInfo), NULL); if (!NT_SUCCESS(Status)) goto Error; Status = NtReadVirtualMemory(ProcessHandle, ProcessBasicInfo.PebBaseAddress, &Peb, sizeof(Peb), &Count); if (!NT_SUCCESS(Status) || Count != sizeof(Peb)) goto Error; memset(&DosHeader, 0, sizeof(DosHeader)); Status = NtReadVirtualMemory(ProcessHandle, Peb.ImageBaseAddress, &DosHeader, sizeof(DosHeader), &Count); if (!NT_SUCCESS(Status) || Count != sizeof(DosHeader)) goto Error; if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) goto Error; memset(&NtHeaders, 0, sizeof(NtHeaders)); Status = NtReadVirtualMemory(ProcessHandle, (char *)Peb.ImageBaseAddress + DosHeader.e_lfanew, &NtHeaders, sizeof(NtHeaders), &Count); if (!NT_SUCCESS(Status) || Count != sizeof(NtHeaders)) goto Error; if (NtHeaders.Signature != IMAGE_NT_SIGNATURE) goto Error; Version = MAKELONG(NtHeaders.OptionalHeader.MinorSubsystemVersion, NtHeaders.OptionalHeader.MajorSubsystemVersion); Error: if (!NT_SUCCESS(Status)) { SetLastErrorByStatus(Status); } } } _SEH2_FINALLY { if (ProcessHandle) CloseHandle(ProcessHandle); } _SEH2_END; return Version; }
PPH_LIST EnumerateAppDomainIpcBlockWow64( _In_ HANDLE ProcessHandle, _In_ AppDomainEnumerationIPCBlock_Wow64* AppDomainIpcBlock ) { LARGE_INTEGER timeout; SIZE_T appDomainInfoBlockLength; HANDLE legacyPrivateBlockMutexHandle = NULL; AppDomainEnumerationIPCBlock_Wow64 tempBlock; AppDomainInfo_Wow64* appDomainInfoBlock = NULL; PPH_LIST appDomainsList = PhCreateList(1); // If the mutex isn't filled in, the CLR is either starting up or shutting down if (!AppDomainIpcBlock->Mutex) { goto CleanupExit; } // Dup the valid mutex handle into this process. if (!NT_SUCCESS(NtDuplicateObject( ProcessHandle, UlongToHandle(AppDomainIpcBlock->Mutex), NtCurrentProcess(), &legacyPrivateBlockMutexHandle, GENERIC_ALL, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES ))) { goto CleanupExit; } // Acquire the mutex, only waiting two seconds. // We can't actually gaurantee that the target put a mutex object in here. if (NtWaitForSingleObject( legacyPrivateBlockMutexHandle, FALSE, PhTimeoutFromMilliseconds(&timeout, 2000) ) == STATUS_WAIT_0) { // Make sure the mutex handle is still valid. If its not, then we lost a shutdown race. if (!AppDomainIpcBlock->Mutex) { goto CleanupExit; } } else { // Again, landing here is most probably a shutdown race. goto CleanupExit; } // Beware: If the target pid is not properly honoring the mutex, the data in the IPC block may still shift underneath us. // If we get here, then hMutex is held by this process. // Make a copy of the IPC block so that we can gaurantee that it's not changing on us. memcpy(&tempBlock, AppDomainIpcBlock, sizeof(AppDomainEnumerationIPCBlock_Wow64)); // It's possible the process will not have any appdomains. if ((tempBlock.ListOfAppDomains == 0) != (tempBlock.SizeInBytes == 0)) { goto CleanupExit; } // All the data in the IPC block is signed integers. They should never be negative, // so check that now. if ((tempBlock.TotalSlots < 0) || (tempBlock.NumOfUsedSlots < 0) || (tempBlock.LastFreedSlot < 0) || (tempBlock.SizeInBytes < 0) || (tempBlock.ProcessNameLengthInBytes < 0)) { goto CleanupExit; } // Allocate memory to read the remote process' memory into appDomainInfoBlockLength = tempBlock.SizeInBytes; // Check other invariants. if (appDomainInfoBlockLength != tempBlock.TotalSlots * sizeof(AppDomainInfo_Wow64)) { goto CleanupExit; } appDomainInfoBlock = (AppDomainInfo_Wow64*)PhAllocate(appDomainInfoBlockLength); memset(appDomainInfoBlock, 0, appDomainInfoBlockLength); if (!NT_SUCCESS(NtReadVirtualMemory( ProcessHandle, UlongToPtr(tempBlock.ListOfAppDomains), appDomainInfoBlock, appDomainInfoBlockLength, NULL ))) { PhFree(appDomainInfoBlock); goto CleanupExit; } // Collect all the AppDomain names into a list of strings. for (INT i = 0; i < tempBlock.NumOfUsedSlots; i++) { SIZE_T appDomainNameLength; PVOID appDomainName; if (!appDomainInfoBlock[i].AppDomainName) continue; // Should be positive, and at least have a null-terminator character. if (appDomainInfoBlock[i].NameLengthInBytes <= 1) continue; // Make sure buffer has right geometry. if (appDomainInfoBlock[i].NameLengthInBytes < 0) continue; // If it's not on a WCHAR boundary, then we may have a 1-byte buffer-overflow. appDomainNameLength = appDomainInfoBlock[i].NameLengthInBytes / sizeof(WCHAR); if ((appDomainNameLength * sizeof(WCHAR)) != appDomainInfoBlock[i].NameLengthInBytes) continue; // It should at least have 1 char for the null terminator. if (appDomainNameLength < 1) continue; // We know the string is a well-formed null-terminated string, // but beyond that, we can't verify that the data is actually truthful. appDomainName = PhAllocate(appDomainInfoBlock[i].NameLengthInBytes + 1); memset(appDomainName, 0, appDomainInfoBlock[i].NameLengthInBytes + 1); if (!NT_SUCCESS(NtReadVirtualMemory( ProcessHandle, UlongToPtr(appDomainInfoBlock[i].AppDomainName), appDomainName, appDomainInfoBlock[i].NameLengthInBytes, NULL ))) { PhFree(appDomainName); continue; } PhAddItemList(appDomainsList, appDomainName); } CleanupExit: if (appDomainInfoBlock) { PhFree(appDomainInfoBlock); } if (legacyPrivateBlockMutexHandle) { NtReleaseMutant(legacyPrivateBlockMutexHandle, NULL); NtClose(legacyPrivateBlockMutexHandle); } return appDomainsList; }
VOID ComputeModInfo( HWND hDlg, HANDLE Process ) { PPEB Peb; NTSTATUS Status; PROCESS_BASIC_INFORMATION BasicInfo; PLDR_DATA_TABLE_ENTRY LdrEntry; LDR_DATA_TABLE_ENTRY LdrEntryData; PLIST_ENTRY LdrHead,LdrNext; PPEB_LDR_DATA Ldr; UNICODE_STRING us; int i,nIndex; HWND ComboList; HANDLE hFile; HANDLE hMappedFile; PIMAGE_DOS_HEADER DosHeader; PIMAGE_NT_HEADERS FileHeader; LPSTR p; PVOID MappedAddress; for (i=0;i<(int)ModInfoNext;i++){ if ( ModInfo[i].BaseAddress && ModInfo[i].BaseAddress != (PVOID) 0xffffffff && ModInfo[i].Name.Buffer ) { RtlFreeAnsiString(&ModInfo[i].Name); } } ModInfoNext = 0; RtlZeroMemory(ModInfo,sizeof(ModInfo)); RtlInitAnsiString(&TotalModInfo.Name," TotalImageCommit"); ComboList = GetDlgItem(hDlg, PXPLODE_IMAGE_COMMIT); SendMessage(ComboList, CB_RESETCONTENT, 0, 0); SendMessage(ComboList, CB_SETITEMDATA, 0L, 0L); nIndex = (int)SendMessage( ComboList, CB_ADDSTRING, 0, (DWORD)TotalModInfo.Name.Buffer ); SendMessage( ComboList, CB_SETITEMDATA, nIndex, (DWORD)&TotalModInfo ); Status = NtQueryInformationProcess( Process, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL ); if ( !NT_SUCCESS(Status) ) { if ( Status == STATUS_INFO_LENGTH_MISMATCH ) { Status = NtQueryInformationProcess( Process, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo)-4, NULL ); if ( !NT_SUCCESS(Status) ) { return; } } else { return; } } Peb = BasicInfo.PebBaseAddress; // // Ldr = Peb->Ldr // Status = NtReadVirtualMemory( Process, &Peb->Ldr, &Ldr, sizeof(Ldr), NULL ); if ( !NT_SUCCESS(Status) ) { return; } LdrHead = &Ldr->InMemoryOrderModuleList; // // LdrNext = Head->Flink; // Status = NtReadVirtualMemory( Process, &LdrHead->Flink, &LdrNext, sizeof(LdrNext), NULL ); if ( !NT_SUCCESS(Status) ) { return; } while ( LdrNext != LdrHead ) { LdrEntry = CONTAINING_RECORD(LdrNext,LDR_DATA_TABLE_ENTRY,InMemoryOrderLinks); Status = NtReadVirtualMemory( Process, LdrEntry, &LdrEntryData, sizeof(LdrEntryData), NULL ); if ( !NT_SUCCESS(Status) ) { return; } ModInfo[ModInfoNext].BaseAddress = LdrEntryData.DllBase; us.Length = LdrEntryData.BaseDllName.Length; us.MaximumLength = LdrEntryData.BaseDllName.MaximumLength; us.Buffer = LocalAlloc(LMEM_ZEROINIT,us.MaximumLength); if ( !us.Buffer ) { return; } Status = NtReadVirtualMemory( Process, LdrEntryData.BaseDllName.Buffer, us.Buffer, us.MaximumLength, NULL ); if ( !NT_SUCCESS(Status) ) { return; } RtlUnicodeStringToAnsiString( &ModInfo[ModInfoNext].Name, &us, TRUE ); LocalFree(us.Buffer); us.Length = LdrEntryData.FullDllName.Length; us.MaximumLength = LdrEntryData.FullDllName.MaximumLength; us.Buffer = LocalAlloc(LMEM_ZEROINIT,us.MaximumLength); if ( !us.Buffer ) { return; } Status = NtReadVirtualMemory( Process, LdrEntryData.FullDllName.Buffer, us.Buffer, us.MaximumLength, NULL ); if ( !NT_SUCCESS(Status) ) { return; } RtlUnicodeStringToAnsiString( &ModInfo[ModInfoNext].FullName, &us, TRUE ); LocalFree(us.Buffer); if ( p = strchr(ModInfo[ModInfoNext].FullName.Buffer,':') ) { ModInfo[ModInfoNext].FullName.Buffer = p - 1; } hFile = CreateFile( ModInfo[ModInfoNext].FullName.Buffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); if ( hFile == INVALID_HANDLE_VALUE ) { return; } hMappedFile = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL ); CloseHandle(hFile); if ( !hMappedFile ) { return; } MappedAddress = MapViewOfFile( hMappedFile, FILE_MAP_READ, 0, 0, 0 ); CloseHandle(hMappedFile); if ( !MappedAddress ) { UnmapViewOfFile(MappedAddress); return; } DosHeader = (PIMAGE_DOS_HEADER)MappedAddress; if ( DosHeader->e_magic != IMAGE_DOS_SIGNATURE ) { UnmapViewOfFile(MappedAddress); return; } FileHeader = (PIMAGE_NT_HEADERS)((ULONG)DosHeader + DosHeader->e_lfanew); if ( FileHeader->Signature != IMAGE_NT_SIGNATURE ) { UnmapViewOfFile(MappedAddress); return; } ModInfo[ModInfoNext].VirtualSize = FileHeader->OptionalHeader.SizeOfImage; UnmapViewOfFile(MappedAddress); nIndex = (int)SendMessage( ComboList, CB_ADDSTRING, 0, (DWORD)ModInfo[ModInfoNext].Name.Buffer ); SendMessage( ComboList, CB_SETITEMDATA, nIndex, (DWORD)&ModInfo[ModInfoNext] ); ModInfoNext++; ModInfo[ModInfoNext].BaseAddress = (PVOID) 0xffffffff; LdrNext = LdrEntryData.InMemoryOrderLinks.Flink; } SendMessage(ComboList, CB_SETCURSEL, 0, 0); }
/* * UsdDumpSharedRegion * * Purpose: * * Display dump of SharedData. * */ VOID UsdDumpSharedRegion( _In_ HWND hwndParent ) { BOOL bCond = FALSE; INT i; DWORD mask; HWND UsdTreeList; ATOM UsdTreeListAtom; NTSTATUS status; SIZE_T memIO = 0x1000; PKUSER_SHARED_DATA pData = NULL; HTREEITEM h_tviRootItem, h_tviSubItem; LPWSTR lpType; TL_SUBITEMS_FIXED subitems; WCHAR szValue[MAX_PATH + 1]; do { //Allocate temp buffer for UserSharedData copy pData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, memIO); if (pData == NULL) { break; } //Attempt to copy UserSharedData status = NtReadVirtualMemory(GetCurrentProcess(), (PVOID)MM_SHARED_USER_DATA_VA, pData, memIO, &memIO); if (!NT_SUCCESS(status)) { break; } UsdTreeList = 0; UsdTreeListAtom = 0; if (!supInitTreeListForDump(hwndParent, &UsdTreeListAtom, &UsdTreeList)) { break; } // //KUSER_SHARED_DATA // h_tviRootItem = TreeListAddItem(UsdTreeList, NULL, TVIF_TEXT | TVIF_STATE, TVIS_EXPANDED, TVIS_EXPANDED, L"KUSER_SHARED_DATA", NULL); if (h_tviRootItem == NULL) { break; } //NtSystemRoot RtlSecureZeroMemory(&subitems, sizeof(subitems)); subitems.Text[0] = pData->NtSystemRoot; subitems.Count = 1; TreeListAddItem(UsdTreeList, h_tviRootItem, TVIF_TEXT | TVIF_STATE, 0, 0, L"NtSystemRoot", &subitems); //NtProductType switch (pData->NtProductType) { case NtProductWinNt: lpType = L"NtProductWinNt"; break; case NtProductLanManNt: lpType = L"NtProductLanManNt"; break; case NtProductServer: lpType = L"NtProductServer"; break; default: lpType = T_UnknownType; break; } ObDumpUlong(UsdTreeList, h_tviRootItem, L"NtProductType", lpType, pData->NtProductType, FALSE, FALSE, 0, 0); ObDumpByte(UsdTreeList, h_tviRootItem, L"ProductTypeIsValid", NULL, pData->ProductTypeIsValid, 0, 0, TRUE); //Version ObDumpUlong(UsdTreeList, h_tviRootItem, L"NtMajorVersion", NULL, pData->NtMajorVersion, FALSE, FALSE, 0, 0); ObDumpUlong(UsdTreeList, h_tviRootItem, L"NtMinorVersion", NULL, pData->NtMinorVersion, FALSE, FALSE, 0, 0); //ProcessorFeatures h_tviSubItem = TreeListAddItem(UsdTreeList, h_tviRootItem, TVIF_TEXT | TVIF_STATE, 0, 0, L"ProcessorFeatures", NULL); if (h_tviSubItem) { for (i = 0; i < PROCESSOR_FEATURE_MAX; i++) { if (pData->ProcessorFeatures[i]) { if (i > 32) { lpType = T_Unknown; } else { lpType = T_PROCESSOR_FEATURES[i]; } RtlSecureZeroMemory(&subitems, sizeof(subitems)); RtlSecureZeroMemory(&szValue, sizeof(szValue)); itostr_w(i, szValue); subitems.Text[0] = szValue; subitems.Text[1] = lpType; subitems.Count = 2; TreeListAddItem(UsdTreeList, h_tviSubItem, TVIF_TEXT | TVIF_STATE, 0, 0, NULL, &subitems); } } } //AlternativeArchitecture switch (pData->AlternativeArchitecture) { case StandardDesign: lpType = L"StandardDesign"; break; case NEC98x86: lpType = L"NEC98x86"; break; default: lpType = T_UnknownType; break; } ObDumpUlong(UsdTreeList, h_tviRootItem, L"AlternativeArchitecture", lpType, pData->AlternativeArchitecture, FALSE, FALSE, 0, 0); //SuiteMask RtlSecureZeroMemory(&subitems, sizeof(subitems)); RtlSecureZeroMemory(&szValue, sizeof(szValue)); szValue[0] = L'0'; szValue[1] = L'x'; ultohex_w(pData->SuiteMask, &szValue[2]); subitems.Text[0] = szValue; subitems.Count = 1; h_tviSubItem = TreeListAddItem(UsdTreeList, h_tviRootItem, TVIF_TEXT | TVIF_STATE, 0, 0, L"SuiteMask", &subitems); if (h_tviSubItem) { mask = pData->SuiteMask; for (i = 0; i < MAX_KNOWN_SUITEMASKS; i++) { if (mask & SuiteMasks[i].dwValue) { RtlSecureZeroMemory(&subitems, sizeof(subitems)); RtlSecureZeroMemory(&szValue, sizeof(szValue)); szValue[0] = L'0'; szValue[1] = L'x'; ultohex_w(SuiteMasks[i].dwValue, &szValue[2]); subitems.Text[0] = szValue; subitems.Text[1] = SuiteMasks[i].lpDescription; subitems.Count = 2; TreeListAddItem(UsdTreeList, h_tviSubItem, TVIF_TEXT | TVIF_STATE, 0, 0, NULL, &subitems); mask &= ~SuiteMasks[i].dwValue; } } } //KdDebuggerEnabled ObDumpByte(UsdTreeList, h_tviRootItem, L"KdDebuggerEnabled", NULL, pData->KdDebuggerEnabled, 0, 0, TRUE); //MitigationPolicies ObDumpByte(UsdTreeList, h_tviRootItem, L"MitigationPolicies", NULL, pData->MitigationPolicies, 0, 0, FALSE); //SafeBootMode ObDumpByte(UsdTreeList, h_tviRootItem, L"SafeBootMode", NULL, pData->SafeBootMode, 0, 0, TRUE); //SharedDataFlags RtlSecureZeroMemory(&subitems, sizeof(subitems)); RtlSecureZeroMemory(&szValue, sizeof(szValue)); szValue[0] = L'0'; szValue[1] = L'x'; ultohex_w(pData->SharedDataFlags, &szValue[2]); subitems.Text[0] = szValue; subitems.Count = 1; h_tviSubItem = TreeListAddItem(UsdTreeList, h_tviRootItem, TVIF_TEXT | TVIF_STATE, 0, 0, L"SharedDataFlags", &subitems); if (h_tviSubItem) { for (i = 0; i < 9; i++) { if (GET_BIT(pData->SharedDataFlags, i)) { RtlSecureZeroMemory(&subitems, sizeof(subitems)); RtlSecureZeroMemory(&szValue, sizeof(szValue)); _strcpy_w(szValue, L"BitPos: "); itostr_w(i, _strend_w(szValue)); subitems.Text[0] = szValue; subitems.Text[1] = (LPTSTR)T_SharedDataFlags[i]; subitems.Count = 2; TreeListAddItem(UsdTreeList, h_tviSubItem, TVIF_TEXT | TVIF_STATE, 0, 0, NULL, &subitems); } } } } while (bCond); if (pData) { HeapFree(GetProcessHeap(), 0, pData); } }
static NTSTATUS UserpGetClientFileName( OUT PUNICODE_STRING ClientFileNameU, HANDLE hProcess) { PLIST_ENTRY ModuleListHead; PLIST_ENTRY Entry; PLDR_DATA_TABLE_ENTRY Module; PPEB_LDR_DATA Ldr; PROCESS_BASIC_INFORMATION ClientBasicInfo; LDR_DATA_TABLE_ENTRY ModuleData; PVOID ClientDllBase; NTSTATUS Status; PPEB Peb; /* Initialize string */ ClientFileNameU->MaximumLength = 0; ClientFileNameU->Length = 0; ClientFileNameU->Buffer = NULL; /* Query process information */ Status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &ClientBasicInfo, sizeof(ClientBasicInfo), NULL); if (!NT_SUCCESS(Status)) return Status; Peb = ClientBasicInfo.PebBaseAddress; if (!Peb) return STATUS_UNSUCCESSFUL; Status = NtReadVirtualMemory(hProcess, &Peb->Ldr, &Ldr, sizeof(Ldr), NULL); if (!NT_SUCCESS(Status)) return Status; ModuleListHead = &Ldr->InLoadOrderModuleList; Status = NtReadVirtualMemory(hProcess, &ModuleListHead->Flink, &Entry, sizeof(Entry), NULL); if (!NT_SUCCESS(Status)) return Status; if (Entry == ModuleListHead) return STATUS_UNSUCCESSFUL; Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); Status = NtReadVirtualMemory(hProcess, Module, &ModuleData, sizeof(ModuleData), NULL); if (!NT_SUCCESS(Status)) return Status; Status = NtReadVirtualMemory(hProcess, &Peb->ImageBaseAddress, &ClientDllBase, sizeof(ClientDllBase), NULL); if (!NT_SUCCESS(Status)) return Status; if (ClientDllBase != ModuleData.DllBase) return STATUS_UNSUCCESSFUL; ClientFileNameU->MaximumLength = ModuleData.BaseDllName.MaximumLength; ClientFileNameU->Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, ClientFileNameU->MaximumLength); Status = NtReadVirtualMemory(hProcess, ModuleData.BaseDllName.Buffer, ClientFileNameU->Buffer, ClientFileNameU->MaximumLength, NULL); if (!NT_SUCCESS(Status)) { RtlFreeHeap(RtlGetProcessHeap(), 0, ClientFileNameU->Buffer); ClientFileNameU->Buffer = NULL; ClientFileNameU->MaximumLength = 0; return Status; } ClientFileNameU->Length = wcslen(ClientFileNameU->Buffer)*sizeof(wchar_t); DPRINT("ClientFileNameU=\'%wZ\'\n", &ClientFileNameU); return STATUS_SUCCESS; }
static BOOLEAN NTAPI PhpWalkThreadStackAnalyzeCallback( _In_ PPH_THREAD_STACK_FRAME StackFrame, _In_opt_ PVOID Context ) { PANALYZE_WAIT_CONTEXT context = (PANALYZE_WAIT_CONTEXT)Context; PPH_STRING name; name = PhGetSymbolFromAddress( context->SymbolProvider, (ULONG64)StackFrame->PcAddress, NULL, NULL, NULL, NULL ); if (!name) return TRUE; context->Found = TRUE; #define FUNC_MATCH(Name) PhStartsWithString2(name, L##Name, TRUE) #define NT_FUNC_MATCH(Name) ( \ PhStartsWithString2(name, L"ntdll.dll!Nt" L##Name, TRUE) || \ PhStartsWithString2(name, L"ntdll.dll!Zw" L##Name, TRUE) \ ) if (!name) { // Dummy } else if (FUNC_MATCH("kernel32.dll!Sleep")) { PhAppendFormatStringBuilder( &context->StringBuilder, L"Thread is sleeping. Timeout: %lu milliseconds.", PtrToUlong(StackFrame->Params[0]) ); } else if (NT_FUNC_MATCH("DelayExecution")) { BOOLEAN alertable = !!StackFrame->Params[0]; PVOID timeoutAddress = StackFrame->Params[1]; LARGE_INTEGER timeout; if (NT_SUCCESS(NtReadVirtualMemory( context->ProcessHandle, timeoutAddress, &timeout, sizeof(LARGE_INTEGER), NULL ))) { if (timeout.QuadPart < 0) { PhAppendFormatStringBuilder( &context->StringBuilder, L"Thread is sleeping. Timeout: %I64u milliseconds.", -timeout.QuadPart / PH_TIMEOUT_MS ); } else { // TODO } } else { PhAppendStringBuilder2( &context->StringBuilder, L"Thread is sleeping." ); } } else if (NT_FUNC_MATCH("DeviceIoControlFile")) { HANDLE handle = (HANDLE)StackFrame->Params[0]; PhAppendStringBuilder2( &context->StringBuilder, L"Thread is waiting for an I/O control request:\r\n" ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else if (NT_FUNC_MATCH("FsControlFile")) { HANDLE handle = StackFrame->Params[0]; PhAppendStringBuilder2( &context->StringBuilder, L"Thread is waiting for a FS control request:\r\n" ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else if (NT_FUNC_MATCH("QueryObject")) { HANDLE handle = StackFrame->Params[0]; // Use the KiFastSystemCall args if the handle we have is wrong. if ((ULONG_PTR)handle % 4 != 0 || !handle) handle = context->PrevParams[1]; PhAppendStringBuilder2( &context->StringBuilder, L"Thread is querying an object:\r\n" ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else if (NT_FUNC_MATCH("ReadFile") || NT_FUNC_MATCH("WriteFile")) { HANDLE handle = StackFrame->Params[0]; PhAppendStringBuilder2( &context->StringBuilder, L"Thread is waiting for file I/O:\r\n" ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else if (NT_FUNC_MATCH("RemoveIoCompletion")) { HANDLE handle = StackFrame->Params[0]; PhAppendStringBuilder2( &context->StringBuilder, L"Thread is waiting for an I/O completion port:\r\n" ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else if ( NT_FUNC_MATCH("ReplyWaitReceivePort") || NT_FUNC_MATCH("RequestWaitReplyPort") || NT_FUNC_MATCH("AlpcSendWaitReceivePort") ) { HANDLE handle = StackFrame->Params[0]; PPH_STRING alpcInfo; PhAppendStringBuilder2( &context->StringBuilder, L"Thread is waiting for an ALPC port:\r\n" ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); if (alpcInfo = PhpaGetAlpcInformation(context->ThreadId)) { PhAppendStringBuilder2( &context->StringBuilder, L"\r\n" ); PhAppendStringBuilder( &context->StringBuilder, &alpcInfo->sr ); } } else if ( NT_FUNC_MATCH("SetHighWaitLowEventPair") || NT_FUNC_MATCH("SetLowWaitHighEventPair") || NT_FUNC_MATCH("WaitHighEventPair") || NT_FUNC_MATCH("WaitLowEventPair") ) { HANDLE handle = StackFrame->Params[0]; if ((ULONG_PTR)handle % 4 != 0 || !handle) handle = context->PrevParams[1]; PhAppendFormatStringBuilder( &context->StringBuilder, L"Thread is waiting (%s) for an event pair:\r\n", name->Buffer ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else if ( FUNC_MATCH("user32.dll!NtUserGetMessage") || FUNC_MATCH("user32.dll!NtUserWaitMessage") ) { PhAppendStringBuilder2( &context->StringBuilder, L"Thread is waiting for a USER message.\r\n" ); } else if (FUNC_MATCH("user32.dll!NtUserMessageCall")) { PPH_STRING receiverString; PhAppendStringBuilder2( &context->StringBuilder, L"Thread is sending a USER message:\r\n" ); receiverString = PhpaGetSendMessageReceiver(context->ThreadId); if (receiverString) { PhAppendStringBuilder(&context->StringBuilder, &receiverString->sr); PhAppendStringBuilder2(&context->StringBuilder, L"\r\n"); } else { PhAppendStringBuilder2(&context->StringBuilder, L"Unknown.\r\n"); } } else if (NT_FUNC_MATCH("WaitForDebugEvent")) { HANDLE handle = StackFrame->Params[0]; PhAppendStringBuilder2( &context->StringBuilder, L"Thread is waiting for a debug event:\r\n" ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else if ( NT_FUNC_MATCH("WaitForKeyedEvent") || NT_FUNC_MATCH("ReleaseKeyedEvent") ) { HANDLE handle = StackFrame->Params[0]; PVOID key = StackFrame->Params[1]; PhAppendFormatStringBuilder( &context->StringBuilder, L"Thread is waiting (%s) for a keyed event (key 0x%Ix):\r\n", name->Buffer, key ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else if ( NT_FUNC_MATCH("WaitForMultipleObjects") || FUNC_MATCH("kernel32.dll!WaitForMultipleObjects") ) { ULONG numberOfHandles = PtrToUlong(StackFrame->Params[0]); PVOID addressOfHandles = StackFrame->Params[1]; WAIT_TYPE waitType = (WAIT_TYPE)StackFrame->Params[2]; BOOLEAN alertable = !!StackFrame->Params[3]; if (numberOfHandles > MAXIMUM_WAIT_OBJECTS) { numberOfHandles = PtrToUlong(context->PrevParams[1]); addressOfHandles = context->PrevParams[2]; waitType = (WAIT_TYPE)context->PrevParams[3]; alertable = FALSE; } PhpGetWfmoInformation( context->ProcessHandle, TRUE, // on x64 this function is only called for WOW64 processes numberOfHandles, addressOfHandles, waitType, alertable, &context->StringBuilder ); } else if ( NT_FUNC_MATCH("WaitForSingleObject") || FUNC_MATCH("kernel32.dll!WaitForSingleObject") ) { HANDLE handle = StackFrame->Params[0]; BOOLEAN alertable = !!StackFrame->Params[1]; if ((ULONG_PTR)handle % 4 != 0 || !handle) { handle = context->PrevParams[1]; alertable = !!context->PrevParams[2]; } PhAppendFormatStringBuilder( &context->StringBuilder, L"Thread is waiting (%s) for:\r\n", alertable ? L"alertable" : L"non-alertable" ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else if (NT_FUNC_MATCH("WaitForWorkViaWorkerFactory")) { HANDLE handle = StackFrame->Params[0]; PhAppendStringBuilder2( &context->StringBuilder, L"Thread is waiting for work from a worker factory:\r\n" ); PhAppendStringBuilder( &context->StringBuilder, &PhpaGetHandleString(context->ProcessHandle, handle)->sr ); } else { context->Found = FALSE; } PhDereferenceObject(name); memcpy(&context->PrevParams, StackFrame->Params, sizeof(StackFrame->Params)); return !context->Found; }