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 push
ed 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:
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:
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):
5A
48
83
C2
08
52
C3
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:
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.