About RIP relative addressing

 

Something that everyone wonders about is RIP relative addressing on x64 systems.  It's the default addressing mode in 64-bit programs.

RIP relative addressing basicly means that you access memory relative to the RIP register (or relative to EIP if the 32-bit address override operand is used).

All the bugs mentioned in this article regarding ml64.exe are for version 8.00.2207, I don't know about other versions. The latest version I tried is 8.00.50215.44 and that version does not contains the bugs mentioned.

When reading this article I'm assuming you already know about assembler programming, this article isn't for beginners as I'm assuming some knowledge.

NOTE: the author of diStorm64 notified me about a (rather serious) error on this page, I hereby want to thank him :)



How RIP/EIP relative addressing works in 32-bit mode

In 32-bit programs you can't do this :

But you will have to do something like this instead :


How RIP/EIP relative addressing works in 64-bit mode

In 64-bit programs you are allowed to write this :

NOTE: ML64 is stupid and doesn't allow you to write the above code sample!

It's also nice to note that the RIP is actualy pointing to the end of the instruction, so RIP will always point to the same offset regarding of how many (useless) operands you added before the opcode.


About useless operands in 64-bit mode

I hope you know what operands, opcodes etc. are :).

In 64-bit mode the segment operands are ignored and if you encode multiple REX bytes (see the AMD64/EM64T manuals) only the last REX byte is taken into account, so if you write a disassembler or if you are writing a program to emulate/protect/encrypt 64-bit executables, you need to take this behaviour into account.  The maximum size of an instruction taking all operand etc into account is 15 bytes (atleast that's what I read in the AMD64 programmer's manual).


Absolutive addressing in 64-bit mode

Absolute addressing was not supported in older ml64 versions, in the latest version I tried (8.00.50215.44) , it worked correctly! :

You had to write this to obtain the same result :

Due to a bug, older versions of ML64 did not assemble this instruction correctly :


RIP/EIP-relative addressing in ML64

I've got bad news for you, ML64, Microsoft's Macro Assembler for x64 systems, does not give us full control over RIP relative addressing.  We can't use RIP nor EIP as a parameter in an address reference.

Instead, when we access a variable then the linker will convert it to RIP relative addressing automaticly.  This means that if you write two times the same instruction that at the binary level it will not be exactly the same :

NOTE: the actualy binary output will differ from the value of RIP at link time and the location of "test" in memory at link time


RIP/EIP-relative addressing in FASM

I've got good news!  You can use RIP relative addressing with flat assembler.


RIP/EIP-relative addressing in YASM

I've got good news!  You can use RIP relative addressing with YASM.


A test program showing the old technique versus the new technique of obtaing the current value of RIP (EIP)

I wrote the following test program which will check if the next instruction is a "nop", if RIP is obtained correctly than it will point to this "nop" instruction.   I had to hardcode some instructions because my version of ML64 does not support the usage of RIP manually (!) (Zipped source code plus executable) :

In order the compile this program, you need to invoke ml64 like this :

ml64 XXX.asm /link /subsystem:windows /defaultlib:kernel32.lib /defaultlib:user32.lib

(assuming kernel32.lib and user32.lib reside in the same directory as ml64.exe)

and

(where XXX is the name of your assembly file)
 


A test program that modifies the next instruction using RIP-relative addressing

I wrote the following test program which will modify the next instruction (Zipped source code plus executable), this program needs ML64 :

In order the compile this program, you need to invoke ml64 like this :

ml64 XXX.asm /link /subsystem:windows /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:Main

(assuming kernel32.lib and user32.lib reside in the same directory as ml64.exe)

and

(where XXX is the name of your assembly file)
 


Extra: Another bug in ML64

NOTE: this bug no longer exists in newer ML64 versions!

While testing the possibilites of ML64 I found another bug : ML64 allowed you to enter 16-bit addressing instructions but when you execute them, they will actually be executed as their 32-bit variants, for example :

is at the binary level exactly the same as :

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值