mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-25 05:32:14 +00:00
Merge remote-tracking branch 'origin/GT-168_astrelsky_PR-2077_astrelsky_TypeDescriptorModel'
This commit is contained in:
commit
8885530330
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user