|
| 1 | +/** |
| 2 | + * The MIT License (MIT) |
| 3 | + * |
| 4 | + * Copyright (c) 2019-2020 Andrew J. Strelsky |
| 5 | + * |
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 7 | + * of this software and associated documentation files (the "Software"), to deal |
| 8 | + * in the Software without restriction, including without limitation the rights |
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 10 | + * copies of the Software, and to permit persons to whom the Software is |
| 11 | + * furnished to do so, subject to the following conditions: |
| 12 | + * |
| 13 | + * The above copyright notice and this permission notice shall be included in |
| 14 | + * all copies or substantial portions of the Software. |
| 15 | + * |
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 19 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 22 | + * THE SOFTWARE. |
| 23 | + * |
| 24 | + */ |
| 25 | +// Iterates through all vtable assignments and changes the assigned variable to |
| 26 | +// the appropriate class datatype. |
1 | 27 | //@category CppClassAnalyzer |
2 | | -import static ghidra.app.cmd.data.rtti.gcc.factory.TypeInfoFactory.getTypeInfo; |
3 | | - |
4 | | -import java.util.LinkedList; |
| 28 | +//@author Andrew J. Strelsky |
| 29 | +import java.util.Arrays; |
5 | 30 | import java.util.List; |
| 31 | +import java.util.Objects; |
| 32 | +import java.util.stream.Collectors; |
6 | 33 |
|
7 | | -import ghidra.app.cmd.data.rtti.ClassTypeInfo; |
8 | | -import ghidra.app.cmd.data.rtti.TypeInfo; |
9 | 34 | import ghidra.app.cmd.data.rtti.Vtable; |
10 | | -import ghidra.app.script.GhidraScript; |
11 | 35 | import ghidra.program.model.address.Address; |
12 | | -import ghidra.program.model.data.InvalidDataTypeException; |
| 36 | +import ghidra.program.model.data.DataType; |
13 | 37 | import ghidra.program.model.data.Structure; |
14 | 38 | import ghidra.program.model.lang.Register; |
15 | 39 | import ghidra.program.model.listing.Function; |
|
19 | 43 | import ghidra.program.model.symbol.Reference; |
20 | 44 | import ghidra.program.model.symbol.ReferenceManager; |
21 | 45 | import ghidra.program.model.symbol.SourceType; |
22 | | -import ghidra.program.model.symbol.Symbol; |
23 | | -import ghidra.program.model.symbol.SymbolTable; |
24 | 46 |
|
25 | | -public class ClassReferences extends GhidraScript { |
| 47 | +import cppclassanalyzer.script.CppClassAnalyzerGhidraScript; |
| 48 | + |
| 49 | +public class ClassReferences extends CppClassAnalyzerGhidraScript { |
| 50 | + |
| 51 | + private int count; |
26 | 52 |
|
27 | 53 | @Override |
28 | 54 | public void run() throws Exception { |
29 | 55 | println("This script is currently in development and may not function properly"); |
30 | | - SymbolTable table = currentProgram.getSymbolTable(); |
31 | | - List<Vtable> vftables = new LinkedList<>(); |
32 | | - List<Symbol> symbols = new LinkedList<>(); |
33 | | - table.getSymbols(TypeInfo.SYMBOL_NAME).forEach(symbols::add); |
34 | | - monitor.initialize(symbols.size()); |
35 | | - monitor.setMessage("Locating Vtables"); |
36 | | - for (Symbol symbol : symbols) { |
| 56 | + |
| 57 | + count = 0; |
| 58 | + List<Vtable> vftables = currentManager.getVtableStream() |
| 59 | + .collect(Collectors.toList()); |
| 60 | + monitor.setMessage("Setting variable datatypes"); |
| 61 | + monitor.initialize(vftables.size()); |
| 62 | + for (Vtable vtable : vftables) { |
37 | 63 | monitor.checkCanceled(); |
38 | | - TypeInfo ti = getTypeInfo(currentProgram, symbol.getAddress()); |
39 | | - try { |
40 | | - ti.validate(); |
41 | | - if (ti instanceof ClassTypeInfo) { |
42 | | - Vtable vtable = ((ClassTypeInfo) ti).getVtable(); |
43 | | - vtable.validate(); |
44 | | - vftables.add(vtable); |
45 | | - } |
46 | | - } catch (InvalidDataTypeException e) {} |
| 64 | + processVtable(vtable); |
47 | 65 | monitor.incrementProgress(1); |
48 | 66 | } |
49 | | - createClassReferences(vftables); |
| 67 | + println("Created "+Integer.toString(count)+" class variable references."); |
50 | 68 | } |
51 | 69 |
|
52 | | - private void createClassReferences(List<Vtable> vftables) throws Exception { |
53 | | - int count = 0; |
| 70 | + private void processVtable(Vtable vtable) throws Exception { |
| 71 | + Address vtableAddress = vtable.getTableAddresses()[0]; |
54 | 72 | ReferenceManager manager = currentProgram.getReferenceManager(); |
55 | | - Listing listing = currentProgram.getListing(); |
56 | | - monitor.initialize(vftables.size()); |
57 | | - monitor.setMessage("Setting variable datatypes"); |
58 | | - for (Vtable vtable : vftables) { |
| 73 | + for (Reference ref : manager.getReferencesTo(vtableAddress)) { |
59 | 74 | monitor.checkCanceled(); |
60 | | - Address vtableAddress = vtable.getTableAddresses()[0]; |
61 | | - VariableSetting: |
62 | | - for (Reference ref : manager.getReferencesTo(vtableAddress)) { |
63 | | - monitor.checkCanceled(); |
64 | | - if (manager.getReferencedVariable(ref) != null) { |
65 | | - Variable var = manager.getReferencedVariable(ref); |
66 | | - if (!(var.getDataType() instanceof Structure)) { |
67 | | - var.setDataType(vtable.getTypeInfo().getClassDataType(), |
68 | | - true, true, SourceType.ANALYSIS); |
69 | | - count++; |
70 | | - continue; |
71 | | - } |
72 | | - } |
73 | | - Instruction inst = listing.getInstructionAt(ref.getFromAddress()); |
74 | | - if (inst == null) { |
75 | | - continue; |
76 | | - } |
77 | | - Function function = listing.getFunctionContaining(inst.getAddress()); |
78 | | - if (function == null) { |
| 75 | + if (manager.getReferencedVariable(ref) != null) { |
| 76 | + Variable var = manager.getReferencedVariable(ref); |
| 77 | + if (!(var.getDataType() instanceof Structure)) { |
| 78 | + var.setDataType(vtable.getTypeInfo().getClassDataType(), |
| 79 | + true, true, SourceType.ANALYSIS); |
| 80 | + count++; |
79 | 81 | continue; |
80 | 82 | } |
81 | | - Object[] objects = inst.getInputObjects(); |
82 | | - if (!(objects[0] instanceof Register)) { |
83 | | - continue; |
| 83 | + } |
| 84 | + ReferenceProcessor processor = new ReferenceProcessor(vtable, ref); |
| 85 | + processor.process(); |
| 86 | + } |
| 87 | + } |
| 88 | + |
| 89 | + private class ReferenceProcessor { |
| 90 | + |
| 91 | + private final Vtable vtable; |
| 92 | + private Instruction inst; |
| 93 | + private Function function; |
| 94 | + |
| 95 | + ReferenceProcessor(Vtable vtable, Reference ref) { |
| 96 | + this.vtable = vtable; |
| 97 | + Listing listing = currentProgram.getListing(); |
| 98 | + this.inst = listing.getInstructionAt(ref.getFromAddress()); |
| 99 | + if (inst != null) { |
| 100 | + this.function = listing.getFunctionContaining(inst.getAddress()); |
| 101 | + } |
| 102 | + } |
| 103 | + |
| 104 | + void process() throws Exception { |
| 105 | + if (inst == null || function == null) { |
| 106 | + return; |
| 107 | + } |
| 108 | + ReferenceManager manager = currentProgram.getReferenceManager(); |
| 109 | + Reference[] refs = inst.getReferencesFrom(); |
| 110 | + Variable var = Arrays.stream(refs) |
| 111 | + .map(manager::getReferencedVariable) |
| 112 | + .filter(Objects::nonNull) |
| 113 | + .findFirst() |
| 114 | + .orElse(null); |
| 115 | + if (var != null) { |
| 116 | + DataType dt = vtable.getTypeInfo().getClassDataType(); |
| 117 | + DataType varDt = var.getDataType(); |
| 118 | + if (varDt.isEquivalent(dt) || varDt.dependsOn(dt)) { |
| 119 | + return; |
84 | 120 | } |
85 | | - Register register = (Register) objects[0]; |
86 | | - inst = inst.getNext(); |
87 | | - while (function.getBody().contains(inst.getAddress())) { |
88 | | - monitor.checkCanceled(); |
89 | | - if (inst.getRegister(0) != null && inst.getRegister(0).contains(register)) { |
90 | | - Reference[] refs = inst.getReferencesFrom(); |
91 | | - if (refs.length == 1 && !refs[0].isOffsetReference() && refs[0].isStackReference()) { |
92 | | - Variable var = manager.getReferencedVariable(refs[0]); |
93 | | - if (var != null) { |
94 | | - var.setDataType(vtable.getTypeInfo().getClassDataType(), |
95 | | - true, true, SourceType.ANALYSIS); |
96 | | - count++; |
97 | | - continue VariableSetting; |
98 | | - } |
99 | | - } |
100 | | - } |
101 | | - inst = inst.getNext(); |
| 121 | + var.setDataType(dt, true, true, SourceType.ANALYSIS); |
| 122 | + Address addr = var.getMinAddress(); |
| 123 | + if (addr != null) { |
| 124 | + String msg = String.format( |
| 125 | + "Set variable %s at %s to %s", |
| 126 | + var, inst.getAddress(), dt.getDataTypePath()); |
| 127 | + println(msg); |
102 | 128 | } |
| 129 | + count++; |
| 130 | + return; |
103 | 131 | } |
104 | | - monitor.incrementProgress(1); |
105 | 132 | } |
106 | | - println("Created "+Integer.toString(count)+" class variabled references."); |
107 | 133 | } |
108 | 134 | } |
0 commit comments