Search code examples
assemblyrustx86inline-assembly

Inline asm jmp - 'invalid operand for instruction'


I'm doing some code injections, and I find it difficult to transcribe the code from C to Rust.

The situation is as follows, at the relative address 0x40147D we put a jump to the address of the instruction injected by the dll, this was done by inserting the bytes manually.

let rel = target_address - to_hook - 5;

let bytes: [u8; 4] =  transmute(rel.to_be());

buf[0] = 0xE9;

for x in 1..5 {
    buf[x] = bytes[4-x]
}

So we run any code in asm and at the end it should return to 0x401484 which is instruction 0x40147D + 7. In C this works as expected, in Rust it doesn't.

C:

DWORD jmp_back = 0x40147D + 7;

__asm {
    add dword ptr[ebp - 0x0C], 03
    mov eax, [ebp - 0x0C]
    jmp [jmp_back]
}

Rust (I put a label to not crash the program):

let jump_back: u32 = 0x40147D + 7;

unsafe {
    asm!(
        "2:",
        "add dword ptr [ebp-0x0C],01",
        "mov eax,[ebp-0x0C]",
        // "jmp 2b", //back to label 2
        "jmp [{}]", in(reg) jump_back,

        // 'invalid operand for instruction' 
        //"jmp 0x401484" 

    );
 }

What is going unnoticed ?

EDIT

As commented by @prl, removing the square brackets resulted in:

enter image description here

I'm researching to know what is actually inside the eax register. But with this modification the program crashes and closes.

OBS To test, I removed the previous jmp instruction ("jmp 5D7B145D")

EDIT 2

As described Inline Asm, apparently to use values as operands in instructions, Rust loads the values into a register at the beginning of the block.

So maybe that's the problem that my instructions also use the same register.

I'll try later, but I'll probably have to change the register used by Rust.

enter image description here

The ideal is not having to use registers for such an action.

EDIT 3

So far I leave my answer as a solution to this question, but it still has problems.

Rust as the first instruction of the asm block moves the values you want to use into a register, a few points:

  • If the register contains values in it ?
  • Why not use constants in block asm ?

Solution

  • Here's a possible solution that only uses eax:

    asm!(
        "push eax",
        "add dword ptr [ebp-0x0C],01",
        "mov eax,[ebp-0x0C]",
        "ret", in("eax") jump_back,
    );
    

    The push puts the location to jump to onto the stack, and the ret jumps to that location after loading eax, avoiding the need for a separate register to hold the address.