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 2 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
220 changes: 203 additions & 17 deletions scripts/ghidra/PatchestryDecompileFunctions.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,23 @@

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.Enum;
kumarak marked this conversation as resolved.
Show resolved Hide resolved
import ghidra.program.model.data.*;

import ghidra.program.model.symbol.ExternalManager;

import ghidra.util.UniversalID;

import com.google.gson.stream.JsonWriter;

import java.io.BufferedWriter;
Expand All @@ -48,13 +55,19 @@
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 static HashMap<String, DataType> type_map = new HashMap<>();
kumarak marked this conversation as resolved.
Show resolved Hide resolved

private class PcodeSerializer extends JsonWriter {
private String arch;
Expand All @@ -81,6 +94,26 @@ public PcodeSerializer(java.io.BufferedWriter writer,
this.original_functions_size = functions.size();
this.seen_functions = new TreeSet<>();
}

private static String id(DataType type) throws Exception {
kumarak marked this conversation as resolved.
Show resolved Hide resolved
String name = type.getName().replaceAll(" ", "");
kumarak marked this conversation as resolved.
Show resolved Hide resolved
CategoryPath category = type.getCategoryPath();
String concat_type = category.toString() + name + Integer.toString(type.getLength());
UniversalID uid = type.getUniversalID();
if (uid != null) {
kumarak marked this conversation as resolved.
Show resolved Hide resolved
return Integer.toHexString(concat_type.hashCode()) + ":" + uid.toString();
}
return Integer.toHexString(concat_type.hashCode());
}

private static String label(DataType type) throws Exception {
kumarak marked this conversation as resolved.
Show resolved Hide resolved
String type_id = id(type);
DataType lookup_type = type_map.get(type_id);
if (lookup_type == null) {
type_map.put(type_id, type);
}
return type_id;
}

private static String label(Address address) throws Exception {
return address.toString(true /* show address space prefix */);
Expand Down Expand Up @@ -156,6 +189,150 @@ private HighVariable lValueOf(Varnode node) throws Exception {
return var;
}

private void serializePointerType(Pointer data_type, Set<String> new_ids) throws Exception {
name("name").value(data_type.getDisplayName().replaceAll(" ", ""));
name("kind").value("pointer");
name("size").value(data_type.getLength());
DataType elem_type = data_type.getDataType();

// element data type can be null
kumarak marked this conversation as resolved.
Show resolved Hide resolved
if (elem_type != null) {
String elem_type_id = label(elem_type);
name("element_type").value(elem_type_id);
new_ids.add(elem_type_id);
}
}

private void serializeTypedefType(TypeDef data_type, Set<String> new_ids) throws Exception {
name("name").value(data_type.getDisplayName().replaceAll(" ", ""));
name("kind").value("typedef");
name("size").value(data_type.getLength());
kumarak marked this conversation as resolved.
Show resolved Hide resolved
name("is_pointer").value(data_type.isPointer());
kumarak marked this conversation as resolved.
Show resolved Hide resolved

DataType base_type = data_type.getBaseDataType();
if (base_type != null) {
String base_type_id = label(base_type);
new_ids.add(base_type_id);
name("base_type").value(base_type_id);
}
pgoodman marked this conversation as resolved.
Show resolved Hide resolved
}

private void serializeArrayType(Array arr, Set<String> new_ids) throws Exception {
name("name").value(arr.getDisplayName().replaceAll(" ", ""));
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
DataType elem_type = arr.getDataType();
if (elem_type != null) {
kumarak marked this conversation as resolved.
Show resolved Hide resolved
String elem_type_id = label(elem_type);
new_ids.add(elem_type_id);
name("element_type").value(elem_type_id);
}
}

private void serializeGenericType(DataType data_type, String kind, Set<String> new_ids) throws Exception {
name("name").value(data_type.getDisplayName().replaceAll(" ", ""));
name("size").value(data_type.getLength());
name("kind").value(kind);
}

private void serializeCompositeType(Composite data_type, String kind, Set<String> new_ids) throws Exception {
name("name").value(data_type.getDisplayName().replaceAll(" ", ""));
name("kind").value(kind);
name("size").value(data_type.getLength());
name("num_fields").value(data_type.getNumComponents());
kumarak marked this conversation as resolved.
Show resolved Hide resolved
name("fields").beginArray();

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

String comp_id = label(dtc.getDataType());
new_ids.add(comp_id);
name("type").value(comp_id);
name("offset").value(dtc.getOffset());

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

private void serialize(DataType data_type, Set<String> new_ids) throws Exception {
if (data_type == null) {
nullValue();
return;
}

if (data_type instanceof Pointer) {
serializePointerType((Pointer) data_type, new_ids);
} else if (data_type instanceof TypeDef) {
serializeTypedefType((TypeDef) data_type, new_ids);
} else if (data_type instanceof Array) {
serializeArrayType((Array) data_type, new_ids);
} else if (data_type instanceof Structure) {
serializeCompositeType((Composite) data_type, "struct", new_ids);
} else if (data_type instanceof Union) {
serializeCompositeType((Composite) data_type, "union", new_ids);
} else if (data_type instanceof AbstractIntegerDataType){
serializeGenericType(data_type, "integer", new_ids);
} else if (data_type instanceof AbstractFloatDataType){
serializeGenericType(data_type, "float", new_ids);
} else if (data_type instanceof BooleanDataType){
serializeGenericType(data_type, "boolean", new_ids);
} else if (data_type instanceof Enum) {
serializeGenericType(data_type, "enum", new_ids);
}
}

private void serializeTypes(Set<String> type_ids) throws Exception {
Set<String> serialized_types = new HashSet<>(); // To keep track of already serialized types
kumarak marked this conversation as resolved.
Show resolved Hide resolved
Set<String> pending_types = new HashSet<>(); // To track types found during serialization

do {
kumarak marked this conversation as resolved.
Show resolved Hide resolved
serialized_types.addAll(type_ids); // Add current typeIds to serialized set
pending_types.clear(); // Clear the pendingTypes for new iteration

for (String id : type_ids) {
name(id).beginObject();
DataType data_type = type_map.get(id);
serialize(data_type, pending_types);
endObject();
}

pending_types.removeAll(serialized_types);
type_ids = new HashSet<>(pending_types);
} while (!pending_types.isEmpty());
println("Total serialized types: " + serialized_types.size());
}

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

name("parameters").beginArray();
for (int i = 0; i < proto.getNumParams(); i++) {
serialize(proto.getParam(i).getHighVariable());
kumarak marked this conversation as resolved.
Show resolved Hide resolved
}
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 +349,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 +503,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,14 +541,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();

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

// Serialize Types
name("types").beginObject();
Set<String> seen_type_ids = new HashSet<>(type_map.keySet());
serializeTypes(seen_type_ids);
endObject();

endObject().endObject();
println("Type map size:" + type_map.size());
}
}

Expand Down