Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recover and serialize types from high pcode #50

Merged
merged 7 commits into from
Oct 24, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
249 changes: 231 additions & 18 deletions scripts/ghidra/PatchestryDecompileFunctions.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,38 @@

import ghidra.program.model.listing.Program;

import ghidra.program.model.pcode.FunctionPrototype;
import ghidra.program.model.pcode.HighFunction;
import ghidra.program.model.pcode.HighParam;
import ghidra.program.model.pcode.HighVariable;
import ghidra.program.model.pcode.PcodeBlock;
import ghidra.program.model.pcode.PcodeBlockBasic;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.SequenceNumber;
import ghidra.program.model.pcode.Varnode;

import ghidra.program.model.data.AbstractFloatDataType;
import ghidra.program.model.data.AbstractIntegerDataType;
import ghidra.program.model.data.Array;
import ghidra.program.model.data.BooleanDataType;
import ghidra.program.model.data.Composite;
import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeComponent;
import ghidra.program.model.data.Enum;
kumarak marked this conversation as resolved.
Show resolved Hide resolved
import ghidra.program.model.data.FunctionDefinition;
import ghidra.program.model.data.ParameterDefinition;
import ghidra.program.model.data.Pointer;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.TypeDef;
import ghidra.program.model.data.Undefined;
import ghidra.program.model.data.Union;
import ghidra.program.model.data.VoidDataType;

import ghidra.program.model.symbol.ExternalManager;

import ghidra.util.UniversalID;

import com.google.gson.stream.JsonWriter;

import java.io.BufferedWriter;
Expand All @@ -48,13 +70,17 @@
import java.nio.file.Path;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

public class PatchestryDecompileFunctions extends GhidraScript {

static final int decompilation_timeout = 30;

private class PcodeSerializer extends JsonWriter {
private String arch;
Expand All @@ -65,6 +91,8 @@ private class PcodeSerializer extends JsonWriter {
private List<Function> functions;
private int original_functions_size;
private Set<Address> seen_functions;
private Set<String> seen_types;
pgoodman marked this conversation as resolved.
Show resolved Hide resolved
private List<DataType> types_to_serialize;

public PcodeSerializer(java.io.BufferedWriter writer,
String arch_, FunctionManager fm_,
Expand All @@ -80,8 +108,10 @@ public PcodeSerializer(java.io.BufferedWriter writer,
this.functions = functions_;
this.original_functions_size = functions.size();
this.seen_functions = new TreeSet<>();
this.seen_types = new HashSet<>();
pgoodman marked this conversation as resolved.
Show resolved Hide resolved
this.types_to_serialize = new ArrayList<>();
}

private static String label(Address address) throws Exception {
return address.toString(true /* show address space prefix */);
}
Expand All @@ -101,6 +131,28 @@ private static String label(PcodeBlock block) throws Exception {
private static String label(PcodeOp op) throws Exception {
return label(op.getSeqnum());
}

private String label(DataType type) throws Exception {
// In type is null, assign VoidDataType in all cases.
// We assume it as void type.
if (type == null) {
type = VoidDataType.dataType;
}
String name = type.getName();
pgoodman marked this conversation as resolved.
Show resolved Hide resolved
CategoryPath category = type.getCategoryPath();
String concat_type = category.toString() + name + Integer.toString(type.getLength());
String type_id = Integer.toHexString(concat_type.hashCode());

UniversalID uid = type.getUniversalID();
if (uid != null) {
type_id += Address.SEPARATOR + uid.toString();
}

if (seen_types.add(type_id)) {
types_to_serialize.add(type);
}
return type_id;
}

// Return the r-value of a varnode.
private Varnode rValueOf(Varnode node) throws Exception {
Expand Down Expand Up @@ -156,6 +208,157 @@ private HighVariable lValueOf(Varnode node) throws Exception {
return var;
}

private void serializePointerType(Pointer ptr) throws Exception {
name("name").value(ptr.getDisplayName());
name("kind").value("pointer");
name("size").value(ptr.getLength());
name("element_type").value(label(ptr.getDataType()));
}

private void serializeTypedefType(TypeDef typedef) throws Exception {
name("name").value(typedef.getDisplayName());
name("kind").value("typedef");
name("size").value(typedef.getLength());
name("base_type").value(label(typedef.getBaseDataType()));
}

private void serializeArrayType(Array arr) throws Exception {
name("name").value(arr.getDisplayName());
name("kind").value("array");
name("size").value(arr.getLength());
name("num_elements").value(arr.getNumElements());
pgoodman marked this conversation as resolved.
Show resolved Hide resolved
name("element_type").value(label(arr.getDataType()));
}

private void serializeBuiltinType(DataType data_type, String kind) throws Exception {
name("name").value(data_type.getDisplayName());
name("size").value(data_type.getLength());
name("kind").value(kind);
}

private void serializeCompositeType(Composite data_type, String kind) throws Exception {
name("name").value(data_type.getDisplayName());
name("kind").value(kind);
name("size").value(data_type.getLength());
name("fields").beginArray();

for (int i = 0; i < data_type.getNumComponents(); i++) {
DataTypeComponent dtc = data_type.getComponent(i);
beginObject();

name("type").value(label(dtc.getDataType()));
name("offset").value(dtc.getOffset());

if (dtc.getFieldName() != null) {
name("name").value(dtc.getFieldName());
}
endObject();
}
endArray();
}

private void serializeFunctionDefinition(FunctionDefinition fd) throws Exception {
name("name").value(fd.getDisplayName());
name("kind").value("function");
name("return_type").value(label(fd.getReturnType()));
name("is_variadic").value(fd.hasVarArgs());
ParameterDefinition[] arguments = fd.getArguments();
name("parameters").beginArray();
for (int i = 0; i < arguments.length; i++) {
beginObject();
String name = arguments[i].getName();
if (name != null && !name.isEmpty()) {
name("name").value(arguments[i].getName());
}
name("size").value(arguments[i].getLength());
name("type").value(label(arguments[i].getDataType()));
endObject();
}
endArray();
}

private void serialize(DataType data_type) throws Exception {
if (data_type == null) {
nullValue();
return;
}

if (data_type instanceof Pointer) {
serializePointerType((Pointer) data_type);
} else if (data_type instanceof TypeDef) {
serializeTypedefType((TypeDef) data_type);
} else if (data_type instanceof Array) {
serializeArrayType((Array) data_type);
} else if (data_type instanceof Structure) {
serializeCompositeType((Composite) data_type, "struct");
} else if (data_type instanceof Union) {
serializeCompositeType((Composite) data_type, "union");
} else if (data_type instanceof AbstractIntegerDataType){
serializeBuiltinType(data_type, "integer");
} else if (data_type instanceof AbstractFloatDataType){
serializeBuiltinType(data_type, "float");
} else if (data_type instanceof BooleanDataType){
serializeBuiltinType(data_type, "boolean");
} else if (data_type instanceof Enum) {
serializeBuiltinType(data_type, "enum");
} else if (data_type instanceof VoidDataType) {
serializeBuiltinType(data_type, "void");
} else if (data_type instanceof Undefined || data_type.toString().contains("undefined")) {
serializeBuiltinType(data_type, "undefined");
} else if (data_type instanceof FunctionDefinition) {
serializeFunctionDefinition((FunctionDefinition) data_type);
} else {
throw new Exception("Unhandled type: " + data_type.toString());
}
}

private void serializeTypes() throws Exception {
for (int i = 0; i < types_to_serialize.size(); i++) {
DataType type = types_to_serialize.get(i);
name(label(type)).beginObject();
serialize(type);
endObject();
}

println("Total serialized types: " + types_to_serialize.size());
}

private void serialize(FunctionPrototype proto) throws Exception {
if (proto == null) {
nullValue();
return;
}

name("parameters").beginArray();
for (int i = 0; i < proto.getNumParams(); i++) {
HighVariable hv = proto.getParam(i).getHighVariable();
// Assert if hv is not an instance of HighParam
assert hv instanceof HighParam;
if (hv != null) {
beginObject();
String hv_name = hv.getName();
if (hv_name != null && !hv_name.isEmpty()) {
name("name").value(hv_name);
}
name("type").value(label(hv.getDataType()));
endObject();
}
}
endArray();
}

private void serialize(HighVariable high_var) throws Exception {
if (high_var == null) {
nullValue();
return;
}

beginObject();
name("name").value(high_var.getName());
name("type").value(label(high_var.getDataType()));
endObject();
}

private void serialize(Varnode node) throws Exception {
if (node == null) {
assert false;
Expand All @@ -172,23 +375,18 @@ private void serialize(Varnode node) throws Exception {

beginObject();

if (node.isConstant()) {
name("type").value("const");
} else if (node.isUnique()) {
name("type").value("unique");
} else if (node.isRegister()) {
name("type").value("register");
} else if (node.isAddress()) {
name("type").value("ram");
} else if (node.getAddress().isStackAddress()) {
name("type").value("stack");
} else {
throw new Exception("Unknown Varnode kind: " + node.toString());
}

Address address = node.getAddress();
name("space").value(address.getAddressSpace().getName());
name("offset").value(node.getOffset());
name("size").value(node.getSize());

name("address").value(label(node.getAddress()));
HighVariable high_var = node.getHigh();
if (high_var != null) {
name("variable").beginObject();
name("name").value(high_var.getName());
name("type").value(label(high_var.getDataType()));
endObject();
}
endObject();
}

Expand Down Expand Up @@ -331,6 +529,12 @@ private void serialize(HighFunction function, PcodeBlockBasic block) throws Exce
private void serialize(HighFunction high_function, Function function, boolean visit_pcode) throws Exception {

name("name").value(function.getName());
FunctionPrototype proto = high_function.getFunctionPrototype();
name("prototype").beginObject();
if (proto != null) {
serialize(proto);
}
endObject();

// If we have a high P-Code function, then serialize the blocks.
if (high_function != null) {
Expand Down Expand Up @@ -363,13 +567,22 @@ public void serialize() throws Exception {
continue;
}

DecompileResults res = ifc.decompileFunction(function, 30, null);
DecompileResults res = ifc.decompileFunction(function, decompilation_timeout, null);
HighFunction high_function = res.getHighFunction();

if (high_function == null) {
continue;
}

name(label(function_address)).beginObject();
serialize(high_function, function, i < original_functions_size);
endObject();
}

// Serialize Types
name("types").beginObject();
serializeTypes();
endObject();

endObject().endObject();
}
}
Expand Down