mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-28 17:11:11 -09:00
GP-1230: Add Taint Analysis prototype and emulator framework support
This commit is contained in:
@@ -28,7 +28,7 @@ import java.util.List;
|
||||
|
||||
import ghidra.app.plugin.assembler.Assembler;
|
||||
import ghidra.app.plugin.assembler.Assemblers;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.DebuggerTracePcodeEmulator;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.BytesDebuggerPcodeEmulator;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.ProgramEmulationUtils;
|
||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
@@ -136,7 +136,7 @@ public class DebuggerEmuExampleScript extends GhidraScript {
|
||||
* library. This emulator will still know how to integrate with the UI, reading through to
|
||||
* open programs and writing state back into the trace.
|
||||
*/
|
||||
DebuggerTracePcodeEmulator emulator = new DebuggerTracePcodeEmulator(tool, trace, 0, null) {
|
||||
BytesDebuggerPcodeEmulator emulator = new BytesDebuggerPcodeEmulator(tool, trace, 0, null) {
|
||||
@Override
|
||||
protected PcodeUseropLibrary<byte[]> createUseropLibrary() {
|
||||
return new DemoPcodeUseropLibrary(language, DebuggerEmuExampleScript.this);
|
||||
@@ -169,7 +169,7 @@ public class DebuggerEmuExampleScript extends GhidraScript {
|
||||
thread.stepInstruction();
|
||||
snapshot =
|
||||
time.createSnapshot("Stepped to " + thread.getCounter());
|
||||
emulator.writeDown(trace, snapshot.getKey(), 0, false);
|
||||
emulator.writeDown(trace, snapshot.getKey(), 0);
|
||||
}
|
||||
printerr("We should not have completed 10 steps!");
|
||||
}
|
||||
|
||||
@@ -29,16 +29,17 @@ import ghidra.program.model.pcode.Varnode;
|
||||
* A userop library for the emulator
|
||||
*
|
||||
* <p>
|
||||
* If you do not have need of a custom userop library, use {@link PcodeUseropLibrary#NIL}. These
|
||||
* libraries allow you to implement userop, including those declared by the language. Without these,
|
||||
* the emulator must interrupt whenever a userop ({@code CALLOTHER}) is encountered. You can also
|
||||
* define new userops, which can be invoked from Sleigh code injected into the emulator.
|
||||
* If you do not need a custom userop library, use {@link PcodeUseropLibrary#NIL}. These libraries
|
||||
* allow you to implement userops, including those declared by the language. Without these, the
|
||||
* emulator must interrupt whenever a userop ({@code CALLOTHER}) is encountered. You can also define
|
||||
* new userops, which can be invoked from Sleigh code injected into the emulator.
|
||||
*
|
||||
* <p>
|
||||
* These libraries can have both Java-callback and p-code implementations of userops. If only using
|
||||
* p-code implementations, the library can be parameterized with type {@code <T>} and just pass that
|
||||
* over to {@link AnnotatedPcodeUseropLibrary}. Because this will demo a Java callback that assumes
|
||||
* concrete bytes, we will fix the library's type to {@code byte[]}.
|
||||
* concrete bytes, we will fix the library's type to {@code byte[]}. With careful use of the
|
||||
* {@link PcodeArithmetic}, you can keep the type an abstract {@code <T>} with Java callbacks.
|
||||
*
|
||||
* <p>
|
||||
* Methods in this class (not including those in its nested classes) are implemented as Java
|
||||
@@ -74,8 +75,7 @@ public class DemoPcodeUseropLibrary extends AnnotatedPcodeUseropLibrary<byte[]>
|
||||
* @return the length of the string in bytes
|
||||
*/
|
||||
@PcodeUserop
|
||||
public byte[] print_utf8(@OpState PcodeExecutorStatePiece<byte[], byte[]> state,
|
||||
byte[] start) {
|
||||
public byte[] print_utf8(@OpState PcodeExecutorState<byte[]> state, byte[] start) {
|
||||
long offset = Utils.bytesToLong(start, start.length, language.isBigEndian());
|
||||
long end = offset;
|
||||
while (state.getVar(space, end, 1, true)[0] != 0) {
|
||||
|
||||
@@ -23,6 +23,7 @@ import ghidra.pcode.emu.linux.EmuLinuxX86SyscallUseropLibrary;
|
||||
import ghidra.pcode.emu.sys.AnnotatedEmuSyscallUseropLibrary;
|
||||
import ghidra.pcode.emu.sys.EmuSyscallLibrary;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.PcodeArithmetic.Purpose;
|
||||
import ghidra.pcode.struct.StructuredSleigh;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
@@ -41,7 +42,8 @@ import ghidra.program.model.listing.Program;
|
||||
* call libraries typically implement that interface by annotating p-code userops with
|
||||
* {@link EmuSyscall}. This allows system calls to be implemented via Java callback or Structured
|
||||
* Sleigh. Conventionally, the Java method names of system calls should be
|
||||
* <em>platform</em>_<em>name</em>. This is to prevent name-space pollution of userops.
|
||||
* <em>platform</em>_<em>name</em>. This is to prevent name conflicts among userops when several
|
||||
* libraries are composed.
|
||||
*
|
||||
* <p>
|
||||
* Stock implementations for a limited set of Linux system calls are provided for x86 and amd64 in
|
||||
@@ -53,7 +55,7 @@ import ghidra.program.model.listing.Program;
|
||||
*
|
||||
* <p>
|
||||
* For demonstration, this will implement one from scratch for no particular operating system, but
|
||||
* it will borrow many conventions from linux-amd64.
|
||||
* it will borrow many conventions from Linux-amd64.
|
||||
*/
|
||||
public class DemoSyscallLibrary extends AnnotatedEmuSyscallUseropLibrary<byte[]> {
|
||||
private final static Charset UTF8 = Charset.forName("utf8");
|
||||
@@ -80,11 +82,11 @@ public class DemoSyscallLibrary extends AnnotatedEmuSyscallUseropLibrary<byte[]>
|
||||
|
||||
/**
|
||||
* Because the system call numbering is derived from the "syscall" overlay on OTHER space, a
|
||||
* program is required. The system call analyzer must be applied to it. The program and its
|
||||
* compiler spec are also used to derive (what it can of) the system call ABI. Notably, it
|
||||
* applies the calling convention of the functions placed in syscall overlay. Those parts which
|
||||
* cannot (yet) be derived from the program are instead implemented as abstract methods of this
|
||||
* class, e.g., {@link #readSyscallNumber(PcodeExecutorStatePiece)} and
|
||||
* program is required. Use the system call analyzer on your program to populate this space. The
|
||||
* program and its compiler spec are also used to derive (what it can of) the system call ABI.
|
||||
* Notably, it applies the calling convention of the functions placed in syscall overlay. Those
|
||||
* parts which cannot (yet) be derived from the program are instead implemented as abstract
|
||||
* methods of this class, e.g., {@link #readSyscallNumber(PcodeExecutorStatePiece)} and
|
||||
* {@link #handleError(PcodeExecutor, PcodeExecutionException)}.
|
||||
*
|
||||
* @param machine the emulator
|
||||
@@ -151,7 +153,7 @@ public class DemoSyscallLibrary extends AnnotatedEmuSyscallUseropLibrary<byte[]>
|
||||
* <p>
|
||||
* The {@link EmuSyscall} annotation allows us to specify the system call name, because the
|
||||
* userop name should be prefixed with the platform name, to avoid naming collisions among
|
||||
* userops.
|
||||
* composed libraries.
|
||||
*
|
||||
* <p>
|
||||
* For demonstration, we will export this as a system call, though that is not required for
|
||||
@@ -173,8 +175,8 @@ public class DemoSyscallLibrary extends AnnotatedEmuSyscallUseropLibrary<byte[]>
|
||||
* copy of the arithmetic as a field at library construction time.
|
||||
*/
|
||||
PcodeArithmetic<byte[]> arithmetic = machine.getArithmetic();
|
||||
long strLong = arithmetic.toConcrete(str).longValue();
|
||||
long endLong = arithmetic.toConcrete(end).longValue();
|
||||
long strLong = arithmetic.toLong(str, Purpose.LOAD);
|
||||
long endLong = arithmetic.toLong(end, Purpose.OTHER);
|
||||
|
||||
byte[] stringBytes =
|
||||
machine.getSharedState().getVar(space, strLong, (int) (endLong - strLong), true);
|
||||
@@ -185,12 +187,17 @@ public class DemoSyscallLibrary extends AnnotatedEmuSyscallUseropLibrary<byte[]>
|
||||
// Second, a Structured Sleigh example
|
||||
|
||||
/**
|
||||
* The nested class for syscall implemented using StructuredSleigh. Note that no matter the
|
||||
* implementation type, the Java method is annotated with {@link EmuSyscall}. We declare it
|
||||
* public so that the annotation processor can access the methods. Alternatively, we could
|
||||
* override {@link #getMethodLookup()}.
|
||||
* The nested class for syscalls implemented using Structured Sleigh. Note that no matter the
|
||||
* implementation type, the Java method is annotated with {@link EmuSyscall}. We declare the
|
||||
* class public so that the annotation processor can access the methods. Alternatively, we could
|
||||
* override {@link #getMethodLookup()} to provide the processor private access.
|
||||
*/
|
||||
public class DemoStructuredPart extends StructuredPart {
|
||||
/**
|
||||
* This creates a handle to the "demo_write" p-code userop for use in Structured Sleigh.
|
||||
* Otherwise, there's no way to refer to the userop. Think of it like a "forward" or
|
||||
* "external" declaration.
|
||||
*/
|
||||
UseropDecl write = userop(type("void"), "demo_write", types("char *", "char *"));
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
//@menupath
|
||||
//@toolbar
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
@@ -88,7 +86,7 @@ public class StandAloneEmuExampleScript extends GhidraScript {
|
||||
*/
|
||||
Address entry = dyn.getAddress(0x00400000);
|
||||
Assembler asm = Assemblers.getAssembler(language);
|
||||
CodeBuffer buffer = new CodeBuffer(asm, entry);
|
||||
AssemblyBuffer buffer = new AssemblyBuffer(asm, entry);
|
||||
buffer.assemble("MOV RCX, 0xdeadbeef");
|
||||
Address injectHere = buffer.getNext();
|
||||
buffer.assemble("MOV RAX, 1");
|
||||
@@ -150,30 +148,4 @@ public class StandAloneEmuExampleScript extends GhidraScript {
|
||||
.evaluate(thread.getExecutor()),
|
||||
8, language.isBigEndian()));
|
||||
}
|
||||
|
||||
public static class CodeBuffer {
|
||||
private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
private final Assembler asm;
|
||||
private final Address entry;
|
||||
|
||||
public CodeBuffer(Assembler asm, Address entry) {
|
||||
this.asm = asm;
|
||||
this.entry = entry;
|
||||
}
|
||||
|
||||
public Address getNext() {
|
||||
return entry.add(baos.size());
|
||||
}
|
||||
|
||||
public byte[] assemble(String line)
|
||||
throws AssemblySyntaxException, AssemblySemanticException, IOException {
|
||||
byte[] bytes = asm.assembleLine(getNext(), line);
|
||||
baos.write(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user