37

While reversing a 32bit Mach-O binary with Hopper, I noticed this peculiar method. The instruction on 0x0000e506 seems to be calling an address right below the instruction.

What would be the reason for this? Is it some kind of register cleaning trickery?

Disassembly listing containing an instruction call 0xe50b at address 0xe506, immediately followed by pop eax at address 0xe50b

5 Answers 5

47

This is for position independent code. The call 0xe50b instruction pushes the address of the next instruction, and then jumps. It jumps to the immediately following instruction, which has no effect. The next instruction, pop eax, loads its own address into eax (as it was the value pushed by call).

Further down it uses an offset from eax:

mov eax, dword [ds:eax-0xe50b+objc_msg_close]

The value being subtracted, 0xe50b, is the address that we moved into eax. If the code hasn't been moved anywhere, eax-0xe50b will be zero, but if the code has been moved to a different location, it will be the offset. We then add the address objc_msg_close, so we'll be able to reference it, even if the code has been moved in memory.

Hopper is actually being quite clever about it, because the instruction just says (from ndisasm):

mov eax,[eax+0x45fe75]

but Hopper knows that eax contains the value of the instruction pointer at 0xe50b, so uses that offset to find the symbol for you.

17

This is a frequently used "trick" to determine the address of the instruction following the call, i.e. the call instruction pushes the return address on the stack, which in this case corresponds to 0xe50b. After the pop instruction, eax contains that address. For instance, this idiom is used for position independent code (pic), but is also quite commonly seen in obfuscated code.

Other disassemblers often display this code sequence as call $+5 (e.g. IDA).

0
14

Now I cannot possibly know what the exact reason is here, but there is another very good reason, not mentioned so far, for using this kind of method: throwing off a disassembler during static analysis.

The mechanics of call $+5 have been discussed, so I'll assume they are known by now - otherwise refer to the other answers. Basically like with any call on IA-32, the return address (the address of the instruction following the call) gets pushed to the stack and the ret instruction inside that called function will presumably return to that address, assuming the stack hasn't been smashed meanwhile.

Fooling static analysis tools

What will even a sophisticated disassembler such as IDA do when it sees a ret opcode? Well, it'll assume that the function boundary has been reached. Here's an example:

IDA trips over this trick

Now this not being the first time I've seen such a thing, I went on and deleted the function, so IDA stops assuming it's a function boundary. If I then tell it to disassemble the very next byte (0Fh) I get this:

IDA trips over this trick #2

What the disassembler cannot realize and what is the reason why interactive disassemblers like Hopper and IDA rock so much, is that something special is going on here. Let's look at the instructions:

51                                      push    rcx
53                                      push    rbx
52                                      push    rdx
E8 00 00 00 00                          call    $+5
5A                                      pop     rdx
48 83 C2 08                             add     rdx, 8
52                                      push    rdx
C3                                      retn
0F 5A 5B 59                             cvtps2pd xmm3, qword ptr [rbx+59h]
89 DF                                   mov     edi, ebx
52                                      push    rdx
48 31 D2                                xor     rdx, rdx

The leading bytes are the actual bytes in the binary, followed by their mnemonic representation. But pay special attention to this part:

call    $+5
pop     rdx ; <- = ADDR
add     rdx, 8
push    rdx
retn

We get the address ADDR in rdx after the pop instruction was executed. We know this much from the description of the mechanism in the other answers. But then it gets odd:

add     rdx, 8

we add ... uhm eight bytes to that address (ADDR+8) and then we push it to the stack and call ret:

push    rdx
retn

If you remember how a call works then you'll remember that it pushes the return address to the stack, then passes execution to the called function and that function later calls ret in order to return to the address found on the stack. This knowledge is being exploited here. It manipulates the "return address" before "returning" to it. But looking back at our disassembly we find to our surprise (or not ;)):

E8 00 00 00 00                          call    $+5
5A                                      pop     rdx
48 83 C2 08                             add     rdx, 8
52                                      push    rdx
C3                                      retn
0F 5A 5B 59                             cvtps2pd xmm3, qword ptr [rbx+59h]

Let's count the opcode bytes (in your tool you can also do the math via the offsets, if you're so inclined):

  1. 5A
  2. 48
  3. 83
  4. C2
  5. 08
  6. 52
  7. C3
  8. 0F

But wait a minute, that means we're literally passing execution to the middle of this peculiar cvtps2pd xmm3, qword ptr [rbx+59h]? That's right. Because 0Fh is one of the prefixes used when encoding instructions on IA-32. So the programmer has tricked our disassembler, but he won't trick us. Undefining that code and then skipping the 0Fh prefix we get:

51                                      push    rcx
53                                      push    rbx
52                                      push    rdx
E8 00 00 00 00                          call    $+5
5A                                      pop     rdx
48 83 C2 08                             add     rdx, 8
52                                      push    rdx
C3                                      retn
0F                                      db  0Fh
5A                                      pop     rdx
5B                                      pop     rbx
59                                      pop     rcx
89 DF                                   mov     edi, ebx
52                                      push    rdx
48 31 D2                                xor     rdx, rdx

or:

No longer tricked thanks to reverse engineer intervening

The apparent single four-byte instruction 0F 5A 5B 59 is now revealed to be bogus and instead we have to ignore the 0F and then resume at 5A, which decodes as pop rdx.

Check out Ange's excellent opcode tables here to find out more about how instructions get encoded on IA-32.

1
  • 4
    I have seen some applications (specifically, an anti-hacking protection known as MetaFortress) which use this technique as a way to embed data into the .text area of an application. Use the call to jump over your embedded data, and then use the return address from the call as the pointer to the embedded data.
    – ajs410
    Commented Dec 12, 2013 at 0:34
11

A CALL instruction has the effect of pushing a return address onto the stack, before performing the control transfer to the call target.

In your example above, the CALL instruction will push the value 0x0000E50B onto the stack, before transferring control to 0x0000E50B. The POP instruction at 0x0000E50B will then pop the last value off of the top of the stack, into EAX. This value will be the POP instructions own address, due to the CALL instruction pushing the return value.

This is a simple technique to get an instructions location in memory at run time.

An instructions location can't always be computed by the linker at compile time as a binary may be relocated in memory due to Address Space Layout Randomization (ASLR).

1
  • The answer from Dougall is superior. Linkers handle ASLR via entries in relocation/fixup tables. This mechanism isn't so much to determine the location as it is to determine the relative offset difference between the address the compiled code is expecting and the actual address at runtime.
    – dyasta
    Commented Apr 8, 2013 at 21:21
6

As others have said, this is for getting current instruction's address. But it's not recommended as it'll hurt performance because it won't return anywhere, causing disagreement of return addresses in data stack and in the CPU's internal calling stack

The recommended way is

GetCurrentAddress:
    mov eax, [esp]
    ret
...
    call GetCurrentAddress
    mov [currentInstruction], eax

The reason is the "hidden variables" inside the processor. All modern processors contain much more state than you can see from the instruction sequence. There are TLBs, L1 and L2 caches, all sorts of stuff that you can't see. The hidden variable that is important here is the return address predictor.

The more recent Pentium (and I believe also Athlon) processors maintain an internal stack that is updated by each CALL and RET instruction. When a CALL is executed, the return address is pushed both onto the real stack (the one that the ESP register points to) as well as to the internal return address predictor stack; a RET instruction pops the top address of the return address predictor stack as well as the real stack.

The return address predictor stack is used when the processor decodes a RET instruction. It looks at the top of the return address predictor stack and says, "I bet that RET instruction is going to return to that address." It then speculatively executes the instructions at that address. Since programs rarely fiddle with return addresses on the stack, these predictions tend to be highly accurate.

https://devblogs.microsoft.com/oldnewthing/20041216-00/?p=36973

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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