When: - caller of dbghelp is a 64bit process, - invoking SymInitialize on a 32bit live target running under WOW64
SymInitialize fails because: - check_live_target() erroneously reads the 64bit PEB of the target, while it actually wants the 32bit PEB. - as the ELF base header address isn't set (hidden in CloudFileFlags) in the 64bit PEB, hence causing the failure
So ensure that check_live_target() actually reads the 32bit PEB when handling a 32bit process.
----
I couldn't find a simpler way to fix it :-( (offsetting PEB address by 0x1000 works but is way too hacky)
And I'm still not happy with the result. Is there a better way to solve this?
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp.c | 58 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 4 deletions(-)
diff --git a/dlls/dbghelp/dbghelp.c b/dlls/dbghelp/dbghelp.c index 00d7b61fbd8..9475e2dc2ac 100644 --- a/dlls/dbghelp/dbghelp.c +++ b/dlls/dbghelp/dbghelp.c @@ -27,6 +27,7 @@ #include "wine/debug.h" #include "wdbgexts.h" #include "winnls.h" +#include <tlhelp32.h>
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
@@ -282,11 +283,51 @@ const WCHAR *process_getenv(const struct process *process, const WCHAR *name) return NULL; }
+/* retrieves the PEB32 address of a 32bit target under wow64 when dbghelp is a 64bit process */ +static PEB* get_peb32_addr(HANDLE proc) +{ + HANDLE snap; + HANDLE thread; + THREADENTRY32 te; + PEB* ret = NULL; + DWORD pid = GetProcessId(proc); + THREAD_BASIC_INFORMATION thread_info; + TEB teb; + TEB32 teb32; + SIZE_T res; + + snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if (snap == INVALID_HANDLE_VALUE) return NULL; + + te.dwSize = sizeof(te); + if (Thread32First(snap, &te)) + { + do + { + if (te.th32OwnerProcessID == pid && + te.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(te.th32OwnerProcessID) && + (thread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, te.th32ThreadID)) != NULL) + { + if (NtQueryInformationThread(thread, ThreadBasicInformation, &thread_info, sizeof(thread_info), NULL) == 0 && + ReadProcessMemory(proc, thread_info.TebBaseAddress, &teb, sizeof(teb), &res ) && + ReadProcessMemory(proc, teb.Tib.ExceptionList, &teb32, sizeof(teb32), &res)) + { + ret = (PEB*)(ULONG_PTR)teb32.Peb; + } + CloseHandle(thread); + } + te.dwSize = sizeof(te); + } while (!ret && Thread32Next(snap, &te)); + } + CloseHandle(snap); + return ret; +} + /****************************************************************** * check_live_target * */ -static BOOL check_live_target(struct process* pcs) +static BOOL check_live_target(struct process* pcs, BOOL wow64, BOOL child_wow64) { PROCESS_BASIC_INFORMATION pbi; ULONG_PTR base = 0, env = 0; @@ -300,11 +341,20 @@ static BOOL check_live_target(struct process* pcs)
if (!pcs->is_64bit) { + void* peb32_addr; DWORD env32; PEB32 peb32; + C_ASSERT(sizeof(void*) != 4 || FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment) == 0x48); - if (!ReadProcessMemory(pcs->handle, pbi.PebBaseAddress, &peb32, sizeof(peb32), NULL)) return FALSE; - if (!ReadProcessMemory(pcs->handle, (char *)pbi.PebBaseAddress + 0x460 /* CloudFileFlags */, &base, sizeof(base), NULL)) return FALSE; + if (!wow64 && child_wow64) + { + peb32_addr = get_peb32_addr(pcs->handle); + if (!peb32_addr) return FALSE; + } + else + peb32_addr = pbi.PebBaseAddress; + if (!ReadProcessMemory(pcs->handle, peb32_addr, &peb32, sizeof(peb32), NULL)) return FALSE; + if (!ReadProcessMemory(pcs->handle, (char *)peb32_addr + 0x460 /* CloudFileFlags */, &base, sizeof(base), NULL)) return FALSE; if (read_process_memory(pcs, peb32.ProcessParameters + 0x48, &env32, sizeof(env32))) env = env32; } else @@ -454,7 +504,7 @@ BOOL WINAPI SymInitializeW(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeP pcs->next = process_first; process_first = pcs;
- if (check_live_target(pcs)) + if (check_live_target(pcs, wow64, child_wow64)) { if (fInvadeProcess) EnumerateLoadedModulesW64(hProcess, process_invade_cb, hProcess);