http://bugs.winehq.org/show_bug.cgi?id=36491
--- Comment #13 from Anastasius Focht focht@gmx.net --- Hello folks,
after unwrapping in entry point, the protection code proceeds to do some harmless debugger checks and then starts bringing up the custom imports resolver.
It walks the OS loader internal InLoadOrderModuleList list, examines the entries, checking the dll base addresses for zero and a magic value 0xABABABAB. Unfortunately the protection code is buggy - it got the "last" entry condition wrong when doing list walking. Pretty stupid for such simple thing as walking a (double) linked list.
The last module entry 'FLink' points to 'ldr.InLoadOrderModuleList.FLink' (cyclic). The iterator code doesn't compare the pointer to list start but interprets the address as 'next' LDR_MODULE entry, looking at 'LDR_MODULE.BaseAddress':
--- snip --- typedef struct _PEB_LDR_DATA { ULONG Length; BOOLEAN Initialized; PVOID SsHandle; LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; } PEB_LDR_DATA, *PPEB_LDR_DATA;
...
typedef struct _LDR_MODULE { LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; void* BaseAddress; void* EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; SHORT LoadCount; SHORT TlsIndex; HANDLE SectionHandle; ULONG CheckSum; ULONG TimeDateStamp; HANDLE ActivationContext; } LDR_MODULE, *PLDR_MODULE; --- snip ---
LDR_MODULE.BaseAddress lives at offset 0x18 (24 bytes for 3 LIST_ENTRY)
How Nikolay's memory dump looks rewritten:
sizeof(PEB_LDR_DATA) = 0x24
--- snip --- ldr+0x00 = PEB_LDR_DATA ... ldr+0x0c (+0x00): 00110800 ; InLoadOrderModuleList.FLink ldr+0x10 (+0x04): 00110200 ; InLoadOrderModuleList.BLink ldr+0x14 (+0x08): 00110808 ; InMemoryOrderModuleList.FLink ldr+0x18 (+0x0C): 00110160 ; InMemoryOrderModuleList.BLink ldr+0x1c (+0x10): 00110168 ; InInitializationOrderModuleList.FLink ldr+0x20 (+0x14): 00110810 ; InInitializationOrderModuleList.BLink <--- PEB_LDR_DATA ends here ---> ldr+0x24 (+0x18): 7ffdf000 ; *problem* ldr+0x28 (+0x1C): 00000000 ... --- snip ---
'ldr' is declared as 'static' module local variable (goes to '.bss' section). Placement/alignment with neighbouring objects matters.
In my case, the area following 'PEB_LDR_DATA' serves as alignment to next 16-byte boundary (zeroed at runtime) hence the protection code sees the exit condition 'LDR_MODULE.BaseAddress == 0' and proceeds further.
One can find 'PEB_LDR_DATA' definitions which carry an additional field:
http://www.nirsoft.net/kernel_struct/vista/PEB_LDR_DATA.html
--- quote --- typedef struct _PEB_LDR_DATA { ULONG Length; UCHAR Initialized; PVOID SsHandle; LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; PVOID EntryInProgress; } PEB_LDR_DATA, *PPEB_LDR_DATA; --- quote ---
It shouldn't harm if Wine adds this 'EntryInProgress' field - even if it's not going to be used. This field reserves/keeps the memory location which should work around the broken protection code.
@Nikolay / Austin:
Can you add this additional field and check if it helps?
Regards