https://bugs.winehq.org/show_bug.cgi?id=50208
Bug ID: 50208 Summary: Multiple kernel drivers need NtQuerySystemInformation(SystemModuleInformation) to return correct ImageBaseAddress and ImageSize for modules (Sentinel HASP 'hardlock.sys') Product: Wine Version: 5.22 Hardware: x86-64 OS: Linux Status: NEW Severity: normal Priority: P2 Component: ntdll Assignee: wine-bugs@winehq.org Reporter: focht@gmx.net Distribution: ---
Hello folks,
as it says.
Download:
https://web.archive.org/web/20201128131118/http://www.cadshop.ru/drivers/HAS...
NOTE: The logs have patch for bug 50201 applied, hence the non-dynamic/default load base address for 'ntoskrnl.exe' 0x8XXXXXXX.
--- snip --- $ WINEDEBUG=+seh,+relay,+loaddll,+ntoskrnl wine net start hardlock ... The hardlock service is starting. ... 0108:Call driver init 00EB4A24 (obj=0012B7C0,str=L"\Registry\Machine\System\CurrentControlSet\Services\hardlock") 0108:trace:seh:dispatch_exception code=c0000096 flags=0 addr=00EB49B6 ip=00eb49b6 tid=0108 0108:trace:seh:dispatch_exception eax=00000400 ebx=00eb4a24 ecx=00eb4a24 edx=00eb766b esi=0012b7c0 edi=0012b874 0108:trace:seh:dispatch_exception ebp=00d0fdd0 esp=00d0fb5c cs=0023 ds=002b es=002b fs=0063 gs=006b flags=00010206 0108:trace:seh:call_vectored_handlers calling handler at 8200DA00 code=c0000096 flags=0 0108:trace:seh:call_vectored_handlers handler at 8200DA00 returned ffffffff ... 0108:Call ntoskrnl.exe.MmIsAddressValid(82008000) ret=00eb4bd3 0108:trace:ntoskrnl:MmIsAddressValid (82008000) 0108:Call KERNEL32.IsBadReadPtr(82008000,00000001) ret=82012dc6 0108:Ret KERNEL32.IsBadReadPtr() retval=00000000 ret=82012dc6 0108:Ret ntoskrnl.exe.MmIsAddressValid() retval=00000001 ret=00eb4bd3 0108:Call ntoskrnl.exe.MmIsAddressValid(82007000) ret=00eb4bd3 0108:trace:ntoskrnl:MmIsAddressValid (82007000) 0108:Call KERNEL32.IsBadReadPtr(82007000,00000001) ret=82012dc6 0108:Ret KERNEL32.IsBadReadPtr() retval=00000000 ret=82012dc6 0108:Ret ntoskrnl.exe.MmIsAddressValid() retval=00000001 ret=00eb4bd3 0108:Call ntoskrnl.exe.MmIsAddressValid(82006000) ret=00eb4bd3 0108:trace:ntoskrnl:MmIsAddressValid (82006000) 0108:Call KERNEL32.IsBadReadPtr(82006000,00000001) ret=82012dc6 0108:Ret KERNEL32.IsBadReadPtr() retval=00000000 ret=82012dc6 0108:Ret ntoskrnl.exe.MmIsAddressValid() retval=00000001 ret=00eb4bd3 0108:Call ntoskrnl.exe.MmIsAddressValid(82005000) ret=00eb4bd3 0108:trace:ntoskrnl:MmIsAddressValid (82005000) 0108:Call KERNEL32.IsBadReadPtr(82005000,00000001) ret=82012dc6 0108:Ret KERNEL32.IsBadReadPtr() retval=00000000 ret=82012dc6 0108:Ret ntoskrnl.exe.MmIsAddressValid() retval=00000001 ret=00eb4bd3 ... 0108:Call ntoskrnl.exe.ZwQuerySystemInformation(0000000b,00d0f8c4,00000120,00d0f9e8) ret=00e9dc56 0108:Call ntdll.NtQuerySystemInformation(0000000b,00d0f8c4,00000120,00d0f9e8) ret=7bc3ab84 0108:Ret ntdll.NtQuerySystemInformation() retval=c0000004 ret=7bc3ab84 0108:Ret ntoskrnl.exe.ZwQuerySystemInformation() retval=c0000004 ret=00e9dc56 0108:Call ntoskrnl.exe.ExAllocatePoolWithTag(00000001,00000358,30396b48) ret=00e9dc67 0108:Call ntdll.RtlAllocateHeap(00a90000,00000000,00000358) ret=82011e8a 0108:Ret ntdll.RtlAllocateHeap() retval=00a923a0 ret=82011e8a 0108:trace:ntoskrnl:ExAllocatePoolWithTag Call ntdll.memchr(003cddd4,00000075,00000007) ret=003b5c6a 0108:Ret ntdll.memchr() retval=003cddd7 ret=003b5c6a 0108:Call ntdll.memchr(003cddd4,00000075,00000007) ret=003b5c6a 0108:Ret ntdll.memchr() retval=003cddd7 ret=003b5c6a 0108:Ret ntoskrnl.exe.ExAllocatePoolWithTag() retval=00a923a0 ret=00e9dc67 0108:Call ntoskrnl.exe.ZwQuerySystemInformation(0000000b,00a923a0,00000358,00d0f9e8) ret=00e9dc85 0108:Call ntdll.NtQuerySystemInformation(0000000b,00a923a0,00000358,00d0f9e8) ret=7bc3ab84 0108:Ret ntdll.NtQuerySystemInformation() retval=00000000 ret=7bc3ab84 0108:Ret ntoskrnl.exe.ZwQuerySystemInformation() retval=00000000 ret=00e9dc85 ... 0108:trace:ntoskrnl:init_driver init done for L"hardlock" obj 0012B7C0 0108:trace:ntoskrnl:init_driver - DriverInit = 00EB4A24 0108:trace:ntoskrnl:init_driver - DriverStartIo = 00000000 0108:trace:ntoskrnl:init_driver - DriverUnload = 00E3F03E 0108:trace:ntoskrnl:init_driver Call ntdll.memchr(003cddd4,00000064,00000007) ret=003b5c6a 0108:Ret ntdll.memchr() retval=003cddd4 ret=003b5c6a 0108:trace:ntoskrnl:init_driver Call ntdll.memchr(003cddd4,00000064,00000007) ret=003b5c6a 0108:Ret ntdll.memchr() retval=003cddd4 ret=003b5c6a ... 0108:Ret ntoskrnl.exe.ZwLoadDriver() retval=c000009a ret=00401392 ... failed to create driver L"\Registry\Machine\System\CurrentControlSet\Services\hardlock": c000009a --- snip ---
The problem can't be seen in trace logs hence debugging of the driver is needed.
The driver is partially code-flow obfuscated and employs a number of anti-debug tricks. The relevant piece of disassembly (not obfuscated):
--- snip --- 00E9DC30 | push ebp 00E9DC31 | mov ebp,esp 00E9DC33 | sub esp,128 00E9DC39 | push ebx 00E9DC3A | lea eax,dword ptr ss:[ebp-4] ; buffer size needed 00E9DC3D | push esi 00E9DC3E | lea ecx,dword ptr ss:[ebp-128] 00E9DC44 | push edi 00E9DC45 | mov esi,dword ptr ds:[&_NtQuerySystemInformation@16] 00E9DC4B | push eax 00E9DC4C | push 120 00E9DC51 | push ecx 00E9DC52 | push B ; SystemModuleInformation 00E9DC54 | call esi ; NtQuerySystemInformation() 00E9DC56 | push 30396B48 00E9DC5B | mov ecx,dword ptr ss:[ebp-4] 00E9DC5E | push ecx 00E9DC5F | push 1 00E9DC61 | call dword ptr ds:[&_ExAllocatePoolWithTag@12] 00E9DC67 | mov ebx,eax 00E9DC69 | test ebx,ebx 00E9DC6B | jne hardlock.E9DC78 00E9DC6D | xor al,al 00E9DC6F | pop edi 00E9DC70 | pop esi 00E9DC71 | pop ebx 00E9DC72 | mov esp,ebp 00E9DC74 | pop ebp 00E9DC75 | ret 8 00E9DC78 | lea eax,dword ptr ss:[ebp-4] 00E9DC7B | mov ecx,dword ptr ss:[ebp-4] 00E9DC7E | push eax 00E9DC7F | push ecx 00E9DC80 | push ebx 00E9DC81 | push B ; SystemModuleInformation 00E9DC83 | call esi ; NtQuerySystemInformation() 00E9DC85 | test eax,eax 00E9DC87 | je hardlock.E9DC9B 00E9DC89 | push ebx 00E9DC8A | call dword ptr ds:[&_ExFreePool@4] 00E9DC90 | xor al,al 00E9DC92 | pop edi 00E9DC93 | pop esi 00E9DC94 | pop ebx 00E9DC95 | mov esp,ebp 00E9DC97 | pop ebp 00E9DC98 | ret 8 00E9DC9B | mov esi,dword ptr ds:[ebx] ; smi.Count 00E9DC9D | lea eax,dword ptr ds:[ebx+4] ; smi.Modules[] 00E9DCA0 | xor edx,edx 00E9DCA2 | mov dword ptr ss:[ebp-8],eax 00E9DCA5 | test esi,esi 00E9DCA7 | je hardlock.E9DCC6 00E9DCA9 | add eax,8 ; mod.ImageSize 00E9DCAC | mov ecx,dword ptr ss:[ebp+8] ; &ExAllocatePoolWithTag@12 00E9DCAF | cmp dword ptr ds:[eax],ecx ; mod.ImageBaseAddress 00E9DCB1 | jae hardlock.E9DCBC 00E9DCB3 | mov edi,dword ptr ds:[eax+4] ; mod.ImageSize 00E9DCB6 | add edi,dword ptr ds:[eax] ; calc end address of module 00E9DCB8 | cmp edi,ecx 00E9DCBA | ja hardlock.E9DCD8 00E9DCBC | add eax,11C ; mod_entry++ 00E9DCC1 | inc edx 00E9DCC2 | cmp edx,esi ; last mod_entry? 00E9DCC4 | jne hardlock.E9DCAF 00E9DCC6 | push ebx 00E9DCC7 | call dword ptr ds:[&_ExFreePool@4] 00E9DCCD | xor al,al 00E9DCCF | pop edi 00E9DCD0 | pop esi 00E9DCD1 | pop ebx 00E9DCD2 | mov esp,ebp 00E9DCD4 | pop ebp 00E9DCD5 | ret 8 00E9DCD8 | lea ecx,dword ptr ds:[edx*8] 00E9DCDF | mov edi,dword ptr ss:[ebp+C] 00E9DCE2 | mov eax,dword ptr ss:[ebp-8] 00E9DCE5 | lea ecx,dword ptr ds:[ecx+ecx*8] 00E9DCE8 | sub ecx,edx 00E9DCEA | push ebx 00E9DCEB | lea esi,dword ptr ds:[eax+ecx*4] 00E9DCEE | mov ecx,47 00E9DCF3 | rep movsd 00E9DCF5 | call dword ptr ds:[&_ExFreePool@4] 00E9DCFB | mov al,1 00E9DCFD | pop edi 00E9DCFE | pop esi 00E9DCFF | pop ebx 00E9DD00 | mov esp,ebp 00E9DD02 | pop ebp 00E9DD03 | ret 8 --- snip ---
Caller to show internal error code getting translated to external 0xC000009A:
--- snip --- ... 00E58E9C | push hardlock.EA1D28 00E58EA1 | mov eax,dword ptr ds:[&_ExAllocatePoolWithTag@12] 00E58EA6 | push eax 00E58EA7 | call hardlock.E9DC30 ; determine ntoskrnl load base 00E58EAC | xor ecx,ecx 00E58EAE | mov cl,al 00E58EB0 | test ecx,ecx 00E58EB2 | jne hardlock.E58EC2 00E58EB8 | mov eax,C000000D ; failure 00E58EBD | jmp hardlock.E58FE4 00E58EC2 | push 35316B48 00E58EC7 | push 8C 00E58ECC | push 0 00E58ECE | call dword ptr ds:[&_ExAllocatePoolWithTag@12] ... 00E485B9 | push edi 00E485BA | pop edi 00E485BB | mov dword ptr ss:[ebp-C],C000009A ; returned to driver entry 00E485C2 | test ebx,ebx 00E485C4 | jb hardlock.E33E36 --- snip ---
This driver uses another, cleaner method to find ntoskrnl.exe base address as compared to https://bugs.winehq.org/show_bug.cgi?id=50201#c0 (which doesn't rely on API / module lists)
It uses the address of 'ntoskrnl.ExAllocatePoolWithTag' API function to find the module in range.
Load addresses at time of driver debugging:
--- snip --- Base Module Path 00320000 sechost.dll ...\lib\wine\sechost.dll 00350000 hal.dll ...\lib\wine\hal.dll 00360000 msvcrt.dll ...\lib\wine\msvcrt.dll 00400000 winedevice.exe ...\lib\wine\winedevice.exe 00410000 ucrtbase.dll ...\lib\wine\ucrtbase.dll 00BA0000 rpcrt4.dll ...\lib\wine\rpcrt4.dll 00E30000 hardlock.sys C:\windows\system32\drivers\hardlock.sys 10000000 advapi32.dll ...\lib\wine\advapi32.dll 7B000000 kernelbase.dll ...\lib\wine\kernelbase.dll 7B600000 kernel32.dll ...\lib\wine\kernel32.dll 7BC00000 ntdll.dll ...\lib\wine\ntdll.dll 82000000 ntoskrnl.exe ...\lib\wine\ntoskrnl.exe --- snip ---
The dumped "fake" system modules list the driver sees. It corresponds to the Wine sources.
--- snip --- 00A923A0 00000003 .... Modules count 00A923A4 00000000 .... Unused 00A923A8 00000000 .... Reserved1/2 00A923AC 10000000 .... ImageBaseAddress 00A923B0 00200000 .. . ImageSize 00A923B4 00000000 .... Flags 00A923B8 00000000 .... Index/Rank 00A923BC 00150001 .... LoadCount/NameOffset 00A923C0 7379535C \Sys Name 00A923C4 526D6574 temR 00A923C8 5C746F6F oot\ 00A923CC 74737973 syst 00A923D0 32336D65 em32 00A923D4 6F746E5C \nto 00A923D8 6E726B73 skrn 00A923DC 78652E6C l.ex 00A923E0 00000065 e... 00A923E4 00000000 .... ... 00A924C0 00000000 .... Unused 00A924C4 00000000 .... Reserved1/2 00A924C8 10200000 .. . ImageBaseAddress 00A924CC 00200000 .. . ImageSize 00A924D0 00000000 .... Flags 00A924D4 00000001 .... Index/Rank 00A924D8 00150001 .... LoadCount/NameOffset 00A924DC 7379535C \Sys Name 00A924E0 526D6574 temR 00A924E4 5C746F6F oot\ 00A924E8 74737973 syst 00A924EC 32336D65 em32 00A924F0 6C61685C \hal 00A924F4 6C6C642E .dll 00A924F8 00000000 .... 00A924FC 00000000 .... 00A92500 00000000 .... 00A92504 00000000 .... ... 00A925DC 00000000 .... Unused 00A925E0 00000000 .... Reserved1/2 00A925E4 10400000 ..@. ImageBaseAddress 00A925E8 00200000 .. . ImageSize 00A925EC 00000000 .... Flags 00A925F0 00000002 .... Index/Rank 00A925F4 001D0001 .... LoadCount/NameOffset 00A925F8 7379535C \Sys Name 00A925FC 526D6574 temR 00A92600 5C746F6F oot\ 00A92604 74737973 syst 00A92608 32336D65 em32 00A9260C 6972645C \dri 00A92610 73726576 vers 00A92614 756F6D5C \mou 00A92618 676D746E ntmg 00A9261C 79732E72 r.sy 00A92620 00000073 s... 00A92624 00000000 .... ... --- snip ---
Wine source:
https://source.winehq.org/git/wine.git/blob/cbca9f847f60773b4e7e5408f6a079f4...
--- snip --- 2326 case SystemModuleInformation: 2327 { 2328 /* FIXME: return some fake info for now */ 2329 static const char *fake_modules[] = 2330 { 2331 "\SystemRoot\system32\ntoskrnl.exe", 2332 "\SystemRoot\system32\hal.dll", 2333 "\SystemRoot\system32\drivers\mountmgr.sys" 2334 }; 2335 2336 ULONG i; 2337 SYSTEM_MODULE_INFORMATION *smi = info; 2338 2339 len = offsetof( SYSTEM_MODULE_INFORMATION, Modules[ARRAY_SIZE(fake_modules)] ); 2340 if (len <= size) 2341 { 2342 memset( smi, 0, len ); 2343 for (i = 0; i < ARRAY_SIZE(fake_modules); i++) 2344 { 2345 SYSTEM_MODULE *sm = &smi->Modules[i]; 2346 sm->ImageBaseAddress = (char *)0x10000000 + 0x200000 * i; 2347 sm->ImageSize = 0x200000; 2348 sm->LoadOrderIndex = i; 2349 sm->LoadCount = 1; 2350 strcpy( (char *)sm->Name, fake_modules[i] ); 2351 sm->NameOffset = strrchr( fake_modules[i], '\' ) - fake_modules[i] + 1; 2352 } 2353 smi->ModulesCount = i; 2354 } 2355 else ret = STATUS_INFO_LENGTH_MISMATCH; 2356 2357 break; 2358 } 2359 2360 case SystemModuleInformationEx: 2361 { 2362 /* FIXME: return some fake info for now */ 2363 static const char *fake_modules[] = 2364 { 2365 "\SystemRoot\system32\ntoskrnl.exe", 2366 "\SystemRoot\system32\hal.dll", 2367 "\SystemRoot\system32\drivers\mountmgr.sys" 2368 }; 2369 2370 ULONG i; 2371 RTL_PROCESS_MODULE_INFORMATION_EX *module_info = info; 2372 2373 len = sizeof(*module_info) * ARRAY_SIZE(fake_modules) + sizeof(module_info->NextOffset); 2374 if (len <= size) 2375 { 2376 memset( info, 0, len ); 2377 for (i = 0; i < ARRAY_SIZE(fake_modules); i++) 2378 { 2379 SYSTEM_MODULE *sm = &module_info[i].BaseInfo; 2380 sm->ImageBaseAddress = (char *)0x10000000 + 0x200000 * i; 2381 sm->ImageSize = 0x200000; 2382 sm->LoadOrderIndex = i; 2383 sm->LoadCount = 1; 2384 strcpy( (char *)sm->Name, fake_modules[i] ); 2385 sm->NameOffset = strrchr( fake_modules[i], '\' ) - fake_modules[i] + 1; 2386 module_info[i].NextOffset = sizeof(*module_info); 2387 } 2388 module_info[ARRAY_SIZE(fake_modules)].NextOffset = 0; 2389 } 2390 else ret = STATUS_INFO_LENGTH_MISMATCH; 2391 2392 break; 2393 } --- snip ---
$ sha1sum HASPDINST_7.32.exe 96520c7e2bdc40a232daca01d6edbd7aa3f162ba HASPDINST_7.32.exe
$ du -sh HASPDINST_7.32.exe 16M HASPDINST_7.32.exe
$ wine --version wine-5.22-196-g2001705a3f0
Regards