mirror of
https://codeberg.org/KeybadeBlox/JSRF-Decompilation.git
synced 2026-02-20 02:07:02 +03:00
197 lines
5.8 KiB
Java
197 lines
5.8 KiB
Java
// 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.ArrayDataType;
|
|
import ghidra.program.model.data.DataType;
|
|
import ghidra.program.model.data.PointerDataType;
|
|
import ghidra.program.model.data.Undefined4DataType;
|
|
import ghidra.program.model.listing.Data;
|
|
import ghidra.program.model.listing.Function;
|
|
import ghidra.program.model.listing.Function.FunctionUpdateType;
|
|
import ghidra.program.model.listing.Parameter;
|
|
import ghidra.program.model.listing.ParameterImpl;
|
|
import ghidra.program.model.symbol.Namespace;
|
|
import ghidra.program.model.symbol.SourceType;
|
|
import ghidra.program.model.symbol.Symbol;
|
|
import ghidra.util.StringUtilities;
|
|
|
|
import java.io.FileReader;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
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<String> 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 " + String.valueOf(i) +
|
|
" is not \"data\" or \"func\""
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void importData(
|
|
final Address addr,
|
|
final String[] parts
|
|
) throws Exception {
|
|
print("Importing data symbol \"" + parts[3] + "\"...");
|
|
|
|
// Create symbol
|
|
final Namespace ns = importNamespace(parts[3]);
|
|
final Symbol s = Optional.ofNullable(getSymbolAt(addr))
|
|
.orElse(createLabel(
|
|
addr,
|
|
unqualified(parts[3]),
|
|
ns,
|
|
true,
|
|
SourceType.USER_DEFINED
|
|
));
|
|
|
|
// Create data
|
|
if (makeType(parts[2]).orElse(null) instanceof DataType t) {
|
|
clearListing(addr, addr.add(Math.max(t.getLength(), 1) - 1));
|
|
currentProgram.getListing().createData(addr, t);
|
|
|
|
println(" done.");
|
|
} else println(" skipping.");
|
|
}
|
|
|
|
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 Optional<DataType> makeType(final String type) throws Exception {
|
|
/* Attempt to create the described type from a known base type */
|
|
final String baseName = StringUtilities.findWord(type, 0);
|
|
final List<DataType> foundTypes = state.getTool()
|
|
.getService(DataTypeQueryService.class)
|
|
.findDataTypes(baseName, null);
|
|
if (foundTypes.size() == 0) {
|
|
print(" can't find data type \"" + baseName + "\",");
|
|
return Optional.empty();
|
|
}
|
|
|
|
return Optional.of(derivedType(
|
|
foundTypes.get(0), // Boldly assume first is right
|
|
type.substring(baseName.length())
|
|
));
|
|
}
|
|
|
|
private static DataType derivedType(
|
|
final DataType t,
|
|
final String modifiers
|
|
) throws Exception {
|
|
/* Return the given datatype with given pointer/array modifiers */
|
|
DataType ret = t;
|
|
for (int i = 0; i < modifiers.length(); i++) switch (modifiers.charAt(i)) {
|
|
case '*':
|
|
ret = new PointerDataType(ret);
|
|
continue;
|
|
|
|
case '[':
|
|
// Read array dimensions
|
|
final ArrayList<Integer> dims = new ArrayList<>();
|
|
do {
|
|
final String n = StringUtilities.findWord(modifiers, i+1);
|
|
i += n.length() + 1;
|
|
|
|
dims.add(Integer.valueOf(n));
|
|
} while (modifiers.charAt(i) == '[');
|
|
|
|
// Apply array
|
|
Collections.reverse(dims);
|
|
for (int dim : dims) ret = new ArrayDataType(ret, dim);
|
|
|
|
continue;
|
|
|
|
case ' ':
|
|
continue;
|
|
|
|
default:
|
|
throw new Exception(
|
|
"Unexpected character \"" +
|
|
String.valueOf(modifiers.charAt(i)) +
|
|
"\" in type modifiers"
|
|
);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
private void importFunc(
|
|
final Address addr,
|
|
final String[] parts
|
|
) throws Exception {
|
|
print("Importing function symbol \"" + parts[6] + "\"...");
|
|
|
|
final Function f = Optional.ofNullable(getFunctionAt(addr))
|
|
.orElse(createFunction(addr, parts[6]));
|
|
|
|
if (makeType(parts[2]).orElse(null) instanceof DataType t)
|
|
f.setReturnType(t, SourceType.USER_DEFINED);
|
|
f.setInline(parts[4].equals("inline"));
|
|
f.setCallFixup(parts[5].equals("nofixup") ? null : parts[5]);
|
|
f.setName(unqualified(parts[6]), SourceType.USER_DEFINED);
|
|
if (importNamespace(parts[6]) instanceof Namespace ns)
|
|
f.setParentNamespace(ns);
|
|
|
|
final ArrayList<Parameter> args = new ArrayList<>();
|
|
for (int i = 7; i < parts.length - 1; i += 2)
|
|
args.add(new ParameterImpl(
|
|
parts[i+1],
|
|
makeType(parts[i]).orElse(Undefined4DataType.dataType),
|
|
currentProgram
|
|
));
|
|
|
|
f.updateFunction(
|
|
parts[3],
|
|
null,
|
|
args,
|
|
FunctionUpdateType.DYNAMIC_STORAGE_FORMAL_PARAMS,
|
|
true,
|
|
SourceType.USER_DEFINED
|
|
);
|
|
|
|
f.setVarArgs(parts[parts.length - 1].equals("..."));
|
|
|
|
println(" done.");
|
|
}
|
|
}
|