Map and projects (the most frequently updated page of this blog)

2010/03/03

Si c'est ton corps qui bouge, c'est ton coeur qui fait tout

Getting the current EIP
While standard code starts at a fixed address, there are several cases when your code needs to know its current IP:
  • after a vulnerability has been triggered, shellcodes can't know in advance where they are executing exactly
  • packers often allocates a buffer and decompress their next layer of code, which will likely need to locate itself at some point
  • relocating code is a good way to avoid breakpoints: same code, somewhere else

Thus, I'll enumerate ways to get your current EIP, in a file, on which you can test your emulator or debugger.

Call/Pop

Since Calls push the next address on the stack, you just need to grab it with a POP and will get the current address. Since a standard E8 call is encoded on 5 bytes, such a 'next line' call is often written CALL $ + 5.
call $ + 5
after_call:
pop edx
cmp edx, after_call
jnz bad

FPU

the FPU knows the address of the last executed fpu instruction. so, to get the current IP, use any FPU opcode - even FNOP - then store the FPU environment in memory via F(N)STENV:
_fpu:
fnop
fnstenv [fpuenv]
mov edx,[fpuenv.DataPointer]
cmp edx, _fpu
jnz bad

Interrupts

Interrupts 2C and 2E will put into EDX the next address. If you step on it with a debugger, it will probably not work correctly
int 02eh
after_int:
cmp edx, after_int
jnz bad


Exceptions

When an exception is triggered, the context of the trigger will be put on the stack, so it's possible to know the address of the trigger this way:
handler:
mov eax, [esp + 0ch]
cmp dword [eax + 0b8h], address
jnz bad


Most exceptions are triggered before executing an incorrect line:
xor eax, eax
_on_the_instruction:
mov [eax], eax

Some exceptions are triggered AFTER executing an instruction that launched them (on purpose):
db 0f1h ; IceBP
_trigger_after_execution
And then some exceptions are triggered the instruction after, to enable stepping:
push 302h
popf
jmp bad
_after bad


Have fun! If I missed something, drop a comment!

Binary Source


Obtenir l'EIP courant
Alors que du code standard commence d'habitude à une adresse fixée, il y a plusieurs cas où votre code a besoin de savoir son adresse courante:
  • après qu'une vulnérabilité soit exploitée, les shellcodes ne peuvent pas savoir à l'avance où ils s'exécutent exactement
  • les packeurs allouent souvent une mémoire tampon et y décompressent leur couche de code suivante, qui aura besoin de savoir sa propre adresse
  • déplacer du code est une façon facile de contourner les points d'arrêt: même code, mais autre part

Je vais donc énumérer les méthodes existantes dans un fichier qui vous permettra de vérifier le comportement correct de votre émulateur ou débogueur.

Call/Pop

Puisque les instructions de type Calls mettent l'adresse suivante sur la pile, on a juste besoin de la récupérer avec un POP. Et puisque un E8 call standard est encodé sur 5 octets, un tel 'appelle la ligne suivante' est souvent écrit CALL $ + 5.
call $ + 5
after_call:
pop edx
cmp edx, after_call
jnz bad

FPU

Le coprocesseur arithmétique sait à quelle adresse a eu lieu la dernière instruction FPU. Donc, pour obtenir l'adresse courante, utilisez n'importe quel instruction FPU - même FNOP - et ensuite stockez l'environnement FPU en mémoire via F(N)STENV :
_fpu:
fnop
fnstenv [fpuenv]
mov edx,[fpuenv.DataPointer]
cmp edx, _fpu

Interruptions

Les interrupts 2C et 2E mettrons dans EDX l'adresse suivante. Si vous êtes en pas-à-pas avec un débogueur, cela ne marchera probablement pas.
int 02eh
after_int:
cmp edx, after_int
jnz bad


Exceptions

Quand une exception est déclenchée, le contexte lors du déclenchement est stocké dans la pile, donc il est possible de savoir l'adresse de cette façon.
handler:
mov eax, [esp + 0ch]
cmp dword [eax + 0b8h], adresse
jnz bad

La plupart des exceptions sont déclenchées avant l'exécution d'une ligne incorrecte :
xor eax, eax
_on_the_instruction:
mov [eax], eax

Certaines seront déclenchées APRÈS une instruction qui les a appelée (volontairement) :
db 0f1h ; IceBP
_trigger_after_execution
Et enfin, certaines exceptions sont déclenchées après l'instruction SUIVANTE, pour permettre le pas-à-pas logiciel :
push 302h
popf
jmp bad
_after bad

Amusez-vous bien ! Si j'ai oublié quelque chose, laissez-moi un commentaire !

Binaire Source

2 comments:

  1. The int 0x2c/2e behaviour for the EDX register is platform-specific and controllable to some degree. The capability comes from a CPUID check for the sysenter/syscall support in 32-bit mode.

    ReplyDelete
  2. Thanks for the extra details.
    I will create a disclaimer mentioning that most of these tricks are probably XP 32 bits only.

    ReplyDelete