diff --git a/ghidra/delink.sh b/ghidra/delink.sh index 9b14b9b..2df52e2 100755 --- a/ghidra/delink.sh +++ b/ghidra/delink.sh @@ -65,11 +65,8 @@ delink() { export MSYS_NO_PATHCONV=1 "$1/support/analyzeHeadless$suffix" "$2" "$3"\ - -readOnly\ -process default.xbe\ -noanalysis\ - -scriptPath ghidra_scripts\ - -preScript MSVC7Mangle.java $4\ -postScript DelinkProgram.java\ /exporter 'COFF relocatable object'\ $(printf "/include-range %s " $4)\ diff --git a/ghidra/ghidra_scripts/MSVC7Mangle.java b/ghidra/ghidra_scripts/MSVC7Mangle.java index 718ca2b..ff13d16 100644 --- a/ghidra/ghidra_scripts/MSVC7Mangle.java +++ b/ghidra/ghidra_scripts/MSVC7Mangle.java @@ -7,20 +7,17 @@ // permissive form (public, non-const, etc.). // // Special symbol names like "operator new" or "scalar deleting destructor" -// are given unique mangling. To properly mangle these, name them as they +// are given unique mangling. To properly demangle these, name them as they // appear in objdiff, replacing spaces with underscores, e.g. "operator_new" // and "`scalar_deleting_destructor'" (notice the ` and '). // -// This script can be called in headless mode with the address ranges to mangle -// as arguments, e.g. 0x1234-0x5678. Any symbols referenced by functions being -// mangled will also be mangled in this mode (so that the references are -// correct if the mangling is done in preparation for exporting functions). -// // @category Symbol import ghidra.app.script.GhidraScript; import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressSet; +import ghidra.program.model.listing.Data; +import ghidra.program.model.listing.Function; +import ghidra.program.model.listing.FunctionSignature; import ghidra.program.model.data.Array; import ghidra.program.model.data.BooleanDataType; import ghidra.program.model.data.CharDataType; @@ -41,7 +38,6 @@ import ghidra.program.model.data.StringDataInstance; import ghidra.program.model.data.Structure; import ghidra.program.model.data.TerminatedUnicodeDataType; import ghidra.program.model.data.TypeDef; -import ghidra.program.model.data.Undefined; import ghidra.program.model.data.Union; import ghidra.program.model.data.UnsignedCharDataType; import ghidra.program.model.data.UnsignedIntegerDataType; @@ -50,9 +46,6 @@ import ghidra.program.model.data.UnsignedLongLongDataType; import ghidra.program.model.data.UnsignedShortDataType; import ghidra.program.model.data.VoidDataType; import ghidra.program.model.data.WideCharDataType; -import ghidra.program.model.listing.Data; -import ghidra.program.model.listing.Function; -import ghidra.program.model.listing.FunctionSignature; import ghidra.program.model.symbol.Namespace; import ghidra.program.model.symbol.Reference; import ghidra.program.model.symbol.SourceType; @@ -72,22 +65,6 @@ import java.util.zip.CRC32; public class MSVC7Mangle extends GhidraScript{ @Override public void run() throws Exception { - // Get selected ranges from arguments if invoked headless - if (isRunningHeadless()) { - final String[] args = getScriptArgs(); - final AddressSet addr = new AddressSet(); - - for (int i = 0; i < args.length; i++) { - final String[] range = args[i].split("-"); - addr.add( - currentAddress.getAddress(range[0]), - currentAddress.getAddress(range[1]) - ); - } - - setCurrentSelection(addr); - } - final SymbolIterator iter = currentProgram.getSymbolTable() .getPrimarySymbolIterator(currentSelection, true); @@ -109,9 +86,6 @@ public class MSVC7Mangle extends GhidraScript{ s.setName(mangled, SourceType.USER_DEFINED); makeGlobal(s); } - - // TODO: in headless mode, also mangle everything - // referenced by functions } } @@ -264,29 +238,24 @@ public class MSVC7Mangle extends GhidraScript{ } private boolean isVirtual(final Function f) { - /* Determine whether a method is virtual - We essentially check whether any references are from a vtable or a - scalar deleting destructor. + /* Attempt to determine whether a method is virtual + We essentially try to figure out if any references are from a vtable + by checking if they lie in non-executable memory, or from a scalar + deleting destructor. */ final Reference[] refs = getReferencesTo(f.getEntryPoint()); for (int i = 0; i < refs.length; i++) { - final Data data = getDataContaining (refs[i].getFromAddress()); - final Function func = getFunctionContaining(refs[i].getFromAddress()); + final Address addr = refs[i].getFromAddress(); + final Optional caller = Optional.ofNullable(getFunctionContaining(addr)) + .map(x -> x.getName(false)); - if (data != null) { - final String name = getSymbolAt(data.getRoot() - .getAddress()).getName(false); - if ( - name.equals("`vftable'") || - name.startsWith("??_7") - ) return true; - } else if (func != null) { - final String name = func.getName(false); - if ( - name.equals("`scalar_deleting_destructor'") || - name.startsWith("??_G") - ) return true; - } + if ( + !getMemoryBlock(addr).isExecute() || + caller.map(x -> x.equals("`scalar_deleting_destructor'")) + .orElse(false) || + caller.map(x -> x.startsWith("??_G")) // From mangled name + .orElse(false) + ) return true; } return false; @@ -336,7 +305,7 @@ public class MSVC7Mangle extends GhidraScript{ */ if (t == null) throw new Exception ( "A data type was reported as null. Ensure that all " + - "data types in the code/data to mangle have been " + + "data types in the demangled code/data have been " + "defined." ); @@ -367,8 +336,7 @@ public class MSVC7Mangle extends GhidraScript{ case Array a -> "PA" + mangleArrDims(a) + mangleType(arrType(a), dict); case FunctionSignature f -> mangleFnType(f, dict); case TypeDef d -> mangleType(d.getBaseDataType(), dict); - case DefaultDataType _ -> throw new Exception ("Encountered data marked \"undefined\". Ensure that all data types in the code/data to mangle have been defined."); - case Undefined _ -> throw new Exception ("Encountered data marked \"undefined\". Ensure that all data types in the code/data to mangle have been defined."); + case DefaultDataType _ -> throw new Exception ("Encountered data marked \"undefined\". All data types must be defined."); default -> throw new Exception ("Unknown type \"" + t.getClass().getName() + "\""); }; }