http://bugs.winehq.org/show_bug.cgi?id=24157
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Component|-unknown |kernel32 Summary|Tera Copy fails to start |Tera Copy fails to start - |(Obsidium v1.x Software |kernel32.DebugBreak() |Protection System) |taints frame pointer | |(Obsidium v1.x Software | |Protection System)
--- Comment #7 from Anastasius Focht focht@gmx.net 2011-06-15 10:44:17 CDT --- Hello again,
well that sucked ... debugging this braindamage is nasty. I'm starting to dream opcodes :|
That Obsidum code is full of short branching in between opcodes to fool disassemblers and debuggers ... very annoying. Various anti debugging tricks and hooking/emulating/stealing of API entry code.
Fortunately this stuff can be bypassed, you need to pass all exceptions (single step, div by zero, access violations, invalid opcode ...) to app installed SEHs. Also don't use soft breakpoints on API entries (int 3) it detects this. Hardware breakpoints are also reset in every SEH.
CheckRemoteDebuggerPresent() needs to be "adjusted" to prevent detection. Wine doesn't lie about this ;-)
+relay actually harms the protector and yields strange results (grrr lost some hours due to this problem)
Without +relay we're left with little diagnostics. Most anti-debugging tricks work out of the box, until this place:
--- snip --- 0021:trace:seh:raise_exception code=80000003 flags=0 addr=0x7b835a2b ip=7b835a2c tid=0021 0021:trace:seh:raise_exception eax=7b8366e5 ebx=0053015c ecx=7b810000 edx=7b8942dc esi=0032fce8 edi=00341e94 0021:trace:seh:raise_exception ebp=0032fcd8 esp=0032fcd8 cs=0073 ds=007b es=007b fs=0033 gs=003b flags=00000202 0021:trace:seh:call_vectored_handlers calling handler at 0x686a7de9 code=80000003 flags=0 0021:trace:seh:call_vectored_handlers handler at 0x686a7de9 returned 0 0021:trace:seh:call_stack_handlers calling handler at 0x531597 code=80000003 flags=0 0021:trace:seh:call_stack_handlers handler at 0x531597 returned 0 0021:trace:seh:raise_exception code=c0000005 flags=0 addr=0x51fd1a ip=0051fd1a tid=0021 0021:trace:seh:raise_exception info[0]=00000001 0021:trace:seh:raise_exception info[1]=3ed59644 0021:trace:seh:raise_exception eax=b2850111 ebx=a4aac3f0 ecx=00008500 edx=00000028 esi=0000db31 edi=0051fd26 0021:trace:seh:raise_exception ebp=0032fce4 esp=0032fcd8 cs=0073 ds=007b es=007b fs=0033 gs=003b flags=00010286 0021:trace:seh:call_vectored_handlers calling handler at 0x686a7de9 code=c0000005 flags=0 0021:trace:seh:call_vectored_handlers handler at 0x686a7de9 returned 0 0021:err:seh:raise_exception Exception frame is not in stack limits => unable to dispatch exception. --- snip ---
The protector calls DebugBreak() on purpose to force exception handler invocation and change execution flow by modifying its own context, so called "continuations". context->eip, context->esp are set to new targets. There is also reset of Dr0-Dr3,Dr7 to harm debuggers.
Upon return from exception handler, the new context is made active and execution proceeds. After some hours I came across this snippet (some junk opcodes removed):
--- snip --- 0051AB65 396D EC CMP DWORD PTR SS:[EBP-14],EBP 0051AB68 EB 04 JMP SHORT 0051AB6E ... <explodes somewhere> ... --- snip ---
There is a check in continuation code for frame pointer validity and this is where Wine gets it wrong ...
kernel32.DebugBreak Source:
http://source.winehq.org/git/wine.git/blob/0fd822f46526df49f5fa29627afbace7c...
kernel32.DebugBreak Disassembly:
--- snip --- 7B8366E5 55 PUSH EBP 7B8366E6 89E5 MOV EBP,ESP 7B8366E8 E8 3BF3FFFF CALL 7B835A28 7B8366ED 5D POP EBP 7B8366EE C3 RETN --- snip ---
(DbgBreakPoint inlined)
--- snip --- 7B835A28 55 PUSH EBP 7B835A29 89E5 MOV EBP,ESP 7B835A2B CC INT3 7B835A2C 5D POP EBP 7B835A2D C3 RETN --- snip ---
When the protector calls DebugBreak(), Wine taints the frame pointer. This value is then propagated to continuation code through the context passed to exception handler.
As fix either use inline without frame pointer or forward this to ntdll (which is probably better for Windows compatibility).
This keeps the protection happy (runs much further) only to end up in endless loop, which seems to be another bug... :|
Regards