mirror of
https://github.com/radareorg/radare2.git
synced 2025-02-05 04:56:10 +00:00
Fixes for dmh in Windows
* Get offset of important globals from ntdll's PDB * Workaround some RtlQueryProcessDebugInformation hangs for Win10
This commit is contained in:
parent
88989b95a8
commit
1eef31a814
@ -51,7 +51,8 @@
|
||||
#define PDI_HEAP_BLOCKS 0x10
|
||||
#define PDI_HEAP_ENTRIES_EX 0x200
|
||||
|
||||
#define RtlpHpHeapGlobalsOffset 0x44A0
|
||||
static size_t RtlpHpHeapGlobalsOffset = 0;
|
||||
static size_t RtlpLFHKeyOffset = 0;
|
||||
|
||||
#define CHECK_INFO(heapInfo)\
|
||||
if (!heapInfo) {\
|
||||
@ -119,6 +120,9 @@ static bool init_func() {
|
||||
if (!RtlDestroyQueryDebugBuffer) {
|
||||
RtlDestroyQueryDebugBuffer = (NTSTATUS (NTAPI *)(PDEBUG_BUFFER))GetProcAddress (ntdll, "RtlDestroyQueryDebugBuffer");
|
||||
}
|
||||
if (!w32_NtQueryInformationProcess) {
|
||||
w32_NtQueryInformationProcess = (NTSTATUS *)GetProcAddress (ntdll, "NtQueryInformationProcess");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -232,40 +236,98 @@ static void free_extra_info(PDEBUG_HEAP_INFORMATION heap) {
|
||||
}
|
||||
}
|
||||
|
||||
static WPARAM GetNtDllOffset(RDebug *dbg) {
|
||||
r_return_val_if_fail (dbg, 0);
|
||||
RList *map_list = r_w32_dbg_maps (dbg);
|
||||
RListIter *iter;
|
||||
static bool GetHeapGlobalsOffset(RDebug *dbg, HANDLE h_proc) {
|
||||
RList *modules = r_w32_dbg_modules (dbg);
|
||||
RListIter *it;
|
||||
RDebugMap *map;
|
||||
WPARAM ntdllOffset = 0;
|
||||
// Get ntdll .data location
|
||||
r_list_foreach (map_list, iter, map) {
|
||||
if (strstr (map->name, "ntdll.dll | .data")) {
|
||||
ntdllOffset = map->addr;
|
||||
bool found = false;
|
||||
const char ntdll[] = "ntdll.dll";
|
||||
int oldfd = 0;
|
||||
static ut64 lastNdtllAddr = 0;
|
||||
r_list_foreach (modules, it, map) {
|
||||
if (!strncmp(map->name, ntdll, sizeof (ntdll))) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
r_list_free (map_list);
|
||||
return ntdllOffset;
|
||||
if (!found) {
|
||||
eprintf ("ntdll.dll not loaded.");
|
||||
r_list_free (modules);
|
||||
return false;
|
||||
}
|
||||
bool doopen = lastNdtllAddr != map->addr;
|
||||
char *ntdllopen = dbg->corebind.cmdstrf (dbg->corebind.core, "ob~%s", ntdll);
|
||||
if (*ntdllopen) {
|
||||
char *saddr = strtok (ntdllopen, " ");
|
||||
for (int i = 0; i < 3; i++) {
|
||||
saddr = strtok (NULL, " ");
|
||||
}
|
||||
ut64 addr = r_num_math (NULL, saddr + 3);
|
||||
if (doopen) {
|
||||
// Close to reopen at the right address
|
||||
int fd = atoi (ntdllopen);
|
||||
dbg->corebind.cmdstrf (dbg->corebind.core, "o-%d", fd);
|
||||
RtlpHpHeapGlobalsOffset = RtlpLFHKeyOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (doopen) {
|
||||
char *ntdllpath = r_lib_path ("ntdll");
|
||||
eprintf ("Opening %s\n", ntdllpath);
|
||||
dbg->corebind.cmdf (dbg->corebind.core, "o %s 0x%"PFMT64x"", ntdllpath, map->addr);
|
||||
lastNdtllAddr = map->addr;
|
||||
}
|
||||
r_list_free (modules);
|
||||
|
||||
if (!RtlpHpHeapGlobalsOffset || !RtlpLFHKeyOffset) {
|
||||
char *res = dbg->corebind.cmdstrf (dbg->corebind.core, "idpi~RtlpHpHeapGlobals");
|
||||
if (!*res) {
|
||||
// Try downloading the pdb
|
||||
free (res);
|
||||
dbg->corebind.cmd (dbg->corebind.core, "idpd");
|
||||
res = dbg->corebind.cmdstrf (dbg->corebind.core, "idpi~RtlpHpHeapGlobals");
|
||||
}
|
||||
if (*res) {
|
||||
RtlpHpHeapGlobalsOffset = r_num_math (NULL, res);
|
||||
} else {
|
||||
free (res);
|
||||
return false;
|
||||
}
|
||||
free (res);
|
||||
res = dbg->corebind.cmdstrf (dbg->corebind.core, "idpi~RtlpLFHKey");
|
||||
if (*res) {
|
||||
RtlpLFHKeyOffset = r_num_math (NULL, res);
|
||||
}
|
||||
free (res);
|
||||
}
|
||||
|
||||
if (doopen) {
|
||||
// Close ntdll.dll
|
||||
char *res = dbg->corebind.cmdstrf (dbg->corebind.core, "o~%s", ntdll);
|
||||
int fd = atoi (res);
|
||||
free (res);
|
||||
dbg->corebind.cmdf (dbg->corebind.core, "o-%d", fd);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static WPARAM GetLFHKey(RDebug *dbg, HANDLE h_proc, bool segment) {
|
||||
r_return_val_if_fail (dbg, 0);
|
||||
WPARAM lfhKey = 0;
|
||||
WPARAM lfhKeyLocation;
|
||||
WPARAM ntdllOffset = GetNtDllOffset (dbg);
|
||||
|
||||
if (ntdllOffset) {
|
||||
if (segment) {
|
||||
WPARAM RtlpHpHeapGlobals = ntdllOffset + RtlpHpHeapGlobalsOffset; // ntdll!RtlpHpHeapGlobals
|
||||
lfhKeyLocation = RtlpHpHeapGlobals + sizeof (WPARAM);
|
||||
} else {
|
||||
lfhKeyLocation = ntdllOffset + 0x7508; // ntdll!RtlpLFHKey
|
||||
}
|
||||
if (!ReadProcessMemory (h_proc, (PVOID)lfhKeyLocation, &lfhKey, sizeof (WPARAM), NULL)) {
|
||||
r_sys_perror ("ReadProcessMemory");
|
||||
eprintf ("LFH key not found.\n");
|
||||
}
|
||||
if (!GetHeapGlobalsOffset (dbg, h_proc)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (segment) {
|
||||
lfhKeyLocation = RtlpHpHeapGlobalsOffset + sizeof (WPARAM);
|
||||
} else {
|
||||
lfhKeyLocation = RtlpLFHKeyOffset; // ntdll!RtlpLFHKey
|
||||
}
|
||||
if (!ReadProcessMemory (h_proc, (PVOID)lfhKeyLocation, &lfhKey, sizeof (WPARAM), NULL)) {
|
||||
r_sys_perror ("ReadProcessMemory");
|
||||
eprintf ("LFH key not found.\n");
|
||||
}
|
||||
return lfhKey;
|
||||
}
|
||||
@ -284,7 +346,7 @@ static bool DecodeHeapEntry(RDebug *dbg, PHEAP heap, PHEAP_ENTRY entry) {
|
||||
return !(((BYTE *)entry)[0] ^ ((BYTE *)entry)[1] ^ ((BYTE *)entry)[2] ^ ((BYTE *)entry)[3]);
|
||||
}
|
||||
|
||||
static bool DecodeLFHEntry (RDebug *dbg, PHEAP heap, PHEAP_ENTRY entry, PHEAP_USERDATA_HEADER userBlocks, WPARAM key, WPARAM addr) {
|
||||
static bool DecodeLFHEntry(RDebug *dbg, PHEAP heap, PHEAP_ENTRY entry, PHEAP_USERDATA_HEADER userBlocks, WPARAM key, WPARAM addr) {
|
||||
r_return_val_if_fail (heap && entry, false);
|
||||
if (dbg->bits == R_SYS_BITS_64) {
|
||||
entry = (WPARAM)entry + dbg->bits;
|
||||
@ -304,12 +366,39 @@ typedef struct _th_query_params {
|
||||
bool fin;
|
||||
} th_query_params;
|
||||
|
||||
static DWORD WINAPI __th_QueryDebugBuffer (th_query_params *params) {
|
||||
static DWORD WINAPI __th_QueryDebugBuffer(th_query_params *params) {
|
||||
params->ret = RtlQueryProcessDebugInformation (params->dbg->pid, params->mask, params->db);
|
||||
params->fin = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static RList *GetListOfHeaps(RDebug *dbg, HANDLE ph) {
|
||||
PROCESS_BASIC_INFORMATION pib;
|
||||
if (w32_NtQueryInformationProcess (ph, ProcessBasicInformation, &pib, sizeof (pib), NULL)) {
|
||||
r_sys_perror ("NtQueryInformationProcess");
|
||||
return NULL;
|
||||
}
|
||||
PEB peb;
|
||||
ReadProcessMemory (ph, pib.PebBaseAddress, &peb, sizeof (PEB), NULL);
|
||||
RList *heaps = r_list_new ();
|
||||
PVOID heapAddress;
|
||||
PVOID *processHeaps;
|
||||
ULONG numberOfHeaps;
|
||||
if (dbg->bits == R_SYS_BITS_64) {
|
||||
processHeaps = *((ut64 *)(((ut8 *)&peb) + 0xF0));
|
||||
numberOfHeaps = *((ULONG *)(((ut8 *)& peb) + 0xE8));
|
||||
} else {
|
||||
processHeaps = *((ut64 *)(((ut8 *)&peb) + 0x90));
|
||||
numberOfHeaps = *((ULONG *)(((ut8 *)& peb) + 0x88));
|
||||
}
|
||||
do {
|
||||
ReadProcessMemory (ph, processHeaps, &heapAddress, sizeof (PVOID), NULL);
|
||||
r_list_push (heaps, heapAddress);
|
||||
processHeaps += 1;
|
||||
} while (--numberOfHeaps);
|
||||
return heaps;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function may fail with PDI_HEAP_BLOCKS if:
|
||||
* There's too many allocations
|
||||
@ -347,7 +436,55 @@ static PDEBUG_BUFFER InitHeapInfo(RDebug *dbg, DWORD mask) {
|
||||
r_sys_perror ("InitHeapInfo");
|
||||
}
|
||||
CloseHandle (th);
|
||||
return db;
|
||||
if (db) {
|
||||
return db;
|
||||
}
|
||||
|
||||
// TODO: Not do this
|
||||
os_info *osi = r_sys_get_osinfo ();
|
||||
if (mask == PDI_HEAPS && osi->major >= 10) {
|
||||
db = RtlCreateQueryDebugBuffer (0, FALSE);
|
||||
if (!db) {
|
||||
return NULL;
|
||||
}
|
||||
free (osi);
|
||||
PHeapInformation heapInfo = R_NEW0 (HeapInformation);
|
||||
if (!heapInfo) {
|
||||
RtlDestroyQueryDebugBuffer (db);
|
||||
return NULL;
|
||||
}
|
||||
HANDLE h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dbg->pid);
|
||||
if (!h_proc) {
|
||||
R_LOG_ERROR ("OpenProcess failed\n");
|
||||
RtlDestroyQueryDebugBuffer (db);
|
||||
return NULL;
|
||||
}
|
||||
RList *heaps = GetListOfHeaps (dbg, h_proc);
|
||||
CloseHandle (h_proc);
|
||||
heapInfo->count = heaps->length;
|
||||
void *tmp = realloc (heapInfo, sizeof (DEBUG_HEAP_INFORMATION) * heapInfo->count + sizeof (heapInfo));
|
||||
if (!tmp) {
|
||||
free (heapInfo);
|
||||
RtlDestroyQueryDebugBuffer (db);
|
||||
return NULL;
|
||||
}
|
||||
heapInfo = tmp;
|
||||
int i = 0;
|
||||
RListIter *it;
|
||||
void *heapBase;
|
||||
r_list_foreach (heaps, it, heapBase) {
|
||||
heapInfo->heaps[i].Base = heapBase;
|
||||
heapInfo->heaps[i].Granularity = sizeof (HEAP_ENTRY);
|
||||
heapInfo->heaps[i].Allocated = 0;
|
||||
heapInfo->heaps[i].Committed = 0;
|
||||
i++;
|
||||
}
|
||||
db->HeapInformation = heapInfo;
|
||||
r_list_free (heaps);
|
||||
return db;
|
||||
}
|
||||
free (osi);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define GROW_BLOCKS()\
|
||||
@ -420,11 +557,8 @@ static bool GetSegmentHeapBlocks(RDebug *dbg, HANDLE h_proc, PVOID heapBase, PHe
|
||||
if (segheapHeader.Signature != 0xddeeddee) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WPARAM RtlpHpHeapGlobals = GetNtDllOffset (dbg) + RtlpHpHeapGlobalsOffset; // ntdll!RtlpHpHeapGlobals
|
||||
|
||||
WPARAM lfhKey;
|
||||
WPARAM lfhKeyLocation = RtlpHpHeapGlobals + sizeof (WPARAM);
|
||||
WPARAM lfhKeyLocation = RtlpHpHeapGlobalsOffset + sizeof (WPARAM);
|
||||
if (!ReadProcessMemory (h_proc, (PVOID)lfhKeyLocation, &lfhKey, sizeof (WPARAM), &bytesRead)) {
|
||||
r_sys_perror ("ReadProcessMemory");
|
||||
eprintf ("LFH key not found.\n");
|
||||
@ -488,7 +622,7 @@ static bool GetSegmentHeapBlocks(RDebug *dbg, HANDLE h_proc, PVOID heapBase, PHe
|
||||
}
|
||||
|
||||
WPARAM RtlpHpHeapGlobal;
|
||||
ReadProcessMemory (h_proc, (PVOID)RtlpHpHeapGlobals, &RtlpHpHeapGlobal, sizeof (WPARAM), &bytesRead);
|
||||
ReadProcessMemory (h_proc, (PVOID)RtlpHpHeapGlobalsOffset, &RtlpHpHeapGlobal, sizeof (WPARAM), &bytesRead);
|
||||
// Backend Blocks (And VS)
|
||||
for (int i = 0; i < 2; i++) {
|
||||
HEAP_SEG_CONTEXT ctx = segheapHeader.SegContexts[i];
|
||||
@ -585,6 +719,7 @@ static PDEBUG_BUFFER GetHeapBlocks(DWORD pid, RDebug *dbg) {
|
||||
PHeapInformation heapInfo = db->HeapInformation;
|
||||
int i;
|
||||
for (i = 0; i < heapInfo->count; i++) {
|
||||
size_t tot_allocated = 0;
|
||||
WPARAM from = 0;
|
||||
ut64 count = 0;
|
||||
PDEBUG_HEAP_INFORMATION heap = &heapInfo->heaps[i];
|
||||
@ -629,6 +764,7 @@ static PDEBUG_BUFFER GetHeapBlocks(DWORD pid, RDebug *dbg) {
|
||||
extra->granularity = sizeof (HEAP_VIRTUAL_ALLOC_ENTRY);
|
||||
extra->unusedBytes = vAlloc.ReserveSize - vAlloc.CommitSize;
|
||||
blocks[count].extra = EXTRA_FLAG | (WPARAM)extra;
|
||||
tot_allocated += blocks[count].size - extra->granularity;
|
||||
count++;
|
||||
entry = vAlloc.Entry.Flink;
|
||||
}
|
||||
@ -700,6 +836,7 @@ static PDEBUG_BUFFER GetHeapBlocks(DWORD pid, RDebug *dbg) {
|
||||
extra->granularity = sizeof (HEAP_ENTRY);
|
||||
extra->segment = curSubsegment;
|
||||
blocks[count].extra = EXTRA_FLAG | (WPARAM)extra;
|
||||
tot_allocated += blocks[count].size - extra->granularity;
|
||||
count++;
|
||||
}
|
||||
mask <<= 1;
|
||||
@ -750,6 +887,7 @@ next_subsegment:
|
||||
blocks[count].flags = heapEntry.Flags | NT_BLOCK | BACKEND_BLOCK;
|
||||
blocks[count].size = real_sz;
|
||||
from += real_sz;
|
||||
tot_allocated += blocks[count].size - extra->granularity;
|
||||
count++;
|
||||
} while (from <= (WPARAM)segment.LastValidEntry);
|
||||
next:
|
||||
@ -759,6 +897,11 @@ next:
|
||||
} while ((WPARAM)oldSegment.SegmentListEntry.Flink != firstSegment);
|
||||
heap->Blocks = blocks;
|
||||
heap->BlockCount = count;
|
||||
|
||||
if (!heap->Committed && !heap->Allocated) {
|
||||
heap->Committed = heapHeader.Counters.TotalMemoryCommitted;
|
||||
heap->Allocated = tot_allocated;
|
||||
}
|
||||
}
|
||||
CloseHandle (h_proc);
|
||||
return db;
|
||||
@ -798,9 +941,8 @@ static PHeapBlock GetSingleSegmentBlock(RDebug *dbg, HANDLE h_proc, PSEGMENT_HEA
|
||||
WPARAM headerOff = offset - granularity;
|
||||
SEGMENT_HEAP heap;
|
||||
ReadProcessMemory (h_proc, heapBase, &heap, sizeof (SEGMENT_HEAP), NULL);
|
||||
WPARAM RtlpHpHeapGlobalsOff = GetNtDllOffset (dbg) + RtlpHpHeapGlobalsOffset;
|
||||
WPARAM RtlpHpHeapGlobal;
|
||||
ReadProcessMemory (h_proc, (PVOID)RtlpHpHeapGlobalsOff, &RtlpHpHeapGlobal, sizeof (WPARAM), NULL);
|
||||
ReadProcessMemory (h_proc, (PVOID)RtlpHpHeapGlobalsOffset, &RtlpHpHeapGlobal, sizeof (WPARAM), NULL);
|
||||
|
||||
WPARAM pgSegOff = headerOff & heap.SegContexts[0].SegmentMask;
|
||||
WPARAM segSignature;
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define WINDOWS_HEAP_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <winternl.h>
|
||||
|
||||
/*
|
||||
Defines most of heap related structures on Windows (some still missing)
|
||||
@ -1001,4 +1002,12 @@ NTSTATUS (NTAPI *RtlQueryProcessDebugInformation)(
|
||||
NTSTATUS (NTAPI *RtlDestroyQueryDebugBuffer)(
|
||||
IN PDEBUG_BUFFER DebugBuffer
|
||||
);
|
||||
|
||||
__kernel_entry NTSTATUS (*w32_NtQueryInformationProcess)(
|
||||
IN HANDLE ProcessHandle,
|
||||
IN PROCESSINFOCLASS ProcessInformationClass,
|
||||
OUT PVOID ProcessInformation,
|
||||
IN ULONG ProcessInformationLength,
|
||||
OUT PULONG ReturnLength
|
||||
);
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user