Search code examples
assemblyx86-64interrupt-handling

Where are program registers stored during an interrupt in x86-64


For a university assignment I'm tasked with overwriting the Divide-By-Zero interrupt handler using assembly code in x86-64, making it so that the divide operation result will be the divided number - 1.

So to my understanding, I need to alter the value of the divided register before returning to the program.

How can I get the program's original register values and alter them? Where are they stored?


Solution

  • Interrupts / exceptions only save CS:RIP, RFLAGS, and the user-space SS:RSP, in the exception frame itself. All other register values are unmodified. x86 doesn't do register bank-switching like some other ISAs.

    Interrupt handlers have to save/restore every register they want to use, to make sure they don't modify the user-space state. You'll need that to get yourself a couple scratch registers (unless you make multiple assumptions and only support one operand-size and instruction length), but the part of the user-space state you want to modify is still in registers.


    Fortunately the dividend is in a fixed location, either AH:AL (aka AX), DX:AX, EDX:EAX, or RDX:RAX depending on the operand-size of the division instruction https://www.felixcloutier.com/x86/idiv or div. (Or if you include 16 / 32-bit compat mode user-space, also possibly just AL for aam imm8)

    So you don't have to decode the addressing mode, just prefixes and the opcode, to decide which parts of RDX and RAX are actually involved.

    But to return with RIP pointing after the divide instruction, you do actually need to work out the instruction length, e.g. 2-byte div ecx vs. div word [rdi + r10*2 + 256] (9 bytes: REX and operand-size prefixes, opcode, modrm+SIB + disp32).

    You do know that the length is <= 15 bytes (including possibly redundant prefixes), otherwise it would have faulted with #UD instead of #DE.