https://bugs.winehq.org/show_bug.cgi?id=38950
Bug ID: 38950 Summary: Creo Elements/Direct Modeling Express 6.0 .NET based licensing tool crashes on startup (Xenocode VM, 'load_native_dll' must also allow imports resolving for 'EXECUTABLE_IMAGE') Product: Wine Version: 1.7.47 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,
while revisiting bug 27827 I found another interesting one...
Starting the main app with workaround https://bugs.winehq.org/show_bug.cgi?id=27827#c9, another process is spawned which seems to be some .NET Framework based licensing tool.
That helper tool crashes on startup, preventing the main app from working.
--- snip --- $ pwd /home/focht/.wine/drive_c/Program Files/PTC/Creo Elements/Direct Modeling Express 6.0/binNT/OLAPE
$ WINEDEBUG=+tid,+seh,+relay wine ./OLAPEP.exe >>log.txt 2>&1 ... 0034:Starting process L"C:\Program Files\PTC\Creo Elements\Direct Modeling Express 6.0\binNT\OLAPE\OLAPEP.exe" (entryproc=0x2131a000) ... 0034:Call ntdll.RtlInitUnicodeString(2142fd38,0015d8a8 L"C:\Program Files\PTC\Creo Elements\Direct Modeling Express 6.0\binNT\OLAPE\OLAPEPP.exe") ret=212e03aa 0034:Ret ntdll.RtlInitUnicodeString() retval=2142fd38 ret=212e03aa 0034:Call ntdll.LdrLoadDll(00000000,00000000,2142fd38,2142fd14) ret=212e03be 0034:Ret ntdll.LdrLoadDll() retval=00000000 ret=212e03be 0034:Call user32.EnumThreadWindows(00000034,212e2ad0,2142fda0) ret=212e2fbb 0034:Call PE DLL (proc=0x7e324070,module=0x7e2c0000 L"winex11.drv",reason=PROCESS_ATTACH,res=(nil)) 0034:Ret PE DLL (proc=0x7e324070,module=0x7e2c0000 L"winex11.drv",reason=PROCESS_ATTACH,res=(nil)) retval=1 0034:Call winex11.drv.wine_get_gdi_driver(0000002e) ret=7eb23c42 0034:Ret winex11.drv.wine_get_gdi_driver() retval=7e3287e0 ret=7eb23c42 0034:Call winex11.drv.CreateDesktopWindow(00010020) ret=7ec571f6 0034:Ret winex11.drv.CreateDesktopWindow() retval=00000001 ret=7ec571f6 0034:Ret user32.EnumThreadWindows() retval=00000001 ret=212e2fbb 0034:Call KERNEL32.GetTickCount() ret=212e2fca 0034:Ret KERNEL32.GetTickCount() retval=00d4485c ret=212e2fca 0034:Call KERNEL32.CreateThread(00000000,00000000,212e2f70,21318bf4,00000000,00000000) ret=212e2fe7 0034:Ret KERNEL32.CreateThread() retval=00000240 ret=212e2fe7 0034:trace:seh:raise_exception code=c0000005 flags=0 addr=0x7f12327e ip=7f12327e tid=0034 0034:trace:seh:raise_exception info[0]=00000000 0034:trace:seh:raise_exception info[1]=00402000 0034:trace:seh:raise_exception eax=7f12327e ebx=00000000 ecx=2142fe24 edx=21317fe8 esi=21317fec edi=00000002 0034:trace:seh:raise_exception ebp=2142fe30 esp=2142fde8 cs=0023 ds=002b es=002b fs=0063 gs=006b flags=00010206 --- snip ---
The import and usage of large number of native API makes this already suspicious.
'ProtectionID' tool doesn't reveal much:
--- snip --- -=[ ProtectionID v0.6.6.7 DECEMBER]=- (c) 2003-2015 CDKiLLER & TippeX Build 24/12/14-22:48:13 Ready... Scanning -> C:\Program Files\PTC\Creo Elements\Direct Modeling Express 6.0\binNT\OLAPE\OLAPEP.exe File Type : 32-Bit Exe (Subsystem : Win GUI / 2), Size : 17768448 (010F2000h) Byte(s) Compilation TimeStamp : 0x00000026 -> Thu 01st Jan 1970 00:00:38 (GMT) [TimeStamp] 0x00000026 -> Thu 01st Jan 1970 00:00:38 (GMT) | PE Header | - | Offset: 0x00000088 | VA: 0x00100088 | - [File Heuristics] -> Flag #1 : 00000000000000001000001000000001 (0x00008201) [Entrypoint Section Entropy] : 2.32 (section #5) ".textxc " | Size : 0x5 (5) byte(s) [DllCharacteristics] -> Flag : (0x0000) -> NONE [SectionCount] 9 (0x9) | ImageSize 0x210F4000 (554647552) byte(s) [VersionInfo] Company Name : Parametric Technology GmbH [VersionInfo] Product Name : Modeling Express [VersionInfo] Product Version : 4.0.0.1 [VersionInfo] File Description : OLAPEPP [VersionInfo] File Version : 4.0.0.1 [VersionInfo] Original FileName : OLAPEPP.exe [VersionInfo] Internal Name : OLAPEPP.exe [VersionInfo] Version Comments : Online Activation Modeling Express PTC Plain [VersionInfo] Legal Copyrights : Copyright © 2011 [CdKeySerial] found "Invalid code" @ VA: 0x210DB100 / Offset: 0x010DB100 [CompilerDetect] -> Visual C++ 6.0 [!] File appears to have no protection or is using an unknown protection - Scan Took : 4.965 Second(s) [000000FC3h (4035) tick(s)] [499 of 573 scan(s) done] --- snip ---
The layout of the entry point and debugging a bit past reveals:
--- snip --- 4241A000 E9 1BC8FCFF JMP OLAPEP.423E6820 4241A005 0000 ADD BYTE PTR DS:[EAX],AL ... 423E6820 E9 3BFEFFFF JMP OLAPEP.423E6660 423E6825 CC INT3 ... 423E6660 55 PUSH EBP 423E6661 8BEC MOV EBP,ESP ... 423E6740 68 182C4042 PUSH OLAPEP.42402C18 ; UNICODE ".\dllmain.cpp" 423E6745 68 342C4042 PUSH OLAPEP.42402C34 ; UNICODE "DoEmbeddedVM" ... 423E67F0 E8 DB5DFDFF CALL OLAPEP.423BC5D0 423E67F5 83C4 0C ADD ESP,0C 423E67F8 6A 10 PUSH 10 ; Style = MB_OK|MB_ICONHAND|MB_APPLMODAL 423E67FA 68 B02F4042 PUSH OLAPEP.42402FB0 ; Title = "Xenocode Virtual Appliance Runtime" 423E67FF 8B55 E4 MOV EDX,DWORD PTR SS:[EBP-1C] 423E6802 52 PUSH EDX ; Text 423E6803 6A 00 PUSH 0 ; hOwner = NULL 423E6805 FF15 28B24142 CALL DWORD PTR DS:[<&USER32.MessageBoxW>] 423E680B E8 00FEFFFF CALL OLAPEP.423E6610 423E6810 6A FF PUSH -1 ; ExitCode = FFFFFFFF 423E6812 F15 08B04142 CALL DWORD PTR DS:[<&KERNEL32.ExitProcess>] 423E6818 CC INT3 --- snip ---
Oh well ... Xenocode ;-)
The crash location:
--- snip --- ... 423E6708 A1 CC8B4142 MOV EAX,DWORD PTR DS:[42418BCC] 423E670D 3BC3 CMP EAX,EBX 423E670F 74 02 JE SHORT 423E6713 423E6711 FFD0 CALL EAX ; call 0x00415857 423E6713 8B4D F4 MOV ECX,DWORD PTR SS:[EBP-C] 423E6716 64:890D 00000000 MOV DWORD PTR FS:[0],ECX 423E671D 5F POP EDI 423E671E 5E POP ESI 423E671F 5B POP EBX 423E6720 8BE5 MOV ESP,EBP 423E6722 5D POP EBP 423E6723 C3 RETN ... 00415857 FF25 00604100 JMP DWORD PTR DS:[416000] ; *boom* 0041585D 0000 ADD BYTE PTR DS:[EAX],AL 0041585F 0000 ADD BYTE PTR DS:[EAX],AL 00415861 0000 ADD BYTE PTR DS:[EAX],AL --- snip ---
Dump of memory reference:
--- snip --- 00416000 00016044 00416004 00000000 00416008 00016030 0041600C 00000000 00416010 00000000 00416014 00016038 00416018 00016000 0041601C 00000000 ... 00416030 00016044 00416034 00000000 00416038 6F63736D msco 0041603C 2E656572 ree. 00416040 006C6C64 dll. 00416044 435F0000 .._C 00416048 7845726F orEx 0041604C 69614D65 eMai 00416050 0000006E n... --- snip ---
As seen in trace log, the Xenocode VM loader calls 'ntdll.LdrLoadDll' which in turn boils down to:
-> ntdll.load_dll -> ntdll.load_native_dll -> load/map images
XenoCode hooks the relevant native API to override the NT loader.
* NtCreateSection * NtMapViewOfSection * <many more but not relevant in this special situation>
Since Wine's loader also calls those native API in sequence, correctly following native NT loader behaviour, those hooked functions get called.
Xenocode unpacks the main executable and all dependencies in memory from PE resources and injects those images as part of loader sequence.
That's also the reason for the high initial load address for the original executable. The Xenocode VM must keep the standard load address ranges, such as 0x400000, 0x10000000+ in process address space free to allow its custom loader to map all internal executable images there.
Wine gets it almost right ... but fails at resolving the imports for the main executable. See the dump earlier: 0x416000 -> address of IAT which is still unprocessed.
Source: https://source.winehq.org/git/wine.git/blob/21c37248135f6379e6af7aa3ec299973...
--- snip --- 1608 static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file, 1609 DWORD flags, WINE_MODREF** pwm ) 1610 { 1611 void *module; 1612 HANDLE mapping; 1613 LARGE_INTEGER size; 1614 IMAGE_NT_HEADERS *nt; 1615 SIZE_T len = 0; 1616 WINE_MODREF *wm; 1617 NTSTATUS status; 1618 1619 TRACE("Trying native dll %s\n", debugstr_w(name)); 1620 1621 size.QuadPart = 0; 1622 status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ, 1623 NULL, &size, PAGE_EXECUTE_READ, SEC_IMAGE, file ); 1624 if (status != STATUS_SUCCESS) return status; 1625 1626 module = NULL; 1627 status = NtMapViewOfSection( mapping, NtCurrentProcess(), 1628 &module, 0, 0, &size, &len, ViewShare, 0, PAGE_EXECUTE_READ ); 1629 if (status < 0) goto done; 1630 1631 /* create the MODREF */ 1632 1633 if (!(wm = alloc_module( module, name ))) 1634 { 1635 status = STATUS_NO_MEMORY; 1636 goto done; 1637 } 1638 1639 /* fixup imports */ 1640 1641 nt = RtlImageNtHeader( module ); 1642 1643 if (!(flags & DONT_RESOLVE_DLL_REFERENCES) && 1644 ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) || 1645 nt->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE)) 1646 { 1647 if ((status = fixup_imports( wm, load_path )) != STATUS_SUCCESS) 1648 { ... --- snip ---
Dump of the in-memory PE image header for the main executable which gets "injected" through Xenocode:
--- snip --- ... 00400080 50 45 00 0>ASCII "PE" ; PE signature (PE) 00400084 4C01 DW 014C ; Machine = IMAGE_FILE_MACHINE_I386 00400086 0400 DW 0004 ; NumberOfSections = 4 00400088 1B000000 DD 0000001B ; TimeDateStamp = 1B 0040008C 00000000 DD 00000000 ; PointerToSymbolTable = 0 00400090 00000000 DD 00000000 ; NumberOfSymbols = 0 00400094 E000 DW 00E0 ; SizeOfOptionalHeader = E0 (224.) 00400096 0E01 DW 010E ; Characteristics = EXECUTABLE_IMAGE|32BIT_MACHINE|LINE_NUMS_STRIPPED|LOCAL_SYMS_STRIPPED 00400098 0B01 DW 010B ; MagicNumber = PE32 0040009A 08 DB 08 ; MajorLinkerVersion = 8 0040009B 00 DB 00 ; MinorLinkerVersion = 0 0040009C 00400100 DD 00014000 ; SizeOfCode = 14000 (81920.) 004000A0 00600000 DD 00006000 ; SizeOfInitializedData = 6000 (24576.) 004000A4 00000000 DD 00000000 ; SizeOfUninitializedData = 0 004000A8 57580100 DD 00015857 ; AddressOfEntryPoint = 15857 004000AC 00200000 DD 00002000 ; BaseOfCode = 2000 004000B0 00600100 DD 00016000 ; BaseOfData = 16000 004000B4 00004000 DD 00400000 ; ImageBase = 400000 004000B8 00200000 DD 00002000 ; SectionAlignment = 2000 004000BC 00020000 DD 00000200 ; FileAlignment = 200 004000C0 0400 DW 0004 ; MajorOSVersion = 4 004000C2 0000 DW 0000 ; MinorOSVersion = 0 004000C4 0000 DW 0000 ; MajorImageVersion = 0 004000C6 0000 DW 0000 ; MinorImageVersion = 0 004000C8 0400 DW 0004 ; MajorSubsystemVersion = 4 004000CA 0000 DW 0000 ; MinorSubsystemVersion = 0 004000CC 00000000 DD 00000000 ; Reserved 004000D0 00C00100 DD 0001C000 ; SizeOfImage = 1C000 (114688.) 004000D4 00040000 DD 00000400 ; SizeOfHeaders = 400 (1024.) 004000D8 00000000 DD 00000000 ; CheckSum = 0 004000DC 0200 DW 0002 ; Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI 004000DE 4085 DW 8540 ; DLLCharacteristics = 8540 004000E0 00001000 DD 00100000 ; SizeOfStackReserve = 100000 (1048576.) 004000E4 00100000 DD 00001000 ; SizeOfStackCommit = 1000 (4096.) 004000E8 00001000 DD 00100000 ; SizeOfHeapReserve = 100000 (1048576.) 004000EC 00100000 DD 00001000 ; SizeOfHeapCommit = 1000 (4096.) 004000F0 00000000 DD 00000000 ; LoaderFlags = 0 004000F4 10000000 DD 00000010 ; NumberOfRvaAndSizes = 10 (16.) 004000F8 00000000 DD 00000000 ; Export Table address = 0 004000FC 00000000 DD 00000000 ; Export Table size = 0 00400100 08600100 DD 00016008 ; Import Table address = 16008 00400104 28000000 DD 00000028 ; Import Table size = 28 (40.) 00400108 00A00100 DD 0001A000 ; Resource Table address = 1A000 0040010C 0A060000 DD 0000060A ; Resource Table size = 60A (1546.) 00400110 00000000 DD 00000000 ; Exception Table address = 0 00400114 00000000 DD 00000000 ; Exception Table size = 0 00400118 00000000 DD 00000000 ; Certificate File pointer = 0 0040011C 00000000 DD 00000000 ; Certificate Table size = 0 00400120 00800100 DD 00018000 ; Relocation Table address = 18000 00400124 0C000000 DD 0000000C ; Relocation Table size = C (12.) 00400128 00000000 DD 00000000 ; Debug Data address = 0 0040012C 00000000 DD 00000000 ; Debug Data size = 0 00400130 00000000 DD 00000000 ; Architecture Data address = 0 00400134 00000000 DD 00000000 ; Architecture Data size = 0 00400138 00000000 DD 00000000 ; Global Ptr address = 0 0040013C 00000000 DD 00000000 ; Must be 0 00400140 00000000 DD 00000000 ; TLS Table address = 0 00400144 00000000 DD 00000000 ; TLS Table size = 0 00400148 00000000 DD 00000000 ; Load Config Table address = 0 0040014C 00000000 DD 00000000 ; Load Config Table size = 0 00400150 00000000 DD 00000000 ; Bound Import Table address = 0 00400154 00000000 DD 00000000 ; Bound Import Table size = 0 00400158 00600100 DD 00016000 ; Import Address Table address = 16000 0040015C 08000000 DD 00000008 ; Import Address Table size = 8 00400160 00000000 DD 00000000 ; Delay Import Descriptor address = 0 00400164 00000000 DD 00000000 ; Delay Import Descriptor size = 0 00400168 00200000 DD 00002000 ; COM+ Runtime Header address = 2000 0040016C 48000000 DD 00000048 ; Import Address Table size = 48 (72.) 00400170 00000000 DD 00000000 ; Reserved 00400174 00000000 DD 00000000 ; Reserved 00400178 2E 74 65 7>ASCII ".textxc" ; SECTION 00400180 5D380100 DD 0001385D ; VirtualSize = 1385D (79965.) 00400184 00200000 DD 00002000 ; VirtualAddress = 2000 00400188 003A0100 DD 00013A00 ; SizeOfRawData = 13A00 (80384.) 0040018C 00040000 DD 00000400 ; PointerToRawData = 400 00400190 00000000 DD 00000000 ; PointerToRelocations = 0 00400194 00000000 DD 00000000 ; PointerToLineNumbers = 0 00400198 0000 DW 0000 ; NumberOfRelocations = 0 0040019A 0000 DW 0000 ; NumberOfLineNumbers = 0 0040019C 20000060 DD 60000020 ; Characteristics = CODE|EXECUTE|READ 004001A0 2E 69 64 6>ASCII ".idata" ; SECTION 004001A8 56000000 DD 00000056 ; VirtualSize = 56 (86.) 004001AC 00600100 DD 00016000 ; VirtualAddress = 16000 004001B0 00020000 DD 00000200 ; SizeOfRawData = 200 (512.) 004001B4 003E0100 DD 00013E00 ; PointerToRawData = 13E00 004001B8 00000000 DD 00000000 ; PointerToRelocations = 0 004001BC 00000000 DD 00000000 ; PointerToLineNumbers = 0 004001C0 0000 DW 0000 ; NumberOfRelocations = 0 004001C2 0000 DW 0000 ; NumberOfLineNumbers = 0 004001C4 40000040 DD 40000040 ; Characteristics = INITIALIZED_DATA|READ 004001C8 2E 72 65 6>ASCII ".reloc" ; SECTION 004001D0 0C000000 DD 0000000C ; VirtualSize = C (12.) 004001D4 00800100 DD 00018000 ; VirtualAddress = 18000 004001D8 00020000 DD 00000200 ; SizeOfRawData = 200 (512.) 004001DC 00400100 DD 00014000 ; PointerToRawData = 14000 004001E0 00000000 DD 00000000 ; PointerToRelocations = 0 004001E4 00000000 DD 00000000 ; PointerToLineNumbers = 0 004001E8 0000 DW 0000 ; NumberOfRelocations = 0 004001EA 0000 DW 0000 ; NumberOfLineNumbers = 0 004001EC 40000042 DD 42000040 ; Characteristics = INITIALIZED_DATA|DISCARDABLE|READ 004001F0 2E 72 73 7>ASCII ".rsrc" ; SECTION 004001F8 0A060000 DD 0000060A ; VirtualSize = 60A (1546.) 004001FC 00A00100 DD 0001A000 ; VirtualAddress = 1A000 00400200 00080000 DD 00000800 ; SizeOfRawData = 800 (2048.) 00400204 00420100 DD 00014200 ; PointerToRawData = 14200 00400208 00000000 DD 00000000 ; PointerToRelocations = 0 0040020C 00000000 DD 00000000 ; PointerToLineNumbers = 0 00400210 0000 DW 0000 ; NumberOfRelocations = 0 00400212 0000 DW 0000 ; NumberOfLineNumbers = 0 00400214 40000040 DD 40000040 ; Characteristics = INITIALIZED_DATA|READ 00400218 00 DB 00 --- snip ---
Characteristics = EXECUTABLE_IMAGE|32BIT_MACHINE|LINE_NUMS_STRIPPED|LOCAL_SYMS_STRIPPED
The check must include 'EXECUTABLE_IMAGE'.
With that part fixed, there is another problem with Xenocode VM bootstrapping full .NET Framework from its own resources (no .NET physically present in WINEPREFIX) but that can be worked around with 'winetricks -q dotnet20'. With that stuff in place the tool presents a license dialog.
$ sha1sum ModelingPE__setup_EN.exe 333736c553c2eb985436e63f20bfcbb59932b6fb ModelingPE__setup_EN.exe
$ du -sh ModelingPE__setup_EN.exe 207M ModelingPE__setup_EN.exe
$ wine --version wine-1.7.47-118-ga90592c
Regards