mirror of
https://codeberg.org/KeybadeBlox/JSRF-Decompilation.git
synced 2026-02-20 10:17:03 +03:00
Compare commits
3 commits
d81bd646fa
...
0922356a40
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0922356a40 | ||
|
|
e0c9fc4c83 | ||
|
|
1e8ae0f72f |
3 changed files with 165 additions and 47 deletions
|
|
@ -1,17 +1,19 @@
|
||||||
// TODO
|
// Writes user-defined data and function symbols to a specified TSV file for
|
||||||
|
// re-import by the EnhancedImport script.
|
||||||
//
|
//
|
||||||
// @category Export
|
// @category Export
|
||||||
|
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.program.flatapi.FlatProgramAPI;
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.listing.Data;
|
import ghidra.program.model.listing.Data;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.program.model.symbol.SourceType;
|
import ghidra.program.model.symbol.SourceType;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
import ghidra.program.model.symbol.Symbol;
|
||||||
import ghidra.program.model.symbol.SymbolIterator;
|
|
||||||
|
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|
||||||
public class EnhancedExport extends GhidraScript{
|
public class EnhancedExport extends GhidraScript{
|
||||||
|
|
@ -19,41 +21,18 @@ public class EnhancedExport extends GhidraScript{
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
final FileWriter out = new FileWriter(askFile("Specify output file", "OK"));
|
final FileWriter out = new FileWriter(askFile("Specify output file", "OK"));
|
||||||
|
|
||||||
final SymbolIterator iter = currentProgram.getSymbolTable()
|
for (final Symbol s : currentProgram.getSymbolTable()
|
||||||
.getPrimarySymbolIterator(true);
|
.getPrimarySymbolIterator(true)) {
|
||||||
while (iter.hasNext() && !monitor.isCancelled()) {
|
|
||||||
final Symbol s = iter.next();
|
|
||||||
if (s.getSource() != SourceType.USER_DEFINED) continue;
|
if (s.getSource() != SourceType.USER_DEFINED) continue;
|
||||||
|
|
||||||
final Object obj = s.getObject();
|
final Object obj = s.getObject();
|
||||||
if (obj != null) switch (obj) {
|
if (obj != null) switch (obj) {
|
||||||
case Data d:
|
case Data d:
|
||||||
out.write(
|
outputData(s.getAddress(), d.getDataType(), s.getName(true), out);
|
||||||
"0x" + s.getAddress().toString() + "\t" +
|
|
||||||
"d" + "\t" +
|
|
||||||
d.getDataType().getDisplayName() + "\t" +
|
|
||||||
s.getName(true) + "\n"
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Function f:
|
case Function f:
|
||||||
out.write(
|
outputFunc(s.getAddress(), f, out);
|
||||||
"0x" + s.getAddress().toString() + "\t" +
|
|
||||||
"f" + "\t" +
|
|
||||||
f.getSignature(true).getReturnType()
|
|
||||||
.getDisplayName() + "\t" +
|
|
||||||
f.getCallingConventionName() + "\t" +
|
|
||||||
f.getName(true) +
|
|
||||||
String.join(
|
|
||||||
"\t",
|
|
||||||
Arrays.stream(f.getSignature(true).getArguments())
|
|
||||||
.map(arg -> "\t" +
|
|
||||||
arg.getDataType().getDisplayName() + "\t" +
|
|
||||||
arg.getName()
|
|
||||||
).toArray(String[]::new)
|
|
||||||
) +
|
|
||||||
(f.hasVarArgs() ? "\t..." : "") + "\n"
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: {}
|
default: {}
|
||||||
|
|
@ -62,4 +41,46 @@ public class EnhancedExport extends GhidraScript{
|
||||||
|
|
||||||
out.close();
|
out.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void outputData(
|
||||||
|
final Address addr,
|
||||||
|
final DataType type,
|
||||||
|
final String name,
|
||||||
|
final FileWriter out
|
||||||
|
) throws Exception {
|
||||||
|
out.write(
|
||||||
|
"0x" + addr.toString() + "\t" +
|
||||||
|
"data" + "\t" +
|
||||||
|
type.getDisplayName() + "\t" +
|
||||||
|
name + "\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void outputFunc(
|
||||||
|
final Address addr,
|
||||||
|
final Function f,
|
||||||
|
final FileWriter out
|
||||||
|
) throws Exception {
|
||||||
|
out.write(
|
||||||
|
"0x" + addr.toString() + "\t" +
|
||||||
|
"func" + "\t" +
|
||||||
|
f.getSignature(true).getReturnType()
|
||||||
|
.getDisplayName() + "\t" +
|
||||||
|
f.getCallingConventionName() + "\t" +
|
||||||
|
(f.isInline() ? "inline" : "notinline") + "\t" +
|
||||||
|
Optional.ofNullable(f.getCallFixup())
|
||||||
|
.orElse("nofixup") + "\t" +
|
||||||
|
f.getName(true) +
|
||||||
|
String.join(
|
||||||
|
"\t",
|
||||||
|
Arrays.stream(f.getSignature(true)
|
||||||
|
.getArguments())
|
||||||
|
.map(arg ->
|
||||||
|
"\t" + arg.getDataType().getDisplayName() +
|
||||||
|
"\t" + arg.getName()
|
||||||
|
).toArray(String[]::new)
|
||||||
|
) +
|
||||||
|
(f.hasVarArgs() ? "\t..." : "") + "\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
102
ghidra/ghidra_scripts/EnhancedImport.java
Normal file
102
ghidra/ghidra_scripts/EnhancedImport.java
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
// 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.DataType;
|
||||||
|
import ghidra.program.model.listing.Data;
|
||||||
|
import ghidra.program.model.listing.Function;
|
||||||
|
import ghidra.program.model.symbol.Namespace;
|
||||||
|
import ghidra.program.model.symbol.SourceType;
|
||||||
|
import ghidra.program.model.symbol.Symbol;
|
||||||
|
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.util.Arrays;
|
||||||
|
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 " + Integer.toString(i) +
|
||||||
|
" is not \"data\" or \"func\""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void importData(
|
||||||
|
final Address addr,
|
||||||
|
final String[] parts
|
||||||
|
) throws Exception {
|
||||||
|
final String name = unqualified(parts[3]);
|
||||||
|
|
||||||
|
print("Importing data symbol \"" + parts[3] + "\"...");
|
||||||
|
|
||||||
|
// Create symbol
|
||||||
|
final Namespace ns = importNamespace(parts[3]);
|
||||||
|
final Symbol s = Optional.ofNullable(getSymbolAt(addr))
|
||||||
|
.orElse(createLabel(addr, name, ns, true, SourceType.USER_DEFINED));
|
||||||
|
|
||||||
|
// Create data (TODO: parse type name to get base name, then pass base type to PointerDataType and ArrayDataType constructors to create final type)
|
||||||
|
final List<DataType> foundTypes = state.getTool()
|
||||||
|
.getService(DataTypeQueryService.class)
|
||||||
|
.findDataTypes(parts[2], null);
|
||||||
|
if (foundTypes.size() == 0) {
|
||||||
|
println(" can't find data type \"" + parts[2] + "\", skipping.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final DataType t = foundTypes.get(0); // Boldly assume first is right
|
||||||
|
|
||||||
|
clearListing(addr, addr.add(Math.max(t.getLength(), 1) - 1));
|
||||||
|
currentProgram.getListing().createData(addr, t);
|
||||||
|
|
||||||
|
println(" done.");
|
||||||
|
}
|
||||||
|
|
||||||
|
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 void importFunc(
|
||||||
|
final Address addr,
|
||||||
|
final String[] parts
|
||||||
|
) throws Exception {
|
||||||
|
println("TODO: function \"" + parts[6] + "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -59,7 +59,6 @@ import ghidra.program.model.symbol.Namespace;
|
||||||
import ghidra.program.model.symbol.Reference;
|
import ghidra.program.model.symbol.Reference;
|
||||||
import ghidra.program.model.symbol.SourceType;
|
import ghidra.program.model.symbol.SourceType;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
import ghidra.program.model.symbol.Symbol;
|
||||||
import ghidra.program.model.symbol.SymbolIterator;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -86,12 +85,8 @@ public class MSVC7Mangle extends GhidraScript{
|
||||||
setCurrentSelection(addr);
|
setCurrentSelection(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
final SymbolIterator iter = currentProgram.getSymbolTable()
|
for (final Symbol s : currentProgram.getSymbolTable()
|
||||||
.getPrimarySymbolIterator(currentSelection, true);
|
.getPrimarySymbolIterator(currentSelection, true)) {
|
||||||
|
|
||||||
while (iter.hasNext() && !monitor.isCancelled()) {
|
|
||||||
final Symbol s = iter.next();
|
|
||||||
|
|
||||||
mangle(s);
|
mangle(s);
|
||||||
|
|
||||||
// Also mangle everything referenced inside functions
|
// Also mangle everything referenced inside functions
|
||||||
|
|
@ -303,9 +298,9 @@ public class MSVC7Mangle extends GhidraScript{
|
||||||
scalar deleting destructor.
|
scalar deleting destructor.
|
||||||
*/
|
*/
|
||||||
final Reference[] refs = getReferencesTo(f.getEntryPoint());
|
final Reference[] refs = getReferencesTo(f.getEntryPoint());
|
||||||
for (int i = 0; i < refs.length; i++) {
|
for (final Reference ref : refs) {
|
||||||
final Data data = getDataContaining (refs[i].getFromAddress());
|
final Data data = getDataContaining (ref.getFromAddress());
|
||||||
final Function func = getFunctionContaining(refs[i].getFromAddress());
|
final Function func = getFunctionContaining(ref.getFromAddress());
|
||||||
|
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
final Symbol s = getSymbolAt(data.getRoot()
|
final Symbol s = getSymbolAt(data.getRoot()
|
||||||
|
|
@ -481,12 +476,12 @@ public class MSVC7Mangle extends GhidraScript{
|
||||||
// freaks out at is actually useful (and Optional still
|
// freaks out at is actually useful (and Optional still
|
||||||
// helped us out here)
|
// helped us out here)
|
||||||
String mangledArgs = "";
|
String mangledArgs = "";
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (final DataType arg : args) {
|
||||||
final String mangledArg = mangleType(args[i], dict, loc);
|
final String mangledArg = mangleType(arg, dict, loc);
|
||||||
|
|
||||||
mangledArgs += mangledArg.length() == 1 ?
|
mangledArgs += mangledArg.length() == 1 ?
|
||||||
mangledArg :
|
mangledArg :
|
||||||
backref(args[i], argDict).orElse(mangledArg);
|
backref(arg, argDict).orElse(mangledArg);
|
||||||
}
|
}
|
||||||
return mangledArgs + (f.hasVarArgs() ? "Z" : "@");
|
return mangledArgs + (f.hasVarArgs() ? "Z" : "@");
|
||||||
}
|
}
|
||||||
|
|
@ -592,8 +587,8 @@ public class MSVC7Mangle extends GhidraScript{
|
||||||
ins = ins.getNext()
|
ins = ins.getNext()
|
||||||
) {
|
) {
|
||||||
final Reference[] refs = ins.getReferencesFrom();
|
final Reference[] refs = ins.getReferencesFrom();
|
||||||
for (int i = 0; i < refs.length; i++) {
|
for (final Reference ref : refs) {
|
||||||
final Symbol symbol = getSymbolAt(refs[i].getToAddress());
|
final Symbol symbol = getSymbolAt(ref.getToAddress());
|
||||||
|
|
||||||
// Guard against spurious references to nonexisting things
|
// Guard against spurious references to nonexisting things
|
||||||
if (
|
if (
|
||||||
|
|
@ -605,10 +600,10 @@ public class MSVC7Mangle extends GhidraScript{
|
||||||
d.getBaseDataType() instanceof Undefined ||
|
d.getBaseDataType() instanceof Undefined ||
|
||||||
d.getBaseDataType() instanceof DefaultDataType
|
d.getBaseDataType() instanceof DefaultDataType
|
||||||
) &&
|
) &&
|
||||||
refs[i].getSource() != SourceType.USER_DEFINED
|
ref.getSource() != SourceType.USER_DEFINED
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
removeReference(refs[i]);
|
removeReference(ref);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue