mirror of
https://codeberg.org/KeybadeBlox/JSRF-Decompilation.git
synced 2026-05-22 17:37:20 +03:00
Support name mangling method pointers
ActSequence uses an array of method pointers, meaning we need to support mangling this obscure corner of the language. The name mangling code is admittedly feeling pretty messy, as this appears to require a lot of special casing.
This commit is contained in:
parent
a6267f4bf0
commit
6916d3a90c
2 changed files with 86 additions and 32 deletions
|
|
@ -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"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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<String> dict = new ArrayList<>();
|
||||
|
||||
final List<String> nameParts = Arrays.asList(nameRaw.split("::"));
|
||||
final List<String> 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<String> dict
|
||||
) {
|
||||
|
|
@ -231,7 +232,8 @@ public class MSVC7Mangle extends GhidraScript {
|
|||
names.
|
||||
*/
|
||||
// Break up names into their mangled order
|
||||
final List<String> parts = Arrays.asList(ident.split("::"));
|
||||
List<String> 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<String> dict,
|
||||
final String loc
|
||||
final DataType t,
|
||||
final Optional<Namespace> classNamespace,
|
||||
final List<String> 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<String> 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<String> 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<DataType> args = Arrays.stream(f.getArguments())
|
||||
.map(ParameterDefinition::getDataType)
|
||||
.toList();
|
||||
args = args.subList(isMethodPtr ? 1 : 0, args.size());
|
||||
|
||||
final ArrayList<DataType> 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<Namespace> 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<Namespace> 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<String> 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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue