From fbca52078f6dc9acd5c585abe3602aa0c452c332 Mon Sep 17 00:00:00 2001 From: Saro G Date: Fri, 4 Aug 2023 15:33:25 -0400 Subject: [PATCH] Formatting; Java-style array declarations; Optimize imports --- DhrakeInit.java | 175 +++++++++++++++++++----------------------- DhrakeParseClass.java | 18 ++--- 2 files changed, 88 insertions(+), 105 deletions(-) diff --git a/DhrakeInit.java b/DhrakeInit.java index 17f122e..f9ab14b 100644 --- a/DhrakeInit.java +++ b/DhrakeInit.java @@ -3,49 +3,32 @@ //@category Delphi //@author Jesko Huettenhain -import java.io.File; -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.io.FileInputStream; -import java.io.BufferedInputStream; -import java.util.Scanner; - -import org.apache.commons.io.FileUtils; - import ghidra.app.decompiler.DecompInterface; import ghidra.app.decompiler.DecompileResults; import ghidra.app.script.GhidraScript; -import ghidra.util.exception.CancelledException; -import ghidra.util.exception.DuplicateNameException; -import ghidra.util.exception.InvalidInputException; -import ghidra.program.model.symbol.*; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.lang.Register; import ghidra.program.model.listing.*; import ghidra.program.model.listing.Function.FunctionUpdateType; -import ghidra.program.model.pcode.HighFunction; -import ghidra.program.model.pcode.HighFunctionDBUtil; -import ghidra.program.model.pcode.PcodeOp; -import ghidra.program.model.pcode.PcodeOpAST; -import ghidra.program.model.pcode.Varnode; +import ghidra.program.model.pcode.*; import ghidra.program.model.scalar.Scalar; -import ghidra.program.model.address.*; -import ghidra.program.model.data.BooleanDataType; -import ghidra.program.model.data.ByteDataType; -import ghidra.program.model.data.CharDataType; -import ghidra.program.model.data.DataType; -import ghidra.program.model.data.FunctionDefinitionDataType; -import ghidra.program.model.data.ParameterDefinitionImpl; -import ghidra.program.model.data.PointerDataType; -import ghidra.program.model.data.UnsignedIntegerDataType; -import ghidra.program.model.data.WideCharDataType; -import ghidra.program.model.lang.Register; +import ghidra.program.model.symbol.RefType; +import ghidra.program.model.symbol.Reference; +import ghidra.program.model.symbol.SourceType; +import ghidra.program.model.symbol.SymbolTable; +import ghidra.util.exception.CancelledException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.exception.InvalidInputException; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class DhrakeInit extends GhidraScript { @@ -61,11 +44,11 @@ public class DhrakeInit extends GhidraScript { static DataType BOOL = BooleanDataType.dataType; static SourceType DhrakeSource = SourceType.ANALYSIS; - + private void renameSymbol(Address entryPoint, String name) throws InvalidInputException { this.renameSymbol(entryPoint, name, DhrakeSource); } - + private void renameSymbol(Address entryPoint, String name, SourceType type) throws InvalidInputException { Function f = this.getFunctionAt(entryPoint); SymbolTable symbolTable = currentProgram.getSymbolTable(); @@ -84,11 +67,11 @@ private void renameSymbol(Address entryPoint, String name, SourceType type) thro } } } - + private void logMsg(String message, Object... args){ this.println(String.format("[Dhrake] %s", String.format(message, args))); } - + private long getConstantCallArgument(Function caller, Address addr, int index) throws IllegalStateException { // This is a very reliable and slow fallback to determine the value of a constant argument // to a function call at a given address within a given function. @@ -113,7 +96,7 @@ private long getConstantCallArgument(Function caller, Address addr, int index) t } throw new IllegalStateException(); } - + private long getStrCatCount(Function caller, Address addr) { // Usually, the second (constant) argument to a *StrCatN function is assigned to // the EDX register right before the call instruction. This method attempts to @@ -123,8 +106,8 @@ private long getStrCatCount(Function caller, Address addr) { Instruction insn = this.getInstructionBefore(addr); if (insn == null || insn.getNumOperands() != 2) return this.getConstantCallArgument(caller, addr, 2); - Object EDX[] = insn.getOpObjects(0); - Object IMM[] = insn.getOpObjects(1); + Object[] EDX = insn.getOpObjects(0); + Object[] IMM = insn.getOpObjects(1); if (insn.getOperandRefType(0) != RefType.WRITE) return this.getConstantCallArgument(caller, addr, 2); if (EDX.length != 1 || !(EDX[0] instanceof Register)) @@ -144,19 +127,19 @@ private void overrideStrCatN(String name, DataType LPTSTR) { DataType PPTSTR = PointerDataType.getPointer(LPTSTR, currentProgram.getDataTypeManager()); Iterator functions = this.getGlobalFunctions(name).iterator(); while (functions.hasNext()) { - Function StrCatN = functions.next(); - Reference refs[] = this.getReferencesTo(StrCatN.getEntryPoint()); + Function StrCatN = functions.next(); + Reference[] refs = this.getReferencesTo(StrCatN.getEntryPoint()); StrCatN.setVarArgs(true); try { StrCatN.replaceParameters( - FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, - true, - DhrakeSource, - new ParameterImpl("Result", PPTSTR, currentProgram), - new ParameterImpl("Count", UINT, currentProgram) + FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, + true, + DhrakeSource, + new ParameterImpl("Result", PPTSTR, currentProgram), + new ParameterImpl("Count", UINT, currentProgram) ); - } catch (Exception e) { + } catch (Exception e) { long offset = StrCatN.getEntryPoint().getOffset(); this.logMsg("%08X Unable to correctly retype %s.", offset, name); } @@ -186,7 +169,7 @@ private void overrideStrCatN(String name, DataType LPTSTR) { // passed in the ECX register. The best solution I could come up with is to add a dummy // variable which represents this third argument, which does not actually exist: args.add(new ParameterDefinitionImpl( - String.format("__dummy_%02d", offset & 0xFF), UINT, "Dummy Variable")); + String.format("__dummy_%02d", offset & 0xFF), UINT, "Dummy Variable")); for (long k=0; k < count; k++) args.add(new ParameterDefinitionImpl(String.format("String%d", count - k), LPTSTR, "")); @@ -195,7 +178,7 @@ private void overrideStrCatN(String name, DataType LPTSTR) { signature.setReturnType(UINT); signature.setVarArgs(false); int transaction = currentProgram.startTransaction( - String.format("Fixing call to %s at %08X", name, offset)); + String.format("Fixing call to %s at %08X", name, offset)); boolean success = false; try { HighFunctionDBUtil.writeOverride(caller, addr, signature); @@ -211,7 +194,7 @@ private void overrideStrCatN(String name, DataType LPTSTR) { } } } - + private boolean importSymbolsFromIDC() { File idc; int progress = 0; @@ -225,10 +208,10 @@ private boolean importSymbolsFromIDC() { return false; } Pattern pattern = Pattern.compile("^\\s*MakeNameEx\\((?:0x)?([A-Fa-f0-9]+),\\s*\"([^\"]*)\",\\s*([xA-Fa-f0-9]+)\\);\\s*$"); - - - try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(idc)); Scanner sc = new Scanner(inputStream, "UTF-8");) { - + + + try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(idc)); Scanner sc = new Scanner(inputStream, StandardCharsets.UTF_8)) { + //count lines while (sc.hasNextLine()) { sc.nextLine(); @@ -239,13 +222,13 @@ private boolean importSymbolsFromIDC() { this.logMsg("file not found: %s", idc.toPath()); return false; } - try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(idc)); Scanner sc = new Scanner(inputStream, "UTF-8");) { + try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(idc)); Scanner sc = new Scanner(inputStream, StandardCharsets.UTF_8)) { while (sc.hasNextLine()) { String line = sc.nextLine(); - + monitor.setProgress(progress++); - + if (!line.contains("MakeNameEx")) continue; Matcher match = pattern.matcher(line); @@ -266,47 +249,47 @@ private boolean importSymbolsFromIDC() { } catch (IOException e) { this.logMsg("file not found: %s", idc.toPath()); return false; - } + } return true; - } + } private void repairStringCompareFunctions() { try { monitor.setMessage("reparing known function signatures"); VariableStorage zfReturn = new VariableStorage( - currentProgram, currentProgram.getRegister("ZF")); + currentProgram, currentProgram.getRegister("ZF")); Map comparators = Map.of( - "@PStrCmp", new DataType[] { LPBYTE, LPBYTE }, - "@LStrCmp", new DataType[] { LPCSTR, LPCSTR }, - "@WStrCmp", new DataType[] { LPWSTR, LPWSTR }, - "@UStrCmp", new DataType[] { LPWSTR, LPWSTR }, - "@AStrCmp", new DataType[] { LPCSTR, LPCSTR, UINT } + "@PStrCmp", new DataType[] { LPBYTE, LPBYTE }, + "@LStrCmp", new DataType[] { LPCSTR, LPCSTR }, + "@WStrCmp", new DataType[] { LPWSTR, LPWSTR }, + "@UStrCmp", new DataType[] { LPWSTR, LPWSTR }, + "@AStrCmp", new DataType[] { LPCSTR, LPCSTR, UINT } ); Register argLocations[] = new Register[] { - currentProgram.getRegister("EAX"), - currentProgram.getRegister("EDX"), - currentProgram.getRegister("ECX") + currentProgram.getRegister("EAX"), + currentProgram.getRegister("EDX"), + currentProgram.getRegister("ECX") }; - String argNames[] = new String[] {"a", "b", "size"}; + String[] argNames = new String[] {"a", "b", "size"}; - for (Map.Entry cmp : comparators.entrySet()) { + for (Map.Entry cmp : comparators.entrySet()) { Iterator functions = this.getGlobalFunctions(cmp.getKey()).iterator(); while (functions.hasNext()) { Function function = functions.next(); function.setCustomVariableStorage(true); function.setReturn(BOOL, zfReturn, DhrakeSource); - DataType argTypes[] = cmp.getValue(); - List args = new ArrayList<>(); + DataType[] argTypes = cmp.getValue(); + List args = new ArrayList<>(); for (int k = 0; k < argTypes.length; k++) args.add(new ParameterImpl(argNames[k], argTypes[k], argLocations[k], currentProgram)); - ParameterImpl argumentArray[] = args.toArray(new ParameterImpl[args.size()]); + ParameterImpl[] argumentArray = args.toArray(new ParameterImpl[args.size()]); try { function.replaceParameters( - FunctionUpdateType.CUSTOM_STORAGE, true, DhrakeSource, argumentArray + FunctionUpdateType.CUSTOM_STORAGE, true, DhrakeSource, argumentArray ); - } catch (DuplicateNameException e) { + } catch (DuplicateNameException e) { this.logMsg("%08X Unable to correctly retype %s.", - function.getEntryPoint().getOffset(), cmp.getKey() + function.getEntryPoint().getOffset(), cmp.getKey() ); } } @@ -315,9 +298,9 @@ private void repairStringCompareFunctions() { this.logMsg("Unexpected error obtaining registers"); } } - + public void repairLibraryFunctionSignatures() { - + this.overrideStrCatN("@LStrCatN", LPCSTR); this.overrideStrCatN("@WStrCatN", LPWSTR); this.overrideStrCatN("@UStrCatN", LPWSTR); @@ -325,33 +308,33 @@ public void repairLibraryFunctionSignatures() { this.repairStringCompareFunctions(); Map comparators = Map.of( - "@LStrCat3", new DataType[] { LPPCSTR, LPCSTR, LPCSTR }, - "@UStrCat3", new DataType[] { LPPWSTR, LPWSTR, LPWSTR }, - "@WStrCat3", new DataType[] { LPPWSTR, LPWSTR, LPWSTR } + "@LStrCat3", new DataType[] { LPPCSTR, LPCSTR, LPCSTR }, + "@UStrCat3", new DataType[] { LPPWSTR, LPWSTR, LPWSTR }, + "@WStrCat3", new DataType[] { LPPWSTR, LPWSTR, LPWSTR } ); - for (Map.Entry sig : comparators.entrySet()) { + for (Map.Entry sig : comparators.entrySet()) { Iterator functions = this.getGlobalFunctions(sig.getKey()).iterator(); while (functions.hasNext()) { - Function function = functions.next(); - DataType argTypes[] = sig.getValue(); - List args = new ArrayList<>(); + Function function = functions.next(); + DataType[] argTypes = sig.getValue(); + List args = new ArrayList<>(); try { for (int k = 0; k < argTypes.length; k++) args.add(new ParameterImpl(String.format("a%d", k), argTypes[k], currentProgram)); - ParameterImpl argumentArray[] = args.toArray(new ParameterImpl[args.size()]); + ParameterImpl[] argumentArray = args.toArray(new ParameterImpl[args.size()]); function.replaceParameters( - FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true, DhrakeSource, argumentArray + FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true, DhrakeSource, argumentArray ); - } catch (Exception e) { + } catch (Exception e) { this.logMsg("%08X Unable to correctly retype %s.", - function.getEntryPoint().getOffset(), sig.getKey() + function.getEntryPoint().getOffset(), sig.getKey() ); } } } } - + private void repairWrongFunctionEntries() { // This function attempts to detect and fix situations where Ghidra has incorrectly placed // the entry point of a Delphi function after the actual entry point. @@ -385,7 +368,7 @@ private void repairWrongFunctionEntries() { currentProgram.endTransaction(transaction, success); } } - + public void run() { monitor.setCancelEnabled(true); monitor.setShowProgressValue(true); diff --git a/DhrakeParseClass.java b/DhrakeParseClass.java index edc5de9..d278524 100644 --- a/DhrakeParseClass.java +++ b/DhrakeParseClass.java @@ -29,7 +29,7 @@ protected DataType addFnType(Function fn) { FunctionDefinitionDataType ft = new FunctionDefinitionDataType(fn, false); return this.putType(ft, DataTypeConflictHandler.KEEP_HANDLER); } - + protected void log(String message) { this.println(String.format("[Dhrake] %s", message)); } @@ -38,14 +38,14 @@ protected void log(String message) { protected void run() throws Exception { String className = null; Address nameAddress = this.toAddr(this.getInt(currentAddress.add(32))); - try { + try { className = new String(this.getBytes(nameAddress.add(1), this.getByte(nameAddress))); } catch (MemoryAccessException e) { this.popup( - "Unfortunately, we got a memory access error trying to even read the class name. " + - "Either you executed this at the wrong address or the class metadata layout is " + - "unknown. If you can figure out how to identify this Delphi compiler and how it " + - "stores class metadata, that'd be Bill-Lumbergh-Level great." + "Unfortunately, we got a memory access error trying to even read the class name. " + + "Either you executed this at the wrong address or the class metadata layout is " + + "unknown. If you can figure out how to identify this Delphi compiler and how it " + + "stores class metadata, that'd be Bill-Lumbergh-Level great." ); return; } @@ -53,8 +53,8 @@ protected void run() throws Exception { this.log(className); this.log(String.format("creating class %s", className)); GhidraClass classNamespace = NamespaceUtils.convertNamespaceToClass( - currentProgram.getSymbolTable().createNameSpace( - currentProgram.getGlobalNamespace(), className, SourceType.USER_DEFINED)); + currentProgram.getSymbolTable().createNameSpace( + currentProgram.getGlobalNamespace(), className, SourceType.USER_DEFINED)); StructureDataType base = new StructureDataType(className, 0); StructureDataType vtbl = new StructureDataType(className + "VT", 0); long vt = this.getInt(currentAddress); @@ -83,7 +83,7 @@ protected void run() throws Exception { } } base.add(this.getCurrentProgram().getDataTypeManager().getPointer(this.putType(vtbl)), - "vt", "Virtual Function Table"); + "vt", "Virtual Function Table"); this.putType(base); }