mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GP-4376 Updated gcc class recovery to allow for special typeinfos that
are not in program memory or external block. Also updated to add a check for unhandled relocations. Also updated to allow for non-mangled typeinfo-name strings.
This commit is contained in:
parent
3e35b4d4a7
commit
b04d5335ca
5 changed files with 318 additions and 128 deletions
|
@ -80,6 +80,7 @@ import ghidra.program.model.data.*;
|
|||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.reloc.Relocation;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.reloc.RelocationTable;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.util.GhidraProgramUtilities;
|
||||
|
@ -210,8 +211,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
|||
if (!runGcc) {
|
||||
return;
|
||||
}
|
||||
//run fixup old elf relocations script
|
||||
runScript("FixElfExternalOffsetDataRelocationScript.java");
|
||||
|
||||
recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, state.getTool(),
|
||||
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
|
||||
nameVfunctions, hasDebugSymbols, monitor);
|
||||
|
@ -232,9 +232,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
|||
return;
|
||||
}
|
||||
|
||||
//run fixup old elf relocations script
|
||||
runScript("FixElfExternalOffsetDataRelocationScript.java");
|
||||
|
||||
hasDebugSymbols = isDwarfLoadedInProgram();
|
||||
if (hasDwarf() && !hasDebugSymbols) {
|
||||
println(
|
||||
|
@ -379,7 +376,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
|||
DWARFProgram.DWARF_ROOT_NAME) || options.getBoolean("DWARF Loaded", false));
|
||||
}
|
||||
|
||||
public String validate() throws CancelledException {
|
||||
public String validate() throws Exception {
|
||||
|
||||
if (currentProgram == null) {
|
||||
return ("There is no open program");
|
||||
|
@ -417,6 +414,8 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
|||
// check that gcc loader or mingw analyzer has fixed the relocations correctly
|
||||
if (isGcc()) {
|
||||
|
||||
runScript("FixElfExternalOffsetDataRelocationScript.java");
|
||||
|
||||
// first check that there is even rtti by searching the special string in memory
|
||||
if (!isStringInProgramMemory("class_type_info")) {
|
||||
return ("This program does not contain RTTI.");
|
||||
|
@ -432,7 +431,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
|||
"contact the Ghidra team so this issue can be fixed.");
|
||||
}
|
||||
|
||||
if (hasUnhandledRelocations()) {
|
||||
if (hasRelocationIssue()) {
|
||||
return ("This program has unhandled elf relocations so cannot continue. Please " +
|
||||
"contact the Ghidra team for assistance.");
|
||||
}
|
||||
|
@ -442,7 +441,13 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
|||
|
||||
}
|
||||
|
||||
private boolean hasUnhandledRelocations() throws CancelledException {
|
||||
/**
|
||||
* Method to determine if the gcc relocations needed to find the special typeinfos/vtables
|
||||
* have any issues that would keep script from running correctly.
|
||||
* @return true if there are any issues with the relocations, false otherwise
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
private boolean hasRelocationIssue() throws CancelledException {
|
||||
|
||||
RelocationTable relocationTable = currentProgram.getRelocationTable();
|
||||
|
||||
|
@ -452,17 +457,39 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
|||
monitor.checkCancelled();
|
||||
Relocation r = relocations.next();
|
||||
|
||||
if (r.getSymbolName().contains("class_type_info") &&
|
||||
(r.getStatus() != Relocation.Status.APPLIED &&
|
||||
r.getStatus() != Relocation.Status.APPLIED_OTHER &&
|
||||
r.getStatus() != Relocation.Status.SKIPPED)) {
|
||||
return true;
|
||||
}
|
||||
String symbolName = r.getSymbolName();
|
||||
|
||||
if (symbolName != null && symbolName.contains("class_type_info")) {
|
||||
|
||||
Status status = r.getStatus();
|
||||
|
||||
// if any relocations for special typeinfo class symbols have failed then there
|
||||
// is an issue
|
||||
if (status == Status.FAILURE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// if any relocations for special typeinfo class symbols are unsupported then
|
||||
// determine where the symbol is located before determining if it is an issue
|
||||
if(status == Status.UNSUPPORTED) {
|
||||
|
||||
//if relocation symbol is the same as the symbol at the relcation address
|
||||
//then this situation is not an issue - it indicates a copy relocation at the
|
||||
//location of the special typeinfo vtable which is a use case that can be handled
|
||||
Address address = r.getAddress();
|
||||
Symbol symbolAtAddress = currentProgram.getSymbolTable().getSymbol(symbolName, address, currentProgram.getGlobalNamespace());
|
||||
if(symbolAtAddress != null) {
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private void analyzeProgramChanges(AddressSetView beforeChanges) throws Exception {
|
||||
|
||||
AddressSetView addressSet = currentProgram.getChanges().getAddressSet();
|
||||
|
|
|
@ -15,10 +15,7 @@
|
|||
*/
|
||||
package classrecovery;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
@ -30,7 +27,7 @@ public class GccTypeinfo extends Typeinfo {
|
|||
private static final String VMI_CLASS_TYPEINFO_NAMESPACE = "__vmi_class_type_info";
|
||||
|
||||
boolean isSpecialTypeinfo;
|
||||
GccTypeinfo inheritedSpecialTypeinfo = null;
|
||||
Namespace inheritedSpecialTypeinfoNamespace = null;
|
||||
Address vtableAddress;
|
||||
boolean inProgramMemory;
|
||||
String mangledNamespaceString = null;
|
||||
|
@ -53,13 +50,13 @@ public class GccTypeinfo extends Typeinfo {
|
|||
return inProgramMemory;
|
||||
}
|
||||
|
||||
public void setInheritedSpecialTypeinfo(GccTypeinfo specialTypeinfo) {
|
||||
inheritedSpecialTypeinfo = specialTypeinfo;
|
||||
public void setInheritedSpecialTypeinfoNamespace(Namespace specialTypeinfoNamespace) {
|
||||
inheritedSpecialTypeinfoNamespace = specialTypeinfoNamespace;
|
||||
}
|
||||
|
||||
|
||||
public GccTypeinfo getInheritedSpecialTypeinfo() {
|
||||
return inheritedSpecialTypeinfo;
|
||||
public Namespace getInheritedSpecialTypeinfoNamespace() {
|
||||
return inheritedSpecialTypeinfoNamespace;
|
||||
}
|
||||
|
||||
|
||||
|
@ -156,21 +153,21 @@ public class GccTypeinfo extends Typeinfo {
|
|||
}
|
||||
|
||||
public boolean isClassTypeinfo() {
|
||||
if(inheritedSpecialTypeinfo.getNamespace().getName().equals(CLASS_TYPEINFO_NAMESPACE)) {
|
||||
if (inheritedSpecialTypeinfoNamespace.getName().equals(CLASS_TYPEINFO_NAMESPACE)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isSiClassTypeinfo() {
|
||||
if(inheritedSpecialTypeinfo.getNamespace().getName().equals(SI_CLASS_TYPEINFO_NAMESPACE)) {
|
||||
if (inheritedSpecialTypeinfoNamespace.getName().equals(SI_CLASS_TYPEINFO_NAMESPACE)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isVmiClassTypeinfo() {
|
||||
if(inheritedSpecialTypeinfo.getNamespace().getName().equals(VMI_CLASS_TYPEINFO_NAMESPACE)) {
|
||||
if (inheritedSpecialTypeinfoNamespace.getName().equals(VMI_CLASS_TYPEINFO_NAMESPACE)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -19,6 +19,8 @@ package classrecovery;
|
|||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.app.cmd.label.DemanglerCmd;
|
||||
import ghidra.app.plugin.core.analysis.ReferenceAddressPair;
|
||||
import ghidra.app.util.NamespaceUtils;
|
||||
|
@ -101,6 +103,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
|
||||
protected final FunctionManager functionManager;
|
||||
protected final Listing listing;
|
||||
protected final Memory memory;
|
||||
|
||||
public RTTIGccClassRecoverer(Program program, ServiceProvider serviceProvider,
|
||||
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
||||
|
@ -113,6 +116,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
|
||||
functionManager = program.getFunctionManager();
|
||||
listing = program.getListing();
|
||||
|
||||
memory = program.getMemory();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -156,7 +162,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
List<GccTypeinfo> specialTypeinfos = createSpecialTypeinfos();
|
||||
if (specialTypeinfos.isEmpty()) {
|
||||
Msg.debug(this, "Could not create special typeinfos");
|
||||
return null;
|
||||
}
|
||||
|
||||
Msg.debug(this, "Creating Special Vtables");
|
||||
|
@ -169,7 +174,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
|
||||
if (specialVtables.size() != specialTypeinfos.size()) {
|
||||
Msg.debug(this, "Not equal number of special vtables and special typeinfos");
|
||||
return null;
|
||||
}
|
||||
|
||||
setComponentOffset();
|
||||
|
@ -355,7 +359,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
// in a non-loaded section that isn't real memory then it shouldn't be the case where the
|
||||
// typeinfo is at the same location as the vtable since it should have enough memory and
|
||||
// real bytes that point to a real typeinfo in program memory
|
||||
if (hasAssociatedFileByes(vtableAddress)) {
|
||||
if (isLoadedAndInitializedMemory(vtableAddress)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -381,7 +385,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
|
||||
}
|
||||
|
||||
private boolean hasAssociatedFileByes(Address address) {
|
||||
private boolean isLoadedAndInitializedMemory(Address address) {
|
||||
|
||||
if (inExternalBlock(address)) {
|
||||
return false;
|
||||
|
@ -391,9 +395,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
}
|
||||
Memory memory = program.getMemory();
|
||||
|
||||
long fileOffset = memory.getAddressSourceInfo(address).getFileOffset();
|
||||
if (fileOffset == -1) {
|
||||
return false;
|
||||
AddressSetView initMem = memory.getLoadedAndInitializedAddressSet();
|
||||
if (initMem.contains(address)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -451,7 +455,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
return null;
|
||||
}
|
||||
|
||||
// TODO: can this be used for regular ones too?
|
||||
private Symbol findTypeinfoSymbolUsingMangledNamespaceString(String mangledNamespace,
|
||||
String namespaceName) throws CancelledException {
|
||||
|
||||
|
@ -2220,6 +2223,19 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
|
||||
SpecialVtable specialVtable = new SpecialVtable(program, vtableAddress, typeinfoRef,
|
||||
isExternal, vtableSymbol.getParentNamespace(), monitor);
|
||||
|
||||
if (specialTypeinfo != null) {
|
||||
specialTypeinfo.setVtableAddress(vtableAddress);
|
||||
}
|
||||
|
||||
if (!specialVtable.isExternal()) {
|
||||
specialVtable.applyVtableData();
|
||||
vtableToSizeMap.put(specialVtable.getAddress(), specialVtable.getLength());
|
||||
createVtableLabel(specialVtable);
|
||||
createVtableComment(specialVtable);
|
||||
createVfunctionSymbol(specialVtable);
|
||||
}
|
||||
|
||||
return specialVtable;
|
||||
}
|
||||
|
||||
|
@ -2362,9 +2378,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
|
||||
typeinfoSymbol = createDemangledTypeinfoSymbol(typeinfoAddress);
|
||||
if (typeinfoSymbol == null) {
|
||||
Msg.debug(this, "Could not create demangled typeinfo symbol at " +
|
||||
typeinfoAddress.toString());
|
||||
continue;
|
||||
//If no mangled class name, check for non-mangled pascal type class name
|
||||
typeinfoSymbol =
|
||||
createTypeinfoSymbolFromNonMangledString(typeinfoAddress);
|
||||
if (typeinfoSymbol == null) {
|
||||
Msg.debug(this, "Could not create typeinfo symbol at " +
|
||||
typeinfoAddress.toString());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2374,9 +2395,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
if (specialTypeinfoNamespaceName == null) {
|
||||
continue;
|
||||
}
|
||||
GccTypeinfo specialTypeinfo =
|
||||
getTypeinfo(specialTypeinfoNamespaceName, specialTypeinfos);
|
||||
typeinfo.setInheritedSpecialTypeinfo(specialTypeinfo);
|
||||
|
||||
typeinfo.setInheritedSpecialTypeinfoNamespace(specialVtable.getNamespace());
|
||||
|
||||
typeinfos.add(typeinfo);
|
||||
continue;
|
||||
}
|
||||
|
@ -2390,7 +2411,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
for (GccTypeinfo typeinfo : typeinfos) {
|
||||
monitor.checkCancelled();
|
||||
Address typeinfoAddress = typeinfo.getAddress();
|
||||
if (typeinfo.getInheritedSpecialTypeinfo() == null) {
|
||||
if (typeinfo.getInheritedSpecialTypeinfoNamespace() == null) {
|
||||
|
||||
typeinfosToRemove.add(typeinfo);
|
||||
continue;
|
||||
|
@ -2436,9 +2457,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
continue;
|
||||
}
|
||||
|
||||
// TODO: update the typeinfo with the correct namespace based on the structure
|
||||
|
||||
String namespaceName = typeinfo.getInheritedSpecialTypeinfo().getNamespace().getName();
|
||||
String namespaceName = typeinfo.getInheritedSpecialTypeinfoNamespace().getName();
|
||||
|
||||
// if typeinfo inherits class_type_info then no Base to update
|
||||
if (namespaceName.equals(CLASS_TYPEINFO_NAMESPACE)) {
|
||||
|
@ -2652,6 +2671,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
|
||||
// ok if has symbol at the actual addr so don't check it
|
||||
if (offset == 0) {
|
||||
offset++;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2848,6 +2868,103 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
return newSymbol;
|
||||
}
|
||||
|
||||
|
||||
private Symbol createTypeinfoSymbolFromNonMangledString(Address typeinfoAddress)
|
||||
throws DuplicateNameException, InvalidInputException, CancelledException {
|
||||
|
||||
Address typeinfoNameAddress = getTypeinfoNameAddress(typeinfoAddress);
|
||||
|
||||
if (typeinfoNameAddress == null) {
|
||||
Msg.debug(this,
|
||||
"Could not get typeinfo-name address from " + typeinfoAddress.toString());
|
||||
return null;
|
||||
}
|
||||
|
||||
String typeinfoNameString = getStringFromMemory(typeinfoNameAddress);
|
||||
|
||||
if (typeinfoNameString == null) {
|
||||
Msg.debug(this, "Could not get typeinfo string from " + typeinfoNameAddress.toString());
|
||||
return null;
|
||||
}
|
||||
|
||||
// get length from start of string
|
||||
String lenString = getAsciiLengthString(typeinfoNameString);
|
||||
if (lenString.isEmpty()) {
|
||||
Msg.debug(this,
|
||||
"Could not get typeinfo-name string len from " + typeinfoNameAddress.toString());
|
||||
return null;
|
||||
}
|
||||
|
||||
// convert lenString to int len
|
||||
try {
|
||||
int len = Integer.parseInt(lenString);
|
||||
|
||||
// get className from string - if not exactly the correct len then return null
|
||||
String className = typeinfoNameString.substring(lenString.length());
|
||||
if (className.length() != len) {
|
||||
Msg.debug(this, "Expected typeinfo-name to be len " + len + " but it was " +
|
||||
className.length());
|
||||
return null;
|
||||
}
|
||||
|
||||
program.getListing()
|
||||
.clearCodeUnits(typeinfoNameAddress,
|
||||
typeinfoNameAddress.add(typeinfoNameString.length()), true);
|
||||
boolean created = createString(typeinfoNameAddress, typeinfoNameString.length());
|
||||
if (!created) {
|
||||
Msg.debug(this, "Could not create string at " + typeinfoNameAddress);
|
||||
}
|
||||
|
||||
// create typeinfo name symbol
|
||||
Namespace classNamespace =
|
||||
symbolTable.getOrCreateNameSpace(globalNamespace, className, SourceType.ANALYSIS);
|
||||
Symbol typeinfoNameSymbol = symbolTable.createLabel(typeinfoNameAddress,
|
||||
"typeinfo-name", classNamespace, SourceType.ANALYSIS);
|
||||
typeinfoNameSymbol.setPrimary();
|
||||
|
||||
// create the new typeinfo symbol in the demangled namespace
|
||||
Symbol typeinfoSymbol = symbolTable.createLabel(typeinfoAddress, "typeinfo",
|
||||
classNamespace, SourceType.ANALYSIS);
|
||||
typeinfoSymbol.setPrimary();
|
||||
|
||||
api.setPlateComment(typeinfoAddress, "typeinfo for " + classNamespace.getName(true));
|
||||
|
||||
return typeinfoSymbol;
|
||||
}
|
||||
catch (NumberFormatException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String getAsciiLengthString(String string) throws CancelledException {
|
||||
|
||||
boolean isDigit = true;
|
||||
int len = 0;
|
||||
String lenString = new String();
|
||||
while (isDigit) {
|
||||
monitor.checkCancelled();
|
||||
String charString = string.substring(len, len);
|
||||
if (!StringUtils.isNumeric(charString)) {
|
||||
return lenString;
|
||||
}
|
||||
lenString.concat(charString);
|
||||
len++;
|
||||
}
|
||||
return lenString;
|
||||
}
|
||||
|
||||
private boolean isAllAscii(Address address, int len) throws CancelledException {
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
monitor.checkCancelled();
|
||||
|
||||
if (!isAscii(address.add(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isTypeinfoNameString(String string) {
|
||||
|
||||
DemangledObject demangledObject = DemanglerUtil.demangle(string);
|
||||
|
@ -2934,6 +3051,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
|
||||
}
|
||||
|
||||
private String getStringFromMemory(Address address, int len) {
|
||||
|
||||
TerminatedStringDataType sdt = new TerminatedStringDataType();
|
||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), address);
|
||||
return (String) sdt.getValue(buf, sdt.getDefaultSettings(), len);
|
||||
|
||||
}
|
||||
|
||||
private int getStringLen(Address addr) {
|
||||
|
||||
int len = 0;
|
||||
|
@ -3544,80 +3669,91 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
|
||||
}
|
||||
|
||||
private Address findSpecialVtable(GccTypeinfo specialTypeinfo,
|
||||
List<GccTypeinfo> specialTypeinfos) throws CancelledException {
|
||||
|
||||
String namespaceName = specialTypeinfo.getNamespace().getName();
|
||||
String mangledNamespaceString = specialTypeinfo.getMangledNamespaceString();
|
||||
|
||||
// try finding with normal symbol name and namespace
|
||||
Symbol vtableSymbol =
|
||||
getSymbolInNamespaces(SPECIAL_CLASS_NAMESPACE, namespaceName, VTABLE_LABEL);
|
||||
if (vtableSymbol == null) {
|
||||
// then try finding with mangled symbol
|
||||
vtableSymbol =
|
||||
findAndReturnDemangledSymbol(MANGLED_VTABLE_PREFIX + mangledNamespaceString,
|
||||
SPECIAL_CLASS_NAMESPACE, namespaceName, VTABLE_LABEL);
|
||||
|
||||
// then try finding top of special vtable by finding ref to special typeinfo
|
||||
if (vtableSymbol == null) {
|
||||
Address vtableAddress = findSpecialVtableUsingSpecialTypeinfo(
|
||||
specialTypeinfo.getAddress(), specialTypeinfos);
|
||||
|
||||
if (vtableAddress == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
vtableSymbol = symbolTable.createLabel(vtableAddress, VTABLE_LABEL,
|
||||
specialTypeinfo.getNamespace(), SourceType.ANALYSIS);
|
||||
api.setPlateComment(vtableAddress,
|
||||
"vtable for " + specialTypeinfo.getNamespace());
|
||||
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (vtableSymbol != null) {
|
||||
return vtableSymbol.getAddress();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<SpecialVtable> findSpecialVtables(List<GccTypeinfo> specialTypeinfos)
|
||||
throws Exception {
|
||||
|
||||
List<SpecialVtable> specialVtables = new ArrayList<SpecialVtable>();
|
||||
|
||||
for (GccTypeinfo specialTypeinfo : specialTypeinfos) {
|
||||
monitor.checkCancelled();
|
||||
Map<String, String> namespaceMap = new HashMap<String, String>();
|
||||
namespaceMap.put(CLASS_TYPEINFO_NAMESPACE, MANGLED_CLASS_TYPEINFO_NAMESPACE);
|
||||
namespaceMap.put(SI_CLASS_TYPEINFO_NAMESPACE, MANGLED_SI_CLASS_TYPEINFO_NAMESPACE);
|
||||
namespaceMap.put(VMI_CLASS_TYPEINFO_NAMESPACE, MANGLED_VMI_CLASS_TYPEINFO_NAMESPACE);
|
||||
|
||||
Address vtableAddress = findSpecialVtable(specialTypeinfo, specialTypeinfos);
|
||||
for (String namespaceName : namespaceMap.keySet()) {
|
||||
|
||||
GccTypeinfo specTypeinfo = getSpecialTypeinfo(specialTypeinfos, namespaceName);
|
||||
|
||||
Address vtableAddress = findSpecialVtableAddress(namespaceName,
|
||||
namespaceMap.get(namespaceName), specialTypeinfos);
|
||||
if (vtableAddress == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SpecialVtable specialVtable = createSpecialVtable(vtableAddress, specialTypeinfo);
|
||||
if (specialVtable != null) {
|
||||
specialVtables.add(specialVtable);
|
||||
specialTypeinfo.setVtableAddress(vtableAddress);
|
||||
if (!specialVtable.isExternal()) {
|
||||
specialVtable.applyVtableData();
|
||||
vtableToSizeMap.put(specialVtable.getAddress(), specialVtable.getLength());
|
||||
createVtableLabel(specialVtable);
|
||||
createVtableComment(specialVtable);
|
||||
createVfunctionSymbol(specialVtable);
|
||||
}
|
||||
}
|
||||
SpecialVtable specialVtable =
|
||||
createSpecialVtable(vtableAddress, specTypeinfo);
|
||||
specialVtables.add(specialVtable);
|
||||
|
||||
}
|
||||
return specialVtables;
|
||||
}
|
||||
|
||||
private Address findSpecialVtableAddress(String namespaceName, String mangledNamespace,
|
||||
List<GccTypeinfo> specialTypeinfos) throws CancelledException {
|
||||
|
||||
//First try to find with special symbols
|
||||
Symbol vtableSymbol = getSymbolInNamespaces(namespaceName, mangledNamespace, VTABLE_LABEL);
|
||||
|
||||
if (vtableSymbol != null) {
|
||||
return vtableSymbol.getAddress();
|
||||
|
||||
}
|
||||
|
||||
// then try finding with mangled symbol
|
||||
vtableSymbol = findAndReturnDemangledSymbol(MANGLED_VTABLE_PREFIX + mangledNamespace,
|
||||
SPECIAL_CLASS_NAMESPACE, namespaceName, VTABLE_LABEL);
|
||||
if (vtableSymbol != null) {
|
||||
return vtableSymbol.getAddress();
|
||||
}
|
||||
|
||||
//Then with special typeinfo if there is one
|
||||
GccTypeinfo specTypeinfo = getSpecialTypeinfo(specialTypeinfos, namespaceName);
|
||||
|
||||
if (specTypeinfo != null) {
|
||||
Address vtableAddress = findSpecialVtableUsingSpecialTypeinfo(specTypeinfo.getAddress(),
|
||||
specialTypeinfos);
|
||||
if (vtableAddress == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
vtableSymbol = symbolTable.createLabel(vtableAddress, VTABLE_LABEL,
|
||||
specTypeinfo.getNamespace(), SourceType.ANALYSIS);
|
||||
api.setPlateComment(vtableAddress, "vtable for " + specTypeinfo.getNamespace());
|
||||
return vtableSymbol.getAddress();
|
||||
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.warn(this,
|
||||
"Found vtable at " + vtableAddress + " but cannot create symbol" + e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private GccTypeinfo getSpecialTypeinfo(List<GccTypeinfo> specialTypeinfos,
|
||||
String namespaceName) {
|
||||
|
||||
for (GccTypeinfo specialTypeinfo : specialTypeinfos) {
|
||||
|
||||
if (specialTypeinfo.getNamespace().getName().equals(namespaceName)) {
|
||||
return specialTypeinfo;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Method to find special vtable using special typeinfo references. This
|
||||
* assumption that vtable is defaultPtrSize above ref to single specialTypeinfo
|
||||
|
|
|
@ -15,9 +15,15 @@
|
|||
*/
|
||||
package classrecovery;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.reloc.Relocation;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.reloc.RelocationTable;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
|
@ -47,6 +53,19 @@ public class SpecialVtable extends Vtable {
|
|||
|
||||
typeinfoRefAddress = vtableAddress.add(defaultPointerSize);
|
||||
|
||||
// check for vtable has memory but all zeros or has possible invalid values which in both
|
||||
// cases would make the pointer to special typeinfo invalid
|
||||
if (hasSpecialCopyUnhandledRelocation(vtableAddress)) {
|
||||
isConstruction = false;
|
||||
isPrimary = true;
|
||||
typeinfoAddress = null;
|
||||
length = 3 * defaultPointerSize; //actually prob 11*defPtr but are all zeros in this case
|
||||
hasVfunctions = true; // they are null though so will count as num=0, need this to be true so check for refs to vfunction top will work
|
||||
numVfunctions = 0;
|
||||
vfunctionTop = vtableAddress.add(2 * defaultPointerSize);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
setTypeinfoAddress();
|
||||
|
||||
|
@ -71,7 +90,9 @@ public class SpecialVtable extends Vtable {
|
|||
|
||||
isConstruction = false;
|
||||
|
||||
classNamespace = typeinfoNamespace;
|
||||
if (classNamespace == null) {
|
||||
classNamespace = typeinfoNamespace;
|
||||
}
|
||||
|
||||
|
||||
setLength();
|
||||
|
@ -82,4 +103,34 @@ public class SpecialVtable extends Vtable {
|
|||
return refFromTypeinfos;
|
||||
}
|
||||
|
||||
private boolean hasSpecialCopyUnhandledRelocation(Address address) {
|
||||
|
||||
RelocationTable relocationTable = program.getRelocationTable();
|
||||
|
||||
List<Relocation> relocations = relocationTable.getRelocations(address);
|
||||
|
||||
for (Relocation relocation : relocations) {
|
||||
|
||||
Status status = relocation.getStatus();
|
||||
if (status == Status.UNSUPPORTED) {
|
||||
|
||||
String symbolName = relocation.getSymbolName();
|
||||
|
||||
if (symbolName == null || !symbolName.contains("class_type_info")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//if relocation symbol is the same as the symbol at the relcation address
|
||||
//then this situation is not an issue - it indicates a copy relocation at the
|
||||
//location of the special typeinfo vtable which is a use case that can be handled
|
||||
Symbol symbolAtAddress = program.getSymbolTable()
|
||||
.getSymbol(symbolName, address, program.getGlobalNamespace());
|
||||
if (symbolAtAddress != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -80,7 +80,9 @@ public class Vtable {
|
|||
this.monitor = monitor;
|
||||
this.typeinfoRefAddress = typeinfoRef.getAddress();
|
||||
this.typeinfo = (GccTypeinfo) typeinfoRef.getReferencedTypeinfo();
|
||||
this.typeinfoNamespace = typeinfo.getNamespace();
|
||||
if (this.typeinfo != null) {
|
||||
this.typeinfoNamespace = typeinfo.getNamespace();
|
||||
}
|
||||
|
||||
AddressSpace addressSpace = vtableAddress.getAddressSpace();
|
||||
defaultPointerSize = addressSpace.getPointerSize();
|
||||
|
@ -390,9 +392,6 @@ public class Vtable {
|
|||
*/
|
||||
private boolean isPossibleFunctionPointer(Address address) throws CancelledException {
|
||||
|
||||
// TODO: make one that works for all casea in helper
|
||||
// TODO: make sure it recognizes the external functions
|
||||
|
||||
long longValue = extendedFlatAPI.getLongValueAt(address);
|
||||
|
||||
Register lowBitCodeMode = program.getRegister("LowBitCodeMode");
|
||||
|
@ -606,26 +605,6 @@ public class Vtable {
|
|||
return internalVtables;
|
||||
}
|
||||
|
||||
|
||||
// TODO: put in helper or ext api
|
||||
private boolean inExternalBlock(Address address) {
|
||||
|
||||
MemoryBlock externalBlock = getExternalBlock();
|
||||
if (externalBlock == null) {
|
||||
return false;
|
||||
}
|
||||
if (externalBlock.contains(address)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
private MemoryBlock getExternalBlock() {
|
||||
return program.getMemory().getBlock("EXTERNAL");
|
||||
}
|
||||
|
||||
|
||||
public void setIsConstructionVtable(Boolean setting) {
|
||||
isConstruction = setting;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue