3

I try to reverse engineering an application and I came to the point that I don't understand. I have the following disassembled code with gdb:

   │0x7ffff76f7e4b <_ZN16CRRegistratorImp8RegisterEbPv+587> je     0x7ffff76f7ce6 <_ZN16CRRegistratorImp8RegisterEbPv+230>                                                              │
   │0x7ffff76f7e51 <_ZN16CRRegistratorImp8RegisterEbPv+593> mov    rdi,QWORD PTR [rbp+0x10]                                                                                             │
   │0x7ffff76f7e55 <_ZN16CRRegistratorImp8RegisterEbPv+597> mov    rax,QWORD PTR [rdi]                                                                                                  │
   │0x7ffff76f7e58 <_ZN16CRRegistratorImp8RegisterEbPv+600> call   QWORD PTR [rax+0x30]                                                                                                 │
   │0x7ffff76f7e5b <_ZN16CRRegistratorImp8RegisterEbPv+603> test   al,al                                                                                                                │
   │0x7ffff76f7e5d <_ZN16CRRegistratorImp8RegisterEbPv+605> je     0x7ffff76f7ce6 <_ZN16CRRegistratorImp8RegisterEbPv+230>                                                              │
   │0x7ffff76f7e63 <_ZN16CRRegistratorImp8RegisterEbPv+611> jmp    0x7ffff76f7d29 <_ZN16CRRegistratorImp8RegisterEbPv+297>      
   │0x7ffff76f7e68 <_ZN16CRRegistratorImp8RegisterEbPv+616> xor    edx,edx                                                                                                              │
   │0x7ffff76f7e6a <_ZN16CRRegistratorImp8RegisterEbPv+618> mov    rsi,r12                                                                                                              │
   │0x7ffff76f7e6d <_ZN16CRRegistratorImp8RegisterEbPv+621> mov    rdi,rbp                                                                                                              │
   │0x7ffff76f7e70 <_ZN16CRRegistratorImp8RegisterEbPv+624> call   0x7ffff7596518 <_Z18CallRegGuiCallbackP13CRRegistratorPv13ERegGUIAction@plt>                                         │
   │0x7ffff76f7e75 <_ZN16CRRegistratorImp8RegisterEbPv+629> jmp    0x7ffff76f7e41 <_ZN16CRRegistratorImp8RegisterEbPv+577>                                                              │
   │0x7ffff76f7e77 <_ZN16CRRegistratorImp8RegisterEbPv+631> mov    edx,0x4                                                                                                              │
   │0x7ffff76f7e7c <_ZN16CRRegistratorImp8RegisterEbPv+636> mov    rsi,r12                                                                                                              │
   │0x7ffff76f7e7f <_ZN16CRRegistratorImp8RegisterEbPv+639> mov    rdi,rbp                                                                                                              │
   │0x7ffff76f7e82 <_ZN16CRRegistratorImp8RegisterEbPv+642> call   0x7ffff7596518 <_Z18CallRegGuiCallbackP13CRRegistratorPv13ERegGUIAction@plt>    

This is not the whole procedure, but I think it is not needed. What I want to know is, how to get to to the address 0x7ffff76f7e68 (+616). I was thinking that somewhere in this procedure I will find something like this instruction:

jmp 0x7ffff76f7e68 <_ZN16CRRegistratorImp8RegisterEbPv+616>

but there is no such instruction in this procedure and it is not possible to get it there because on address +611 there is the the jmp instruction. So I have the following questions:

  1. Is it dead code?
  2. Is it possible to jump directly to this specific address (+616) from other procedure?

  3. Is there another way to get to this address?

4

There are several possibilities. At least it doesn't look like junk, so probably the disassembler engine built into GDB is right about the opcodes.

GDB is somewhat limited when it comes to showing those details that count when reverse engineering a bigger target. This could actually be dead code, since the names indicate that this is C++ code. Hence there's always a chance that certain virtual functions are never referenced and yet remain in the binary. Essentially there are corner cases that would lead to dead code. But it's hard to tell from this small window into the target that you provide and without more knowledge about the target in question.

First I would start by demangling the names, since you seem to have debug symbols for the application:

CRRegistratorImp::Register(bool, void*)
CallRegGuiCallback(CRRegistrator*, void*, ERegGUIAction)

As per this list you can see that the Linux ABI (System V AMD64 ABI) makes use of the following registers (in order) on x86-64: RDI, RSI, RDX, RCX, R8, R9, XMM0–7.

From this knowledge I'd deduce that these could be two very small wrapper functions to do a similar job:

; first function
xor    edx,edx
mov    rsi,r12
mov    rdi,rbp
call   0x7ffff7596518 <_Z18CallRegGuiCallbackP13CRRegistratorPv13ERegGUIAction@plt>
jmp    0x7ffff76f7e41 <_ZN16CRRegistratorImp8RegisterEbPv+577>
; second function below
mov    edx,0x4
mov    rsi,r12
mov    rdi,rbp
call   0x7ffff7596518 <_Z18CallRegGuiCallbackP13CRRegistratorPv13ERegGUIAction@plt>

Roughly (respectively:

CallRegGuiCallback($RDI, $RSI, 0);
CallRegGuiCallback($RDI, $RSI, 0x4);

Without a proper disassembler you won't be able to tell if that code is dead (== unreferenced). GDB is just too crude a tool for this job. And even with a proper disassembler you will not be a 100% sure that it is dead code even though the disassembler "reasoned" it is.

That said, give radare2 (free of charge, open source), Hopper (commercial, but affordable) or IDA Pro (commercial, but relatively expensive, yet very very powerful) a try. These should give you a considerably better idea of what parts of the code are referenced by other parts of the code.

To answer your questions:

  1. Is it dead code?

    Possible, but there's no way to tell for certain (i.e. to rule out false negatives!).

  2. Is it possible to jump directly to this specific address (+616) from other procedure?

    Certainly, a jmp may actually even be sufficient, semantically, because these small functions seem to pass the parameters to the call themselves.

  3. Is there another way to get to this address?

    Yeah, from the top of my head I could come up with about half a dozen or so, and there are probably more sneaky ones. However, that (sub-)question is somewhat open-ended. Anyway, you could jmp or use any kind of conditional jump. You could call or you could load the address into a register and do an indirect call or you could obfuscate the address, load it into a register and then do whatever kind of bit-juggling and arithmetic and an indirect call, or you could have a vtable that would end up calling this particular chunk of code.

A bigger chunk of disassembly might help in this case.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.