[Bug 7065] Get SecuROM copy-protection working

wine-bugs at winehq.org wine-bugs at winehq.org
Mon Jan 28 13:52:32 CST 2008


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





--- Comment #74 from Anastasius Focht <focht at gmx.net>  2008-01-28 13:52:23 ---
Hello,

well I finally received the original media of "Homeworld 2" v1.x game mentioned
here.

Listed here: http://appdb.winehq.org/objectManager.php?sClass=version&iId=3803

wine version used: wine-0.9.54
cleaned .wine

Installed fine from CD.

Main executable scan with Protection ID:

--- snip ---
Scanning -> c:\Program Files\Sierra\Homeworld2\Bin\Release\Homeworld2.exe
File Type : Exe, Size : 5390337 (0524001h) Byte(s)
-> File has 57345 (0E001h) bytes of appended data starting at offset 0516000h
[!] SecuROM Detected - Version 4.84.84
[!] Possible CD/DVD-Key or Serial Check -> CDKey
--- snip ---

There exists a patch for that game, but I did analysis unpatched.

When you start the game after installation, it live locks forever eating CPU.

--- snip ---
..
0009:Call KERNEL32.GetWindowsDirectoryA(0034b760,00000100) ret=007f2902
0009:Ret  KERNEL32.GetWindowsDirectoryA() retval=0000000a ret=007f2902
0009:Call KERNEL32.FindFirstFileA(0034b760
"c:\\windows\\System32\\Drivers\\*.sys",0034b620) ret=007f2a60
0009:Ret  KERNEL32.FindFirstFileA() retval=ffffffff ret=007f2a60
0009:Call KERNEL32.GetTickCount() ret=007f2aeb
0009:Ret  KERNEL32.GetTickCount() retval=00001155 ret=007f2aeb
0009:trace:seh:raise_exception code=c0000094 flags=0 addr=0x7f2afa
0009:trace:seh:raise_exception  eax=000038bf ebx=7b8ae084 ecx=7bc9fda0
edx=00000000 esi=0000004b edi=00403000
0009:trace:seh:raise_exception  ebp=0034b990 esp=0034b880 cs=0073 ds=007b
es=007b fs=0033 gs=003b flags=00210202
0009:trace:seh:call_stack_handlers calling handler at 0x7790c0 code=c0000094
flags=0
0009:trace:seh:call_stack_handlers handler at 0x7790c0 returned 0 
..
endless exception loop
--- snip ---

The copy protection code expects at least one .sys driver in
"c:\windows\system32\drivers" which isn't the case on clean .wine with game
install.
The first *.sys entry found is used to derive a temporary filename from it.
This filename is later used to create a copy protection device driver on the
fly (from resource) which is later loaded.

You can fake this part by placing an empty "<whatevername>.sys" file into
drivers to let FindFirstFileA("c:\\windows\\System32\\Drivers\\*.sys") succeed.

Ideally wine should make sure there is at least one .sys driver on clean wine.
Fortunately, wine now ships with a builtin one: mount manager (mountmgr.sys).
The solution is to let wine create a fake .sys (like fake dll) in drivers:

--- snip patch #1 ---
diff --git a/tools/wine.inf b/tools/wine.inf
index c3cb89c..719ff5f 100644
--- a/tools/wine.inf
+++ b/tools/wine.inf
@@ -2230,6 +2230,7 @@ HKLM,%CurrentVersion%\Telephony\Country
List\998,"SameAreaRule",,"G"
 11,,imaadp32.acm
 11,,imagehlp.dll
 11,,kernel32.dll
+12,,mountmgr.sys
 11,,msadp32.acm
 11,,msg711.acm
 11,,mshtml.dll
--- snip patch #1 ---

With this patch it goes further only to crash again ...

--- snip ---
..
0009:Call KERNEL32.CreateFileA(0034cdec
"qmountmg.sys",80000000,00000003,0034b918,00000003,00000080,00000000)
ret=00808a16
0009:Ret  KERNEL32.CreateFileA() retval=ffffffff ret=00808a16
0009:Call KERNEL32.GetLastError() ret=00808a34
0009:Ret  KERNEL32.GetLastError() retval=00000002 ret=00808a34
0009:Call KERNEL32.GetTempPathA(00000100,0034ccec) ret=007f297a
0009:Ret  KERNEL32.GetTempPathA() retval=00000010 ret=007f297a
0009:Call KERNEL32.CreateFileA(0034ccec
"C:\\windows\\temp\\qmountmg.sys",40000000,00000000,00000000,00000002,00000000,00000000)
ret=007f4114
0009:Ret  KERNEL32.CreateFileA() retval=000000d0 ret=007f4114
0009:Call KERNEL32.WriteFile(000000d0,008c491c,00004600,0034b9a8,00000000)
ret=007f413f
0009:Ret  KERNEL32.WriteFile() retval=00000001 ret=007f413f
0009:Call KERNEL32.CloseHandle(000000d0) ret=007f4149
0009:Ret  KERNEL32.CloseHandle() retval=00000001 ret=007f4149
0009:Call advapi32.OpenSCManagerA(00000000,00000000,000f003f) ret=007f549f
0009:Ret  advapi32.OpenSCManagerA() retval=00149520 ret=007f549f
0009:Call advapi32.OpenServiceA(00149520,0034ceec "qmountmg",000f01ff)
ret=007f54c6
0009:Ret  advapi32.OpenServiceA() retval=00000000 ret=007f54c6
0009:Call advapi32.OpenSCManagerA(00000000,00000000,000f003f) ret=007f5199
0009:Ret  advapi32.OpenSCManagerA() retval=00149540 ret=007f5199
0009:Call
advapi32.CreateServiceA(00149540,0034ceec,0034ceec,000f01ff,00000001,00000003,00000001,0034ccec,00000000,00000000,00000000,00000000,00000000)
ret=007f51ee
0009:Ret  advapi32.CreateServiceA() retval=001572b8 ret=007f51ee
0009:Call advapi32.StartServiceA(001572b8,00000000,00000000) ret=007f5254 
..
002b:Call driver init 0x4615e0
(obj=0x602d3a60,str=L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\xmountmg")
002b:trace:seh:raise_exception code=c0000005 flags=0 addr=0x4615e8
002b:trace:seh:raise_exception  info[0]=00000001
002b:trace:seh:raise_exception  info[1]=00016740
002b:trace:seh:raise_exception  eax=00016740 ebx=602d3674 ecx=7ece6b00
edx=602d3a60 esi=7ece6b08 edi=004615e0
002b:trace:seh:raise_exception  ebp=7ece69c8 esp=7ece6940 cs=0073 ds=007b
es=007b fs=0033 gs=003b flags=00210206
002b:Call KERNEL32.__wine_emulate_instruction(7ece68e8,7ece661c) ret=6033d092
002b:Ret  KERNEL32.__wine_emulate_instruction() retval=00000001 ret=6033d092
*boom*
--- snip ---

This one is a bit tricky ... it boils down to following code sequence in driver
entry proc (bit simplified):

--- snip ---
call    sub_463260
or      dword ptr [eax], 1   ; *boom* here

..
sub_463260:
mov     eax, offset dword_466740
retn

..
.data:00466740 dword_466740 dd ?
--- snip ---

The offset loaded into eax at run time is always the same: 0x00016740.
Let's look at PE mapping:

--- snip ---
003a:trace:module:load_native_dll Trying native dll
L"C:\\windows\\temp\\smountmg.sys"
003a:trace:module:map_image mapped PE file at 0x460000-0x469000
003a:trace:module:map_image mapping section .text at 0x461000 off 400 size 3400
virt 32a4 flags 68000020
003a:trace:module:map_image clearing 0x464400 - 0x465000
003a:trace:module:map_image mapping section .rdata at 0x465000 off 3800 size
200 virt 194 flags 48000040
003a:trace:module:map_image clearing 0x465200 - 0x466000
003a:trace:module:map_image mapping section .data at 0x466000 off 3a00 size 200
virt 968 flags c8000040
003a:trace:module:map_image clearing 0x466200 - 0x467000
003a:trace:module:map_image mapping section INIT at 0x467000 off 3c00 size 600
virt 4e8 flags e2000020
003a:trace:module:map_image clearing 0x467600 - 0x468000
003a:trace:module:map_image mapping section .reloc at 0x468000 off 4200 size
400 virt 2e0 flags 42000040
003a:trace:module:map_image clearing 0x468400 - 0x469000
003a:warn:module:alloc_module disabling no-exec because of L"smountmg.sys" 
--- snip ---

And the preferred image base for the .sys driver: 0x00010000
Looks like relocation fixups problem because there exists a .reloc section in
driver which wine didn't apply...

Now lets fix this:

--- snip patch #2 ---
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index 1c44d49..7f1a1d0 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -1149,6 +1149,7 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, char
*base, SIZE_T total_siz

     if (ptr != base &&
         ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) ||
+         (nt->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE) ||
           !NtCurrentTeb()->Peb->ImageBaseAddress) )
     {
         const IMAGE_DATA_DIRECTORY *relocs;
--- snip patch #2 ---

With this patch applied, fixups are now done when the driver is loaded by
winedevice.

It goes further then only to crash at unimplemented ntoskrnl API:

--- snip ---
0013:Call
ntoskrnl.exe.IoCreateDevice(601dcd40,00000040,00000000,00000022,00000000,00000001,64be1718)
ret=004616ea
0013:trace:ntoskrnl:IoCreateDevice (0x601dcd40, 64, <null>, 34, 0, 1,
0x64be1718)
0013:Call ntdll.RtlAllocateHeap(00110000,00000008,000000f8) ret=602470fc
0013:Ret  ntdll.RtlAllocateHeap() retval=0012c538 ret=602470fc
0013:Ret  ntoskrnl.exe.IoCreateDevice() retval=00000000 ret=004616ea
0013:Call ntdll.RtlInitUnicodeString(64be16e4,64be16ec L"\\Device\\CdRom0")
ret=00461409
0013:Ret  ntdll.RtlInitUnicodeString() retval=0000001c ret=00461409
0013:Call KERNEL32.RaiseException(80000100,00000001,00000002,64be16a8)
ret=60247485
0013:trace:seh:raise_exception code=80000100 flags=1 addr=0x7b8414e0
0013:trace:seh:raise_exception  info[0]=602474e0
0013:trace:seh:raise_exception  info[1]=6024955d
wine: Call from 0x7b8414e0 to unimplemented function
ntoskrnl.exe.IoGetDeviceObjectPointer, aborting
0013:trace:seh:call_stack_handlers calling handler at 0x7bc37e90 code=80000100
flags=1
0013:Call KERNEL32.UnhandledExceptionFilter(64be10d4) ret=7bc37ed3
wine: Unimplemented function ntoskrnl.exe.IoGetDeviceObjectPointer called at
address 0x7b8414e0 (thread 0013), starting debugger...
0013:trace:seh:start_debugger Starting debugger "winedbg --auto 16 120"
0013:Ret  KERNEL32.UnhandledExceptionFilter() retval=00000000 ret=7bc37ed3
0013:trace:seh:call_stack_handlers handler at 0x7bc37e90 returned 1
Unhandled exception: unimplemented function
ntoskrnl.exe.IoGetDeviceObjectPointer called in 32-bit code (0x7b841558). 
--- snip ---

The security driver requests device object for "\\Device\\CdRom0" to
create/forward synchronous fs requests to lower device drivers by using
IofCallDriver().
There is no point to stub/implement IoGetDeviceObjectPointer without additional
wine server infrastructure present (support of layered drivers).

Regards


-- 
Configure bugmail: http://bugs.winehq.org/userprefs.cgi?tab=email
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