[Bug 24157] Tera Copy fails to start - kernel32.DebugBreak() taints frame pointer (Obsidium v1.x Software Protection System)

wine-bugs at winehq.org wine-bugs at winehq.org
Wed Jun 15 10:44:18 CDT 2011


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

Anastasius Focht <focht at 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 at 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/0fd822f46526df49f5fa29627afbace7ce3d242c:/dlls/kernel32/debugger.c#l360

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

-- 
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