Search code examples
assemblyx86visual-studio-debuggingirvine32stack-pointer

How to create a dumpRegisters PROC in assembly?


I'm creating a program that shows the registers called dumpRegisters. The registers need to match what is shown in the Registers window in the debugger (using Visual Studio). The registers in the window of the debugger are: EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP, EIP, EFL. 10 registers total.

I know the Irvine Library already has this procedure, but I'm creating it from scratch.

I'm able to show most of the registers. However, I'm struggling on how to display the ESP (extended stack pointer) register?

I use push and pop throughout the program, so when I call a showRegister procedure, it outputs the ESP at that point, but ESP continues to change, so the when the program exits, the ESP I showed is not the same. I've tried to push and pop esp, however, it still doesn't match depending on where I push and pop esp, sometimes it also only shows the first 4 registers.

How can I get the ESP register to match the registers window in the debugger?

dumpRegisters PROC
    push eax
    push edx
    mov edx, OFFSET essp
    mov eax, esp
    INVOKE showRegister, OFFSET essp, esp
    pop edx
    pop eax
dumpRegisters ENDP
showRegister PROC,
                regName:PTR BYTE , regValue:DWORD

    ;push esp

    call writeString
    call writeHex
    Tab
    
    ;pop esp 

    ret
showRegister ENDP

Solution

  • After printing or saving other incoming args, calculate what ESP must have been before the call dumpRegsiters (typo?) that pushed a 4-byte return address, plus whatever other pushes you did.

    lea eax, [esp+12] should be correct after 2 pushes.

    You should probably start with a pushf to save EFLAGS first, so you can use instructions that modify FLAGS like add or sub. Then of course adjust your offsets accordingly. Unless it turns out that the Irvine32 functions like WriteHex save/restore EFLAGS themselves, then you're probably just juggling incoming data.

    You could even start with pusha and loop through popping and printing, if you don't need to print register names with the values. One of the few use-cases for that instruction, although you still might want to calculate ESP instead of using what it pushed.

    (And I guess get EIP from your return address, if you don't mind having the address after the call. If you want the address before, you have to figure out whether it was a 5-byte call rel32, or a call through a function pointer like 2-byte call eax.)