Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Meaning of REX.w prefix before AMD64 jmp (FF25)

While solving a bug I came across a difference between import jump tables of two Win64 DLLs. 64bit version of kernel32.dll uses plain FF25 jmp instruction in its import jump tables. On the other hand 64bit version of advapi32.dll uses 48FF25 which indicates REX.w=1 prefix before the jmp opcode. However, both seem to have 32bit operand specifying a RIP+offset address.

Is there any meaning for REX.w prefix on this specific opcode?

I'm not working with machine code often, so please excuse any factual mistakes.

like image 756
Daniel Balas Avatar asked Apr 22 '16 08:04

Daniel Balas


1 Answers

The REX.W prefix is ignored. In 64-bit mode the FF /4 opcode is always has a 64-bit operand (JMP r/m64), so operand size changing prefixes (REX.W, 66) have no effect.

The reason why this REX.W prefix is present is probably to conform with the Microsoft's x64 calling convention's rules regarding unwinding. The jump import stub is effectively a one instruction function, and since exceptions on Windows are asynchronous, they can happen at any time, it's possible for an exception to be generated while executing this function. Microsoft places a number of restrictions on instructions used at the start and end of functions. In particular the function must end with an epilogue that contains only certain instructions. According Kevin Frei's blog on MSDN if the last instruction is a indirect jump it must use the REX.W prefix:

One other note: if the final jmp isn’t an ip-relative jmp, but an indirect jmp, it must be preceded by the REX prefix, to indicate to the OS unwind routines that the jump is headed outside of the function, otherwise, the OS assumes it’s a jump to a different location inside the same function.

The inconsistency between using REX.W may have come about because this rule described above is not entirely consistent with what Microsoft official documentation requires of a final JMP instruction:

Only a subset of jmp statements are allowable in the epilog. These are exclusively of the class of jmps with ModRM memory references where ModRM mod field value 00. The use of jmps in the epilog with ModRM mod field value 01 or 10 is prohibited.

Note that since this would exclude relative JMP instructions which don't use a ModR/M encoding, the most common kind of JMP to end a function with, so I'm inclined to believe it's the official documentation that's in error here.

Other possible reasons for the inconsistency are the Microsoft's unwinder handles import jump stubs specially or that jump stubs without a REX.W prefix are a bug and would cause the program to be terminated in the very unlikely case when an exception happens to occur while they're being executed.

like image 130
Ross Ridge Avatar answered Sep 22 '22 05:09

Ross Ridge