Controlling registers

When a binary is dynamically compiled, it contains a selection of functions to allow the linking.

This functions contain a selection of gadgets that we can use to populate registers ( in order to create ROP chain for example ).

__libc_csu_init is a main target, cause it contains two useful gadget.

Like a POP star

0x004011a2      5b             pop rbx
0x004011a3      5d             pop rbp
0x004011a4      415c           pop r12
0x004011a6      415d           pop r13
0x004011a8      415e           pop r14
0x004011aa      415f           pop r15
0x004011ac      c3             ret

This gadget allow to pop several useful registers.

Note that, pop r12 pop r13 pop r14 and pop r15 are coded using two bytes, so it's possible to jump a the second byte to make others pop :

  • 0x004011a2 + 3 --> 0x004011a5 5c pop rsp

  • 0x004011a2 + 5 --> 0x004011a5 5c pop rbp

  • 0x004011a2 + 7 --> 0x004011a5 5c pop rsi

  • 0x004011a2 + 9 --> 0x004011a5 5c pop rdi

A simple gadget permit to control 9 registers.

Call me maybe

0x00401188      4c89f2         mov rdx, r14                ; char **ubp_av
0x0040118b      4c89ee         mov rsi, r13                ; int argc
0x0040118e      4489e7         mov edi, r12d               ; func main
0x00401191      41ff14df       call qword [r15 + rbx*8]

This gadget might not look interesting, but it calls r15 + rbx*8, and the first gadget allows to control both r15 and rbx, meaning that the call argument can be controled.

Note it's call qword [r15 + rbx*8], not call qword r15 + rbx*8. This means it'll calculate r15 + rbx*8 then go to that memory address, read it, and call that value.

This means that a memory address containing the desired jump location must be found.

More, this gadget allows to populate RDX ( wich is an important register for parameters ) using the mov rdx, r14 instruction.


Last updated