0

i want to inject an assembler code inside of a program.

Right now im only trying something simple:

[bits 64]
;[org 0x11e5]
global _start

_start:
    jmp 0x1040

It works if i use ORG directive for specify the address where the injected code is being executed.

As this is some kind of execise from my school i have seen other projects doing it without ORG directive, but for some reason (i suppose version, OS, architecture...) if i write jmp 0x1040 when i compile with nasm test.s the hex code generated doesn't specify 0x1040 it specify a relative path from where the code is to 0x1040 (this is the reason it works using ORG directive).

My thought is to perform a direct jump instead of a indirect, i thought the solution was jmp far but it didn't work and i'm not sure if my implementation was correct:

[bits 64]
;[org 0x11e5]
global _start

_start:
    jmp far 0x1040

My main question would be how to perform the jmp without using ORG directive.

EDIT:

After inject this assembly code to address 0x11e5 as new entrypoint:

[bits 64]
global _start

_start:
    mov rax, 0x1040
    jmp rax

output from objdump -d infected_bin

Infected address:

...
    11e5:   b8 40 10 00 00          mov    $0x1040,%eax
    11ea:   ff e0                   jmpq   *%rax
...

Address to jump:

0000000000001040 <_start>:
    1040:   f3 0f 1e fa             endbr64 
    1044:   31 ed                   xor    %ebp,%ebp
    1046:   49 89 d1                mov    %rdx,%r9
    1049:   5e                      pop    %rsi
...
  • 1
    You don't want a far jmp; that would also require hard-coding a CS segment selector. (You *could* just use whatever the OS uses for 64-bit user-space code segments, which will be the same for every process on the system.) But it's slow. If you can use a register or the stack, much better to just put an absolute address in a register if you want to make machine code that can jump to a given absolute address without depending on where it runs from. x86 has no absolute direct near jump, and far jmp is slow. – Peter Cordes Jan 25 '21 at 05:48
  • Im not concern, right now, with speed and optimization, im more exploring the exercise. From what you say i understand that with a far jmp i could achieve it, is my implementation from a far jmp correct? – Jaume Garcia Sanchez Jan 25 '21 at 06:02
  • 1
    No, it's missing a segment specifier to go with the offset, that's why it doesn't assemble. Also, 64-bit mode doesn't have direct jmp far. For small RIP values like this it might be possible to use 16-bit operand-size. But as the linked duplicates show, it's much easier to just put the destination address in a register and jmp reg. – Peter Cordes Jan 25 '21 at 06:05
  • Also note that `jmp 0x1040` isn't *indirect*, it's relative (direct near), i.e. `jmp rel32` that does RIP += rel32 when it executes. The assembler calculates the right rel32 to reach the target address from the current location (which it knows based on the `org` setting). – Peter Cordes Jan 25 '21 at 06:06
  • Well without a direct jmp the only thing i can do is use ORG directive. Thank you for the help. – Jaume Garcia Sanchez Jan 25 '21 at 06:13
  • Yes, correct, if you want to use `jmp 0x1040` you need a correct ORG, that was my whole point. But you can easily use an absolute indirect near jump like `jmp rax`. – Peter Cordes Jan 25 '21 at 06:23
  • i tried already `mov rax 0x1040 \ jmp rax` but worked exactly as `jmp 0x1040`. Should it work? – Jaume Garcia Sanchez Jan 25 '21 at 06:42
  • Also, i was thinking.. if i would want automatize a bit the process, like some kind of generic program for insert assembly code (like in a packer i think) i would have the assembler code compiled already and i would modify the parameters directly in the hexcode meaning that i could not change `ORG` directive. In this case the solution would be instead of replace with the address replace with the relative address which i must calcul? – Jaume Garcia Sanchez Jan 25 '21 at 06:52
  • Yes, `mov eax, 0x1040` / `jmp rax` will always set RIP=0x1040, which is exactly what you said you want. Of course, it destroys the contents of RAX; I don't know if that's important for your injection use-case. Pick a different register, perhaps R11, if you want. – Peter Cordes Jan 25 '21 at 07:03
  • re: making a template where you can modify values: yes, to modify a `jmp rel32` encoding, you'd simply do `target - end_of_jmp` and store the 32-bit 2's complement integer into the last 4 bytes of the instruction. Like I got NASM to do for me in manually encoding a `jmp` in [How does $ work in NASM, exactly?](https://stackoverflow.com/q/47494744) – Peter Cordes Jan 25 '21 at 07:08
  • Thank for the explication of the calcul, i forgot totally about 2's complement. Apart from this, im trying to play with this scenario, but im not able to make an absolute indirect near jump working. My assembler code would be `mov eax, 0x1040` / `jmp rax` i compile it with `nasm test.s`, i have tried with different registers, in case the jmp destruction is the culprit, but no luck. Do you have any idea what am i doing wrong? – Jaume Garcia Sanchez Jan 25 '21 at 16:24
  • No. You haven't shown disassembly or a debugger single-stepping the process you injected the code into so I have no way to figure out how you're breaking the correct machine code that will produce. (Note that NASM source files are normally called `.asm`. `.s` files are for GCC / `as`, but NASM doesn't really care about file extension.) – Peter Cordes Jan 25 '21 at 16:31
  • I have added some dissasembly output, i suppose the injector works as using `ORG` directive with a normal jmp works. – Jaume Garcia Sanchez Jan 25 '21 at 19:11
  • Are you injecting into a normal Linux PIE executable? `0x1040` isn't a real address, it's an offset from the "image base" that's randomized every time the process is loaded. If ORG was working, that's because you're injecting into a specific place in memory that's the right *relative* distance. I should have mentioned this earlier, but `0x1040` is not normally mappable at all; [`mmap_min_addr`](https://wiki.debian.org/mmap_min_addr) defaults to 65536 on Linux. – Peter Cordes Jan 25 '21 at 19:25
  • Attach to the process with GDB to see the actual virtual address while it's running. That's the absolute address you'd need to use with `mov rax, imm64`. But using `jmp rel32` nicely avoids that problem by being relative instead of needing the actual randomized absolute address which is different every time. Letting the assembler calculate the relative offset for you with ORG and `jmp 0x1040` works just fine without relocating both source and destination. – Peter Cordes Jan 25 '21 at 19:25

0 Answers0