NationalSecurityAgency / ghidra

Ghidra is a software reverse engineering (SRE) framework
https://www.nsa.gov/ghidra
Apache License 2.0
50.55k stars 5.78k forks source link

Emulator discards changed PC register value when stepping #6867

Open zb3 opened 2 weeks ago

zb3 commented 2 weeks ago

Describe the bug I'd like to skip to a specific address, so I edit the PC register (aarch64). After this, the dynamic listing changes its location, and the new PC register value is visible in the threads panel. However, after I press "Step the integrated emulator a single instruction", it steps to the next instruction that'd be executed if I didn't change the PC register - IOW, it ignores my PC register change.

Maybe changing the PC register is not the correct way to make a given thread "jump" to arbitrary location, but then I couldn't find out how to do it..

To Reproduce Steps to reproduce the behavior:

  1. Open any aarch64 program in the emulator
  2. Right click any instruction, press "Emulate program in new trace"
  3. Populate memory, for instance via "load emulator from programs"
  4. Step a single instruction, observe PC now being X
  5. Change the PC register to point to a different location Y
  6. Step a single instruction, observing that instruction at X was executed, not at Y

Expected behavior In the step 6, the instruction at Y should be executed.

Environment (please complete the following information):

zb3 commented 2 weeks ago

Note invalidating emulator cache does not help

nsadeveloper789 commented 2 weeks ago

Okay. I believe it's because the emulator keeps a copy of the counter, rather than reading it from the state every loop. It seems I need to treat patches affecting it as a special case. I think this will be an easy fix. In the meantime, a possible workaround is to use the Go To Time action. (Yes, I agree, that is not intuitive, but hey, it's a workaround....) After Step 5 in your process above, access the action by pressing Ctrl-G or in the menus: Debugger → Go To Time. At the very end of the expression, you should see something like {pc=Y}. Change that to {goto Y}.

Furthermore, if this is a section of code you want to skip every time, consider placing an injection breakpoint. Use K to place a SW_EXECUTE breakpoint at X. Right-click it and choose Set Injection (Emulator). Clear the default and enter goto Y; (mind the semicolon) and press OK. You'll need to invalidate the emulator cache for that to take effect.

zb3 commented 2 weeks ago

@nsadeveloper789 thanks for your help and fast reply :)

I eventually figured out a more invasive way - patching the dynamic listing so that there's an unconditional branch, but I see these injection breakpoints are interesting, I didn't even know they exist.