[PATCH 1/4] kernel32: Allow EnumProcessModules() to succeed on a WoW64 process.
Zebediah Figura
zfigura at codeweavers.com
Fri May 25 17:50:07 CDT 2018
Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
dlls/kernel32/kernel_private.h | 1 +
dlls/kernel32/module.c | 97 +++++++++++++++++++++++++++++++++++++++++-
dlls/kernel32/process.c | 2 +-
dlls/psapi/tests/Makefile.in | 1 +
dlls/psapi/tests/psapi_main.c | 67 +++++++++++++++++++++++++++++
5 files changed, 166 insertions(+), 2 deletions(-)
diff --git a/dlls/kernel32/kernel_private.h b/dlls/kernel32/kernel_private.h
index 9073e18..ad4621c 100644
--- a/dlls/kernel32/kernel_private.h
+++ b/dlls/kernel32/kernel_private.h
@@ -52,6 +52,7 @@ static inline obj_handle_t console_handle_unmap(HANDLE h)
#define KERNEL32_CONSOLE_ALLOC ((HANDLE)1)
#define KERNEL32_CONSOLE_SHELL ((HANDLE)2)
+extern BOOL is_wow64 DECLSPEC_HIDDEN;
extern HMODULE kernel32_handle DECLSPEC_HIDDEN;
extern SYSTEM_BASIC_INFORMATION system_info DECLSPEC_HIDDEN;
diff --git a/dlls/kernel32/module.c b/dlls/kernel32/module.c
index 6f123ca..4cf5c20 100644
--- a/dlls/kernel32/module.c
+++ b/dlls/kernel32/module.c
@@ -1493,10 +1493,56 @@ FARPROC WINAPI DelayLoadFailureHook( LPCSTR name, LPCSTR function )
return NULL;
}
+typedef struct _PEB32
+{
+ BOOLEAN InheritedAddressSpace;
+ BOOLEAN ReadImageFileExecOptions;
+ BOOLEAN BeingDebugged;
+ BOOLEAN SpareBool;
+ DWORD Mutant;
+ DWORD ImageBaseAddress;
+ DWORD LdrData;
+} PEB32;
+
+typedef struct _LIST_ENTRY32
+{
+ DWORD Flink;
+ DWORD Blink;
+} LIST_ENTRY32;
+
+typedef struct _PEB_LDR_DATA32
+{
+ ULONG Length;
+ BOOLEAN Initialized;
+ DWORD SsHandle;
+ LIST_ENTRY32 InLoadOrderModuleList;
+} PEB_LDR_DATA32;
+
+typedef struct _UNICODE_STRING32
+{
+ USHORT Length;
+ USHORT MaximumLength;
+ DWORD Buffer;
+} UNICODE_STRING32;
+
+typedef struct _LDR_MODULE32
+{
+ LIST_ENTRY32 InLoadOrderModuleList;
+ LIST_ENTRY32 InMemoryOrderModuleList;
+ LIST_ENTRY32 InInitializationOrderModuleList;
+ DWORD BaseAddress;
+ DWORD EntryPoint;
+ ULONG SizeOfImage;
+ UNICODE_STRING32 FullDllName;
+ UNICODE_STRING32 BaseDllName;
+} LDR_MODULE32;
+
typedef struct {
+ BOOL wow64;
HANDLE process;
PLIST_ENTRY head, current;
LDR_MODULE ldr_module;
+ LDR_MODULE32 ldr_module32;
} MODULE_ITERATOR;
static BOOL init_module_iterator(MODULE_ITERATOR *iter, HANDLE process)
@@ -1505,6 +1551,15 @@ static BOOL init_module_iterator(MODULE_ITERATOR *iter, HANDLE process)
PPEB_LDR_DATA ldr_data;
NTSTATUS status;
+ if (!IsWow64Process(process, &iter->wow64))
+ return FALSE;
+
+ if (is_wow64 && !iter->wow64)
+ {
+ SetLastError(ERROR_PARTIAL_COPY);
+ return FALSE;
+ }
+
/* Get address of PEB */
status = NtQueryInformationProcess(process, ProcessBasicInformation,
&pbi, sizeof(pbi), NULL);
@@ -1514,6 +1569,30 @@ static BOOL init_module_iterator(MODULE_ITERATOR *iter, HANDLE process)
return FALSE;
}
+ if (!is_wow64 && iter->wow64)
+ {
+ PEB_LDR_DATA32 *ldr_data32_ptr;
+ DWORD ldr_data32, first_module;
+ PEB32 *peb32;
+
+ peb32 = (PEB32 *)(DWORD_PTR)pbi.PebBaseAddress;
+
+ if (!ReadProcessMemory(process, &peb32->LdrData, &ldr_data32,
+ sizeof(ldr_data32), NULL))
+ return FALSE;
+ ldr_data32_ptr = (PEB_LDR_DATA32 *)(DWORD_PTR) ldr_data32;
+
+ if (!ReadProcessMemory(process,
+ &ldr_data32_ptr->InLoadOrderModuleList.Flink,
+ &first_module, sizeof(first_module), NULL))
+ return FALSE;
+ iter->head = (LIST_ENTRY *)&ldr_data32_ptr->InLoadOrderModuleList;
+ iter->current = (LIST_ENTRY *)(DWORD_PTR) first_module;
+ iter->process = process;
+
+ return TRUE;
+ }
+
/* Read address of LdrData from PEB */
if (!ReadProcessMemory(process, &pbi.PebBaseAddress->LdrData,
&ldr_data, sizeof(ldr_data), NULL))
@@ -1536,6 +1615,19 @@ static int module_iterator_next(MODULE_ITERATOR *iter)
if (iter->current == iter->head)
return 0;
+ if (!is_wow64 && iter->wow64)
+ {
+ LIST_ENTRY32 *entry32 = (LIST_ENTRY32 *)iter->current;
+
+ if (!ReadProcessMemory(iter->process,
+ CONTAINING_RECORD(entry32, LDR_MODULE32, InLoadOrderModuleList),
+ &iter->ldr_module32, sizeof(iter->ldr_module32), NULL))
+ return -1;
+
+ iter->current = (LIST_ENTRY *)(DWORD_PTR) iter->ldr_module32.InLoadOrderModuleList.Flink;
+ return 1;
+ }
+
if (!ReadProcessMemory(iter->process,
CONTAINING_RECORD(iter->current, LDR_MODULE, InLoadOrderModuleList),
&iter->ldr_module, sizeof(iter->ldr_module), NULL))
@@ -1594,7 +1686,10 @@ BOOL WINAPI K32EnumProcessModules(HANDLE process, HMODULE *lphModule,
{
if (cb >= sizeof(HMODULE))
{
- *lphModule++ = iter.ldr_module.BaseAddress;
+ if (!is_wow64 && iter.wow64)
+ *lphModule++ = (HMODULE) (DWORD_PTR)iter.ldr_module32.BaseAddress;
+ else
+ *lphModule++ = iter.ldr_module.BaseAddress;
cb -= sizeof(HMODULE);
}
size += sizeof(HMODULE);
diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c
index ff56e9a..be3e40e 100644
--- a/dlls/kernel32/process.c
+++ b/dlls/kernel32/process.c
@@ -83,9 +83,9 @@ typedef struct
static DWORD shutdown_flags = 0;
static DWORD shutdown_priority = 0x280;
-static BOOL is_wow64;
static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
+BOOL is_wow64;
HMODULE kernel32_handle = 0;
SYSTEM_BASIC_INFORMATION system_info = { 0 };
diff --git a/dlls/psapi/tests/Makefile.in b/dlls/psapi/tests/Makefile.in
index 535fb54..980ed0a 100644
--- a/dlls/psapi/tests/Makefile.in
+++ b/dlls/psapi/tests/Makefile.in
@@ -1,4 +1,5 @@
TESTDLL = psapi.dll
+IMPORTS = user32
C_SRCS = \
psapi_main.c
diff --git a/dlls/psapi/tests/psapi_main.c b/dlls/psapi/tests/psapi_main.c
index 8638d73..169f9b0 100644
--- a/dlls/psapi/tests/psapi_main.c
+++ b/dlls/psapi/tests/psapi_main.c
@@ -33,6 +33,7 @@
#include "winnt.h"
#include "winternl.h"
#include "winnls.h"
+#include "winuser.h"
#include "psapi.h"
#include "wine/test.h"
@@ -62,6 +63,11 @@ static BOOL (WINAPI *pInitializeProcessForWsWatch)(HANDLE);
static BOOL (WINAPI *pQueryWorkingSet)(HANDLE, PVOID, DWORD);
static NTSTATUS (WINAPI *pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
static NTSTATUS (WINAPI *pNtQueryVirtualMemory)(HANDLE, LPCVOID, ULONG, PVOID, SIZE_T, SIZE_T *);
+static BOOL (WINAPI *pIsWow64Process)(HANDLE, BOOL *);
+static BOOL (WINAPI *pWow64DisableWow64FsRedirection)(void **);
+static BOOL (WINAPI *pWow64RevertWow64FsRedirection)(void *);
+
+static BOOL wow64;
static BOOL InitFunctionPtrs(HMODULE hpsapi)
{
@@ -87,6 +93,9 @@ static BOOL InitFunctionPtrs(HMODULE hpsapi)
(void *)GetProcAddress(hpsapi, "GetProcessImageFileNameW");
pNtQuerySystemInformation = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQuerySystemInformation");
pNtQueryVirtualMemory = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryVirtualMemory");
+ pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
+ pWow64DisableWow64FsRedirection = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "Wow64DisableWow64FsRedirection");
+ pWow64RevertWow64FsRedirection = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "Wow64RevertWow64FsRedirection");
return TRUE;
}
@@ -110,6 +119,10 @@ static void test_EnumProcesses(void)
static void test_EnumProcessModules(void)
{
+ char buffer[200] = "C:\\windows\\system32\\notepad.exe";
+ PROCESS_INFORMATION pi = {0};
+ STARTUPINFOA si = {0};
+ void *cookie;
HMODULE hMod;
DWORD ret, cbNeeded = 0xdeadbeef;
@@ -151,6 +164,57 @@ static void test_EnumProcessModules(void)
ok(hMod == GetModuleHandleA(NULL),
"hMod=%p GetModuleHandleA(NULL)=%p\n", hMod, GetModuleHandleA(NULL));
ok(cbNeeded % sizeof(hMod) == 0, "not a multiple of sizeof(HMODULE) cbNeeded=%d\n", cbNeeded);
+
+ ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
+ ok(ret, "CreateProcess failed: %u\n", GetLastError());
+
+ ret = WaitForInputIdle(pi.hProcess, 1000);
+ ok(!ret, "wait timed out\n");
+
+ SetLastError(0xdeadbeef);
+ hMod = NULL;
+ ret = pEnumProcessModules(pi.hProcess, &hMod, sizeof(HMODULE), &cbNeeded);
+ ok(ret == 1, "got %d, error %u\n", ret, GetLastError());
+ ok(!!hMod, "expeced non-NULL module\n");
+ ok(cbNeeded % sizeof(hMod) == 0, "got %u\n", cbNeeded);
+
+ TerminateProcess(pi.hProcess, 0);
+
+ if (sizeof(void *) == 8)
+ {
+ strcpy(buffer, "C:\\windows\\syswow64\\notepad.exe");
+ ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
+ ok(ret, "CreateProcess failed: %u\n", GetLastError());
+
+ ret = WaitForInputIdle(pi.hProcess, 1000);
+ ok(!ret, "wait timed out\n");
+
+ SetLastError(0xdeadbeef);
+ hMod = NULL;
+ ret = pEnumProcessModules(pi.hProcess, &hMod, sizeof(HMODULE), &cbNeeded);
+ ok(ret == 1, "got %d, error %u\n", ret, GetLastError());
+ ok(!!hMod, "expeced non-NULL module\n");
+ ok(cbNeeded % sizeof(hMod) == 0, "got %u\n", cbNeeded);
+
+ TerminateProcess(pi.hProcess, 0);
+ }
+ else if (wow64)
+ {
+ pWow64DisableWow64FsRedirection(&cookie);
+ ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
+ pWow64RevertWow64FsRedirection(cookie);
+ ok(ret, "CreateProcess failed: %u\n", GetLastError());
+
+ ret = WaitForInputIdle(pi.hProcess, 1000);
+ ok(!ret, "wait timed out\n");
+
+ SetLastError(0xdeadbeef);
+ ret = pEnumProcessModules(pi.hProcess, &hMod, sizeof(HMODULE), &cbNeeded);
+ ok(!ret, "got %d\n", ret);
+ ok(GetLastError() == ERROR_PARTIAL_COPY, "got error %u\n", GetLastError());
+
+ TerminateProcess(pi.hProcess, 0);
+ }
}
static void test_GetModuleInformation(void)
@@ -781,6 +845,9 @@ START_TEST(psapi_main)
{
DWORD pid = GetCurrentProcessId();
+ if (pIsWow64Process)
+ IsWow64Process(GetCurrentProcess(), &wow64);
+
hpSR = OpenProcess(STANDARD_RIGHTS_REQUIRED, FALSE, pid);
hpQI = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
hpVR = OpenProcess(PROCESS_VM_READ, FALSE, pid);
--
2.7.4
More information about the wine-devel
mailing list