diff --git a/decompile/objdiff.json b/decompile/objdiff.json index 49093d5..8000d87 100644 --- a/decompile/objdiff.json +++ b/decompile/objdiff.json @@ -30,8 +30,7 @@ }, "symbol_mappings": { "?Exec0Default__jumptable@CActSequence@@3EA": "$L1709", - "?Exec0Default__jumptargets@CActSequence@@3PAPAXA": "$L1710", - "?fSequenceMethods@CActSequence@@3PAP6EXPAU1@@ZA": "?fSequenceMethods@@3PAP8CActSequence@@AEXXZA" + "?Exec0Default__jumptargets@CActSequence@@3PAPAXA": "$L1710" } }, { diff --git a/ghidra/ghidra_scripts/MSVC7Mangle.java b/ghidra/ghidra_scripts/MSVC7Mangle.java index 317aba1..a7dba56 100644 --- a/ghidra/ghidra_scripts/MSVC7Mangle.java +++ b/ghidra/ghidra_scripts/MSVC7Mangle.java @@ -122,7 +122,7 @@ public class MSVC7Mangle extends GhidraScript { // Get mangled name final String mangled = switch (s.getObject()) { case Function f -> mangleFn (f); - case Data d -> mangleData(d, name); + case Data d -> mangleData(d, name, getClassNamespace(s)); default -> null; }; @@ -190,12 +190,12 @@ public class MSVC7Mangle extends GhidraScript { final ArrayList dict = new ArrayList<>(); - final List nameParts = Arrays.asList(nameRaw.split("::")); + final List nameParts = Arrays.asList(nameRaw.split("::")); Collections.reverse(nameParts); - final boolean isMethod = f.getCallingConventionName() - .equals("__thiscall") && - nameParts.size() >= 2; - final String name = mangleIdentifier(nameRaw, isMethod, f.getReturnType(), dict); + final boolean isMethod = f.getCallingConventionName() + .equals("__thiscall") && + nameParts.size() >= 2; + final String name = mangleIdentifier(nameRaw, isMethod, false, f.getReturnType(), dict); // Special methods with unique formats if (isMethod) { @@ -204,7 +204,7 @@ public class MSVC7Mangle extends GhidraScript { if (unqualified.equals( clsName)) { // Constructor return "?" + name + "QAE@" + - mangleArgs(f.getSignature(true), dict, nameRaw + "()") + + mangleArgs(f.getSignature(true), false, dict, nameRaw + "()") + "Z"; } else if (unqualified.equals("~" + clsName)) { // Destructor return "?" + name + (isVirtual(f) ? "UAE" : "QAE") + "@XZ"; @@ -218,6 +218,7 @@ public class MSVC7Mangle extends GhidraScript { private static String mangleIdentifier( final String ident, final boolean isMethod, + final boolean isMethodPtr, final DataType retType, // Function return type, nullable final List dict ) { @@ -231,7 +232,8 @@ public class MSVC7Mangle extends GhidraScript { names. */ // Break up names into their mangled order - final List parts = Arrays.asList(ident.split("::")); + List parts = Arrays.asList(ident.split("::")); + parts = parts.subList(isMethodPtr ? 1 : 0, parts.size()); Collections.reverse(parts); // Non-method special names @@ -386,8 +388,8 @@ public class MSVC7Mangle extends GhidraScript { ) throws Exception { /* Mangle everything in f but its name and visibility/linkage */ return mangleCallC(f) + - mangleType(f.getReturnType(), dict, loc) + - mangleArgs(f, dict, loc) + "Z"; + mangleType(f.getReturnType(), Optional.empty(), dict, loc) + + mangleArgs(f, false, dict, loc) + "Z"; } private static String mangleCallC(final FunctionSignature f) throws Exception { @@ -402,9 +404,10 @@ public class MSVC7Mangle extends GhidraScript { } private static String mangleType( - final DataType t, - final List dict, - final String loc + final DataType t, + final Optional classNamespace, + final List dict, + final String loc ) throws Exception { /* Mangle a data type in a function name All types are assumed to have no CV qualifiers. @@ -429,19 +432,23 @@ public class MSVC7Mangle extends GhidraScript { case DoubleDataType x -> "N"; case LongDoubleDataType x -> "O"; case Pointer p -> "P" + - (p.getDataType() instanceof FunctionSignature ? "6" : "A") + - mangleType(p.getDataType(), dict, loc); - case Union u -> "T" + mangleIdentifier(u.getName(), false, null, dict); - case Structure s -> "U" + mangleIdentifier(s.getName(), false, null, dict); - case Enum e -> "W4" + mangleIdentifier(e.getName(), false, null, dict); + (p.getDataType() instanceof FunctionSignature f ? ( + classNamespace.isPresent() ? "8" : "6" + ) : "A" + ) + mangleType(p.getDataType(), classNamespace, dict, loc); + case Union u -> "T" + mangleIdentifier(u.getName(), false, false, null, dict); + case Structure s -> "U" + mangleIdentifier(s.getName(), false, false, null, dict); + case Enum e -> "W4" + mangleIdentifier(e.getName(), false, false, null, dict); case VoidDataType x -> "X"; case LongLongDataType x -> "_J"; case UnsignedLongLongDataType x -> "_K"; case BooleanDataType x -> "_N"; case WideCharDataType x -> "_W"; - case Array a -> "PA" + mangleArrDims(a) + mangleType(arrType(a), dict, loc); - case FunctionSignature f -> mangleFnType(f, dict, "function typedef \"" + f.getName() + "\""); - case TypeDef d -> mangleType(d.getBaseDataType(), dict, "typedef \"" + d.getName() + "\""); + case Array a -> "PA" + mangleArrDims(a) + mangleType(arrType(a), classNamespace, dict, loc); + case FunctionSignature f -> classNamespace.isPresent() ? + mangleMethodPtr(f, classNamespace.get(), dict, loc) : + mangleFnType(f, dict, "function typedef \"" + f.getName() + "\""); + case TypeDef d -> mangleType(d.getBaseDataType(), classNamespace, dict, "typedef \"" + d.getName() + "\""); case DefaultDataType x -> throw new Exception ("Encountered data marked \"undefined\" at " + loc + ". Ensure that all data types in the code/data to mangle have been defined."); case Undefined x -> throw new Exception ("Encountered data marked \"undefined\" at " + loc + ". Ensure that all data types in the code/data to mangle have been defined."); default -> throw new Exception ("Unknown type \"" + t.getClass().getName() + "\" at " + loc); @@ -490,19 +497,33 @@ public class MSVC7Mangle extends GhidraScript { return t instanceof Array a_ ? arrType(a_) : t; } + private static String mangleMethodPtr( + final FunctionSignature f, + final Namespace classNamespace, + final List dict, + final String loc + ) throws Exception { + /* Mangle pointed-to part of a method pointer (i.e. after "3PAP8") */ + return classNamespace.getName() + "@@AE" + + mangleType(f.getReturnType(), Optional.empty(), dict, loc) + + mangleArgs(f, true, dict, loc) + "Z"; + } + private static String mangleArgs( final FunctionSignature f, + final boolean isMethodPtr, final List dict, final String loc ) throws Exception { /* Mangle the arguments for a function */ - final DataType[] args = Arrays.stream(f.getArguments()) - .map(ParameterDefinition::getDataType) - .toArray(DataType[]::new); + List args = Arrays.stream(f.getArguments()) + .map(ParameterDefinition::getDataType) + .toList(); + args = args.subList(isMethodPtr ? 1 : 0, args.size()); final ArrayList argDict = new ArrayList<>(); - if (args.length == 0) return "X"; + if (args.size() == 0) return "X"; else { // I try to be more expression-oriented, but not being // able to throw in lambdas, not having an error sum @@ -518,7 +539,7 @@ public class MSVC7Mangle extends GhidraScript { // helped us out here) String mangledArgs = ""; for (final DataType arg : args) { - final String mangledArg = mangleType(arg, dict, loc); + final String mangledArg = mangleType(arg, Optional.empty(), dict, loc); mangledArgs += mangledArg.length() == 1 ? mangledArg : @@ -528,9 +549,17 @@ public class MSVC7Mangle extends GhidraScript { } } + private Optional getClassNamespace(final Symbol s) { + /* Return the namespace of the class containing s, if there is one */ + final Namespace ns = s.getParentNamespace(); + return ns.getType() == Namespace.Type.CLASS ? Optional.of(ns) + : Optional.empty(); + } + private String mangleData( - final Data d, - final String name + final Data d, + final String name, + final Optional classNamespace ) throws Exception { /* Set the data symbol's name to its mangled version */ // String constants @@ -547,13 +576,19 @@ public class MSVC7Mangle extends GhidraScript { } final ArrayList dict = new ArrayList<>(); - final String ident = mangleIdentifier(name, false, null, dict); + final String ident = mangleIdentifier( + name, + false, + classNamespace.isPresent() && isFnPtr(d.getDataType(), "0x" + d.getAddress().toString()), + null, + dict + ); // vtable if (ident.startsWith("?_7")) return "?" + ident + "6B@"; return "?" + ident + "3" + - mangleType(d.getDataType(), dict, "0x" + d.getAddress().toString()) + + mangleType(d.getDataType(), classNamespace, dict, "0x" + d.getAddress().toString()) + "A"; } @@ -625,6 +660,26 @@ public class MSVC7Mangle extends GhidraScript { return (int)crc.getValue() ^ 0xFFFFFFFF; } + private static boolean isFnPtr( + final DataType t, + final String loc + ) throws Exception { + /* Determine whether the type is a function pointer (or wraps one) */ + if (t == null) throw new Exception ( + "A data type at " + loc + " was reported as null. " + + "Ensure that all data types in the code/data to " + + "mangle have been defined." + ); + + return switch(t) { + case Pointer p -> isFnPtr(p.getDataType() , loc); + case Array a -> isFnPtr(arrType(a) , loc); + case TypeDef d -> isFnPtr(d.getBaseDataType(), loc); + case FunctionSignature f -> true; + default -> false; + }; + } + private void mangleRefs( final Function f, final Set seenSymbols