Can someone explain to me the following behavior on x64 platform:
If I call from my executable to a function in another dll in x64 the disassembled code looks something like this:
000000014000149E FF 15 34 CF 00 00 call qword ptr [__imp_CFuncInDll (14000E3D8h)]
I realize that the debugger calculates the relative address to this absolute address 14000E3C0h. However unlike x86 code if I’ll disassemble the address 14000E3D8h it looks like garbage:
__imp_CFuncInDll:
000000014000E3D8 19 10 sbb dword ptr [rax],edx
000000014000E3DA 25 FC FE 07 00 and eax,7FEFCh
000000014000E3DF 00 14 10 add byte ptr [rax+rdx],dl
000000014000E3E2 25 FC FE 07 00 and eax,7FEFCh
000000014000E3E7 00 00 add byte ptr [rax],al
.......
When I step into the call I can see that instead of getting into the garbage address the code jumps to a valid address:
000007FEFC251019 E9 62 00 00 00 jmp CFuncInDll (7FEFC251080h)
My question:
How the call instruction is decoded on x64 when the target is in another module?
In x86 the call target of this code:
FF 15 34 CF 00 00 call
was: target = next instruction address + 0x0000CF34
While on x64 it looks like this is not the case.
call qword ptr [__imp_CFuncInDll (14000E3D8h)]is an indirect call through a pointer. The pointer’s address is 0x14000E3D8. If you look at the code bytes of your non-sense disassembly, they turn out to contain the following:Which is a little-endian quadword is:
000007fe.fc251019– the address of thejmp CFuncInDllinstruction you get to when you single step.Basically, the call to an import function is being assembled as a call through an entry in a table of addresses to a small ‘thunk’ that jumps to the actual function implementation.