-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathDhrakeParseClass.java
105 lines (89 loc) · 3.8 KB
/
DhrakeParseClass.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//Creates structs based on Delphi type information.
//@category Delphi
//@author Jesko Huettenhain
//@keybinding F8
import ghidra.app.script.GhidraScript;
import ghidra.app.util.NamespaceUtils;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.GhidraClass;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.exception.DuplicateNameException;
public class DhrakeParseClass extends GhidraScript {
protected DataType putType(DataType dt, DataTypeConflictHandler h) {
return this.getCurrentProgram().getDataTypeManager().addDataType(dt, h);
}
protected DataType putType(DataType dt) {
return this.putType(dt, DataTypeConflictHandler.REPLACE_HANDLER);
}
protected DataType addFnType(Function fn) {
FunctionDefinitionDataType ft = new FunctionDefinitionDataType(fn, false);
return this.putType(ft, DataTypeConflictHandler.KEEP_HANDLER);
}
protected void log(String message) {
this.println(String.format("[Dhrake] %s", message));
}
private void log(String message, Object... args) {
this.println(String.format("[Dhrake] %s", String.format(message, args)));
}
@Override
protected void run() throws Exception {
String className = null;
Address nameAddress = this.toAddr(this.getInt(currentAddress.add(32)));
try {
this.clearListing(nameAddress, nameAddress.add(1));
this.createData(nameAddress, PascalString255DataType.dataType);
className = new String(this.getBytes(nameAddress.add(1), this.getByte(nameAddress)));
} catch (MemoryAccessException e) {
this.popup("Unfortunately, we got a memory access error trying to even read the class name. " +
"Either you executed this at the wrong address or the class metadata layout is " +
"unknown. If you can figure out how to identify this Delphi compiler and how it " +
"stores class metadata, that'd be Bill-Lumbergh-Level great.");
return;
}
// Create Data Structures + Methods
if (className.toUpperCase().startsWith("T") || className.toUpperCase().startsWith("E")) {
this.log(className);
GhidraClass classNamespace = null;
try {
this.log("Creating class %s", className);
classNamespace = NamespaceUtils.convertNamespaceToClass(currentProgram.getSymbolTable()
.getOrCreateNameSpace(currentProgram.getGlobalNamespace(), className, SourceType.USER_DEFINED));
} catch (DuplicateNameException e) {
this.log("Class %s already exists, stopping", className);
}
StructureDataType base = new StructureDataType(className, 0);
StructureDataType vtbl = new StructureDataType(className + "VT", 0);
long vt = this.getInt(currentAddress);
if (classNamespace != null) {
for (long tooDamnHigh = vt + 4 * 100; vt < tooDamnHigh; vt += 4) {
try {
long offset = this.getInt(this.toAddr(vt));
String name = null;
Address entryPoint = this.toAddr(offset);
Function function = this.getFunctionAt(entryPoint);
if (function == null) {
name = this.getSymbolAt(entryPoint).toString();
if (name == null) {
name = String.format("FUN_%08X", offset);
}
this.log(String.format("defining function at 0x%08X, name %s", offset, name));
function = this.createFunction(entryPoint, name);
}
if (function == null) break;
function.setParentNamespace(classNamespace);
name = function.getName();
this.log(String.format("adding function %s::%s", className, name));
vtbl.add(this.addFnType(function), 4, name, "");
} catch (Exception e) {
break;
}
}
base.add(this.getCurrentProgram().getDataTypeManager().getPointer(this.putType(vtbl)), "vt", "Virtual Function Table");
this.putType(base);
}
}
}
}