3

Is there a way to access the value in the instruction pointer (RIP) without using a call followed by a pop in assembly language? Or is there a machine code opcode that can do it?

I have been googling with no clear results.

My problem is that I can't have any zeroes in the machine code, or else I get a SIGSEGV error. It's due to the way the server loads the code and executes it from a string of bytes. A near call has zeroes in the distance to the subroutine, so using call is not an option.

I'm on linux, 64-bit, and have nasm and yasm.

phuclv
  • 37,963
  • 15
  • 156
  • 475
Madness
  • 41
  • 1
  • 2
  • I also cannot have any 0xff bytes, so calling a subroutine above won't settle the issue. – Madness Aug 28 '18 at 03:03
  • Looking at the Intel docs for `mov` I see: *The MOV instruction cannot be used to load the CS register. Attempting to do so results in an invalid opcode exception (#UD). To load the CS register, use the far JMP, CALL, or RET instruction.* – David Wohlferd Aug 28 '18 at 04:02
  • 2
    You can use LEA to get the address of RIP. Syntax depends on assembler `lea rax, [rip+0x00]` may work. In NASM you can use `lea rax, [rel $+7]` (which will get RIP relative to the next instruction after the LEA).Unfortunately both will result in 0x00 or 0xff bytes. I'll assume this is a shellcode exploit you are writing? – Michael Petch Aug 28 '18 at 04:09
  • 2
    how about `lea rax, [rip + 0x01020304]; sub rax, 0x01020304`? – phuclv Aug 28 '18 at 04:59
  • @phuclv: yeah that'll work for shellcode, great idea to get *some* known address and then use other instructions to fix it up. You should post that as an answer (including disassembly so we can see the opcode / modrm bytes.) – Peter Cordes Aug 28 '18 at 05:12
  • Basically a duplicate of [Avoiding 0xFF bytes in shellcode using CALL to read RIP?](//stackoverflow.com/q/55778839) where I re-invented @phuclv's idea. (I didn't consciously remember it, but probably having seen it on this question helped me "invent" it again.) My version uses a label so you directly get the address of some nearby data into a register, instead of just the end of a RIP-relative LEA. – Peter Cordes Jun 19 '19 at 23:58

1 Answers1

6

In x86_64 the standard way is to use RIP-relative addressing instead of CALL like in x86. Even then, call/pop is not a recommended way1

Normally you'll use lea rax, [rip] to get RIP into RAX (which is actually encoded as lea rax, [rip + 0] with four bytes for the immediate at the end). However since LEA doesn't dereference the memory address, you can just add any constant displacements to the RIP and subtract it later

0:  48 8d 05 04 03 02 01    lea    rax,[rip+0x1020304]
7:  48 2d 04 03 02 01       sub    rax,0x1020304

You can choose any immediate values that don't have a zero or 0xFF byte. If you want the address of the instruction after lea (which is 7 bytes long) you can fix up accordingly with sub rax, 0x01020304 - 7


1The recommended way is

GetCurrentAddress:
    mov eax, [esp]
    ret
...
    call GetCurrentAddress
    mov [currentInstruction], eax

in order to avoid mismatching between the call stack and the return stack buffer (RSB). But probably it isn't important in shellcode

phuclv
  • 37,963
  • 15
  • 156
  • 475
  • 4
    Turns out `call +0` is a special case, and doesn't break the RSB, and we've been worried over nothing. Henry actually tested it: http://blog.stuffedcow.net/2018/04/ras-microbenchmarks/. `call +0` / `pop` is fine on (nearly) everything. But still use RIP-relative LEA in 64-bit mode, of course. – Peter Cordes Aug 28 '18 at 06:19
  • 4
    RIP-relative addressing is relative to the *end* of the instruction (like relative jump offsets), so your code block already gives you the address of the `sub`. If you want the end of *that*, `sub rax, 0x01020304 - 6`. (You can get the `6` from `label2-label1`, so changing `rax` to any other register will recalculate the offset when the special no-ModR/M opcode isn't usable.) – Peter Cordes Aug 28 '18 at 06:23
  • @PeterCordes Wow! I didn't know that. I have to keep that in mind. – fuz Aug 28 '18 at 07:58