[Bug 36491] Theatre of War 3: Korea Demo hangs on start

wine-bugs at winehq.org wine-bugs at winehq.org
Sat May 24 16:48:57 CDT 2014


http://bugs.winehq.org/show_bug.cgi?id=36491

--- Comment #13 from Anastasius Focht <focht at 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

-- 
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.



More information about the wine-bugs mailing list