From: Yuxuan Shui yshui@codeweavers.com
--- dlls/kernel32/kernel_main.c | 2 + dlls/kernel32/kernel_private.h | 1 + dlls/kernel32/tests/toolhelp.c | 19 +---- dlls/kernel32/toolhelp.c | 124 ++++++++++++++++++++++++++++++++- 4 files changed, 128 insertions(+), 18 deletions(-)
diff --git a/dlls/kernel32/kernel_main.c b/dlls/kernel32/kernel_main.c index edf54e84b72..410ba0088ac 100644 --- a/dlls/kernel32/kernel_main.c +++ b/dlls/kernel32/kernel_main.c @@ -35,6 +35,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(process);
static STARTUPINFOA startup_infoA; +BOOL is_wow64;
/*********************************************************************** * set_entry_point @@ -161,6 +162,7 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls( hinst ); + IsWow64Process( GetCurrentProcess(), &is_wow64 ); return process_attach( hinst ); case DLL_PROCESS_DETACH: WritePrivateProfileSectionW( NULL, NULL, NULL ); diff --git a/dlls/kernel32/kernel_private.h b/dlls/kernel32/kernel_private.h index 3c35a4b1bba..c6f81992f29 100644 --- a/dlls/kernel32/kernel_private.h +++ b/dlls/kernel32/kernel_private.h @@ -44,5 +44,6 @@ extern SYSTEM_BASIC_INFORMATION system_info;
extern WCHAR *FILE_name_AtoW( LPCSTR name, BOOL alloc ); extern DWORD FILE_name_WtoA( LPCWSTR src, INT srclen, LPSTR dest, INT destlen ); +extern BOOL is_wow64;
#endif diff --git a/dlls/kernel32/tests/toolhelp.c b/dlls/kernel32/tests/toolhelp.c index 302a1c7fc38..9d35de0f86d 100644 --- a/dlls/kernel32/tests/toolhelp.c +++ b/dlls/kernel32/tests/toolhelp.c @@ -473,13 +473,7 @@ static void test_module32_only(DWORD pid) MODULEENTRY32 me;
hSnapshot = create_toolhelp_snapshot( TH32CS_SNAPMODULE32, pid ); - todo_wine ok(hSnapshot != INVALID_HANDLE_VALUE, "Cannot create snapshot\n"); - if (hSnapshot == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - { - skip("Cannot create snapshot handle\n"); - return; - } - + ok(hSnapshot != INVALID_HANDLE_VALUE, "Cannot create snapshot\n"); ok(!pModule32First( hSnapshot, &me ), "Got unexpected module entry\n"); CloseHandle( hSnapshot ); } @@ -508,11 +502,6 @@ static void test_module(DWORD pid, struct expected_module expected[], unsigned n
hSnapshot = create_toolhelp_snapshot( snapshot_flags, pid ); ok(hSnapshot != INVALID_HANDLE_VALUE, "Cannot create snapshot %#lx\n", GetLastError()); - if (hSnapshot == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - { - skip("CreateToolhelp32Snapshot doesn't support requested flags\n"); - return; - }
for (i = 0; i < num_expected; i++) found[i] = 0; me.dwSize = sizeof(me); @@ -528,10 +517,9 @@ static void test_module(DWORD pid, struct expected_module expected[], unsigned n num++; } while (pModule32Next( hSnapshot, &me )); } - todo_if(winetest_platform_is_wine && module32 && is_win64) ok(found[0] == expected_main_exe_count, "Main exe was found %d time(s)\n", found[0]); for (i = 1; i < num_expected; i++) - todo_if((winetest_platform_is_wine && expected[i].wow64 == 1) || (is_old_wow && !expected[i].wow64)) + todo_if(is_old_wow && !expected[i].wow64) ok(found[i] == 1, "Module %s is %s\n", expected[i].module, found[i] ? "listed more than once" : "not listed");
@@ -549,10 +537,9 @@ static void test_module(DWORD pid, struct expected_module expected[], unsigned n num--; } while (pModule32Next( hSnapshot, &me )); } - todo_if(winetest_platform_is_wine && module32 && is_win64) ok(found[0] == expected_main_exe_count, "Main exe was found %d time(s)\n", found[0]); for (i = 1; i < num_expected; i++) - todo_if((winetest_platform_is_wine && expected[i].wow64 == 1) || (is_old_wow && !expected[i].wow64)) + todo_if(is_old_wow && !expected[i].wow64) ok(found[i] == 1, "Module %s is %s\n", expected[i].module, found[i] ? "listed more than once" : "not listed"); ok(!num, "mismatch in counting\n"); diff --git a/dlls/kernel32/toolhelp.c b/dlls/kernel32/toolhelp.c index 28971dbd07e..e6275fb751b 100644 --- a/dlls/kernel32/toolhelp.c +++ b/dlls/kernel32/toolhelp.c @@ -69,18 +69,56 @@ static WCHAR *fetch_string( HANDLE hProcess, UNICODE_STRING* us) return local; }
+typedef struct _LDR_DATA_TABLE_ENTRY32 +{ + LIST_ENTRY32 InLoadOrderLinks; + LIST_ENTRY32 InMemoryOrderLinks; + LIST_ENTRY32 InInitializationOrderLinks; + DWORD DllBase; + DWORD EntryPoint; + ULONG SizeOfImage; + UNICODE_STRING32 FullDllName; + UNICODE_STRING32 BaseDllName; +} LDR_DATA_TABLE_ENTRY32; + +typedef LIST_ENTRY32 *PLIST_ENTRY32; + +static inline void ldr_data_table_entry_32to64(LDR_DATA_TABLE_ENTRY *dst, LDR_DATA_TABLE_ENTRY32 *src) +{ + dst->BaseDllName.Buffer = (PWSTR)(DWORD_PTR)src->BaseDllName.Buffer; + dst->BaseDllName.Length = src->BaseDllName.Length; + dst->FullDllName.Buffer = (PWSTR)(DWORD_PTR)src->FullDllName.Buffer; + dst->FullDllName.Length = src->FullDllName.Length; + dst->DllBase = (void *)(DWORD_PTR)src->DllBase; + dst->SizeOfImage = src->SizeOfImage; +} + static BOOL fetch_module( DWORD process, DWORD flags, LDR_DATA_TABLE_ENTRY **ldr_mod, ULONG *num ) { + static const BOOL is_win64 = (sizeof(void *) > sizeof(int)); HANDLE hProcess; PROCESS_BASIC_INFORMATION pbi; PPEB_LDR_DATA pLdrData; PLIST_ENTRY head, curr; + PLIST_ENTRY32 head32, curr32; BOOL ret = FALSE; + BOOL target_wow64; + PEB32* peb32; + DWORD pLdrData32, tmp; + WCHAR system32[MAX_PATH], syswow64[MAX_PATH]; + int system32_len = 0, syswow64_len = 0;
*num = 0;
if (!(flags & TH32CS_SNAPMODULE)) return TRUE;
+ if (flags & TH32CS_SNAPMODULE32) + { + /* need system directory paths for path rewrites */ + if (!(system32_len = GetSystemDirectoryW(system32, ARRAY_SIZE(system32)))) return FALSE; + if (!(syswow64_len = GetSystemWow64DirectoryW(syswow64, ARRAY_SIZE(syswow64)))) return FALSE; + } + if (process) { hProcess = OpenProcess( PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, process ); @@ -90,6 +128,18 @@ static BOOL fetch_module( DWORD process, DWORD flags, LDR_DATA_TABLE_ENTRY **ldr else hProcess = GetCurrentProcess();
+ if (hProcess != GetCurrentProcess()) + { + if (!IsWow64Process( hProcess, &target_wow64 )) return FALSE; + } + else target_wow64 = is_wow64; + + if (is_wow64 && !target_wow64) + { + SetLastError( ERROR_PARTIAL_COPY ); + goto out; + } + if (set_ntstatus( NtQueryInformationProcess( hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL ))) { @@ -101,7 +151,7 @@ static BOOL fetch_module( DWORD process, DWORD flags, LDR_DATA_TABLE_ENTRY **ldr goto out; }
- /* pLdrData is NULL on "old" wow64. Don't fail, just return an empty modules list. */ + /* pLdrData can be NULL on "old" wow64 configuration. Don't fail. */ if (pLdrData) { head = &pLdrData->InLoadOrderModuleList; @@ -131,8 +181,78 @@ static BOOL fetch_module( DWORD process, DWORD flags, LDR_DATA_TABLE_ENTRY **ldr HeapFree( GetProcessHeap(), 0, (*ldr_mod)[*num].BaseDllName.Buffer ); } } + } + + if (!is_win64 || !target_wow64 || !(flags & TH32CS_SNAPMODULE32)) + { ret = TRUE; + goto out; + } + if (!set_ntstatus( NtQueryInformationProcess( hProcess, ProcessWow64Information, + &peb32, sizeof(peb32), NULL )) || + !ReadProcessMemory( hProcess, &peb32->LdrData, &pLdrData32, sizeof(pLdrData32), NULL ) || + !ReadProcessMemory( hProcess, + &((PPEB_LDR_DATA32)(DWORD_PTR)pLdrData32)->InLoadOrderModuleList.Flink, + &tmp, sizeof(tmp), NULL )) + { + goto out; + } + + curr32 = (PLIST_ENTRY32)(DWORD_PTR)tmp; + head32 = &((PPEB_LDR_DATA32)(DWORD_PTR)pLdrData32)->InLoadOrderModuleList; + while (curr32 != head32) + { + LDR_DATA_TABLE_ENTRY32 entry32; + LDR_DATA_TABLE_ENTRY* out_entry; + int full_dll_name_len; + if (!*num) + *ldr_mod = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LDR_DATA_TABLE_ENTRY) ); + else + *ldr_mod = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *ldr_mod, + (*num + 1) * sizeof(LDR_DATA_TABLE_ENTRY) ); + out_entry = &(*ldr_mod)[*num]; + if (!ReadProcessMemory( hProcess, + CONTAINING_RECORD(curr32, LDR_DATA_TABLE_ENTRY32, InLoadOrderLinks), + &entry32, sizeof(entry32), NULL )) + break; + + curr32 = (PLIST_ENTRY32)(DWORD_PTR)entry32.InLoadOrderLinks.Flink; + ldr_data_table_entry_32to64(out_entry, &entry32); + if (!fetch_string( hProcess, &out_entry->BaseDllName )) continue; + if (!fetch_string( hProcess, &out_entry->FullDllName )) + { + HeapFree( GetProcessHeap(), 0, out_entry->BaseDllName.Buffer ); + continue; + } + + /* rewrite path in system32 into syswow64 for 32bit modules */ + full_dll_name_len = out_entry->FullDllName.Length / sizeof(WCHAR); + if (full_dll_name_len >= system32_len && + CompareStringW( LOCALE_INVARIANT, NORM_IGNORECASE, + system32, system32_len, + out_entry->FullDllName.Buffer, system32_len ) == CSTR_EQUAL) + { + int new_len = full_dll_name_len - system32_len + syswow64_len + 1; + WCHAR *new_path = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, new_len * sizeof(WCHAR) ); + + if (!new_path) + { + HeapFree( GetProcessHeap(), 0, out_entry->BaseDllName.Buffer ); + HeapFree( GetProcessHeap(), 0, out_entry->FullDllName.Buffer ); + continue; + } + + lstrcpyW( new_path, syswow64 ); + memcpy( new_path + syswow64_len, out_entry->FullDllName.Buffer + system32_len, + out_entry->FullDllName.Length - system32_len * sizeof(WCHAR) ); + HeapFree( GetProcessHeap(), 0, out_entry->FullDllName.Buffer ); + out_entry->FullDllName.Buffer = new_path; + out_entry->FullDllName.Length = new_len * sizeof(WCHAR); + } + + (*num)++; } + ret = TRUE;
out: if (process) CloseHandle( hProcess ); @@ -298,7 +418,7 @@ HANDLE WINAPI CreateToolhelp32Snapshot( DWORD flags, DWORD process ) HANDLE hSnapShot = 0;
TRACE("%lx,%lx\n", flags, process ); - if (!(flags & (TH32CS_SNAPPROCESS|TH32CS_SNAPTHREAD|TH32CS_SNAPMODULE))) + if (!(flags & (TH32CS_SNAPPROCESS|TH32CS_SNAPTHREAD|TH32CS_SNAPMODULE|TH32CS_SNAPMODULE32))) { FIXME("flags %lx not implemented\n", flags ); SetLastError( ERROR_CALL_NOT_IMPLEMENTED );