WIP Recompile
This commit is contained in:
@@ -16,14 +16,22 @@ import java.util.List;
|
||||
import java.util.Scanner;
|
||||
import java.util.Arrays;
|
||||
import ghidra.app.cmd.label.AddLabelCmd;
|
||||
import ghidra.app.decompiler.ClangMarkup;
|
||||
import ghidra.app.decompiler.ClangNode;
|
||||
import ghidra.app.decompiler.ClangTokenGroup;
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.decompiler.DecompileResults;
|
||||
import ghidra.app.decompiler.DecompiledFunction;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressFactory;
|
||||
import ghidra.program.model.data.AbstractStringDataType;
|
||||
import ghidra.program.model.data.BuiltInDataType;
|
||||
import ghidra.program.model.data.DataOrganization;
|
||||
import ghidra.program.model.data.DataOrganizationImpl;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.PointerDataType;
|
||||
import ghidra.program.model.data.StringDataInstance;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Variable;
|
||||
@@ -39,6 +47,7 @@ import ghidra.program.model.pcode.Varnode;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.SymbolTable;
|
||||
import ghidra.program.model.symbol.SymbolType;
|
||||
|
||||
public class DecompileC extends GhidraScript {
|
||||
public class PCallTracer {
|
||||
@@ -113,6 +122,10 @@ public class DecompileC extends GhidraScript {
|
||||
private static final String OUTPUT_DIR = "game_re";
|
||||
private static final int TIMEOUT = 10000;
|
||||
|
||||
// The static memory block
|
||||
private Address staticMemoryBlockStart;
|
||||
private Address staticMemoryBlockEnd;
|
||||
|
||||
// Auto rename invalid symbols
|
||||
private static final boolean AUTO_RENAME_SYMBOLS = true;
|
||||
|
||||
@@ -129,7 +142,6 @@ public class DecompileC extends GhidraScript {
|
||||
|
||||
void loadFunctionBlacklist() {
|
||||
functionAddrBlackList.clear();
|
||||
|
||||
File blacklistFile = new File(outputDir, "blacklist.txt");
|
||||
try (Scanner scanner = new Scanner(blacklistFile)) {
|
||||
while (scanner.hasNextLine()) {
|
||||
@@ -261,93 +273,143 @@ public class DecompileC extends GhidraScript {
|
||||
}
|
||||
|
||||
String escapeCString(String str) {
|
||||
str = str.replaceAll("\"", "\\\"");
|
||||
str = str.replaceAll("\n", "\\n");
|
||||
str = str.replaceAll("\r", "\\r");
|
||||
str = str.replaceAll("\t", "\\t");
|
||||
str = str.replaceAll("\b", "\\b");
|
||||
str = str.replaceAll("\f", "\\f");
|
||||
str = str.replaceAll("\0", "\\0");
|
||||
str = str.replace("\\", "\\\\");
|
||||
str = str.replace("\"", "\\\"");
|
||||
// str = str.replaceAll("\n", "\\n");
|
||||
// str = str.replaceAll("\r", "\\r");
|
||||
// str = str.replaceAll("\t", "\\t");
|
||||
// str = str.replaceAll("\b", "\\b");
|
||||
// str = str.replaceAll("\f", "\\f");
|
||||
// str = str.replaceAll("\0", "\\0");
|
||||
return str;
|
||||
}
|
||||
|
||||
String readCString(Address addr, int maxLen) throws Exception {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int ofs = 0;
|
||||
while (true) {
|
||||
Address read = addr.add(ofs++);
|
||||
// println("Reading: " + read);
|
||||
byte b = currentProgram.getMemory().getByte(read);
|
||||
// println("Read: " + b);
|
||||
if (b == 0 || ofs >= maxLen) {
|
||||
break;
|
||||
}
|
||||
sb.append((char) b);
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
println("STR \"" + sb.toString() + "\"");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
void decompileFunction(Hashtable<String, HighSymbol> outGlobalSymbols, DecompInterface decomp, Function function)
|
||||
throws Exception {
|
||||
String fileName = sanitizeFunctionName(function.getName()) + ".cxx";
|
||||
|
||||
File f1 = new File(dirDecompFix, fileName);
|
||||
if (f1.exists()) {
|
||||
println("Func " + function.getName() + " skipped (gh_fix)");
|
||||
return;
|
||||
}
|
||||
|
||||
File f0 = new File(dirDecompAuto, fileName);
|
||||
if (f0.exists()) {
|
||||
f0.delete();
|
||||
}
|
||||
|
||||
println("Processing " + function.getName() + " => " + f0.toString());
|
||||
|
||||
DecompileResults decompRes = decomp.decompileFunction(function, TIMEOUT, monitor);
|
||||
PrintWriter writer2 = new PrintWriter(f0, "UTF-8");
|
||||
writer2.println("// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!! ");
|
||||
writer2.println("// " + function.getEntryPoint());
|
||||
writer2.println();
|
||||
writer2.println("#include <gh_auto_shared.h>");
|
||||
writer2.println("#include \"../gh_global.h\"");
|
||||
writer2.println();
|
||||
|
||||
HighFunction highFunction = decompRes.getHighFunction();
|
||||
// ClangTokenGroup
|
||||
// ClangNode.
|
||||
// ClangTokenGroup ctg = decompRes.getCCodeMarkup();
|
||||
// for (ClangTokenGroup it = ctg.groupIterator(); it.hasNext();) {
|
||||
// }
|
||||
writer2.println(cm.getCode());
|
||||
|
||||
writer2.close();
|
||||
|
||||
// Collect referenced global symbols
|
||||
Iterator<HighSymbol> smyIt = decompRes.getHighFunction().getGlobalSymbolMap().getSymbols();
|
||||
while (smyIt.hasNext()) {
|
||||
HighSymbol gsym = smyIt.next();
|
||||
if (outGlobalSymbols.containsKey(gsym.getName()))
|
||||
continue;
|
||||
outGlobalSymbols.put(gsym.getName(), gsym);
|
||||
}
|
||||
}
|
||||
|
||||
void decompileAll(DecompInterface decomp, List<Function> functions) throws Exception {
|
||||
Hashtable<String, HighSymbol> globalSymbols = new Hashtable<>();
|
||||
|
||||
for (Function function : functions) {
|
||||
String fileName = sanitizeFunctionName(function.getName()) + ".c";
|
||||
|
||||
File f1 = new File(dirDecompFix, fileName);
|
||||
if (f1.exists()) {
|
||||
println("Func " + function.getName() + " skipped (gh_fix)");
|
||||
continue;
|
||||
}
|
||||
|
||||
File f0 = new File(dirDecompAuto, fileName);
|
||||
if (f0.exists()) {
|
||||
f0.delete();
|
||||
}
|
||||
|
||||
println("Processing " + function.getName() + " => " + f0.toString());
|
||||
|
||||
DecompileResults decompRes = decomp.decompileFunction(function, TIMEOUT, monitor);
|
||||
PrintWriter writer2 = new PrintWriter(f0, "UTF-8");
|
||||
writer2.println("// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!! ");
|
||||
writer2.println("// " + function.getEntryPoint());
|
||||
writer2.println();
|
||||
writer2.println("#include <gh_auto_shared.h>");
|
||||
writer2.println();
|
||||
writer2.println(decompRes.getDecompiledFunction().getC());
|
||||
|
||||
writer2.close();
|
||||
|
||||
// Collect referenced global symbols
|
||||
Iterator<HighSymbol> smyIt = decompRes.getHighFunction().getGlobalSymbolMap().getSymbols();
|
||||
while (smyIt.hasNext()) {
|
||||
HighSymbol gsym = smyIt.next();
|
||||
if (globalSymbols.containsKey(gsym.getName()))
|
||||
continue;
|
||||
globalSymbols.put(gsym.getName(), gsym);
|
||||
}
|
||||
decompileFunction(globalSymbols, decomp, function);
|
||||
}
|
||||
writer.close();
|
||||
|
||||
File globalSymbolsListH = new File(outputDir, "gh_global.h");
|
||||
File globalSymbolsListC = new File(outputDir, "gh_global.c");
|
||||
PrintWriter hwriter = new PrintWriter(globalSymbolsListH, "UTF-8");
|
||||
hwriter.println("// AUTO-GENERATED FILE ");
|
||||
hwriter.println("#include <gh_auto_shared.h>");
|
||||
|
||||
File globalSymbolsListC = new File(outputDir, "gh_global.cxx");
|
||||
PrintWriter cwriter = new PrintWriter(globalSymbolsListC, "UTF-8");
|
||||
for (HighSymbol sym : globalSymbols.values()) {
|
||||
DataType dt = sym.getDataType();
|
||||
String sanitizedName = sanitizeFunctionName(sym.getName());
|
||||
if (!sanitizedName.equals(sym.getName())) {
|
||||
println("Invalid global symbol name: " + sym.getName() + " - " + sym.getHighFunction().getFunction().getName());
|
||||
cwriter.println("// AUTO-GENERATED FILE ");
|
||||
cwriter.println("#include <gh_auto_shared.h>");
|
||||
for (HighSymbol highSym : globalSymbols.values()) {
|
||||
DataType dt = highSym.getDataType();
|
||||
String dataType = dt.getDisplayName();
|
||||
String name = highSym.getName();
|
||||
String sanitizedName = sanitizeFunctionName(highSym.getName());
|
||||
if (!sanitizedName.equals(highSym.getName())) {
|
||||
println("Invalid global symbol name: " + highSym.getName() + " - "
|
||||
+ highSym.getHighFunction().getFunction().getName());
|
||||
} else {
|
||||
Address address = sym.getStorage().getMinAddress();
|
||||
MemoryBlock block = currentProgram.getMemory().getBlock(address);
|
||||
String dataType = dt.toString();
|
||||
String name = sym.getName();
|
||||
|
||||
if (block == null) {
|
||||
println("Can not read variable " + name + " (" + dataType + ") at " + address);
|
||||
continue;
|
||||
Symbol symbol = highSym.getSymbol();
|
||||
VariableStorage storage = highSym.getStorage();
|
||||
Address addr = storage.getMinAddress();
|
||||
int symSize = highSym.getSize();
|
||||
if (addr == null) {
|
||||
// Not sure why this is sometimes null
|
||||
// also when it is not null, Symbol.getAddress() is not correct but very small
|
||||
// like 00000056
|
||||
// Not that storage will be <undefined> so maybe can check that
|
||||
addr = symbol.getAddress();
|
||||
}
|
||||
|
||||
if (dt instanceof AbstractStringDataType) {
|
||||
// String type
|
||||
hwriter.println("extern " + dataType + " " + name + "; // " + address);
|
||||
|
||||
String srcBlock = "";
|
||||
// Read the actual string data from Ghidra
|
||||
if (block != null && block.isInitialized()) {
|
||||
byte[] bytes = new byte[dt.getLength()];
|
||||
block.getBytes(address, bytes);
|
||||
// Parse from UTF-8
|
||||
String stringValue = new String(bytes, StandardCharsets.UTF_8);
|
||||
srcBlock = dataType + " " + name + " = \"" + escapeCString(stringValue) + "\";";
|
||||
println("Symbol: " + symbol + " Addr: " + addr + " Size:" + symSize + " " + storage.getSerializationString());
|
||||
try {
|
||||
String initBlk = " = ";
|
||||
if (dt instanceof AbstractStringDataType) {
|
||||
AbstractStringDataType sdt = (AbstractStringDataType) dt;
|
||||
dataType = "const char*";
|
||||
// String type
|
||||
initBlk += "\"" + escapeCString(readCString(addr, 2048)) + "\"";
|
||||
} else if (dt instanceof PointerDataType) {
|
||||
PointerDataType pdt = (PointerDataType) dt;
|
||||
DataType baseType = pdt.getDataType();
|
||||
dataType = baseType.getDisplayName() + "*";
|
||||
initBlk += "gh_ptr(0x" + addr + ")";
|
||||
} else {
|
||||
initBlk = " = 0";
|
||||
}
|
||||
cwriter.println(srcBlock + " // " + address);
|
||||
cwriter.println(dataType + " " + name + initBlk + "; // " + addr);
|
||||
} catch (Exception e) {
|
||||
println("Error processing global symbol: " + e);
|
||||
println("Symbol: " + highSym.getName() + " - " + addr + " - "
|
||||
+ highSym.getHighFunction().getFunction().getName());
|
||||
}
|
||||
|
||||
hwriter.println("extern " + dataType + " " + name + "; // " + addr);
|
||||
}
|
||||
}
|
||||
hwriter.close();
|
||||
@@ -360,6 +422,9 @@ public class DecompileC extends GhidraScript {
|
||||
return;
|
||||
}
|
||||
|
||||
staticMemoryBlockStart = currentProgram.getAddressFactory().getAddress("005b6400");
|
||||
staticMemoryBlockEnd = currentProgram.getAddressFactory().getAddress("00843fff");
|
||||
|
||||
// Make sure to create OUTPUT_PATH
|
||||
rootDir = new File(sourceFile.getAbsolutePath()).getParentFile().getParentFile();
|
||||
outputDir = new File(rootDir, OUTPUT_DIR);
|
||||
@@ -390,15 +455,11 @@ public class DecompileC extends GhidraScript {
|
||||
functions.add(function);
|
||||
}
|
||||
|
||||
// File functionList = new File(outputDir, "functions.txt");
|
||||
// PrintWriter writer = new PrintWriter(functionList, "UTF-8");
|
||||
|
||||
int mode = 1;
|
||||
if (mode == 0) { // Sanitize symbols
|
||||
sanitizeGlobalSymbolsPass(decomp, functions);
|
||||
} else if (mode == 1) { // Decompile all functions
|
||||
decompileAll(decomp, functions);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user