본문 바로가기

Programming

Anti Debugging with POP SS

This little trick is very interesting, my first encounter with it was in a commercial protection, it left me wondering why a Push / Pop SS would implicit execute the next instruction without the Debugger knowing of it, i.e. raising a single-step exception, so I’ve decided to look into it and try to figure out why, and I believe I have found the explanation , but first let me show you how this technique can be used to detect debuggers relying on the Single Step flag for tracing.

If a debugger executes something like this:

PUSHFD -> push Efflags to Stack .

debuggers such as Olly is kind enough to “shadow” itself, And clean the result produced by this instruction and removing the trap flag from the EFflags pushed to stack.

(8번째 TF 비트를 참조)


But if it’s done like this:

Push ss
pop ss
pushfd

Olly will not remove the trap flag, which is very interesting and leaves it very vulnerable to trace detection. The Explanation seems to be pretty straight forward if you check out the Intel manuals and look up pop , you will find a passage similar to this :

POP SS instruction inhibits all interrupts, including the NMI interrupt, until after
Execution of the next instruction. This action allows sequential execution of POP SS
And MOV ESP, EBP instructions without the danger of having an invalid stack during
An interrupt 


세그먼트 레지스터가 수정 가능한거였나? 하고 검색을 해보니

위키피디아 내용이 다음과 같았다...

Note that, in protected mode, code may always modify all segment registers except CS (the code segment selector). This is because the current privilege level (CPL) of the processor is stored in the lower 2 bits of the CS register. The only way to raise the processor privilege level (and reload CS) is through the lcall (far call) and int (interrupt) instructions. Similarly, the only way to lower the privilege level (and reload CS) is through lret (far return) and iret (interrupt return) instructions


Well most of this can be boiled down to , if POP SS is executed , the CPU will prevent triggering of interrupts , as to avoid corruption of the stack. So why on earth is this affecting us when we are tracing using the single-step flag, well simply because when the Single-step flag is set , it triggers and interrupt in the CPU , but when a POP SS is executed it won’t trigger interrupts before it has executed the next instruction after it , and thus olly will never get a single-step exception for the PUSHFD and won’t know it has been executed , and thus wont clean out the trap-flag and leave us vulnerable to detection.

Circumventing this trick , is tricky since simply patching it out is easy , but if implementet correctly it can prevent tracing of your code very effectively and be a pain in the ass.


한마디로 원래 디버거가 한스텝씩 코드를 실행하는 원리가 TF 플래그를 셋팅해놓으면

어셈블리 명령 하나를 수행한 뒤에 exception 이 발생하여 CPU 가 다시 디버거로 이동했다가 next instruction을

수행하지만 POP SS 명령의 경우 next instruction이 수행되기 전까지 어떠한 interrupt 도 발생시키지 않기 때문에

POP SS 명령 바로 뒤의 명령은 single step in 할수 없다.  여기서 중요한 점은 pushf 명령이 디버깅되지 않고 

실제로 스택상에 EFLAG 레지스터가 들어가게되면, 디버깅 당하는 프로세스상에서 자신이 디버깅 되고있는지

확인이 가능해진다는 점이다.  따라서 이 특성이 anti debugging 에 사용될 수 있다.

아래의 글에 더 자세히 설명되있다.

Anti Debugging

I found this nice page about Anti-Debugging tricks. It covers so many of them and if you know the techniques it’s really fun to read it quickly one by one. You can take a look yourself here: Window Anti-Debug Reference. One of the tricks really attracted my focus and it was soemthing like this:

push ss
pop ss
pushf

What really happens is that you write to SS and the processor has a protection mechanism, so you can safely update rSP immediately as well. Because it could have led to catastrophic results if an interrupt would occur precisely after only SS is updated but rSP wasn’t yet. Therefore the processor locks all interrupts until the end of the next instruction, whatever it is. However, it locks interrupts only once during the next instruction no matter what, and it won’t work if you pop ss and then do it again… This issue means that if you are under a debugger or a tracer, the above code will push onto the stack the real flags of the processor’s current execution context.

Thus doing this:
pop eax
and eax, 0×100
jnz under_debugging

Anding the flags we just popped with 0×100 actually examines the trap flag which if you simply try to pushf and then pop eax, will show that the trap flag is clear and you’re not being debugged, which is a potential lie. So even the trap flag is getting pended or just stalled ’till next instruction and then the debugger engine can’t get to recognize a pushf instruction and fix it. How lovely.

I really agree with some other posts I saw that claim that an anti-debugging trick is just like a zero-day, if you’re the first to use it – you will win and use it well, until it is taken care of and gets known. Although, to be honest, a zero-day is way cooler and another different story, but oh well… Besides anti-debugging can’t really harm, just waste some time for the reverser.

Since I wrote diStorm and read the specs of both Intel and AMD regarding most instructions upside down, I immediately knew about “mov ss” too. Even the docs state about this special behavior. But it never occurred to me to use this trick. Anyway, another way to do the same is:

mov eax, ss
mov ss, eax
pushf

A weird issue was that the mov ss, eax, must really be mov ss, ax. Although all disassemblers will show them all as mov ss, ax (as if it were in 16 bits). In truth you will need a db 0×66 to make this mov to work… You can do also lots of fooling around with this instruction, like mov ss, ax; jmp $-2; and if you single step that, without seeing the next instruction you might get crazy before you realize what’s going on. :)

I even went further and tried to use a priviliged instruction like CLI after the writing to SS in the hope that the processor is executing in a special mode and there might be a weird bug. And guess what? It didn’t work and an exception was raised, of course. Probably otherwise I won’t have written about it here :) . It seems the processors’ logic have a kind of an internal flag to pend interrupts till end of next instruction and that’s all. To find bugs you need to be creative…never harm to try even if it sounds stupid. Maybe with another privileged instruction in different rings and modes (like pmode/realmode/etc) it can lead to something weird, but I doubt it, and I’m too lazy to check it out myself. But imagine you can run a privileged instruction from ring3…now stop.


그런데 GDB 로 직접 테스트를 해보니 확실히 si 명령으로 명령을 하나하나 수행할때는

디버깅하는 경우와 run 하는 경우가 달라서 anti debugging 이 된다고 생각했다.

그러나 혹시나해서 해보니 pop ss 보다 좀 앞에 브레이크포인트를 걸고 pop ss 부분보다

좀 뒤에 또 브레이크 포인트를 건뒤, 해당 부분은 single step 이 아닌 continue 로 넘어가면

이때는 어차피 실제 eflags 레지스터에 TF 가 세트 안되있기때문에 아무 문제가 안된다는

사실을 알았다 -_-;; 그래서 뭐 아래와 같은식으로


push ss

push ss

push ss

pop ss

[jmp, call 등의 명령]

pop ss

[jmp, call 등의 명령]

pop ss

[jmp, call 등의 명령]

...

이런식으로 코드를 구성하면 jmp, call 등에서 single step in 을 할 수 없기때문에
매번 직접 브레이크포인트를 걸어야하므로 디버깅을 귀찮게 하는 정도는 가능하지만 
다른 안티디버깅 방법들에 비해서 별 효과는 없는것 같다.


참고 - http://www.woodmann.com/forum/entry.php?116-POP-SS-and-Debuggers,

http://www.ragestorm.net/blogs/?p=45


'Programming' 카테고리의 다른 글

linux/windows SSL client example  (0) 2013.02.04
QEMU Detection  (0) 2013.01.28
x86 linux idt hooking  (0) 2013.01.24
gcc inline assembly  (0) 2013.01.24
x86 Segment Registers  (1) 2013.01.24