https://bugs.winehq.org/show_bug.cgi?id=45510
--- Comment #15 from Anastasius Focht focht@gmx.net --- Hello folks,
addendum just for documentation, how the imports resolver works in a nutshell.
The obfuscated driver uses a technique called API hashing. This technique is also used by lots of malware to disguise their actions.
Driver IAT dumped from memory with most imports already resolved except the last few entries to test the algorithm. Initially the table contains only the 32-bit hashes.
--- snip --- 0000000000D77280 0000000000D91850 hal.HalGetBusDataByOffset 0000000000D77288 0000000000000000 0000000000D77290 0000000000332F80 ntoskrnl.RtlRandom 0000000000D77298 000000000032BE70 ntoskrnl.KeWaitForSingleObject 0000000000D772A0 000000000032C8D0 ntoskrnl.KeDelayExecutionThread 0000000000D772A8 000000000032C040 ntoskrnl.KeSetEvent 0000000000D772B0 0000000000323CD0 ntoskrnl.MmIsAddressValid 0000000000D772B8 0000000000321FF0 ntoskrnl.IofCallDriver 0000000000D772C0 000000000032BF10 ntoskrnl.KeInitializeEvent 0000000000D772C8 00000000003244B0 ntoskrnl.ObfDereferenceObject 0000000000D772D0 0000000000313598 ntoskrnl.__wine_stub_KeInsertQueueDpc 0000000000D772D8 000000000032C230 ntoskrnl.KeClearEvent 0000000000D772E0 0000000000324D80 ntoskrnl.KeSetTargetProcessorDpc 0000000000D772E8 0000000000324CD0 ntoskrnl.KeInitializeDpc 0000000000D772F0 0000000000323420 ntoskrnl.KeQueryActiveProcessors 0000000000D772F8 0000000000330DF0 ntoskrnl.__C_specific_handler 0000000000D77300 0000000000323FB0 ntoskrnl.MmUnlockPages 0000000000D77308 0000000000323DD0 ntoskrnl.MmMapLockedPagesSpecifyCache 0000000000D77310 000000000031FD30 ntoskrnl.IoFreeMdl 0000000000D77318 0000000000323F10 ntoskrnl.MmProbeAndLockPages 0000000000D77320 000000000031FE50 ntoskrnl.IoAllocateMdl 0000000000D77328 0000000000331D10 ntoskrnl.NtDeleteValueKey 0000000000D77330 0000000000331C80 ntoskrnl.NtCreateKey 0000000000D77338 0000000000332380 ntoskrnl.NtSetValueKey 0000000000D77340 0000000000331D00 ntoskrnl.NtDeleteKey 0000000000D77348 0000000000331D60 ntoskrnl.NtEnumerateKey 0000000000D77350 0000000000331D70 ntoskrnl.NtEnumerateValueKey 0000000000D77358 00000000003229C0 ntoskrnl.ExAllocatePoolWithTag 0000000000D77360 00000000003320D0 ntoskrnl.NtQueryKey 0000000000D77368 0000000000331EF0 ntoskrnl.NtOpenKey 0000000000D77370 0000000000321950 ntoskrnl.IoDeleteDevice 0000000000D77378 0000000000322540 ntoskrnl.IoUnregisterShutdownNotification 0000000000D77380 0000000000323FF0 ntoskrnl.MmUnmapIoSpace 0000000000D77388 0000000000323D30 ntoskrnl.MmMapIoSpace 0000000000D77390 0000000000322890 ntoskrnl.IofCompleteRequest 0000000000D77398 0000000000311990 ntoskrnl.__wine_stub_ExInterlockedInsertTailList 0000000000D773A0 000000000031F530 ntoskrnl.IoGetCurrentProcess 0000000000D773A8 0000000000312D10 ntoskrnl.__wine_stub_IoRegisterLastChanceShutdownNotification 0000000000D773B0 0000000000322500 ntoskrnl.IoRegisterShutdownNotification 0000000000D773B8 000000000031ED40 ntoskrnl.ObReferenceObjectByHandle 0000000000D773C0 0000000000324600 ntoskrnl.PsCreateSystemThread 0000000000D773C8 0000000000325280 ntoskrnl.KeLeaveCriticalRegion 0000000000D773D0 000000000032EA20 ntoskrnl.ExReleaseResourceLite 0000000000D773D8 000000000032D960 ntoskrnl.ExAcquireResourceSharedLite 0000000000D773E0 0000000000325230 ntoskrnl.KeEnterCriticalRegion 0000000000D773E8 000000000032D550 ntoskrnl.ExAcquireResourceExclusiveLite 0000000000D773F0 000000000032D450 ntoskrnl.ExInitializeResourceLite 0000000000D773F8 000000000032D4C0 ntoskrnl.ExDeleteResourceLite 0000000000D77400 00000000003314C0 ntoskrnl.toupper 0000000000D77408 0000000000323550 ntoskrnl.KeSetPriorityThread 0000000000D77410 000000000032D0F0 ntoskrnl.ExInterlockedRemoveHeadList 0000000000D77418 00000000003292C0 ntoskrnl.IoGetDeviceProperty 0000000000D77420 0000000000325350 ntoskrnl.KeBugCheckEx 0000000000D77428 000000007DC7C8B3 hash1 0000000000D77430 00000000F8BD1FE5 hash2 0000000000D77438 00000000B061FF53 hash3 0000000000D77440 00000000D8F8AA3E hash4 0000000000D77448 0000000000000000 0000000000D77450 0000000000000000 0000000000D77458 0000000000000000 --- snip ---
I won't bother you with the disassembly of the routine because its obfuscated. If you are interested:
--- snip --- ... 0000000000D803E1 | call aksfridge.D802A2 | calc_hash() 0000000000D803E6 | jmp aksfridge.D803F4 | EAX = 32-bit hash 0000000000D803F4 | cmp eax,esi | 0000000000D803F6 | je aksfridge.D80437 | --- snip ---
--- snip --- Base Module Path 0000000000220000 sechost.dll ...\lib64\wine\sechost.dll 0000000000250000 ucrtbase.dll ...\lib64\wine\ucrtbase.dll 0000000000310000 ntoskrnl.exe ...\lib64\wine\ntoskrnl.exe 0000000000360000 msvcrt.dll ...\lib64\wine\msvcrt.dll 0000000000AD0000 rpcrt4.dll ...\lib64\wine\rpcrt4.dll 0000000000D60000 aksfridge.sys C:\windows\system32\drivers\aksfridge.sys 0000000000D90000 hal.dll ...\lib64\wine\hal.dll 000000007B000000 kernelbase.dll ...\lib64\wine\kernelbase.dll 000000007B600000 kernel32.dll ...\lib64\wine\kernel32.dll 000000007BC00000 ntdll.dll ...\lib64\wine\ntdll.dll 0000000140000000 winedevice.exe ...\lib64\wine\winedevice.exe 0000000180000000 advapi32.dll ...\lib64\wine\advapi32.dll --- snip ---
The 32-bit and 64-bit driver uses the same algorithm / 32-bit API hashes.
I turned the driver's API hashing function into a piece of Python code.
'aksfridge_hash_api.py':
--- snip --- #!/usr/bin/env python import sys
def to_hash(str): hash_val = 5 for i in range(len(str)): hash_val = ror(hash_val, 7, 32) hash_val += ord(str[i]) return hash_val
# Rotate right: 0b1001 --> 0b1100 ror = lambda val, r_bits, max_bits: \ ((val & (2**max_bits-1)) >> r_bits%max_bits) | \ (val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))
# check to_hash() working with known correct hashes test_hash1 = to_hash("CcMdlWriteComplete") assert test_hash1 == 0x73F2510A test_hash2 = to_hash("CcPinMappedData") assert test_hash2 == 0x238B94BB
for api_name in sys.argv[1:]: hash = to_hash(api_name) print("{} = 0x{:X}".format(api_name, hash)) --- snip ---
The hashing is lossy, hence there is no "api-name-from-hash" functionality. That's not a problem - simply hash all known ntoskrnl exports and lookup the value. That's what the driver essentially does. If Wine's ntoskrnl.exe doesn't export the API (commented out in .spec file or missing) then the driver would fail/crash at one point.
Download a reasonable complete/up-to-date 'ntoskrnl.def' from whatever Github repo:
https://github.com/msys2-contrib/mingw-w64/blob/master/mingw-w64-crt/lib64/n...
--- snip --- $ wget https://raw.githubusercontent.com/msys2-contrib/mingw-w64/master/mingw-w64-c... --- snip ---
Now feed the content of the .def file to the script. Each line of the input file is converted into a script argument using "$(echo $(cat xxx))". The script doesn't handle invalid input / non-API functions. It just treats everything as string for simplicity.
It prints the calculated hashes for each string argument:
--- snip --- $ ./aksfridge_hash_api.py $(echo $(cat ntoskrnl.def)) ...
AlpcGetHeaderSize = 0xB8450BA0 AlpcGetMessageAttribute = 0xEC22F2AA AlpcInitializeMessageAttribute = 0x69D899AC CcCanIWrite = 0x318059A6 CcCoherencyFlushAndPurgeCache = 0x5254F917 CcCopyRead = 0xF3787B88 CcCopyWrite = 0x320759AC ... wcsspn = 0xC30F9EAD wcsstr = 0xCB0F9EB1 wcstombs = 0x3EB304C2 wcstoul = 0x698227A9 wctomb = 0xBCFFA6A1 --- snip ---
Back in the old days when Wine's 'ntoskrnl.exe' exports were less complete and one API hash couldn't be found, you'd simply:
--- snip --- $ ./aksfridge_hash_api.py $(echo $(cat ntoskrnl.def)) | grep 7DC7C8B3
ZwQueryValueKey = 0x7DC7C8B3 --- snip ---
Regards