[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