reverser
November 3rd, 2004, 21:55
Sorry for the late reply, been kinda busy.
Now for some answers.
Quote:
- What kind of exception are you getting.
- Where does the exception occur & what code is there
- What are the appropriate register values there.
|
I'm getting an AV, trying to execute code at 7FFFFFFFh. It's not really clear where it happens as the stack is pretty much screwed up, and also lots of program code is copied into allocated buffers before execution, so you don't know anymore which function it comes from. I suspect it comes from the code like this, which is present in plenty:
Code:
mov edx, [esp+5ACh+Context.Dr3] //get the address of the copied function
push offset AntiDebug5 //next function to copy&execute
xor edx, 7FFFFFFFh //xor address back
call edx //call it
add esp, 4
If the value of DR3 is 0, then we get an exception.
I had some progress on the program. I was able to run it by patching it so it doesn't call the anti-debugging code (I tried that before but skipped too much). While it seems to work, there are some strange errors, so maybe I will need to "break" the code after all, but for now I have a working program.
I will, however, post some snippets that use SEH, it might be interesting for someone.
Code:
AntiDebug3_1 proc near
pRegist = dword ptr -1Ch
save_esp = dword ptr -18h
pExceptionPointers= dword ptr -14h
prevreg = dword ptr -10h
handler = dword ptr -0Ch
scopetable = dword ptr -8
_trylevel = dword ptr -4
_ebp = dword ptr 0
retaddr = dword ptr 4
dst = dword ptr 8
src = dword ptr 0Ch
count = dword ptr 10h
push ebp
mov ebp, esp
push 0FFFFFFFFh
push offset Antidebug3_scopetable
push offset _except_handler3
mov eax, large fs:0
push eax
mov large fs:0, esp
sub esp, 0Ch
push ebx
push esi
push edi
mov [ebp+save_esp], esp
;[...]
;do some work
;[...]
mov [ebp+_trylevel], 0
mov eax, large fs:0
mov [ebp+pRegist], eax
mov eax, [ebp+pRegist]
mov dword ptr [eax+4], offset return_seh
pushfw
pop eax
or eax, 100h ;set trace flag -> call return_seh
push eax
popfw
jmp short @@handled_by_debugger
; トトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトト
Antidebug3_filter:
mov eax, 1
retn
; トトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトト
Antidebug3_handler:
mov esp, [ebp+save_esp]
@@handled_by_debugger:
mov [ebp+_trylevel], 0FFFFFFFFh
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
mov ecx, [ebp+prevreg]
mov large fs:0, ecx
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
retn
AntiDebug3_1 endp
The function sets up its own SEH handler, and tries to invoke it by setting the single step flag. If it's being debugged, then (I guess) the exception gets ignored and excecution continues "normally". I can't see it doing anything nasty to the debugger, unless it can't handle such stuff.
The handler looks like this:
Code:
return_seh proc near
pContext = dword ptr 0Ch
mov eax, [esp+pContext]
push ebx
mov ecx, [eax+CONTEXT.Esp]
mov edx, [ecx]
add ecx, 4
mov [eax+CONTEXT.Edi], edx ; pop edi
mov edx, [ecx]
mov [eax+CONTEXT.Esi], edx ; pop esi
mov ecx, [ecx+4]
mov [eax+CONTEXT.Ebx], ecx ; pop ebx
mov ecx, [eax+CONTEXT.Ebp]
mov edx, [ecx]
add ecx, 4
mov [eax+CONTEXT.Ebp], edx ; ebp = [ebp+0] = saved ebp
mov edx, [ecx]
add ecx, 4
mov [eax+CONTEXT.Eip], edx ; eip = [ebp+4] = retaddr
mov [eax+CONTEXT.Esp], ecx ; esp = ebp+8, basically effect of mov esp, ebp; pop ebp; retn
mov [eax+CONTEXT.Dr7], 400h
push eax
push ebx
mov eax, large fs:0
mov ebx, [eax] ;restore SEH handler
mov ebx, [ebx]
mov [eax], ebx
pop ebx
pop eax
xor eax, eax
pop ebx
retn
return_seh endp
So basically it does what the epilogue code should do, and sets up context to return to the caller.
There is another handler used in a bunch of other places that does about the same, only returns to DR2, not return address in the stack:
Code:
ret_to_dr2 proc near
pContext = dword ptr 18h
push ebx
push eax
push ebx
mov eax, large fs:0
mov ebx, [eax]
mov ebx, [ebx]
mov [eax], ebx
pop ebx
pop eax
mov eax, [esp-8+pContext]
pop ebx
mov ecx, [eax+CONTEXT.Esp]
mov edx, [ecx]
add ecx, 4
mov [eax+CONTEXT.Edi], edx ; pop edi
mov edx, [ecx]
mov [eax+CONTEXT.Esi], edx ; pop esi
mov ecx, [ecx+4]
mov [eax+CONTEXT.Ebx], ecx ; pop ebx
mov ecx, [eax+CONTEXT.Ebp]
mov edx, [ecx]
add ecx, 8
mov [eax+CONTEXT.Esp], ecx ; esp = ebp+8 (move esp, ebp; pop ebp; retn)
mov ecx, [eax+CONTEXT.Dr2]
xor ecx, 7FFFFFFFh
mov [eax+CONTEXT.Ebp], edx ; ebp = [ebp+0] = saved ebp
mov [eax+CONTEXT.Dr7], 400h
mov [eax+CONTEXT.Eip], ecx ; eip = dr2 ^ 0x7ffffff
xor eax, eax
retn
ret_to_dr2 endp
The rest is pretty much moving code back and forth with little pieces of real work done in between. It's quite a pain to read, and I've achieved my goal for now, so I'm putting it aside.
Thanks for reading and sorry for wasting your time.