Assemble far calls or far jumps (j* instructions)

2

I'm trying to create a dispatch table which changes the location of some instruction in another address which is allocated by AllocateMemoryOnRemoteProcess.

One of the problems that I encountered was almost all of Calls and all kind of Jumps are near and relative and as long as I load the assemblies in new location, then these instructions won't work.

As I know I should convert these instructions to far jump or far call one of the solutions that I saw during my googling was using push and ret like :

push 0xdeadbeef
ret

or someone suggests using registers for absolute addressing like :

mov %eax,0xdeadbeef
jmp %eax

These solutions won't work in my case because as long as I'm in a function routine, changing the stack state or in the second case changing a register like %eax causes failure.

Someone in this question wrote :

  • call far (with opcode 9A) jumps to an absolute segment and offset. ie, it's like setting CS and ?IP at once.

So it seems I should use opcode with 9A for far calls, but this just works for the calls and I have no idea about converting all kinds of Jumps with this method!

I regularly use objdump to disassemble a binary, then use clang as the assembler by using the following command :

clang -c MyAsm.asm -m32

But when I assemble with the above command then the result is relative.

For example when MyAsm.asm is :

call   0x402af2

The result of objdump is :

    MyAsm.o:    file format Mach-O 32-bit i386

Disassembly of section __TEXT,__text:
__text:
       0:   e8 ed 2a 40 00  calll   4205293 <__text+0x402AF2>

These results are relative.

So my questions are :

  1. How can I assemble far calls or far jumps (j* instructions) with clang or any other tools (which of course, work for both 80x86 and Amd64 structures)?
  2. Is there any other instruction like calls or jumps that use relative addressing, so I should reassemble in order to avoid the problem?
assembly
x86
clang
x86-64
objdump

1 Answer

4

If you can spare a register, I advise you to use

    movabs $addr,%rax
    jmp *%rax

or, if you can ensure that the address is within the first 2 GB of address space,

    mov $addr,%eax
    jmp *%eax

I strongly advise you against using

    push $addr
    ret

as this trashes the return prediction, making the next few function returns slower than necessary. Far jumps and calls (ljmp and lcall) are a red herring. While they could technically be used, they won't help you achieve your goal and are actually meant for a different purpose (changing cs) and are implemented as slow, micro-coded instructions on modern processors.

If you cannot spare a register, you can use this sort of trick instead:

    jmp *0f(%rip)
0:  .quad addr

This should just work and in addition doesn't require you to use an extra register. It is slower than using a register though.

Note that conditional jumps strictly require the jump target to be immediate. If you want to do a conditional jump to an absolute address, use an idiom like this:

    # for jz addr
    jnz 1f
    jmp *0f(%rip)
0:  .quad addr
1:
answered on Stack Overflow Jan 29, 2018 by fuz • edited Jan 29, 2018 by fuz

User contributions licensed under CC BY-SA 3.0