[Bug 7679] IMVU 3D Avatar Chat client crashes

Wine Bugs wine-bugs at winehq.org
Thu Apr 26 19:16:26 CDT 2007


------- Additional Comments From focht at gmx.net  2007-26-04 19:16 -------

i read some discussion on developer list regarding this one ... so it catched my
interest :)

Fired up my debugger and let go (+few cups of coffee).

In short: it's an interesting (subtile) bug in wine trigged by unusual PE
section protection flags :)

First, the root cause is a c++ exception generated by precompiled boost::python
module which should not hurt at all.
When being passed to upper exception handler chains it finally arrives at a
point where the application tries to make sense of it.
That task is accomplished by a hooking library which exports several APIs to
gather process/module information, hook either by patching the import address
tables of all modules (1st level hooker) and/or to patch entrypoints of system
functions itself (2nd level hooker, trampolines).

The hooker enumerates all modules and their import tables.
It modifies the page protection attributes to get write access to the IAT of
each module.
This is done by a series of VirtualQuery/VirtualProtect.

To answer the question "lots of access violations being seen in debugger":
completely harmless and expected.
The code checks if page write access has already been enabled to system
functions code area by using IsBadWritePtr (2nd level hooking/trampoline).
Checks for trampolines code (e.g. insertion of jmp/call opcodes on entry) are
made too.

Well, back to topic.
One module "Blowfish.pyd" has a rather unusal protection attributes combination
to its .idata (imports) section: C0000040 -> readable | writable | initialized data.
Usually it should be: readable | initialized data  .. i'm pretty sure it was on
accident by developers.

This triggers the interesting wine bug.
With the module being mapped by wine loader, the page gets PAGE_WRITECOPY attribute.
At one place, the hooker basically does following:

    if( VirtualQuery( IAT_addr_of_module, &info, sizeof(info)) == sizeof(info))
        DWORD prot = info.AllocationProtect & (PAGE_NOACCESS | PAGE_READWRITE |
        prot |= PAGE_READWRITE;

        if( VirtualProtect( IAT_addr_of_module, ... , prot, &oldProtect))
            // access the IAT

Now the problem: VirtualQuery() -> info.AllocationProtect -> returns 0x8 =
PAGE_WRITECOPY for this specific module.
and the passed to VirtualProtect().
Guess. VirtualProtect() returns TRUE and the hooker tries to access IAT area.
Now you have literally a "double fault" - the module which should gather
exception information produced exception by itself :)

You may ask where is the wine bug?
Well, wine should never have returned TRUE on VirtualProtect with PAGE_READWRITE
and PAGE_WRITECOPY flags both set.
This is a very little known (undocumented) limitation starting with Windows 2000
and higher.
I had this issue some years ago - that's why I remembered this one.
The mode attribues PAGE_READWRITE and PAGE_WRITECOPY are mutually exclusive.
You can test it by yourself on windows systems (Win2k, WinXp), VirtualProtect
will fail if both set.

For verification that my findings are correct you have to options:

- change the section protection of "Blowfish.pyd" .idata section to 0x40000040
(read | initialized data).
  VirtualProtect will succeed and the app finally starts up with login screen.

- fix wine itself: VirtualProtect( PAGE_READWRITE | PAGE_WRITECOPY) on Win2K+
must return FALSE. PAGE_WRITECOPY is not supported by Win9X. Though I couldnt
verify NT4. I'd say: prohibit this combination at all.

Actually these are the bugs i like (along with stack smashers). I had some fun :)


Configure bugmail: http://bugs.winehq.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug, or are watching the assignee.

More information about the wine-bugs mailing list