mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GP-141 handle non-standard RTTI type_info
This commit is contained in:
parent
4300bec382
commit
0f6d3cbc35
9 changed files with 332 additions and 122 deletions
|
@ -30,6 +30,7 @@ import ghidra.util.datastruct.ListAccumulator;
|
|||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
import utility.function.TerminatingConsumer;
|
||||
|
||||
/**
|
||||
* <CODE>ProgramMemoryUtil</CODE> contains some static methods for
|
||||
|
@ -725,7 +726,7 @@ public class ProgramMemoryUtil {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds the string in memory indicated by the searchString limited to the indicated
|
||||
* memory blocks and address set.
|
||||
|
@ -740,9 +741,36 @@ public class ProgramMemoryUtil {
|
|||
public static List<Address> findString(String searchString, Program program,
|
||||
List<MemoryBlock> blocks, AddressSetView set, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
|
||||
List<Address> addresses = new ArrayList<>();
|
||||
|
||||
// just add each found location to the list, no termination of search
|
||||
TerminatingConsumer<Address> collector = (i) -> addresses.add(i);
|
||||
|
||||
locateString(searchString, collector, program, blocks, set, monitor);
|
||||
|
||||
return addresses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the string in memory indicated by the searchString limited to the indicated
|
||||
* memory blocks and address set. Each found location calls the foundLocationConsumer.consume(addr)
|
||||
* method. If the search should terminate, (ie. enough results found), then terminateRequested() should
|
||||
* return true. Requesting termination is different than a cancellation from the task monitor.
|
||||
*
|
||||
* @param searchString the string to find
|
||||
* @param foundLocationConsumer location consumer with consumer.accept(Address addr) routine defined
|
||||
* @param program the program to search
|
||||
* @param blocks the only blocks to search
|
||||
* @param set a set of the addresses to limit the results
|
||||
* @param monitor a task monitor to allow
|
||||
* @throws CancelledException if the user cancels
|
||||
*/
|
||||
public static void locateString(String searchString, TerminatingConsumer<Address> foundLocationConsumer, Program program,
|
||||
List<MemoryBlock> blocks, AddressSetView set, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
|
||||
monitor.setMessage("Finding \"" + searchString + "\".");
|
||||
List<Address> addresses = new ArrayList<>();
|
||||
int length = searchString.length();
|
||||
byte[] bytes = searchString.getBytes();
|
||||
Memory memory = program.getMemory();
|
||||
|
@ -759,7 +787,10 @@ public class ProgramMemoryUtil {
|
|||
break; // no more found in block.
|
||||
}
|
||||
if (set.contains(foundAddress)) {
|
||||
addresses.add(foundAddress);
|
||||
foundLocationConsumer.accept(foundAddress);
|
||||
if (foundLocationConsumer.terminationRequested()) {
|
||||
return; // termination of search requested
|
||||
}
|
||||
}
|
||||
try {
|
||||
startAddress = foundAddress.add(length);
|
||||
|
@ -770,7 +801,6 @@ public class ProgramMemoryUtil {
|
|||
}
|
||||
while (startAddress.compareTo(endAddress) <= 0);
|
||||
}
|
||||
return addresses;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,10 +25,15 @@ import ghidra.program.model.address.*;
|
|||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.UndefinedValueException;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.mem.DumbMemBufferImpl;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.model.util.AddressSetPropertyMap;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import mdemangler.*;
|
||||
import mdemangler.datatype.MDDataType;
|
||||
import mdemangler.datatype.complex.MDComplexType;
|
||||
|
@ -248,15 +253,18 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel {
|
|||
* @return true if the data type has a vf table pointer. Otherwise, it has a hash value.
|
||||
*/
|
||||
private static boolean hasVFPointer(Program program) {
|
||||
// Should be true when 64 bit or RTTI.
|
||||
if (MSDataTypeUtils.is64Bit(program)) {
|
||||
|
||||
Address typeInfoVftableAddress = null;
|
||||
try {
|
||||
typeInfoVftableAddress = RttiUtil.findTypeInfoVftableAddress(program, TaskMonitor.DUMMY);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
throw new AssertException(e);
|
||||
}
|
||||
if (typeInfoVftableAddress != null) {
|
||||
return true;
|
||||
}
|
||||
Address address = RttiUtil.getTypeInfoTypeDescriptorAddress(program);
|
||||
if (address == null) {
|
||||
return false;
|
||||
}
|
||||
return RttiUtil.isTypeInfoTypeDescriptorAddress(program, address);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -350,9 +358,11 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel {
|
|||
throw new UndefinedValueException(
|
||||
"No vf table pointer is defined for this TypeDescriptor model.");
|
||||
}
|
||||
|
||||
Address vfTableAddress;
|
||||
// component 0 is either vf table pointer or hash value.
|
||||
Address vfTableAddress =
|
||||
EHDataTypeUtilities.getAddress(getDataType(), VF_TABLE_OR_HASH_ORDINAL, getMemBuffer());
|
||||
vfTableAddress = EHDataTypeUtilities.getAddress(getDataType(), VF_TABLE_OR_HASH_ORDINAL, getMemBuffer());
|
||||
|
||||
return vfTableAddress.getOffset() != 0 ? vfTableAddress : null;
|
||||
}
|
||||
|
||||
|
|
|
@ -187,7 +187,7 @@ public class CreateVfTableBackgroundCmd extends AbstractCreateDataBackgroundCmd<
|
|||
|
||||
// Create functions that are referred to by the vf table.
|
||||
if (applyOptions.shouldCreateFunction()) {
|
||||
int elementCount = model.getCount();
|
||||
int elementCount = model.getElementCount();
|
||||
for (int tableElementIndex = 0; tableElementIndex < elementCount; tableElementIndex++) {
|
||||
monitor.checkCanceled();
|
||||
Address vfPointer = model.getVirtualFunctionPointer(tableElementIndex);
|
||||
|
|
|
@ -15,16 +15,14 @@
|
|||
*/
|
||||
package ghidra.app.cmd.data.rtti;
|
||||
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAbsoluteAddress;
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.cmd.data.TypeDescriptorModel;
|
||||
import ghidra.app.util.NamespaceUtils;
|
||||
import ghidra.app.util.PseudoDisassembler;
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.MemoryByteProvider;
|
||||
import ghidra.app.util.datatype.microsoft.MSDataTypeUtils;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.listing.GhidraClass;
|
||||
|
@ -34,20 +32,23 @@ import ghidra.program.model.mem.MemoryBlock;
|
|||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.util.ProgramMemoryUtil;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import utility.function.TerminatingConsumer;
|
||||
|
||||
/**
|
||||
* RttiUtil provides constants and static methods for processing RTTI information.
|
||||
*/
|
||||
public class RttiUtil {
|
||||
|
||||
private static final String TYPE_INFO_NAMESPACE = "type_info";
|
||||
private static final int MIN_MATCHING_VFTABLE_PTRS = 5;
|
||||
static final String CONST_PREFIX = "const ";
|
||||
public static final String TYPE_INFO_STRING = ".?AVtype_info@@";
|
||||
|
||||
public static final String TYPE_INFO_LABEL = "class_type_info_RTTI_Type_Descriptor";
|
||||
private static final String MANGLED_TYPE_INFO_SYMBOL = "??_R0?AVtype_info@@@8";
|
||||
public static final String TYPE_INFO_STRING = ".?AVtype_info@@";
|
||||
private static final String CLASS_PREFIX_CHARS = ".?A";
|
||||
private static Map<Program, Address> vftableMap = new WeakHashMap<>();
|
||||
|
||||
private RttiUtil() {
|
||||
// utility class; can't create
|
||||
|
@ -151,6 +152,12 @@ public class RttiUtil {
|
|||
: false) {
|
||||
break; // Not pointing to text section.
|
||||
}
|
||||
|
||||
// any references after the first one ends the table
|
||||
if (tableSize > 0 && program.getReferenceManager().hasReferencesTo(currentVfPointerAddress)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pseudoDisassembler.isValidSubroutine(referencedAddress, true)) {
|
||||
break; // Not pointing to possible function.
|
||||
}
|
||||
|
@ -178,63 +185,185 @@ public class RttiUtil {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the address of the base type_info structure in the provided program.
|
||||
* The descriptor will only be manually located if {@value TYPE_INFO_STRING} is present.
|
||||
* @param program the program
|
||||
* @return the address of the type_info structure or null if not found
|
||||
* Identify common TypeInfo address through examination of discovered VtTables
|
||||
*/
|
||||
public static Address getTypeInfoTypeDescriptorAddress(Program program) {
|
||||
SymbolTable table = program.getSymbolTable();
|
||||
List<Symbol> symbols = table.getGlobalSymbols(TYPE_INFO_LABEL);
|
||||
if (symbols.isEmpty()) {
|
||||
symbols = table.getGlobalSymbols(MANGLED_TYPE_INFO_SYMBOL);
|
||||
private static class CommonRTTIMatchCounter implements TerminatingConsumer<Address> {
|
||||
int matchingAddrCount = 0;
|
||||
int defaultPointerSize = 4;
|
||||
boolean terminationRequest = false;
|
||||
Address commonVftableAddress = null;
|
||||
Program program;
|
||||
|
||||
public CommonRTTIMatchCounter(Program program) {
|
||||
this.program = program;
|
||||
defaultPointerSize = program.getDefaultPointerSize();
|
||||
}
|
||||
if (!symbols.isEmpty()) {
|
||||
for (Symbol symbol : symbols) {
|
||||
if (isTypeInfoTypeDescriptorAddress(program, symbol.getAddress())) {
|
||||
return symbol.getAddress();
|
||||
}
|
||||
}
|
||||
|
||||
public Address getinfoVfTable() {
|
||||
return commonVftableAddress;
|
||||
}
|
||||
return locateTypeInfoAddress(program);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the provided address is a TypeDescriptor containing the
|
||||
* {@value TYPE_INFO_STRING} component
|
||||
* @param program the program
|
||||
* @param address the descriptor address
|
||||
* @return true if {@value TYPE_INFO_STRING} is present in the descriptor at the address
|
||||
*/
|
||||
public static boolean isTypeInfoTypeDescriptorAddress(Program program, Address address) {
|
||||
MemoryByteProvider provider = new MemoryByteProvider(program.getMemory(), address);
|
||||
try {
|
||||
BinaryReader reader = new BinaryReader(provider, !program.getLanguage().isBigEndian());
|
||||
String value = reader.readAsciiString(program.getDefaultPointerSize() * 2);
|
||||
return TYPE_INFO_STRING.equals(value);
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
@Override
|
||||
public boolean terminationRequested() {
|
||||
return terminationRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Address foundAddress) {
|
||||
Address mangledClassNameAddress = foundAddress;
|
||||
|
||||
Address pointerToTypeInfoVftable =
|
||||
mangledClassNameAddress.subtract(2 * defaultPointerSize);
|
||||
|
||||
Address possibleVftableAddress =
|
||||
MSDataTypeUtils.getAbsoluteAddress(program, pointerToTypeInfoVftable);
|
||||
if (possibleVftableAddress == null) {
|
||||
return; // valid address not found
|
||||
}
|
||||
if (possibleVftableAddress.getOffset() == 0) {
|
||||
return; // don't want zero_address to count
|
||||
}
|
||||
// if ever we find one that doesn't match, start count over
|
||||
if (!possibleVftableAddress.equals(commonVftableAddress)) {
|
||||
if (matchingAddrCount > 2) {
|
||||
return; // already have more than one match, assume this one was outlier, ignore
|
||||
}
|
||||
matchingAddrCount = 0;
|
||||
}
|
||||
|
||||
commonVftableAddress = possibleVftableAddress;
|
||||
matchingAddrCount++;
|
||||
|
||||
if (matchingAddrCount > MIN_MATCHING_VFTABLE_PTRS) {
|
||||
// done finding good addresses have at Minimum matching number
|
||||
terminationRequest = true;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static Address locateTypeInfoAddress(Program program) {
|
||||
Memory memory = program.getMemory();
|
||||
try {
|
||||
List<MemoryBlock> dataBlocks = ProgramMemoryUtil.getMemoryBlocksStartingWithName(
|
||||
program, program.getMemory(), ".data", TaskMonitor.DUMMY);
|
||||
for (MemoryBlock memoryBlock : dataBlocks) {
|
||||
Address typeInfoAddress =
|
||||
memory.findBytes(memoryBlock.getStart(), memoryBlock.getEnd(),
|
||||
TYPE_INFO_STRING.getBytes(), null, true, TaskMonitor.DUMMY);
|
||||
if (typeInfoAddress != null) {
|
||||
return TypeDescriptorModel.getBaseAddress(program, typeInfoAddress);
|
||||
}
|
||||
}
|
||||
} catch (CancelledException e) {
|
||||
// impossible
|
||||
throw new AssertException(e);
|
||||
/**
|
||||
* Method to figure out the type_info vftable address using pointed to value by all RTTI classes
|
||||
* @param program the current program
|
||||
* @param monitor the TaskMonitor
|
||||
* @return the type_info address or null if it cannot be determined
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
public static Address findTypeInfoVftableAddress(Program program, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
|
||||
// Checked for cached value
|
||||
if (vftableMap.containsKey(program)) {
|
||||
return vftableMap.get(program);
|
||||
}
|
||||
|
||||
// if type info vftable already a symbol, just use the address of the symbol
|
||||
Address infoVftableAddress = findTypeInfoVftableLabel(program);
|
||||
if (infoVftableAddress == null) {
|
||||
|
||||
// search for mangled class prefix names, and locate the vftable pointer relative to some
|
||||
// minimum number that all point to the same location which should be the vftable
|
||||
AddressSetView set = program.getMemory().getLoadedAndInitializedAddressSet();
|
||||
List<MemoryBlock> dataBlocks =
|
||||
ProgramMemoryUtil.getMemoryBlocksStartingWithName(program, set, ".data", monitor);
|
||||
|
||||
CommonRTTIMatchCounter vfTableAddrChecker = new CommonRTTIMatchCounter(program);
|
||||
|
||||
ProgramMemoryUtil.locateString(CLASS_PREFIX_CHARS, vfTableAddrChecker, program,
|
||||
dataBlocks, set, monitor);
|
||||
infoVftableAddress = vfTableAddrChecker.getinfoVfTable();
|
||||
}
|
||||
|
||||
// cache result of search
|
||||
vftableMap.put(program, infoVftableAddress);
|
||||
|
||||
return infoVftableAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* find type info vftable by existing type_info::vftable symbol
|
||||
* @param program program to check
|
||||
* @return return vftable addr if symbol exists
|
||||
*/
|
||||
private static Address findTypeInfoVftableLabel(Program program) {
|
||||
SymbolTable symbolTable = program.getSymbolTable();
|
||||
Namespace typeinfoNamespace =
|
||||
symbolTable.getNamespace(TYPE_INFO_NAMESPACE, program.getGlobalNamespace());
|
||||
Symbol vftableSymbol =
|
||||
symbolTable.getLocalVariableSymbol("vftable", typeinfoNamespace);
|
||||
if (vftableSymbol != null) {
|
||||
return vftableSymbol.getAddress();
|
||||
}
|
||||
|
||||
vftableSymbol = symbolTable.getLocalVariableSymbol("`vftable'", typeinfoNamespace);
|
||||
if (vftableSymbol != null) {
|
||||
return vftableSymbol.getAddress();
|
||||
}
|
||||
|
||||
vftableSymbol = symbolTable.getLocalVariableSymbol("type_info", typeinfoNamespace);
|
||||
if (vftableSymbol != null) {
|
||||
return vftableSymbol.getAddress();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create type_info vftable label (and namespace if needed) at the given address
|
||||
* @param program the current program
|
||||
* @param address the given address
|
||||
*/
|
||||
public static void createTypeInfoVftableSymbol(Program program, Address address) {
|
||||
|
||||
SymbolTable symbolTable = program.getSymbolTable();
|
||||
|
||||
Namespace typeinfoNamespace =
|
||||
symbolTable.getNamespace(TYPE_INFO_NAMESPACE, program.getGlobalNamespace());
|
||||
|
||||
if (typeinfoNamespace == null) {
|
||||
try {
|
||||
typeinfoNamespace = symbolTable.createClass(program.getGlobalNamespace(),
|
||||
TYPE_INFO_NAMESPACE, SourceType.IMPORTED);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
Msg.error(RttiUtil.class, "Duplicate type_info class namespace at " +
|
||||
program.getName() + " " + address + ". " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.error(RttiUtil.class, "Invalid input creating type_info class namespace " +
|
||||
program.getName() + " " + address + ". " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check to see if symbol already exists both non-pdb and pdb versions
|
||||
Symbol vftableSymbol = symbolTable.getSymbol(TYPE_INFO_NAMESPACE, address, typeinfoNamespace);
|
||||
if (vftableSymbol != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
vftableSymbol = symbolTable.getSymbol("`vftable'", address, typeinfoNamespace);
|
||||
if (vftableSymbol != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
vftableSymbol =
|
||||
symbolTable.createLabel(address, "vftable", typeinfoNamespace, SourceType.IMPORTED);
|
||||
if (vftableSymbol == null) {
|
||||
Msg.error(RttiUtil.class,
|
||||
program.getName() + " Couldn't create type_info vftable symbol. ");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.error(RttiUtil.class,
|
||||
program.getName() + " Couldn't create type_info vftable symbol. " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ public class VfTableModel extends AbstractCreateDataTypeModel {
|
|||
private Program lastProgram;
|
||||
private DataType lastDataType;
|
||||
private int lastElementCount = -1;
|
||||
private int elementCount = 0;
|
||||
|
||||
/**
|
||||
* Creates the model for the vf table data.
|
||||
|
@ -54,8 +55,18 @@ public class VfTableModel extends AbstractCreateDataTypeModel {
|
|||
*/
|
||||
public VfTableModel(Program program, Address vfTableAddress,
|
||||
DataValidationOptions validationOptions) {
|
||||
super(program, RttiUtil.getVfTableCount(program, vfTableAddress), vfTableAddress,
|
||||
// use one for the data type element count, because there is only one array of some element size
|
||||
super(program, 1, vfTableAddress,
|
||||
validationOptions);
|
||||
elementCount= RttiUtil.getVfTableCount(program, vfTableAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of vftable elements in this vftable
|
||||
* @return number of elements
|
||||
*/
|
||||
public int getElementCount() {
|
||||
return elementCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -79,7 +90,7 @@ public class VfTableModel extends AbstractCreateDataTypeModel {
|
|||
long entrySize = individualEntryDataType.getLength();
|
||||
|
||||
// Each entry is a pointer to where a function can possibly be created.
|
||||
long numEntries = getCount();
|
||||
long numEntries = elementCount;
|
||||
if (numEntries == 0) {
|
||||
throw new InvalidDataTypeException(
|
||||
getName() + " data type at " + getAddress() + " doesn't have a valid vf table.");
|
||||
|
@ -120,9 +131,8 @@ public class VfTableModel extends AbstractCreateDataTypeModel {
|
|||
|
||||
lastProgram = program;
|
||||
lastDataType = null;
|
||||
lastElementCount = -1;
|
||||
|
||||
lastElementCount = getCount();
|
||||
lastElementCount = elementCount;
|
||||
|
||||
if (lastElementCount > 0) {
|
||||
DataTypeManager dataTypeManager = program.getDataTypeManager();
|
||||
PointerDataType pointerDt = new PointerDataType(dataTypeManager);
|
||||
|
|
|
@ -19,18 +19,14 @@ import java.util.*;
|
|||
|
||||
import ghidra.app.cmd.data.CreateTypeDescriptorBackgroundCmd;
|
||||
import ghidra.app.cmd.data.TypeDescriptorModel;
|
||||
import ghidra.app.cmd.data.rtti.CreateRtti4BackgroundCmd;
|
||||
import ghidra.app.cmd.data.rtti.Rtti4Model;
|
||||
import ghidra.app.cmd.data.rtti.RttiUtil;
|
||||
import ghidra.app.cmd.data.rtti.*;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.util.datatype.microsoft.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.InvalidDataTypeException;
|
||||
import ghidra.program.model.lang.UndefinedValueException;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.util.ProgramMemoryUtil;
|
||||
import ghidra.util.bytesearch.*;
|
||||
import ghidra.util.exception.*;
|
||||
|
@ -77,48 +73,47 @@ public class RttiAnalyzer extends AbstractAnalyzer {
|
|||
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
|
||||
throws CancelledException {
|
||||
|
||||
Address typeInfoRtti0Address = RttiUtil.getTypeInfoTypeDescriptorAddress(program);
|
||||
if (typeInfoRtti0Address == null) {
|
||||
log.appendMsg(this.getName(), "Couldn't find RTTI type info structure.");
|
||||
Address commonVfTableAddress = RttiUtil.findTypeInfoVftableAddress(program, monitor);
|
||||
|
||||
if (commonVfTableAddress == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// ensure the label is present
|
||||
try {
|
||||
program.getSymbolTable().createLabel(
|
||||
typeInfoRtti0Address, RttiUtil.TYPE_INFO_LABEL, SourceType.ANALYSIS);
|
||||
} catch (InvalidInputException e) {
|
||||
// not invalid
|
||||
throw new AssertException(e);
|
||||
}
|
||||
|
||||
// Get the address of the vf table data in common for all RTTI 0.
|
||||
TypeDescriptorModel typeDescriptorModel =
|
||||
new TypeDescriptorModel(program, typeInfoRtti0Address, validationOptions);
|
||||
try {
|
||||
Address commonVfTableAddress = typeDescriptorModel.getVFTableAddress();
|
||||
if (commonVfTableAddress == null) {
|
||||
log.appendMsg(this.getName(),
|
||||
"Couldn't get vf table address for RTTI 0 @ " + typeInfoRtti0Address + ". ");
|
||||
return false;
|
||||
}
|
||||
|
||||
int alignment = program.getDefaultPointerSize();
|
||||
List<MemoryBlock> dataBlocks = ProgramMemoryUtil.getMemoryBlocksStartingWithName(
|
||||
program, program.getMemory(), ".data", TaskMonitor.DUMMY);
|
||||
Set<Address> possibleTypeAddresses = ProgramMemoryUtil.findDirectReferences(program,
|
||||
dataBlocks, alignment, commonVfTableAddress, monitor);
|
||||
|
||||
// We now have a list of potential rtti0 addresses.
|
||||
processRtti0(possibleTypeAddresses, program, monitor);
|
||||
|
||||
RttiUtil.createTypeInfoVftableSymbol(program,commonVfTableAddress);
|
||||
|
||||
Set<Address> possibleTypeAddresses = locatePotentialRTTI0Entries(program, set, monitor);
|
||||
if (possibleTypeAddresses == null) {
|
||||
return true;
|
||||
}
|
||||
catch (InvalidDataTypeException | UndefinedValueException e) {
|
||||
log.appendMsg(this.getName(), "Couldn't get vf table address for RTTI 0 @ " +
|
||||
typeInfoRtti0Address + ". " + e.getMessage());
|
||||
return false;
|
||||
|
||||
// We now have a list of potential rtti0 addresses.
|
||||
processRtti0(possibleTypeAddresses, program, monitor);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* locate any potential RTTI0 based on pointers to the type_info vftable
|
||||
* @param program proram to locate within
|
||||
* @param set restricted set to locate within
|
||||
* @param monitor monitor for canceling
|
||||
* @return set of potential RTTI0 entries
|
||||
* @throws CancelledException
|
||||
*/
|
||||
private Set<Address> locatePotentialRTTI0Entries(Program program, AddressSetView set,
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
Address commonVfTableAddress = RttiUtil.findTypeInfoVftableAddress(program, monitor);
|
||||
if (commonVfTableAddress == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// use the type_info vftable address to find a list of potential RTTI0 addresses
|
||||
int alignment = program.getDefaultPointerSize();
|
||||
List<MemoryBlock> dataBlocks = ProgramMemoryUtil.getMemoryBlocksStartingWithName(
|
||||
program, program.getMemory(), ".data", TaskMonitor.DUMMY);
|
||||
Set<Address> possibleTypeAddresses = ProgramMemoryUtil.findDirectReferences(program,
|
||||
dataBlocks, alignment, commonVfTableAddress, monitor);
|
||||
return possibleTypeAddresses;
|
||||
}
|
||||
|
||||
private void processRtti0(Collection<Address> possibleRtti0Addresses, Program program,
|
||||
|
@ -168,6 +163,9 @@ public class RttiAnalyzer extends AbstractAnalyzer {
|
|||
dataBlocks.addAll(ProgramMemoryUtil.getMemoryBlocksStartingWithName(program,
|
||||
program.getMemory(), ".data", monitor));
|
||||
|
||||
dataBlocks.addAll(ProgramMemoryUtil.getMemoryBlocksStartingWithName(program,
|
||||
program.getMemory(), ".text", monitor));
|
||||
|
||||
List<Address> rtti4Addresses =
|
||||
getRtti4Addresses(program, dataBlocks, rtti0Locations, validationOptions, monitor);
|
||||
|
||||
|
|
|
@ -269,7 +269,7 @@ class AbstractRttiTest extends AbstractCreateDataTypeModelTest {
|
|||
vfTableModel.validate();
|
||||
assertEquals(addressVfTable, vfTableModel.getAddress());
|
||||
int numVfTableEntries = vfAddresses.length;
|
||||
assertEquals(numVfTableEntries, vfTableModel.getCount());
|
||||
assertEquals(numVfTableEntries, vfTableModel.getElementCount());
|
||||
for (int i = 0; i < numVfTableEntries; i++) {
|
||||
assertEquals(addr(program, vfAddresses[i]), vfTableModel.getVirtualFunctionPointer(i));
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ public class RttiModelTest extends AbstractRttiTest {
|
|||
setupRtti4_32(builder, 0x01001340L, 0, 0, 0, "0x01005364", "0x0100137c");
|
||||
Address address = builder.addr(0x01001340L);
|
||||
checkInvalidModel(new Rtti4Model(program, address, defaultValidationOptions),
|
||||
"TypeDescriptor data type at 01005364 doesn't point to a vfTable address in a loaded and initialized memory block.");
|
||||
"No vf table pointer is defined for this TypeDescriptor model.");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -62,7 +62,7 @@ public class RttiModelTest extends AbstractRttiTest {
|
|||
setupRtti0_32(builder, 0x01001364, "0x01007700", "0x0", "stuff");
|
||||
Address address = builder.addr(0x01001340L);
|
||||
checkInvalidModel(new Rtti4Model(program, address, defaultValidationOptions),
|
||||
"TypeDescriptor data type at 01001364 doesn't point to a vfTable address in a loaded and initialized memory block.");
|
||||
"No vf table pointer is defined for this TypeDescriptor model.");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package utility.function;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* TerminatingConsumer is a Consumer {@link Consumer} that can request termination
|
||||
* of the supplier once some condition is reached, for example some number of consumed results
|
||||
* accepted. If termination is required override the terminationRequested()
|
||||
* method to return true when termination state is reached.
|
||||
*
|
||||
* @param <T> the type of the input to the operation
|
||||
*/
|
||||
public interface TerminatingConsumer<T> extends Consumer<T> {
|
||||
|
||||
default boolean terminationRequested() {
|
||||
return false;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue