Merge remote-tracking branch 'origin/GT-168_astrelsky_PR-2077_astrelsky_TypeDescriptorModel'

This commit is contained in:
ghidravore 2020-09-18 16:02:42 -04:00
commit 8885530330
5 changed files with 109 additions and 60 deletions

View File

@ -15,9 +15,7 @@
*/
package ghidra.app.cmd.data;
import java.util.List;
import ghidra.app.plugin.prototype.MicrosoftCodeAnalyzerPlugin.RttiAnalyzer;
import ghidra.app.cmd.data.rtti.RttiUtil;
import ghidra.app.util.datatype.microsoft.DataValidationOptions;
import ghidra.app.util.datatype.microsoft.MSDataTypeUtils;
import ghidra.app.util.demangler.DemangledObject;
@ -31,9 +29,6 @@ import ghidra.program.model.mem.*;
import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.util.ProgramMemoryUtil;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import mdemangler.*;
import mdemangler.datatype.MDDataType;
import mdemangler.datatype.complex.MDComplexType;
@ -257,23 +252,11 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel {
if (MSDataTypeUtils.is64Bit(program)) {
return true;
}
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(),
RttiAnalyzer.TYPE_INFO_STRING.getBytes(), null, true, TaskMonitor.DUMMY);
if (typeInfoAddress != null) {
return true; // RTTI has type info string in the data section.
}
}
Address address = RttiUtil.getTypeInfoTypeDescriptorAddress(program);
if (address == null) {
return false;
}
catch (CancelledException e) {
// Shouldn't happen since using dummy monitor. Do nothing.
}
return false;
return RttiUtil.isTypeInfoTypeDescriptorAddress(program, address);
}
/**

View File

@ -17,9 +17,14 @@ package ghidra.app.cmd.data.rtti;
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAbsoluteAddress;
import java.io.IOException;
import java.util.List;
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.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.GhidraClass;
@ -27,15 +32,22 @@ import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.Memory;
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.task.TaskMonitor;
/**
* RttiUtil provides constants and static methods for processing RTTI information.
*/
class RttiUtil {
public class RttiUtil {
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";
private RttiUtil() {
// utility class; can't create
@ -111,7 +123,7 @@ class RttiUtil {
* @param vfTableBaseAddress the base address in the program for the vf table
* @return the number of virtual function addresses in the vf table
*/
static int getVfTableCount(Program program, Address vfTableBaseAddress) {
public static int getVfTableCount(Program program, Address vfTableBaseAddress) {
Memory memory = program.getMemory();
MemoryBlock textBlock = memory.getBlock(".text");
@ -157,7 +169,7 @@ class RttiUtil {
* @param rtti0Model the model for the type descriptor whose namespace is to be returned.
* @return the namespace or the empty string.
*/
static String getDescriptorTypeNamespace(TypeDescriptorModel rtti0Model) {
public static String getDescriptorTypeNamespace(TypeDescriptorModel rtti0Model) {
String descriptorTypeNamespace = rtti0Model.getDescriptorTypeNamespace(); // Can be null.
if (descriptorTypeNamespace == null) {
descriptorTypeNamespace = ""; // Couldn't get namespace so leave it off.
@ -165,4 +177,64 @@ class RttiUtil {
return descriptorTypeNamespace;
}
/**
* 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
*/
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);
}
if (!symbols.isEmpty()) {
for (Symbol symbol : symbols) {
if (isTypeInfoTypeDescriptorAddress(program, symbol.getAddress())) {
return symbol.getAddress();
}
}
}
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;
}
}
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);
}
return null;
}
}

View File

@ -21,6 +21,7 @@ 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.services.*;
import ghidra.app.util.datatype.microsoft.*;
import ghidra.app.util.importer.MessageLog;
@ -29,9 +30,10 @@ 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.CancelledException;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
/**
@ -48,7 +50,6 @@ public class RttiAnalyzer extends AbstractAnalyzer {
// they are used for RTTI, then change the CLASS_PREFIX_CHARS to ".". Need to be
// careful that changing to this doesn't cause problems to RTTI analysis.
private static final String CLASS_PREFIX_CHARS = ".?A";
public static final String TYPE_INFO_STRING = ".?AVtype_info@@";
private DataValidationOptions validationOptions;
private DataApplyOptions applyOptions;
@ -76,30 +77,20 @@ public class RttiAnalyzer extends AbstractAnalyzer {
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
List<MemoryBlock> dataBlocks =
ProgramMemoryUtil.getMemoryBlocksStartingWithName(program, set, ".data", monitor);
List<Address> typeInfoAddresses =
ProgramMemoryUtil.findString(TYPE_INFO_STRING, program, dataBlocks, set, monitor);
int typeInfoCount = typeInfoAddresses.size();
if (typeInfoCount != 1) {
if (typeInfoCount == 0) {
log.appendMsg(this.getName(), "Couldn't find type info structure.");
return true;
}
log.appendMsg(this.getName(),
"Found " + typeInfoCount + " type info structures when expecting only 1.");
return false;
}
// Found exactly 1 type info string, so use it to find RTTI structures.
Address typeInfoStringAddress = typeInfoAddresses.get(0);
Address typeInfoRtti0Address =
TypeDescriptorModel.getBaseAddress(program, typeInfoStringAddress);
Address typeInfoRtti0Address = RttiUtil.getTypeInfoTypeDescriptorAddress(program);
if (typeInfoRtti0Address == null) {
log.appendMsg(this.getName(), "Couldn't find RTTI type info structure.");
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 =
@ -113,6 +104,8 @@ public class RttiAnalyzer extends AbstractAnalyzer {
}
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);

View File

@ -20,8 +20,9 @@ import static org.junit.Assert.*;
import org.junit.Assert;
import generic.test.AbstractGenericTest;
import ghidra.app.cmd.data.rtti.RttiUtil;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.app.plugin.prototype.MicrosoftCodeAnalyzerPlugin.RttiAnalyzer;
import ghidra.app.services.DataTypeManagerService;
import ghidra.app.util.datatype.microsoft.DataApplyOptions;
import ghidra.app.util.datatype.microsoft.DataValidationOptions;
@ -139,7 +140,7 @@ public class AbstractCreateDataTypeModelTest extends AbstractGenericTest {
builder.createMemory(".rdata", "0x01003000", 0x2000);
builder.createMemory(".data", "0x01005000", 0x2000);
setupDTMService(builder.getProgram());
builder.setBytes("0x01005008", RttiAnalyzer.TYPE_INFO_STRING.getBytes());
builder.setBytes("0x01005008", RttiUtil.TYPE_INFO_STRING.getBytes());
return builder;
}
@ -157,7 +158,7 @@ public class AbstractCreateDataTypeModelTest extends AbstractGenericTest {
builder.createMemory(".rdata", "0x101003000", 0x2000);
builder.createMemory(".data", "0x101005000", 0x2000);
setupDTMService(builder.getProgram());
builder.setBytes("0x101005010", RttiAnalyzer.TYPE_INFO_STRING.getBytes());
builder.setBytes("0x101005010", RttiUtil.TYPE_INFO_STRING.getBytes());
return builder;
}
@ -192,7 +193,7 @@ public class AbstractCreateDataTypeModelTest extends AbstractGenericTest {
builder.createMemory(".text", "0x101001000", 0x2000);
builder.createMemory(".rdata", "0x101003000", 0x2000);
builder.createMemory(".data", "0x101005000", 0x2000);
builder.setBytes("0x101005010", RttiAnalyzer.TYPE_INFO_STRING.getBytes());
builder.setBytes("0x101005010", RttiUtil.TYPE_INFO_STRING.getBytes());
return builder;
}

View File

@ -16,7 +16,7 @@
package ghidra.app.cmd.data.exceptionhandling;
import ghidra.app.cmd.data.AbstractCreateDataTypeModelTest;
import ghidra.app.plugin.prototype.MicrosoftCodeAnalyzerPlugin.RttiAnalyzer;
import ghidra.app.cmd.data.rtti.RttiUtil;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address;
@ -46,7 +46,7 @@ public class AbstractEHTest extends AbstractCreateDataTypeModelTest {
getHexAddress32AsByteString(tryAddress, bigEndian));
builder.setBytes(ipCountCompAddr.toString(), getIntAsByteString(ipCount, bigEndian));
builder.setBytes(ipCompAddr.toString(), getHexAddress32AsByteString(ipAddress, bigEndian));
builder.setBytes("0x01005008", RttiAnalyzer.TYPE_INFO_STRING.getBytes());
builder.setBytes("0x01005008", RttiUtil.TYPE_INFO_STRING.getBytes());
}
protected void setupV2FuncInfo32(ProgramBuilder builder, long address, int magicNum,
@ -98,7 +98,7 @@ public class AbstractEHTest extends AbstractCreateDataTypeModelTest {
getHexAddressAsIbo32ByteString(builder, ipAddress, bigEndian));
builder.setBytes(unwindHelpCompAddr.toString(),
getIntAsByteString(unwindHelpDisplacement, bigEndian));
builder.setBytes("0x101005010", RttiAnalyzer.TYPE_INFO_STRING.getBytes());
builder.setBytes("0x101005010", RttiUtil.TYPE_INFO_STRING.getBytes());
}
protected void setupV2FuncInfo64(ProgramBuilder builder, long address, int magicNum,
@ -301,7 +301,7 @@ public class AbstractEHTest extends AbstractCreateDataTypeModelTest {
// FuncInfo
setupV1FuncInfo32(builder, 0x01003340, EHFunctionInfoModel.EH_MAGIC_NUMBER_V1, 3,
"0x01003368", 2, "0x01003380", 4, "0x010033d0"); // 28 bytes
builder.setBytes("0x01005008", RttiAnalyzer.TYPE_INFO_STRING.getBytes());
builder.setBytes("0x01005008", RttiUtil.TYPE_INFO_STRING.getBytes());
setupCompleteFlow32NoESTypeList(builder);
}
@ -309,7 +309,7 @@ public class AbstractEHTest extends AbstractCreateDataTypeModelTest {
// FuncInfo
setupV2FuncInfo32(builder, 0x01003340, EHFunctionInfoModel.EH_MAGIC_NUMBER_V2, 3,
"0x01003368", 2, "0x01003380", 4, "0x010033d0", "0x010033f0"); // 32 bytes
builder.setBytes("0x01005008", RttiAnalyzer.TYPE_INFO_STRING.getBytes());
builder.setBytes("0x01005008", RttiUtil.TYPE_INFO_STRING.getBytes());
setupCompleteFlow32(builder);
}
@ -317,7 +317,7 @@ public class AbstractEHTest extends AbstractCreateDataTypeModelTest {
// FuncInfo
setupV3FuncInfo32(builder, 0x01003340, EHFunctionInfoModel.EH_MAGIC_NUMBER_V3, 3,
"0x01003368", 2, "0x01003380", 4, "0x010033d0", "0x010033f0", 0x1); // 36 bytes
builder.setBytes("0x01005008", RttiAnalyzer.TYPE_INFO_STRING.getBytes());
builder.setBytes("0x01005008", RttiUtil.TYPE_INFO_STRING.getBytes());
setupCompleteFlow32(builder);
}
@ -421,7 +421,7 @@ public class AbstractEHTest extends AbstractCreateDataTypeModelTest {
// FuncInfo
setupV1FuncInfo64(builder, 0x101003340L, EHFunctionInfoModel.EH_MAGIC_NUMBER_V1, 3,
"0x101003368", 2, "0x101003380", 4, "0x1010033d0", 0x00000200);
builder.setBytes("0x101005010", RttiAnalyzer.TYPE_INFO_STRING.getBytes());
builder.setBytes("0x101005010", RttiUtil.TYPE_INFO_STRING.getBytes());
setupCompleteFlow64NoESTypeList(builder);
}
@ -429,7 +429,7 @@ public class AbstractEHTest extends AbstractCreateDataTypeModelTest {
// FuncInfo
setupV2FuncInfo64(builder, 0x101003340L, EHFunctionInfoModel.EH_MAGIC_NUMBER_V2, 3,
"0x101003368", 2, "0x101003380", 4, "0x1010033d0", 0x00000200, "0x1010033f0");
builder.setBytes("0x101005010", RttiAnalyzer.TYPE_INFO_STRING.getBytes());
builder.setBytes("0x101005010", RttiUtil.TYPE_INFO_STRING.getBytes());
setupCompleteFlow64(builder);
}
@ -437,7 +437,7 @@ public class AbstractEHTest extends AbstractCreateDataTypeModelTest {
// FuncInfo
setupV3FuncInfo64(builder, 0x101003340L, EHFunctionInfoModel.EH_MAGIC_NUMBER_V3, 3,
"0x101003368", 2, "0x101003380", 4, "0x1010033d0", 0x00000200, "0x1010033f0", 0x1);
builder.setBytes("0x101005010", RttiAnalyzer.TYPE_INFO_STRING.getBytes());
builder.setBytes("0x101005010", RttiUtil.TYPE_INFO_STRING.getBytes());
setupCompleteFlow64(builder);
}