ghidra
ghidra copied to clipboard
Instruction Patching history
Hi Guys,
Recently I was doing an instruction patching on a binary. I saved a project and then I realized I lost the possibility of 'undo' for my changes. Which could be understandable. However, a view/history of patched instructions would be very welcome. This way, when the project is saved, it would still be possible to see what changes has been made to the binary.
Thanks!
Perhaps my suggestion is not as convenient as what you are suggesting, but you should be able to use the Diff feature to show all patched bytes. You can filter what the Diff displays to reduce the noise as needed.
Yes, that's a good suggestion, thanks. I think it would work perfectly as a workaround. But dedicated view for that would be very appreciated.
Sounds like what the Relocation Table should evolve into, since we have started to use it to track changes outside of what one would consider a classic relocation.
Yeah, this gets a bit dicey, since in the end, the patcher is just modifying the bytes. Bytes can also be modified directly from the hex (bytes) viewer. As @ryanmkurtz points out, importers can also apply fixups, which are byte modifications.... Quickly reverting to or just viewing the original bytes might be useful, but I think keeping a history of all patches is a bit heavy. If you'd like to keep revision history, you might consider using the Ghidra Server, or make copies of your program database.
To clarify: Would a "view / revert to original bytes" action suffice? Or do you have a case where you need to keep a (potentially long) history of changes at one address? I'm not saying we'll actually make such an action, but knowing whether it would fit helps us understand the issue better.
I think "view / revert to original bytes" would be good enough. Take a look at IDA. It has a "Patched bytes" view with a list of address, length, original byte, patched byte.
The patch feature currently is very hard to use in an iterative workflow.
- You patch an instruction and test it.
- You gather further insights and add them as comments, labels etc.
- You do a few rounds of these (goto 1).
- Now you understand where the root cause of the issue is and one single nop will do the trick.
- You want to undo a few patches, but you don't know what you have changed (comments and bookmarks will help) and if you want to use undo, you will also undo all the other useful changes.
My super simple patch improvement feature request:
- A patch is like a bookmark, you keep a list of it. It includes the original instruction.
- You have a patch view (like the bookmark list view).
- You can deactivate a patch (uncheck) or delete it.
- To simplify things: you cannot patch patched code.
An alternative approach: snapshot code.
- Before making new changes, create a snapshot
- Make changes
- Show deltas
- Revert when finished
Is there a way at the moment to know which patches were made to the current project?
This is neither optimized nor tested, but should provide the gist of how you might do it with a script:
public class ListPatchesScript extends GhidraScript {
@Override
protected void run() throws Exception {
Memory memory = currentProgram.getMemory();
AddressSet patches = new AddressSet();
for (MemoryBlock block : memory.getBlocks()) {
for (MemoryBlockSourceInfo info : block.getSourceInfos()) {
Optional<FileBytes> optFileBytes = info.getFileBytes();
if (optFileBytes.isEmpty()) {
continue;
}
FileBytes fileBytes = optFileBytes.get();
// Won't suffice for files larger than 2GiB
byte[] memData = new byte[(int) info.getLength()];
memory.getBytes(info.getMinAddress(), memData);
byte[] fileData = new byte[(int) info.getLength()];
fileBytes.getOriginalBytes(info.getFileBytesOffset(), fileData);
for (int i = 0; i < memData.length; i++) {
if (memData[i] != fileData[i]) {
patches.add(info.getMinAddress().add(i));
}
}
}
}
for (AddressRange patch : patches.getAddressRanges()) {
println("PATCH: " + patch);
AddressSourceInfo aInfo = memory.getAddressSourceInfo(patch.getMinAddress());
MemoryBlockSourceInfo bInfo = aInfo.getMemoryBlockSourceInfo();
// ... Print any additional info you may want, e.g., original/modified bytes in hex
}
}
}
It's possible this will include relocation fixups applied by the loader....
A script is the right way to do it. But you can export the program in the Original File format, normally with, but optionally without, user mods. Then use cmp -l to find the changed bytes.