GP-141 handle non-standard RTTI type_info

This commit is contained in:
ghidra007 2020-11-04 12:58:49 -05:00 committed by ghidra1
parent 4300bec382
commit 0f6d3cbc35
9 changed files with 332 additions and 122 deletions

View file

@ -30,6 +30,7 @@ import ghidra.util.datastruct.ListAccumulator;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
import ghidra.util.task.TaskMonitorAdapter; import ghidra.util.task.TaskMonitorAdapter;
import utility.function.TerminatingConsumer;
/** /**
* <CODE>ProgramMemoryUtil</CODE> contains some static methods for * <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 * Finds the string in memory indicated by the searchString limited to the indicated
* memory blocks and address set. * memory blocks and address set.
@ -740,9 +741,36 @@ public class ProgramMemoryUtil {
public static List<Address> findString(String searchString, Program program, public static List<Address> findString(String searchString, Program program,
List<MemoryBlock> blocks, AddressSetView set, TaskMonitor monitor) List<MemoryBlock> blocks, AddressSetView set, TaskMonitor monitor)
throws CancelledException { 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 + "\"."); monitor.setMessage("Finding \"" + searchString + "\".");
List<Address> addresses = new ArrayList<>();
int length = searchString.length(); int length = searchString.length();
byte[] bytes = searchString.getBytes(); byte[] bytes = searchString.getBytes();
Memory memory = program.getMemory(); Memory memory = program.getMemory();
@ -759,7 +787,10 @@ public class ProgramMemoryUtil {
break; // no more found in block. break; // no more found in block.
} }
if (set.contains(foundAddress)) { if (set.contains(foundAddress)) {
addresses.add(foundAddress); foundLocationConsumer.accept(foundAddress);
if (foundLocationConsumer.terminationRequested()) {
return; // termination of search requested
}
} }
try { try {
startAddress = foundAddress.add(length); startAddress = foundAddress.add(length);
@ -770,7 +801,6 @@ public class ProgramMemoryUtil {
} }
while (startAddress.compareTo(endAddress) <= 0); while (startAddress.compareTo(endAddress) <= 0);
} }
return addresses;
} }
/** /**

View file

@ -25,10 +25,15 @@ import ghidra.program.model.address.*;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.lang.UndefinedValueException; import ghidra.program.model.lang.UndefinedValueException;
import ghidra.program.model.listing.Program; 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.scalar.Scalar;
import ghidra.program.model.symbol.Namespace; import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.Symbol; 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.*;
import mdemangler.datatype.MDDataType; import mdemangler.datatype.MDDataType;
import mdemangler.datatype.complex.MDComplexType; 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. * @return true if the data type has a vf table pointer. Otherwise, it has a hash value.
*/ */
private static boolean hasVFPointer(Program program) { 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; return true;
} }
Address address = RttiUtil.getTypeInfoTypeDescriptorAddress(program); return false;
if (address == null) {
return false;
}
return RttiUtil.isTypeInfoTypeDescriptorAddress(program, address);
} }
/** /**
@ -350,9 +358,11 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel {
throw new UndefinedValueException( throw new UndefinedValueException(
"No vf table pointer is defined for this TypeDescriptor model."); "No vf table pointer is defined for this TypeDescriptor model.");
} }
Address vfTableAddress;
// component 0 is either vf table pointer or hash value. // component 0 is either vf table pointer or hash value.
Address vfTableAddress = vfTableAddress = EHDataTypeUtilities.getAddress(getDataType(), VF_TABLE_OR_HASH_ORDINAL, getMemBuffer());
EHDataTypeUtilities.getAddress(getDataType(), VF_TABLE_OR_HASH_ORDINAL, getMemBuffer());
return vfTableAddress.getOffset() != 0 ? vfTableAddress : null; return vfTableAddress.getOffset() != 0 ? vfTableAddress : null;
} }

View file

@ -187,7 +187,7 @@ public class CreateVfTableBackgroundCmd extends AbstractCreateDataBackgroundCmd<
// Create functions that are referred to by the vf table. // Create functions that are referred to by the vf table.
if (applyOptions.shouldCreateFunction()) { if (applyOptions.shouldCreateFunction()) {
int elementCount = model.getCount(); int elementCount = model.getElementCount();
for (int tableElementIndex = 0; tableElementIndex < elementCount; tableElementIndex++) { for (int tableElementIndex = 0; tableElementIndex < elementCount; tableElementIndex++) {
monitor.checkCanceled(); monitor.checkCanceled();
Address vfPointer = model.getVirtualFunctionPointer(tableElementIndex); Address vfPointer = model.getVirtualFunctionPointer(tableElementIndex);

View file

@ -15,16 +15,14 @@
*/ */
package ghidra.app.cmd.data.rtti; 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.*;
import java.util.List;
import ghidra.app.cmd.data.TypeDescriptorModel; import ghidra.app.cmd.data.TypeDescriptorModel;
import ghidra.app.util.NamespaceUtils; import ghidra.app.util.NamespaceUtils;
import ghidra.app.util.PseudoDisassembler; import ghidra.app.util.PseudoDisassembler;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.datatype.microsoft.MSDataTypeUtils;
import ghidra.app.util.bin.MemoryByteProvider;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView; import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.GhidraClass; import ghidra.program.model.listing.GhidraClass;
@ -34,20 +32,23 @@ import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
import ghidra.program.util.ProgramMemoryUtil; import ghidra.program.util.ProgramMemoryUtil;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.exception.AssertException; import ghidra.util.exception.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
import utility.function.TerminatingConsumer;
/** /**
* RttiUtil provides constants and static methods for processing RTTI information. * RttiUtil provides constants and static methods for processing RTTI information.
*/ */
public class RttiUtil { 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 "; 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"; 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() { private RttiUtil() {
// utility class; can't create // utility class; can't create
@ -151,6 +152,12 @@ public class RttiUtil {
: false) { : false) {
break; // Not pointing to text section. 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)) { if (!pseudoDisassembler.isValidSubroutine(referencedAddress, true)) {
break; // Not pointing to possible function. 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. * Identify common TypeInfo address through examination of discovered VtTables
* 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
*/ */
public static Address getTypeInfoTypeDescriptorAddress(Program program) { private static class CommonRTTIMatchCounter implements TerminatingConsumer<Address> {
SymbolTable table = program.getSymbolTable(); int matchingAddrCount = 0;
List<Symbol> symbols = table.getGlobalSymbols(TYPE_INFO_LABEL); int defaultPointerSize = 4;
if (symbols.isEmpty()) { boolean terminationRequest = false;
symbols = table.getGlobalSymbols(MANGLED_TYPE_INFO_SYMBOL); Address commonVftableAddress = null;
Program program;
public CommonRTTIMatchCounter(Program program) {
this.program = program;
defaultPointerSize = program.getDefaultPointerSize();
} }
if (!symbols.isEmpty()) {
for (Symbol symbol : symbols) { public Address getinfoVfTable() {
if (isTypeInfoTypeDescriptorAddress(program, symbol.getAddress())) { return commonVftableAddress;
return symbol.getAddress();
}
}
} }
return locateTypeInfoAddress(program);
}
/** @Override
* Checks if the provided address is a TypeDescriptor containing the public boolean terminationRequested() {
* {@value TYPE_INFO_STRING} component return terminationRequest;
* @param program the program }
* @param address the descriptor address
* @return true if {@value TYPE_INFO_STRING} is present in the descriptor at the address @Override
*/ public void accept(Address foundAddress) {
public static boolean isTypeInfoTypeDescriptorAddress(Program program, Address address) { Address mangledClassNameAddress = foundAddress;
MemoryByteProvider provider = new MemoryByteProvider(program.getMemory(), address);
try { Address pointerToTypeInfoVftable =
BinaryReader reader = new BinaryReader(provider, !program.getLanguage().isBigEndian()); mangledClassNameAddress.subtract(2 * defaultPointerSize);
String value = reader.readAsciiString(program.getDefaultPointerSize() * 2);
return TYPE_INFO_STRING.equals(value); Address possibleVftableAddress =
} catch (IOException e) { MSDataTypeUtils.getAbsoluteAddress(program, pointerToTypeInfoVftable);
return false; 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(); * Method to figure out the type_info vftable address using pointed to value by all RTTI classes
try { * @param program the current program
List<MemoryBlock> dataBlocks = ProgramMemoryUtil.getMemoryBlocksStartingWithName( * @param monitor the TaskMonitor
program, program.getMemory(), ".data", TaskMonitor.DUMMY); * @return the type_info address or null if it cannot be determined
for (MemoryBlock memoryBlock : dataBlocks) { * @throws CancelledException if cancelled
Address typeInfoAddress = */
memory.findBytes(memoryBlock.getStart(), memoryBlock.getEnd(), public static Address findTypeInfoVftableAddress(Program program, TaskMonitor monitor)
TYPE_INFO_STRING.getBytes(), null, true, TaskMonitor.DUMMY); throws CancelledException {
if (typeInfoAddress != null) {
return TypeDescriptorModel.getBaseAddress(program, typeInfoAddress); // Checked for cached value
} if (vftableMap.containsKey(program)) {
} return vftableMap.get(program);
} catch (CancelledException e) {
// impossible
throw new AssertException(e);
} }
// 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; 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;
}
}
} }

View file

@ -44,6 +44,7 @@ public class VfTableModel extends AbstractCreateDataTypeModel {
private Program lastProgram; private Program lastProgram;
private DataType lastDataType; private DataType lastDataType;
private int lastElementCount = -1; private int lastElementCount = -1;
private int elementCount = 0;
/** /**
* Creates the model for the vf table data. * Creates the model for the vf table data.
@ -54,8 +55,18 @@ public class VfTableModel extends AbstractCreateDataTypeModel {
*/ */
public VfTableModel(Program program, Address vfTableAddress, public VfTableModel(Program program, Address vfTableAddress,
DataValidationOptions validationOptions) { 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); 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 @Override
@ -79,7 +90,7 @@ public class VfTableModel extends AbstractCreateDataTypeModel {
long entrySize = individualEntryDataType.getLength(); long entrySize = individualEntryDataType.getLength();
// Each entry is a pointer to where a function can possibly be created. // Each entry is a pointer to where a function can possibly be created.
long numEntries = getCount(); long numEntries = elementCount;
if (numEntries == 0) { if (numEntries == 0) {
throw new InvalidDataTypeException( throw new InvalidDataTypeException(
getName() + " data type at " + getAddress() + " doesn't have a valid vf table."); getName() + " data type at " + getAddress() + " doesn't have a valid vf table.");
@ -120,9 +131,8 @@ public class VfTableModel extends AbstractCreateDataTypeModel {
lastProgram = program; lastProgram = program;
lastDataType = null; lastDataType = null;
lastElementCount = -1; lastElementCount = elementCount;
lastElementCount = getCount();
if (lastElementCount > 0) { if (lastElementCount > 0) {
DataTypeManager dataTypeManager = program.getDataTypeManager(); DataTypeManager dataTypeManager = program.getDataTypeManager();
PointerDataType pointerDt = new PointerDataType(dataTypeManager); PointerDataType pointerDt = new PointerDataType(dataTypeManager);

View file

@ -19,18 +19,14 @@ import java.util.*;
import ghidra.app.cmd.data.CreateTypeDescriptorBackgroundCmd; import ghidra.app.cmd.data.CreateTypeDescriptorBackgroundCmd;
import ghidra.app.cmd.data.TypeDescriptorModel; import ghidra.app.cmd.data.TypeDescriptorModel;
import ghidra.app.cmd.data.rtti.CreateRtti4BackgroundCmd; import ghidra.app.cmd.data.rtti.*;
import ghidra.app.cmd.data.rtti.Rtti4Model;
import ghidra.app.cmd.data.rtti.RttiUtil;
import ghidra.app.services.*; import ghidra.app.services.*;
import ghidra.app.util.datatype.microsoft.*; import ghidra.app.util.datatype.microsoft.*;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.InvalidDataTypeException; import ghidra.program.model.data.InvalidDataTypeException;
import ghidra.program.model.lang.UndefinedValueException;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemoryBlock; import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.util.ProgramMemoryUtil; import ghidra.program.util.ProgramMemoryUtil;
import ghidra.util.bytesearch.*; import ghidra.util.bytesearch.*;
import ghidra.util.exception.*; import ghidra.util.exception.*;
@ -77,48 +73,47 @@ public class RttiAnalyzer extends AbstractAnalyzer {
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException { throws CancelledException {
Address typeInfoRtti0Address = RttiUtil.getTypeInfoTypeDescriptorAddress(program); Address commonVfTableAddress = RttiUtil.findTypeInfoVftableAddress(program, monitor);
if (typeInfoRtti0Address == null) {
log.appendMsg(this.getName(), "Couldn't find RTTI type info structure."); if (commonVfTableAddress == null) {
return true; return true;
} }
// ensure the label is present RttiUtil.createTypeInfoVftableSymbol(program,commonVfTableAddress);
try {
program.getSymbolTable().createLabel( Set<Address> possibleTypeAddresses = locatePotentialRTTI0Entries(program, set, monitor);
typeInfoRtti0Address, RttiUtil.TYPE_INFO_LABEL, SourceType.ANALYSIS); if (possibleTypeAddresses == null) {
} 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);
return true; return true;
} }
catch (InvalidDataTypeException | UndefinedValueException e) {
log.appendMsg(this.getName(), "Couldn't get vf table address for RTTI 0 @ " + // We now have a list of potential rtti0 addresses.
typeInfoRtti0Address + ". " + e.getMessage()); processRtti0(possibleTypeAddresses, program, monitor);
return false;
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, private void processRtti0(Collection<Address> possibleRtti0Addresses, Program program,
@ -168,6 +163,9 @@ public class RttiAnalyzer extends AbstractAnalyzer {
dataBlocks.addAll(ProgramMemoryUtil.getMemoryBlocksStartingWithName(program, dataBlocks.addAll(ProgramMemoryUtil.getMemoryBlocksStartingWithName(program,
program.getMemory(), ".data", monitor)); program.getMemory(), ".data", monitor));
dataBlocks.addAll(ProgramMemoryUtil.getMemoryBlocksStartingWithName(program,
program.getMemory(), ".text", monitor));
List<Address> rtti4Addresses = List<Address> rtti4Addresses =
getRtti4Addresses(program, dataBlocks, rtti0Locations, validationOptions, monitor); getRtti4Addresses(program, dataBlocks, rtti0Locations, validationOptions, monitor);

View file

@ -269,7 +269,7 @@ class AbstractRttiTest extends AbstractCreateDataTypeModelTest {
vfTableModel.validate(); vfTableModel.validate();
assertEquals(addressVfTable, vfTableModel.getAddress()); assertEquals(addressVfTable, vfTableModel.getAddress());
int numVfTableEntries = vfAddresses.length; int numVfTableEntries = vfAddresses.length;
assertEquals(numVfTableEntries, vfTableModel.getCount()); assertEquals(numVfTableEntries, vfTableModel.getElementCount());
for (int i = 0; i < numVfTableEntries; i++) { for (int i = 0; i < numVfTableEntries; i++) {
assertEquals(addr(program, vfAddresses[i]), vfTableModel.getVirtualFunctionPointer(i)); assertEquals(addr(program, vfAddresses[i]), vfTableModel.getVirtualFunctionPointer(i));
} }

View file

@ -51,7 +51,7 @@ public class RttiModelTest extends AbstractRttiTest {
setupRtti4_32(builder, 0x01001340L, 0, 0, 0, "0x01005364", "0x0100137c"); setupRtti4_32(builder, 0x01001340L, 0, 0, 0, "0x01005364", "0x0100137c");
Address address = builder.addr(0x01001340L); Address address = builder.addr(0x01001340L);
checkInvalidModel(new Rtti4Model(program, address, defaultValidationOptions), 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 @Test
@ -62,7 +62,7 @@ public class RttiModelTest extends AbstractRttiTest {
setupRtti0_32(builder, 0x01001364, "0x01007700", "0x0", "stuff"); setupRtti0_32(builder, 0x01001364, "0x01007700", "0x0", "stuff");
Address address = builder.addr(0x01001340L); Address address = builder.addr(0x01001340L);
checkInvalidModel(new Rtti4Model(program, address, defaultValidationOptions), 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 @Test

View file

@ -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;
}
}