mirror of
https://codeberg.org/KeybadeBlox/JSRF-Decompilation.git
synced 2026-05-23 01:47: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": {
|
"symbol_mappings": {
|
||||||
"?Exec0Default__jumptable@CActSequence@@3EA": "$L1709",
|
"?Exec0Default__jumptable@CActSequence@@3EA": "$L1709",
|
||||||
"?Exec0Default__jumptargets@CActSequence@@3PAPAXA": "$L1710",
|
"?Exec0Default__jumptargets@CActSequence@@3PAPAXA": "$L1710"
|
||||||
"?fSequenceMethods@CActSequence@@3PAP6EXPAU1@@ZA": "?fSequenceMethods@@3PAP8CActSequence@@AEXXZA"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ public class MSVC7Mangle extends GhidraScript {
|
||||||
// Get mangled name
|
// Get mangled name
|
||||||
final String mangled = switch (s.getObject()) {
|
final String mangled = switch (s.getObject()) {
|
||||||
case Function f -> mangleFn (f);
|
case Function f -> mangleFn (f);
|
||||||
case Data d -> mangleData(d, name);
|
case Data d -> mangleData(d, name, getClassNamespace(s));
|
||||||
default -> null;
|
default -> null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -190,12 +190,12 @@ public class MSVC7Mangle extends GhidraScript {
|
||||||
|
|
||||||
final ArrayList<String> dict = new ArrayList<>();
|
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);
|
Collections.reverse(nameParts);
|
||||||
final boolean isMethod = f.getCallingConventionName()
|
final boolean isMethod = f.getCallingConventionName()
|
||||||
.equals("__thiscall") &&
|
.equals("__thiscall") &&
|
||||||
nameParts.size() >= 2;
|
nameParts.size() >= 2;
|
||||||
final String name = mangleIdentifier(nameRaw, isMethod, f.getReturnType(), dict);
|
final String name = mangleIdentifier(nameRaw, isMethod, false, f.getReturnType(), dict);
|
||||||
|
|
||||||
// Special methods with unique formats
|
// Special methods with unique formats
|
||||||
if (isMethod) {
|
if (isMethod) {
|
||||||
|
|
@ -204,7 +204,7 @@ public class MSVC7Mangle extends GhidraScript {
|
||||||
|
|
||||||
if (unqualified.equals( clsName)) { // Constructor
|
if (unqualified.equals( clsName)) { // Constructor
|
||||||
return "?" + name + "QAE@" +
|
return "?" + name + "QAE@" +
|
||||||
mangleArgs(f.getSignature(true), dict, nameRaw + "()") +
|
mangleArgs(f.getSignature(true), false, dict, nameRaw + "()") +
|
||||||
"Z";
|
"Z";
|
||||||
} else if (unqualified.equals("~" + clsName)) { // Destructor
|
} else if (unqualified.equals("~" + clsName)) { // Destructor
|
||||||
return "?" + name + (isVirtual(f) ? "UAE" : "QAE") + "@XZ";
|
return "?" + name + (isVirtual(f) ? "UAE" : "QAE") + "@XZ";
|
||||||
|
|
@ -218,6 +218,7 @@ public class MSVC7Mangle extends GhidraScript {
|
||||||
private static String mangleIdentifier(
|
private static String mangleIdentifier(
|
||||||
final String ident,
|
final String ident,
|
||||||
final boolean isMethod,
|
final boolean isMethod,
|
||||||
|
final boolean isMethodPtr,
|
||||||
final DataType retType, // Function return type, nullable
|
final DataType retType, // Function return type, nullable
|
||||||
final List<String> dict
|
final List<String> dict
|
||||||
) {
|
) {
|
||||||
|
|
@ -231,7 +232,8 @@ public class MSVC7Mangle extends GhidraScript {
|
||||||
names.
|
names.
|
||||||
*/
|
*/
|
||||||
// Break up names into their mangled order
|
// 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);
|
Collections.reverse(parts);
|
||||||
|
|
||||||
// Non-method special names
|
// Non-method special names
|
||||||
|
|
@ -386,8 +388,8 @@ public class MSVC7Mangle extends GhidraScript {
|
||||||
) throws Exception {
|
) throws Exception {
|
||||||
/* Mangle everything in f but its name and visibility/linkage */
|
/* Mangle everything in f but its name and visibility/linkage */
|
||||||
return mangleCallC(f) +
|
return mangleCallC(f) +
|
||||||
mangleType(f.getReturnType(), dict, loc) +
|
mangleType(f.getReturnType(), Optional.empty(), dict, loc) +
|
||||||
mangleArgs(f, dict, loc) + "Z";
|
mangleArgs(f, false, dict, loc) + "Z";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String mangleCallC(final FunctionSignature f) throws Exception {
|
private static String mangleCallC(final FunctionSignature f) throws Exception {
|
||||||
|
|
@ -402,9 +404,10 @@ public class MSVC7Mangle extends GhidraScript {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String mangleType(
|
private static String mangleType(
|
||||||
final DataType t,
|
final DataType t,
|
||||||
final List<String> dict,
|
final Optional<Namespace> classNamespace,
|
||||||
final String loc
|
final List<String> dict,
|
||||||
|
final String loc
|
||||||
) throws Exception {
|
) throws Exception {
|
||||||
/* Mangle a data type in a function name
|
/* Mangle a data type in a function name
|
||||||
All types are assumed to have no CV qualifiers.
|
All types are assumed to have no CV qualifiers.
|
||||||
|
|
@ -429,19 +432,23 @@ public class MSVC7Mangle extends GhidraScript {
|
||||||
case DoubleDataType x -> "N";
|
case DoubleDataType x -> "N";
|
||||||
case LongDoubleDataType x -> "O";
|
case LongDoubleDataType x -> "O";
|
||||||
case Pointer p -> "P" +
|
case Pointer p -> "P" +
|
||||||
(p.getDataType() instanceof FunctionSignature ? "6" : "A") +
|
(p.getDataType() instanceof FunctionSignature f ? (
|
||||||
mangleType(p.getDataType(), dict, loc);
|
classNamespace.isPresent() ? "8" : "6"
|
||||||
case Union u -> "T" + mangleIdentifier(u.getName(), false, null, dict);
|
) : "A"
|
||||||
case Structure s -> "U" + mangleIdentifier(s.getName(), false, null, dict);
|
) + mangleType(p.getDataType(), classNamespace, dict, loc);
|
||||||
case Enum e -> "W4" + mangleIdentifier(e.getName(), false, null, dict);
|
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 VoidDataType x -> "X";
|
||||||
case LongLongDataType x -> "_J";
|
case LongLongDataType x -> "_J";
|
||||||
case UnsignedLongLongDataType x -> "_K";
|
case UnsignedLongLongDataType x -> "_K";
|
||||||
case BooleanDataType x -> "_N";
|
case BooleanDataType x -> "_N";
|
||||||
case WideCharDataType x -> "_W";
|
case WideCharDataType x -> "_W";
|
||||||
case Array a -> "PA" + mangleArrDims(a) + mangleType(arrType(a), dict, loc);
|
case Array a -> "PA" + mangleArrDims(a) + mangleType(arrType(a), classNamespace, dict, loc);
|
||||||
case FunctionSignature f -> mangleFnType(f, dict, "function typedef \"" + f.getName() + "\"");
|
case FunctionSignature f -> classNamespace.isPresent() ?
|
||||||
case TypeDef d -> mangleType(d.getBaseDataType(), dict, "typedef \"" + d.getName() + "\"");
|
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 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.");
|
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);
|
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;
|
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(
|
private static String mangleArgs(
|
||||||
final FunctionSignature f,
|
final FunctionSignature f,
|
||||||
|
final boolean isMethodPtr,
|
||||||
final List<String> dict,
|
final List<String> dict,
|
||||||
final String loc
|
final String loc
|
||||||
) throws Exception {
|
) throws Exception {
|
||||||
/* Mangle the arguments for a function */
|
/* Mangle the arguments for a function */
|
||||||
final DataType[] args = Arrays.stream(f.getArguments())
|
List<DataType> args = Arrays.stream(f.getArguments())
|
||||||
.map(ParameterDefinition::getDataType)
|
.map(ParameterDefinition::getDataType)
|
||||||
.toArray(DataType[]::new);
|
.toList();
|
||||||
|
args = args.subList(isMethodPtr ? 1 : 0, args.size());
|
||||||
|
|
||||||
final ArrayList<DataType> argDict = new ArrayList<>();
|
final ArrayList<DataType> argDict = new ArrayList<>();
|
||||||
|
|
||||||
if (args.length == 0) return "X";
|
if (args.size() == 0) return "X";
|
||||||
else {
|
else {
|
||||||
// I try to be more expression-oriented, but not being
|
// I try to be more expression-oriented, but not being
|
||||||
// able to throw in lambdas, not having an error sum
|
// able to throw in lambdas, not having an error sum
|
||||||
|
|
@ -518,7 +539,7 @@ public class MSVC7Mangle extends GhidraScript {
|
||||||
// helped us out here)
|
// helped us out here)
|
||||||
String mangledArgs = "";
|
String mangledArgs = "";
|
||||||
for (final DataType arg : args) {
|
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 ?
|
mangledArgs += mangledArg.length() == 1 ?
|
||||||
mangledArg :
|
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(
|
private String mangleData(
|
||||||
final Data d,
|
final Data d,
|
||||||
final String name
|
final String name,
|
||||||
|
final Optional<Namespace> classNamespace
|
||||||
) throws Exception {
|
) throws Exception {
|
||||||
/* Set the data symbol's name to its mangled version */
|
/* Set the data symbol's name to its mangled version */
|
||||||
// String constants
|
// String constants
|
||||||
|
|
@ -547,13 +576,19 @@ public class MSVC7Mangle extends GhidraScript {
|
||||||
}
|
}
|
||||||
|
|
||||||
final ArrayList<String> dict = new ArrayList<>();
|
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
|
// vtable
|
||||||
if (ident.startsWith("?_7")) return "?" + ident + "6B@";
|
if (ident.startsWith("?_7")) return "?" + ident + "6B@";
|
||||||
|
|
||||||
return "?" + ident + "3" +
|
return "?" + ident + "3" +
|
||||||
mangleType(d.getDataType(), dict, "0x" + d.getAddress().toString()) +
|
mangleType(d.getDataType(), classNamespace, dict, "0x" + d.getAddress().toString()) +
|
||||||
"A";
|
"A";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -625,6 +660,26 @@ public class MSVC7Mangle extends GhidraScript {
|
||||||
return (int)crc.getValue() ^ 0xFFFFFFFF;
|
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(
|
private void mangleRefs(
|
||||||
final Function f,
|
final Function f,
|
||||||
final Set seenSymbols
|
final Set seenSymbols
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue