I looked at the trace log you attached to your email, and recognised (unfortunately) familiar copy protection output :-(
Is anyone working on implementing what would be needed to successfuly run copy-protected softwares ?
I ran into the same problems when I tried to play The Longuest Journey with Wine. I disassembled a large part of the code and rewrote it in C to try to understand what was going on. If anyone is interested I can send my work by e-mail (I won't send it to the list as the files are quite big).
Basically, the copy protection scheme I studied used the following technique. One of the sections in the PE file is encrypted. The decryption key is generated from the content of the other sections. The process of decrypting the encrypted section tried to detect if a debugger is running, and fails to run properly if so. This results in the inability to decrypt the PE file if the unencrypted section is modified or if a debugger is running.
There must be some code to detect if the application CD is genuine but I've never been able to go past the decryption part.
To detect if a debugger is running, the following actions are performed (in no particular order):
- the code tries to open some files using CreateFileA : "\.\SICE", "\.\SIWVID" and "\.\NTICE". This fails as the SoftICE VxDs are not loaded, so no problems there
- it also tries to read/write to the debug registers. this produces an unhandled exception. should be trivial to write an exception handler to support that (right ?)
- the code writes binary code to the interrupt vector table (at address 0 - division by 0 handler), and then cause to the division by 0 interrupt handler to be called by dividing a value by 0.
- the TIB (Thread Information Block, which address is located at fs:0) is read. The following C code illustrates the technique (which I don't understand :-)
bool detect_debugger_from_TIB { char *pTIB; asm ( "mov %%fs:0x18, %", "=g"(pTIB) ); if ( pTIB[0x20] == 0 ) return FALSE; else return TRUE; }
- another debugger detection technique uses int 0x68, functino 0x4300. If the content of eax when returning from int 0x68 is not 0x4300, a debugger is present. This is not performed on some NEC Japanese systems, which probably use int 0x68 for another purpose.
- the last attempt to detect a debugger uses int 0x01 (enter SMM/ICE mode), which checks if an external hardware emulator is connected to the processor. I haven't been able to understand what the code is supposed to do.
There might be some other anti-debugging techniques, I gave up after 2 weeks of disassembly :-)
Hope these observations will help someone.
Laurent Pinchart
- it also tries to read/write to the debug registers. this produces an
unhandled exception. should be trivial to write an exception handler to support that (right ?)
how does it do the writing exactly ? (I'd suspect more the program wants to catch itself a watchpoint)
bool detect_debugger_from_TIB { char *pTIB; asm ( "mov %%fs:0x18, %", "=g"(pTIB) ); if ( pTIB[0x20] == 0 ) return FALSE; else return TRUE; }
fs:0x18 points in memory to the TEB structure and offset 0x20 (from thread.h) says: 20 Process id (win95: debug context) so I assume you run it on Win9x, and got it tested this way (I wouldn't be surprised that under nt it did test dword 0x64 and/or 0x68)
basically, wine shouldn't be too far away for correctly allowing this
the debug register stuff seems to be the showstopper right now
A+
On Monday 18 March 2002 22:58, Eric Pouech wrote:
- it also tries to read/write to the debug registers. this produces an
unhandled exception. should be trivial to write an exception handler to support that (right ?)
how does it do the writing exactly ? (I'd suspect more the program wants to catch itself a watchpoint)
Here's the C code I wrote from the disassembler output. It might not be correct, and might not even compile, but the idea is there.
BOOL ReadWriteDR2 (DWORD command, DWORD * value) { struct { WORD limit; DWORD * base; } idtr;
void *int0Handler; DWORD int0handlerHigh; DWORD int0handlerLow;
DWORD valDR2; BOOL writeDR2;
if ( value == 0 ) return FALSE;
if ( command == 0x1010 ) { writeDR2 = FALSE; } else if ( command == 0x1011 ) { writeDR2 = TRUE; valDR2 = *value; } else return FALSE;
idtr = reg.IDTR; int0Handler = idtr.base[4] & 0xffff0000; int0Handler |= idtr.base[0];
int0handlerLow = ((DWORD*)int0Handler)[0]; int0handlerHigh = ((DWORD*)int0Handler)[1];
/* Install the division by 0 handler: pop %eax pop %eax push %cs push %ebx iret */ ((DWORD*)int0Handler)[0] = 0x530e5858; ((DWORD*)int0Handler)[1] = 0x000000cf;
asm ( " movl %%ebx, (%0) " : "=m"(return_label1) ); asm ( " xorl %%eax, %%eax; div %%eax, %%eax " );
return_label1: if ( writeDR2 ) { reg.DR2 = valDR2; } else { valDR2 = reg.dr2; }
idtr = reg.IDTR; int0Handler = idtr.base[4] & 0xffff0000; int0Handler |= idtr.base[0];
/* Install the division by 0 handler: pop %eax pop %eax push %cs push %ebx iret */ ((DWORD*)int0Handler)[0] = 0x53515858; ((DWORD*)int0Handler)[1] = 0x000000cf;
asm ( " xorl %%ecx, %%ecx; movw %%ecx, %%cs " ); asm ( " movl %%ebx, (%0) " : "=m"(return_label2) ); asm ( " xorl %%eax, %%eax; div %%eax, %%eax " );
return_label2: ((DWORD*)int0Handler)[0] = int0handlerLow; ((DWORD*)int0Handler)[1] = int0handlerHigh;
if ( ! writeDR2 ) *value = valDR2;
return TRUE; }
The only call to the ReadWriteDR2 function I found in the disassembler output is a read call, and the DR2 value is compared with 0xffb31146. Hope this helps.
bool detect_debugger_from_TIB { char *pTIB; asm ( "mov %%fs:0x18, %", "=g"(pTIB) ); if ( pTIB[0x20] == 0 ) return FALSE; else return TRUE; }
fs:0x18 points in memory to the TEB structure and offset 0x20 (from thread.h) says: 20 Process id (win95: debug context) so I assume you run it on Win9x, and got it tested this way (I wouldn't be surprised that under nt it did test dword 0x64 and/or 0x68)
You're right, that function is for Win9x. I haven't disassembled the NT function but I can do if needed.
Where can I find some doc about how the fs and gs registers are used ?
Laurent Pinchart
Here's the C code I wrote from the disassembler output. It might not be correct, and might not even compile, but the idea is there.
I'll look into this later
Where can I find some doc about how the fs and gs registers are used ?
under windows, $fs always refer to the teb (threab environment block) usually, the way to get the linear address is to use the $fs[0x18] (which stores the linear address (flat model) of the teb) look into include/thread for a more precise description of the teb fields
HTH
A+
The only call to the ReadWriteDR2 function I found in the disassembler output is a read call, and the DR2 value is compared with 0xffb31146. Hope this helps.
well, not really DR0..3 contain the linear address where you want to put your breakpoint... so there's no reason it's updated by the 0 fault, however is DR2 set by hand before the call to the function similary is DR7 set in the nearby (this is the register that enables/disables among other things, the use of the addresses stored in the DR0..3 regs)
A+
The only call to the ReadWriteDR2 function I found in the disassembler output is a read call, and the DR2 value is compared with 0xffb31146. Hope this helps.
well, not really DR0..3 contain the linear address where you want to put your breakpoint... so there's no reason it's updated by the 0 fault, however is DR2 set by hand before the call to the function similary is DR7 set in the nearby (this is the register that enables/disables among other things, the use of the addresses stored in the DR0..3 regs)
I haven't noticed any access to DR7. The code looks like DR2 should be written at some point, but I haven't been able to find where. I think it would help if we could implement an exception handler for DR0..3 read/write accesses which would just store the value somewhere in memory and return it when the DR registers are read.
Laurent Pinchart
I haven't noticed any access to DR7. The code looks like DR2 should be written at some point, but I haven't been able to find where. I think it would help if we could implement an exception handler for DR0..3 read/write accesses which would just store the value somewhere in memory and return it when the DR registers are read.
let me know if this helps A+
Index: memory/instr.c =================================================================== RCS file: /home/cvs/cvsroot/wine/wine/memory/instr.c,v retrieving revision 1.14 diff -u -r1.14 instr.c --- memory/instr.c 10 Mar 2002 00:18:34 -0000 1.14 +++ memory/instr.c 21 Mar 2002 22:17:01 -0000 @@ -525,6 +525,52 @@ } /* fallthrough to illegal instruction */ break; + case 0x23: /* mov e?a, drX */ + { + BYTE *addr = INSTR_GetOperandAddr(context, instr + 2, + long_addr, segprefix, &len ); + unsigned dr_idx = (instr[2]-0xC0)/8; + + if (addr && dr_idx <= 7 && dr_idx != 4 && dr_idx != 5) + { + switch (dr_idx) + { + case 0: context->Dr0 = *(DWORD*)addr; break; + case 1: context->Dr1 = *(DWORD*)addr; break; + case 2: context->Dr2 = *(DWORD*)addr; break; + case 3: context->Dr3 = *(DWORD*)addr; break; + case 6: context->Dr6 = *(DWORD*)addr; break; + case 7: context->Dr7 = *(DWORD*)addr; break; + } + context->Eip += prefixlen+3; + return TRUE; + } + } + /* fallthrough to illegal instruction */ + break; + case 0x21: /* mov drX, e?x */ + { + BYTE *addr = INSTR_GetOperandAddr(context, instr + 2, + long_addr, segprefix, &len ); + int dr_idx = (instr[2]-0xC0)/8; + + if (addr && dr_idx <= 7 && dr_idx != 4 && dr_idx != 5) + { + switch (dr_idx) + { + case 0: *(DWORD*)addr = context->Dr0; break; + case 1: *(DWORD*)addr = context->Dr1; break; + case 2: *(DWORD*)addr = context->Dr2; break; + case 3: *(DWORD*)addr = context->Dr3; break; + case 6: *(DWORD*)addr = context->Dr6; break; + case 7: *(DWORD*)addr = context->Dr7; break; + } + context->Eip += prefixlen+3; + return TRUE; + } + } + /* fallthrough to illegal instruction */ + break; case 0xa1: /* pop fs */ { WORD seg = *(WORD *)get_stack( context );
I haven't noticed any access to DR7. The code looks like DR2 should be written at some point, but I haven't been able to find where. I think it would help if we could implement an exception handler for DR0..3 read/write accesses which would just store the value somewhere in memory and return it when the DR registers are read.
let me know if this helps
Your patch looks fine, and I think it will solve my problem, but I haven't been able to test it. Before accessing DR2, the program tries to read/write from the interrupt vector table, which results in an exception and the debugger being launched.
I'd try to implement support for that in wine, but I don't know where to look... I basically need to be able to read/write the interrupt vector table (for int 0x00 here), AND to execute the modified interrupt vector when a division by 0 is executed. Any idea ?
Laurent Pinchart
I'd try to implement support for that in wine, but I don't know where to look... I basically need to be able to read/write the interrupt vector table (for int 0x00 here), AND to execute the modified interrupt vector when a division by 0 is executed. Any idea ?
I'm not sure we're really want to inject this type of support in the wine tree (very specific, bound to old windows architecture...) (this holds true for the DR? support patch)
what I'd do is: - simulate (as for DR?) the IDTR read/write (memory/instr) - provide our own interrupt table - then hook the signal catches to this table (dlls/ntdll/ - in your case, especially the divide by 0 signal to entry 1 of this table
however, I don't think this is the best way to go. It will add lots of code to Wine (mainly i386 virtualization), and let programs modify things they shouldn't normally need to touch.
I'd rather try to test with the NT mode, which shouldn't toy with all those parts
A+
what I'd do is:
- simulate (as for DR?) the IDTR read/write (memory/instr)
- provide our own interrupt table
- then hook the signal catches to this table (dlls/ntdll/
- in your case, especially the divide by 0 signal to entry 1 of this
table
however, I don't think this is the best way to go. It will add lots of code to Wine (mainly i386 virtualization), and let programs modify things they shouldn't normally need to touch.
Even if you did this, it probably wouldn't help much, as the interrupt routine is supposed to be executed in ring 0 (which presumably is the very *reason* the program does this nonsense).
So you'll fail immediately afterwards due to privilege violations as the app does whatever it wants to do in ring 0 ...
Of course, you could add virtualization for all the ring 0 stuff, but this is quite open-ended :-(
Bye, Ulrich
what I'd do is:
- simulate (as for DR?) the IDTR read/write (memory/instr)
- provide our own interrupt table
- then hook the signal catches to this table (dlls/ntdll/
- in your case, especially the divide by 0 signal to entry 1 of this
table
however, I don't think this is the best way to go. It will add lots of code to Wine (mainly i386 virtualization), and let programs modify things they shouldn't normally need to touch.
Even if you did this, it probably wouldn't help much, as the interrupt routine is supposed to be executed in ring 0 (which presumably is the very *reason* the program does this nonsense).
Does that mean that a win95/98 app can execute arbitrary ring 0 code by using this method ?
So you'll fail immediately afterwards due to privilege violations as the app does whatever it wants to do in ring 0 ...
Of course, you could add virtualization for all the ring 0 stuff, but this is quite open-ended :-(
I agree with you
Laurent Pinchart
Even if you did this, it probably wouldn't help much, as the interrupt routine is supposed to be executed in ring 0 (which presumably is the very *reason* the program does this nonsense).
Does that mean that a win95/98 app can execute arbitrary ring 0 code by using this method ?
Yes, by this or any of a couple of other methods ...
Did anybody claim Win9x had kernel/user space separation? ;-)
Bye, Ulrich
On Mon, 25 Mar 2002, Ulrich Weigand wrote:
what I'd do is:
- simulate (as for DR?) the IDTR read/write (memory/instr)
- provide our own interrupt table
- then hook the signal catches to this table (dlls/ntdll/
- in your case, especially the divide by 0 signal to entry 1 of this
table
however, I don't think this is the best way to go. It will add lots of code to Wine (mainly i386 virtualization), and let programs modify things they shouldn't normally need to touch.
Even if you did this, it probably wouldn't help much, as the interrupt routine is supposed to be executed in ring 0 (which presumably is the very *reason* the program does this nonsense).
So you'll fail immediately afterwards due to privilege violations as the app does whatever it wants to do in ring 0 ...
Of course, you could add virtualization for all the ring 0 stuff, but this is quite open-ended :-(
The copy-protection support in WineX does some of this stuff. If the stuff the application in question does is just another copy protection (sounds like it), then the additional ring 0 stuff you need to virtualize is probably just access to the debug registers.
what I'd do is:
- simulate (as for DR?) the IDTR read/write (memory/instr)
- provide our own interrupt table
- then hook the signal catches to this table (dlls/ntdll/
- in your case, especially the divide by 0 signal to entry 1 of this
table
however, I don't think this is the best way to go. It will add lots of code to Wine (mainly i386 virtualization), and let programs modify things they shouldn't normally need to touch.
Even if you did this, it probably wouldn't help much, as the interrupt routine is supposed to be executed in ring 0 (which presumably is the very *reason* the program does this nonsense).
So you'll fail immediately afterwards due to privilege violations as the app does whatever it wants to do in ring 0 ...
Of course, you could add virtualization for all the ring 0 stuff, but this is quite open-ended :-(
The copy-protection support in WineX does some of this stuff. If the stuff the application in question does is just another copy protection (sounds like it), then the additional ring 0 stuff you need to virtualize is probably just access to the debug registers.
The application tries to execute some (trivial) code in ring 0 mode by modifying the IDTR when run in win95/win98 mode. The problem doesn't occur in winNT mode, so I don't think we should implement a complete ring 0 virtualization.
In winNT mode the debugger detection is done by calling int 0x01 and checking a 'side effect' (probably an exception handler effect). I'll check if the detection fails or not.
Laurent Pinchart
On Monday 25 March 2002 07:31, Eric Pouech wrote:
I'd try to implement support for that in wine, but I don't know where to look... I basically need to be able to read/write the interrupt vector table (for int 0x00 here), AND to execute the modified interrupt vector when a division by 0 is executed. Any idea ?
I'm not sure we're really want to inject this type of support in the wine tree (very specific, bound to old windows architecture...) (this holds true for the DR? support patch)
what I'd do is:
- simulate (as for DR?) the IDTR read/write (memory/instr)
- provide our own interrupt table
- then hook the signal catches to this table (dlls/ntdll/
- in your case, especially the divide by 0 signal to entry 1 of this
table
however, I don't think this is the best way to go. It will add lots of code to Wine (mainly i386 virtualization), and let programs modify things they shouldn't normally need to touch.
I'd rather try to test with the NT mode, which shouldn't toy with all those parts
I agree with you. I tried NT mode, but unfortunately I'm not sucessful here either.
I ran into 3 problems: 1 - NtQueryInformationProcess 2 - int 0x01 3 - Secdrv.vxd
1 - NtQueryInformationProcess is a stub, except when called with ProcessInformationClass set to ProcessDebugPort, which is exactly what the copy protection does :-), so this is not really a problem. BTW, I found this link on the MSDN website while searching for some doc about NtQueryInformationProcess
http://msdn.microsoft.com/msdn-files/026/002/137/NTDLL/Source Files/ntdll_cpp.asp
Unfortunately the server returns an error, but it might be worth investigating :-)
2 - int 0x01 is called from within a try{} block (if I read the assembly code correctly), and the copy protection code seems to be looking for a side effect: the debugger detection returns false (no debugger present) if some memory location (0x00435b90), which has been initialized with the value -1, contains 0xc0000005 upon completion of int 0x01. Does this ring a bell to someone ?
3 - fixme:win32:DEVICE_Open Unknown/unsupported VxD Secdrv. Try --winver nt40 or win31 ! I haven't been ablt to find any Secdrv.vxd, but there's a secdrv.sys on the CD... Should I disassembly it and add the code to wine ? :-)
Laurent Pinchart
1 - NtQueryInformationProcess is a stub, except when called with ProcessInformationClass set to ProcessDebugPort, which is exactly what the copy protection does :-), so this is not really a problem. BTW, I found this link on the MSDN website while searching for some doc about NtQueryInformationProcess
http://msdn.microsoft.com/msdn-files/026/002/137/NTDLL/Source Files/ntdll_cpp.asp
hmm I think NtQueryInformationProcess should set the length of the modified data (4 for a DWORD)
Unfortunately the server returns an error, but it might be worth investigating :-)
2 - int 0x01 is called from within a try{} block (if I read the assembly code correctly), and the copy protection code seems to be looking for a side effect: the debugger detection returns false (no debugger present) if some memory location (0x00435b90), which has been initialized with the value -1, contains 0xc0000005 upon completion of int 0x01. Does this ring a bell to someone ?
C0000005 is STATUS_ACCESS_VIOLATION sounds like the code that has been caught in the exception handler
3 - fixme:win32:DEVICE_Open Unknown/unsupported VxD Secdrv. Try --winver nt40 or win31 ! I haven't been ablt to find any Secdrv.vxd, but there's a secdrv.sys on the CD... Should I disassembly it and add the code to wine ? :-)
of course not ;-) perhaps in that case (true in step 2) it tries to look for further information wrt debuggers
A+