PDA

View Full Version : A cute anti-tracing trick


naides
November 5th, 2007, 13:44
I have been tracing this app, which had the irritating tendency to escape the debugger and run to execution.

This is the way it does it: peppered throughout the code you find something like this:

Code:
11001857 55 PUSH EBP
11001858 8BEC MOV EBP,ESP
1100185A 51 PUSH ECX
1100185B 53 PUSH EBX
1100185C 56 PUSH ESI
1100185D 57 PUSH EDI
1100185E E8 72F9FFFF CALL XXXXXXX.110011D5 ; If I trace over this call with F8 the program takes off

11001863 -E9 6A006A00 JMP 116A18D2
11001868 FF15 C0180011 CALL DWORD PTR DS:[<&KERNEL32.GetModuleH>; kernel32.GetModuleHandleA
1100186E 50 PUSH EAX
1100186F E8 06FDFFFF CALL mc2_eval.1100157A
11001874 59 POP ECX
11001875 59 POP ECX


But if I trace into the call f7(Which the normal flow of program execution will do ) we arrive a this little snippet

Code:
110011D4 C3 RETN
110011D5 FE0424 INC BYTE PTR SS:[ESP] ; Quick and elegant
110011D8 C3 RETN


means that when we return the actual code that is executed is:

Code:
11001864 6A 00 PUSH 0 ; This instruction used to be 11001863 -E9 6A006A00 JMP 116A18D2, but now the EIP has updated to 11001864
Tricking Olly, who had placed the trace-over breakpoint at 11001863 -E9

11001866 6A 00 PUSH 0
11001868 FF15 C0180011 CALL DWORD PTR DS:[<&KERNEL32.GetModuleH>; kernel32.GetModuleHandleA
1100186E 50 PUSH EAX



A few hundred of these trace traps over the code makes tracing this baby a pain in the ass!

JMI
November 5th, 2007, 13:49
Nice find naides.

Regards,

blurcode
November 5th, 2007, 15:16
It is used in Thinstall Virtual OS loader.

ZaiRoN
November 5th, 2007, 17:54
Is there something more? Or, is it always the same trick (inc,ret combination)? In this case you should be able to solve the problem writing a simple script. Don't know, removing the call with a "jmp $+6" instruction...

Extremist
November 5th, 2007, 18:53
Stone-age tricks are still effective, just like a stone-age club can still bash your head in.

rendari
November 5th, 2007, 19:38
Just write something to check if the call leads to inc dword ptr[esp], ret, and if so, nop it. There, 2 min. of annoyance.

Kayaker
November 5th, 2007, 23:06
Funny, I just happened to be browsing the ImmDbg site (not that I use it but I've been playing with Python lately) and found a discussion on this exact obfuscation trick and scripting to get around it.

http://forum.immunityinc.com/?topic=34.0

LLXX
November 10th, 2007, 03:13
@Extremist: Indeed, this sort of code has been around since the very first processors to have a stack/call/return instructions, it's nothing new. It's known as an "NRC" or Non-Returning-Call (in the sense that EF does not return to the instruction after the call) and can be useful for situations other than anti-tracing (jump table lookups come to mind).

Many variations of this are possible, like
Code:
; some code that sets eax to the requested destination goes here
call .do_nrc
jmps .dest_1
jmps .dest_2
jmps .dest_3
...

.dest_1 ; some code goes here
...
.dest_2 ; some code goes here
...
.dest_3 ; ...etc
...
.do_nrc
lea eax [2*eax+eax]
add [esp] eax ; compute destination
ret
I'm assuming the debugger isn't breaking because it's setting explicit breakpoints on where it "thinks" the next instruction would be, rather than using the single-step flag and continuing until it finds a return instruction, at which point it traces one more time to the instruction "after" the call (wherever that may be). This doesn't solve NRCs which truly never return (in which case "step over" _should_ run until a return), but better than the behavior here. In the example, tracing F8 over should result in the next instruction being at 11001864.

(Add this to OllyDbg 2.0?)