NationalSecurityAgency / ghidra

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

Dynamic Scripting for the debugger #4233

Closed ghost closed 2 years ago

ghost commented 2 years ago

Why don't we have dbg.readMemory(), dbg.writeMemory() yet? Or when will we get it?

nsadeveloper789 commented 2 years ago

It's there, just not the most obvious thing to access :) . Maybe we could add an interface with a bunch of default methods that makes this easier from a GhidraScript. There are two possible solutions in the meantime:

  1. Get a handle to the recorder. This should work on either patch or master branches, but requires the target to be live.
DebuggerTraceManagerService traceManager =
    state.getTool().getService(DebuggerTraceManagerService.class);
DebuggerModelService modelService = state.getTool().getService(DebuggerModelService.class);

Trace currentTrace = traceManager.getCurrentTrace();
TraceRecorder recorder = modelService.getRecorder(currentTrace);
AddressSpace dynamicSpace = currentTrace.getBaseAddressFactory().getDefaultAddressSpace();

byte data[] = recorder.readMemory(dynamicSpace.getAddress(0x00401234), 16).get();
recorder.writeMemory(dynamicSpace.getAddress(0x00404321),
    new byte[] { 0x11, 0x22, 0x33, 0x44 }).get();
  1. If you're on master and would like to adhere to the user's "edit mode" toggle, then for writing memory, do this instead:
DebuggerStateEditingService editingService =
    state.getTool().getService(DebuggerStateEditingService.class);
StateEditor editor = editingService.createStateEditor(currentTrace);

editor.setVariable(dynamicSpace.getAddress(0x00404321),
    new byte[] { 0x11, 0x22, 0x33, 0x44 }).get();

Note that the addresses given are with respect to the "Dynamic Listing" not the static Listing. To get the user's current dynamic location, use DebuggerListingService.getCurrentLocation(). If you need to convert from static to dynamic, use DebuggerStaticMappingService.getOpenMappedLocation(Trace,ProgramLocation,long). The pattern to get services should be apparent in the examples above.

I'll also note that for "dead traces," you can read and write the recorded memory via currentTrace.getMemoryManager().

ghost commented 2 years ago

For what I want (1) Any binary as live target. (2) Pause. (3) Run a GhidraScript that write the self-erasing/modifying/restoring shellcode at a thread's RIP.

That way I can send() a message on a socket in a Windows running executable, I suppose, without being victim to Checksum verification, ret addr checks etc. If you write to the [ESP] first (the ret slot), the implanted shellcode should beat ret addr checks.. if no ring0 protection.

I'm unfortunately busy with IRL untrained job practice for months. So I won't do it now.

I wasn't expecting there to even be dynamic read/write memory capability yet in 'master'. 👍

I like option 1 "Handle to the recorder" the best.

(Edit) Lol, on second thought forget my Host->guest / vmi question.

Bonus question instead: Writing on dead traces = for pcode emulation?

nsadeveloper789 commented 2 years ago

Generally, yes. To set up pcode emulation, I recommend you write the initial state to a chosen snapshot in a trace. You can start emulating just by clicking the stepper buttons in the Threads window. If you want to patch the emulator's state, the recommended way is to add patch steps to the "emulation schedule." If the target is dead, then editing values in Registers and Watches will add those patch steps for you. The 'master' branch lets you choose the "edit mode" directly, using the toggle next to the "debug" button; It also allows you to patch memory from the listing and bytes windows. (In the latest release, you have to use Watches to modify memory.) You can also enter the emulation schedule manually using the side menu of the Threads window -> Go To Time (master branch or latest release). The syntax of a patch step is a single line of Sleigh.

Scripting an emulator is definitely possible as is, but we're amidst some API improvements and adding documentation.

Kingloko commented 2 years ago

Scripting an emulator is definitely possible as is, but we're amidst some API improvements and adding documentation. This is really awesome stuff! I have two questions: 1) What's the current object I should be looking for if I want to script the "live" emulator? (Specifically, I'm trying to add a "continue" button to the emulator I set up in the UI so I don't have to step one instruction at a time) 2) Can I help with the API improvements? If so how?

nsadeveloper789 commented 2 years ago

re/ 1, it's on our radar to do, but not quite there for the UI. You might have some luck by poking around in the service, though. See DebuggerEmulationService#getCachedEmulator, but heed the warnings. You can also instantiate your own DebuggerTracePcodeEmulator. As part of our API improvements, we're working on example scripts to do that sort of thing.

re/ 2, hopefully we'll have the improvements merged soon. At that point, the most useful thing is probably some feedback.

nsadeveloper789 commented 2 years ago

They're up. Take a look: https://github.com/NationalSecurityAgency/ghidra/tree/master/Ghidra/Debug/Debugger/ghidra_scripts