GP-1230: Add Taint Analysis prototype and emulator framework support

This commit is contained in:
Dan
2022-08-22 14:15:14 -04:00
parent 4bfd8d1112
commit 51a1933ab3
205 changed files with 11214 additions and 3714 deletions

View File

@@ -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!");
}

View File

@@ -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) {

View File

@@ -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 *"));
/**

View File

@@ -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();
}
}
}