Structured Exceptions Handling is a complex mechanism that makes many anti-debuggers / anti-emulators possible. After setting a handler (check Subtle SEH for exotic ways, but never used in the wild), you trigger the exception. And typically, packers rely blindly on the trigger itself, such as the actual error code: in short, trigger the wrong exception, and execution will fail (tampering is deected).
The most common ones are:
Int3 BREAKPOINT 080000003hBut what about the rest?
mov [0], ... ACCESS_VIOLATION 0c0000005h
I put together common exception triggers. There is no point listing all of them and all possible triggers, just common ones found in packers or malware, or the ones with a non-obvious behavior.
Access violation
This is probably the most common one, as it can happen 'naturally'. Access a wrong address, and it will trigger. Note that would also happen on trying to write a readonly address.
Also, most interrupts, including CD01 Int 1 and CD20 int 20h, will trigger this exception. This is different from F1 IceBP, which is sometimes written Int1, and triggers a Single step exception, and Int 20h used to be for VxdCalls under Windows 9x, so this is not relevant today anymore.
To be exact, all interrupts 00-FFh, except 3, 4, 2A-2E, trigger this exception.
Breakpoint
One of the most common, as it's triggered by CC Int3. It's also triggered by it's double bytes counterpart CD03 Int 3.
It's also triggered by CD2D Int 2Dh, but that one is special: no exception is triggered if a debugger is present, which makes it a stealth anti-debug. It's quite interesting to see that one with your own debugger, the best way to avoid it is to patch it with another Breakpoint trigger like CC. However, a packer using this trick will likely check the bytes that triggered the exception, so pay attention ;)
Last, calling the API kernel32.dll!DebugBreak, does, as expected, execute an Int3. This is just the 'clean' way to trigger a breakpoint exception.
Page guard violation
Similar to access violation, this exception can be triggered by accessing an address with the PAGE_GUARD memory protection. However, this is the technic that OllyDbg itself uses for software memory breakpoint, so OllyDbg will just stop and give a message
Break-on-access when executing [....]instead of offering you to skip the exception as usual
Use Shift+F7/F8/F9 to pass exception to program, which makes things annoying.
Privileged Instruction
That one is quite straightfoward. Typically it's triggered with opcodes such as F4 HLT, FA cli, FB sti. If you're debugging a driver in user mode, operations such as accessing 0F20C0 mov eax,cr0 will trigger it. And the classic anti-vmware in 'VMXh', 'VX' will trigger it, if not in vmware.
Single step
Single step exception occurs AFTER the 'undocumented' F1 IceBP/Int1. The other ways to trigger is using the hardware breakpoints - but that's worth a dedicated blog entry - and setting TF, the trap flag (100h in EFLAGS), via 9d popf or an context change (exception, SetContext). In the case of TF, the exception is triggered after the FOLLOWING instruction is executed, which makes you think nothing happens while stepping.
Invalid Handle
Invalid Handle is triggered when an API is called with an invalid handle, and is usually handled internally by the system. However, OllyDbg fails to skip it - even if you explicitly bypass it - so it makes it an easy anti-ollydbg. Using OllyAdvanced or a similar plugin will help to fix the problem.
This exception is usually triggered by kernel32.dll!CloseHandle, but there are many other possibilities such as advapi32.dll!RegCloseKey
Invalid lock sequence
F0 Lock is a prefix that can only be used on specific opcodes (add/xadd/adc/or/and/sub/sbb/xchg/dec/inc/not/neg (*NOT* mov!), btr/btc/bts (not bt), cmpxchg/cmpxchg8b), and on memory operands only, so using it on even a F090 lock: nop will trigger an exception, or a F000c0 lock: add eax, eax.
it also became famous for crashing Pentium CPUs via f00fc7c8 lock:cmpxchg8b eax.
Integer overflow
Integer overflow is a standard exception that can be triggered on typical arithmetical operations, such as DIV, but also by CD04 int 4 - the only interrupt to do so - and CE into, which triggers on OF, which is the only conditional interrupt.
the File
The file itself implements all these triggers and exceptions. Because of the Int2D/Page Guard/CloseHandle, it will not run easily under a naked OllyDbg. And All interrupts are generated and triggered, so it triggers in total 264 exceptions.
Binary
Let me know if I missed a trigger that is commonly used as an anti-analysis.
déclencheurs d'exceptions
les SEH (Structured Exceptions Handling) sont un mécanisme complexe qui permet beaucoup d'anti-débogueurs/anti-émulateurs. Après avoir défini le handler (voir Subtle SEH pour des façons exotiques mais jamais utilisées en vrai), on peut déclencher l'exception. Et en général, les packeurs utilisent directement les caractéristiques du déclenchement lui-même, tel que son code d'erreur: en raccourci, déclenchez la mauvaise exception, et l'exécution échouera (quelque chose d'anormal a été détecté).
Les plus communs sont :
Int3 BREAKPOINT 080000003hMais qu'en est-il du reste ?
mov [0], ... ACCESS_VIOLATION 0c0000005h
J'ai rassemblé les déclenchements d'exception répandus. Il n'y a pas d'interêt à les énumérer tous, donc juste ceux qu'on trouve communément dans les packeurs et les malwares, ou ceux dont le comportement est inattendu.
Access violation
C'est probablement le plus répandu, puisqu'il peut arriver 'naturellement'. Accédez à une adresse inexistante, et cela déclenchera. Cela se produit aussi si on essaie d'écrire à une adresse en lecture seule.
De même, la plupart des interruptions, y compris CD01 Int 1 et CD20 int 20h, vont déclencher cette exception. C'est différent de F1 IceBP, parfois écrit Int1 et qui déclenche une exception Single Step, et Int 20h était avant utilisée pour les VxdCalls sous Windows 9X, ce qui n'est plus d'actualité.
Pour être exact, toutes les interruptions de 0 à FFh, exceptées 3, 4, 2A-2E, déclenche cette exception.
Breakpoint
Une des plus communes, puisqu'elle est déclenchée par le point d'arrêt logiciel, CC Int3. Elle est aussi déclenchée par son équivalent sur 2 octets, CD03 Int 3.
Elle est aussi déclenchée par l'interruption CD2D Int 2Dh, mais celle-ci est spéciale: aucune exception n'est déclenchée si un débogueur est présent, ce qui en fait un anti-débogueur silencieux. C'est plutôt intéressant à voir sous son propre débogueur, et la meilleure façon de l'éviter est de patcher avec un autre déclencheur de Breakpoint tel que CC. Cependant, un packeur utilisant cette astuce vérifiera les octets originaux dès que possible, donc gardez l'oeil ouvert ;)
Enfin, appeler l'API kernel32.dll!DebugBreak fera, comme on si attend, exécuter une Int3. C'est la façon propre de déclencher une exception de type Breakpoint.
Page guard violation
Un peu comme l'exception 'access violation', cette exception sera déclenchée en accédant à une adresse qui est protégé par l'accès PAGE_GUARD. Par contre, c'est la technique qu'OllyDbg lui-même utilise pour les points d'arrêts mémoire logiciel, donc OllyDbg s'arrêtera tout simplement en donnant le message
Break-on-access when executing [....]plutôt que l'habituel
Use Shift+F7/F8/F9 to pass exception to programce qui complique les choses.
Privileged Instruction
Cette exception est directe: d'habitude, elle est déclenchee par des opcodes tels que F4 HLT, FA cli, FB sti. Si vous déboguez un driver en mode utilisateur, des opérations tels qu'accéder à cr0 (0F20C0 mov eax,cr0) la déclencheront. Et l'anti-vmware classique in 'VMXh', 'VX' la déclenchera - si on n'est pas sous VmWare.
Single step
L'exception Single step se produit APRÈS l'opcode 'non documenté F1 IceBP/Int1. L'autre manière de la déclencher est les points-d'arrêts matériels - mais ça justifie un billet dans ce blog à eux seuls - et lever le drapeau TF, appelé trap flag (100h dans EFLAGS), via 9d popf ou un changement de contexte (exception, SetContext). Dans le cas de TF, l'exception sera déclenchée après l'exécution de l'instruction SUIVANTE, ce qui laisse penser que rien ne se produit lors de l'exécution pas à pas: popf - exécution - exception !
Invalid Handle
Invalid Handle est déclenchée quand une API est appelée avec un handle invalide, et est gérée par le système en interne. Cependant, OllyDbg n'arrive pas à la passer silencieusement - même si on l'a bien précisée dans les options - ce qui en fait un anti-Ollydbg facile. Utiliser OllyAdvanced ou un plug-in similaire pourra résoudre ce problème.
Cette exception est déclenchée d'habitude par kernel32.dll!CloseHandle, mais il y a beaucoup d'autres possibilités telles que advapi32.dll!RegCloseKey
Invalid lock sequence
F0 Lock est un préfixe qui ne peut être utilisé que certains opcodes spécifiques (add/xadd/adc/or/and/sub/sbb/xchg/dec/inc/not/neg (*PAS* mov!), btr/btc/bts (PAS bt), cmpxchg/cmpxchg8b), et sur la mémoire uniquement, donc même un innocent F090 lock: nop va déclencher l'exception, de même qu'un F000c0 lock: add eax, eax.
Il est aussi devenu célèbre pour faire planter les processeurs Pentiums via f00fc7c8 lock:cmpxchg8b eax.
Integer overflow
Integer overflow est une exception pouvant être déclenchée par une opération arithmétique standard telle que DIV, mais aussi par CD04 int 4 - la seule interruption à le faire - et CE into, qui déclenche sur le drapeau OF, qui est la seule interruption conditionnelle.
le fichier
Le fichier implémente tous ces déclencheurs et exceptions. À cause des Int2D/Page Guard/CloseHandle, il ne tournera pas directement sous un OllyDbg nu. Et, comme toutes les interruptions sont générées et déclenchées, il déclenchera au total 264 exceptions.
Binaire
N'hésitez pas à me signaler si j'ai oublié une exception ou un déclencheur particulier, utilisé comme anti-analyse.
There is an unexpected behaviour regarding long-form INTO (CD04), just like the long-form INT3 (CD03). Try it and see. :-) (or check my Anti-Unpacker papers).
ReplyDeleteThat's weird , Int 4 (VA 400685 in the binary) is not handled by the system, and if I handle it, I get the right address in the context.
ReplyDeleteDid I miss something ?
Notice the value of EIP when the exception occurs. It's not pointing at the start of the instruction...
ReplyDelete