IceCreamBoi23
IceCreamBoi23

Reputation: 419

x86 / x64 Using a relative jump to return from a subroutine

I'm needing to write a bit of assembly that I will be writing into the address space of another process (already running.)

Essentially what I am wanting to do is every time this assembly is invoked, it will compare a value from the stack to a predefined value and then if it matches the pre defined value I want to call a function whose pointer will be hard coded into the assembly and if not, I want the assembly to essentially do nothing, so return.

So far I have the following (just going to post the snippet for x86 to keep things simple)

mov eax, [esp+0x04] ; this is the value from the stack
cmp eax, 0x01 ; this is the predefined value I am comparing to

As stated above, if the value in eax matches the 0x01 in this case, I want it to jump to a function (predefined pointer so can hardcode into the assembly,) else I want the sub routine to return. The problem is I don't know how to do this without the use of a label, which I don't believe I will be able to use as this is going to be executed in the context of another process and so the addresses will not start at 0 (for the assembly I will be calling.)

I've heard that you can do a relative jump but I was having trouble implementing something along those lines.

Could somebody show me how I could achieve this using a relative jump or another method?

Upvotes: 0

Views: 1714

Answers (1)

Peter Cordes
Peter Cordes

Reputation: 364428

You're injecting this into an already-running process, so you definitely have the source and target addresses available while you're copying this in.

x86 conditional branches are available with a 32-bit rel32 displacement, relative to the end of the branch instruction. i.e. if the branch condition is true, they do RIP += rel32 after the usual setting RIP = end of this instruction.

jz rel32 is a good way to make a conditional tailcall to another function, or fall through to a ret instruction.

See https://www.felixcloutier.com/x86/jcc for the opcodes. How does $ work in NASM, exactly? has an example of manually encoding a call rel32, and the resulting machine code.

Also Write a jump command to a x86-64 binary file for another Q&A about branch encoding.

    mov   eax, [esp+0x04]
    cmp   eax, 1

    db 0x0f, 0x84      ; opcode for je rel32
branch_offset: dd 0    ; the rel32 itself

    ; fall-through path
    ret

After you assemble this into machine code, you should write code to modify that dword (aka int32_t) 0 once you know the source and target addresses in the target process. The 0 is just a placeholder.

(je +0 will just go to the next instruction whether ZF is set or not.)

Or if you know the source and target addresses, you can get YASM to do the math for you at assemble time:

    bits 64
    org  0x12345             ; this block of code will start at this address

    cmp  dword [rsp+4], 1
    je   0x123456
    ret

Assembling this into a flat binary gives us:

$ yasm -f bin -l /dev/stdout jz.asm
     1                                 %line 1+1 jz.asm
     2                                 [bits 64]
     3                                 [org 0x12345]
     4                                 
     5 00000000 837C240401              cmp dword [rsp+4], 1
     6 00000005 0F84FD101100            je 0x123456
     7 0000000B C3                      ret
     8                                 
     9 0000000C B854230100              mov eax, $

The ORG directive doesn't seem to work with NASM, only YASM. I don't know why.

The mov instruction is there to see what address the assembler thinks its assembling at. With NASM we get B8[0C000000] instead of the expected 54 23 01 00 as the immediate of the mov instruction (its own address).


If you know the relative displacement ahead of time / as an assemble-time constant (but not either absolute address), that's fine, too.

In NASM syntax, je +0x555555 assembles to 0F 84 55 55 55 00.

But not in YASM: in YASM +0x555555 is just the absolute address 0x555555 as a branch target.


Related:

Upvotes: 1

Related Questions