diff --git a/ghidra/ghidra_scripts/EnhancedExport.java b/ghidra/ghidra_scripts/EnhancedExport.java index e8f294a..de693af 100644 --- a/ghidra/ghidra_scripts/EnhancedExport.java +++ b/ghidra/ghidra_scripts/EnhancedExport.java @@ -1,19 +1,17 @@ -// Writes user-defined data and function symbols to a specified TSV file for -// re-import by the EnhancedImport script. +// TODO // // @category Export import ghidra.app.script.GhidraScript; -import ghidra.program.model.address.Address; -import ghidra.program.model.data.DataType; +import ghidra.program.flatapi.FlatProgramAPI; import ghidra.program.model.listing.Data; import ghidra.program.model.listing.Function; import ghidra.program.model.symbol.SourceType; import ghidra.program.model.symbol.Symbol; +import ghidra.program.model.symbol.SymbolIterator; import java.io.FileWriter; import java.util.Arrays; -import java.util.Optional; public class EnhancedExport extends GhidraScript{ @@ -21,18 +19,41 @@ public class EnhancedExport extends GhidraScript{ public void run() throws Exception { final FileWriter out = new FileWriter(askFile("Specify output file", "OK")); - for (final Symbol s : currentProgram.getSymbolTable() - .getPrimarySymbolIterator(true)) { + final SymbolIterator iter = currentProgram.getSymbolTable() + .getPrimarySymbolIterator(true); + while (iter.hasNext() && !monitor.isCancelled()) { + final Symbol s = iter.next(); if (s.getSource() != SourceType.USER_DEFINED) continue; final Object obj = s.getObject(); if (obj != null) switch (obj) { case Data d: - outputData(s.getAddress(), d.getDataType(), s.getName(true), out); + out.write( + "0x" + s.getAddress().toString() + "\t" + + "d" + "\t" + + d.getDataType().getDisplayName() + "\t" + + s.getName(true) + "\n" + ); break; case Function f: - outputFunc(s.getAddress(), f, out); + out.write( + "0x" + s.getAddress().toString() + "\t" + + "f" + "\t" + + f.getSignature(true).getReturnType() + .getDisplayName() + "\t" + + f.getCallingConventionName() + "\t" + + f.getName(true) + + String.join( + "\t", + Arrays.stream(f.getSignature(true).getArguments()) + .map(arg -> "\t" + + arg.getDataType().getDisplayName() + "\t" + + arg.getName() + ).toArray(String[]::new) + ) + + (f.hasVarArgs() ? "\t..." : "") + "\n" + ); break; default: {} @@ -41,46 +62,4 @@ public class EnhancedExport extends GhidraScript{ out.close(); } - - private static void outputData( - final Address addr, - final DataType type, - final String name, - final FileWriter out - ) throws Exception { - out.write( - "0x" + addr.toString() + "\t" + - "data" + "\t" + - type.getDisplayName() + "\t" + - name + "\n" - ); - } - - private static void outputFunc( - final Address addr, - final Function f, - final FileWriter out - ) throws Exception { - out.write( - "0x" + addr.toString() + "\t" + - "func" + "\t" + - f.getSignature(true).getReturnType() - .getDisplayName() + "\t" + - f.getCallingConventionName() + "\t" + - (f.isInline() ? "inline" : "notinline") + "\t" + - Optional.ofNullable(f.getCallFixup()) - .orElse("nofixup") + "\t" + - f.getName(true) + - String.join( - "\t", - Arrays.stream(f.getSignature(true) - .getArguments()) - .map(arg -> - "\t" + arg.getDataType().getDisplayName() + - "\t" + arg.getName() - ).toArray(String[]::new) - ) + - (f.hasVarArgs() ? "\t..." : "") + "\n" - ); - } } diff --git a/ghidra/ghidra_scripts/EnhancedImport.java b/ghidra/ghidra_scripts/EnhancedImport.java deleted file mode 100644 index 3bdf040..0000000 --- a/ghidra/ghidra_scripts/EnhancedImport.java +++ /dev/null @@ -1,102 +0,0 @@ -// Imports data from a file produced by the EnhancedExport script. -// -// @category Import - -import ghidra.app.script.GhidraScript; -import ghidra.app.services.DataTypeQueryService; -import ghidra.program.model.address.Address; -import ghidra.program.model.data.DataType; -import ghidra.program.model.listing.Data; -import ghidra.program.model.listing.Function; -import ghidra.program.model.symbol.Namespace; -import ghidra.program.model.symbol.SourceType; -import ghidra.program.model.symbol.Symbol; - -import java.io.FileReader; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; - - -public class EnhancedImport extends GhidraScript{ - @Override - public void run() throws Exception { - final FileReader in = new FileReader(askFile("Select input file", "OK")); - final List lines = in.readAllLines(); - in.close(); - - for (int i = 0; i < lines.size(); i++) { - final String[] parts = lines.get(i).split("\t");; - final Address addr = toAddr(parts[0]); - - switch (parts[1]) { - case "data": importData(addr, parts); break; - case "func": importFunc(addr, parts); break; - default: throw new Exception( - "Symbol type \"" + parts[1] + - "\" on line " + Integer.toString(i) + - " is not \"data\" or \"func\"" - ); - } - } - } - - private void importData( - final Address addr, - final String[] parts - ) throws Exception { - final String name = unqualified(parts[3]); - - print("Importing data symbol \"" + parts[3] + "\"..."); - - // Create symbol - final Namespace ns = importNamespace(parts[3]); - final Symbol s = Optional.ofNullable(getSymbolAt(addr)) - .orElse(createLabel(addr, name, ns, true, SourceType.USER_DEFINED)); - - // Create data (TODO: parse type name to get base name, then pass base type to PointerDataType and ArrayDataType constructors to create final type) - final List foundTypes = state.getTool() - .getService(DataTypeQueryService.class) - .findDataTypes(parts[2], null); - if (foundTypes.size() == 0) { - println(" can't find data type \"" + parts[2] + "\", skipping."); - return; - } - - final DataType t = foundTypes.get(0); // Boldly assume first is right - - clearListing(addr, addr.add(Math.max(t.getLength(), 1) - 1)); - currentProgram.getListing().createData(addr, t); - - println(" done."); - } - - private static String unqualified(final String qualifiedName) { - /* Strips the namespaces off of a qualified name */ - final String[] parts = qualifiedName.split("::"); - return parts[parts.length - 1]; - } - - private Namespace importNamespace(final String qualifiedName) throws Exception { - /* Creates namespaces from the given name, returning the deepest one - Returns null if the qualified name is in the global namespace. - */ - final String[] parts = qualifiedName.split("::"); - - if (parts.length < 2) return null; - - final String[] names = Arrays.copyOfRange(parts, 0, parts.length - 1); - - Namespace ns = null; - for (final String name : names) ns = createNamespace(ns, name); - - return ns; - } - - private void importFunc( - final Address addr, - final String[] parts - ) throws Exception { - println("TODO: function \"" + parts[6] + "\""); - } -} diff --git a/ghidra/ghidra_scripts/MSVC7Mangle.java b/ghidra/ghidra_scripts/MSVC7Mangle.java index 7bf4ab5..b62ed52 100644 --- a/ghidra/ghidra_scripts/MSVC7Mangle.java +++ b/ghidra/ghidra_scripts/MSVC7Mangle.java @@ -59,6 +59,7 @@ import ghidra.program.model.symbol.Namespace; import ghidra.program.model.symbol.Reference; import ghidra.program.model.symbol.SourceType; import ghidra.program.model.symbol.Symbol; +import ghidra.program.model.symbol.SymbolIterator; import java.util.Arrays; import java.util.ArrayList; @@ -85,8 +86,12 @@ public class MSVC7Mangle extends GhidraScript{ setCurrentSelection(addr); } - for (final Symbol s : currentProgram.getSymbolTable() - .getPrimarySymbolIterator(currentSelection, true)) { + final SymbolIterator iter = currentProgram.getSymbolTable() + .getPrimarySymbolIterator(currentSelection, true); + + while (iter.hasNext() && !monitor.isCancelled()) { + final Symbol s = iter.next(); + mangle(s); // Also mangle everything referenced inside functions @@ -298,9 +303,9 @@ public class MSVC7Mangle extends GhidraScript{ scalar deleting destructor. */ final Reference[] refs = getReferencesTo(f.getEntryPoint()); - for (final Reference ref : refs) { - final Data data = getDataContaining (ref.getFromAddress()); - final Function func = getFunctionContaining(ref.getFromAddress()); + for (int i = 0; i < refs.length; i++) { + final Data data = getDataContaining (refs[i].getFromAddress()); + final Function func = getFunctionContaining(refs[i].getFromAddress()); if (data != null) { final Symbol s = getSymbolAt(data.getRoot() @@ -476,12 +481,12 @@ public class MSVC7Mangle extends GhidraScript{ // freaks out at is actually useful (and Optional still // helped us out here) String mangledArgs = ""; - for (final DataType arg : args) { - final String mangledArg = mangleType(arg, dict, loc); + for (int i = 0; i < args.length; i++) { + final String mangledArg = mangleType(args[i], dict, loc); mangledArgs += mangledArg.length() == 1 ? mangledArg : - backref(arg, argDict).orElse(mangledArg); + backref(args[i], argDict).orElse(mangledArg); } return mangledArgs + (f.hasVarArgs() ? "Z" : "@"); } @@ -587,8 +592,8 @@ public class MSVC7Mangle extends GhidraScript{ ins = ins.getNext() ) { final Reference[] refs = ins.getReferencesFrom(); - for (final Reference ref : refs) { - final Symbol symbol = getSymbolAt(ref.getToAddress()); + for (int i = 0; i < refs.length; i++) { + final Symbol symbol = getSymbolAt(refs[i].getToAddress()); // Guard against spurious references to nonexisting things if ( @@ -600,10 +605,10 @@ public class MSVC7Mangle extends GhidraScript{ d.getBaseDataType() instanceof Undefined || d.getBaseDataType() instanceof DefaultDataType ) && - ref.getSource() != SourceType.USER_DEFINED + refs[i].getSource() != SourceType.USER_DEFINED ) ) { - removeReference(ref); + removeReference(refs[i]); continue; }