mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-25 17:00:36 -09:00
Merge remote-tracking branch 'origin/GP-729_jmlagor_Process_the_.pdata_section_to_parse_exception_handling_data--SQUASHED'
This commit is contained in:
@@ -22,6 +22,7 @@ import java.util.List;
|
||||
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
|
||||
import ghidra.app.util.bin.format.pe.ImageRuntimeFunctionEntries._IMAGE_RUNTIME_FUNCTION_ENTRY;
|
||||
import ghidra.app.util.bin.format.pe.debug.DebugCOFFSymbol;
|
||||
import ghidra.app.util.bin.format.pe.debug.DebugCOFFSymbolAux;
|
||||
import ghidra.program.model.data.*;
|
||||
@@ -45,7 +46,7 @@ import ghidra.util.exception.DuplicateNameException;
|
||||
* WORD Characteristics; // MANDATORY
|
||||
* } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class FileHeader implements StructConverter {
|
||||
/**
|
||||
@@ -55,128 +56,131 @@ public class FileHeader implements StructConverter {
|
||||
/**
|
||||
* The size of the <code>IMAGE_FILE_HEADER</code> in bytes.
|
||||
*/
|
||||
public final static int IMAGE_SIZEOF_FILE_HEADER = 20;
|
||||
public final static int IMAGE_SIZEOF_FILE_HEADER = 20;
|
||||
|
||||
/**
|
||||
* Relocation info stripped from file.
|
||||
*/
|
||||
public final static int IMAGE_FILE_RELOCS_STRIPPED = 0x0001;
|
||||
/**
|
||||
* File is executable (no unresolved externel references).
|
||||
*/
|
||||
public final static int IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002;
|
||||
/**
|
||||
* Line nunbers stripped from file.
|
||||
*/
|
||||
public final static int IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004;
|
||||
/**
|
||||
* Local symbols stripped from file.
|
||||
*/
|
||||
public final static int IMAGE_FILE_LOCAL_SYMS_STRIPPED = 0x0008;
|
||||
/**
|
||||
* Agressively trim working set
|
||||
*/
|
||||
public final static int IMAGE_FILE_AGGRESIVE_WS_TRIM = 0x0010;
|
||||
/**
|
||||
* App can handle >2gb addresses
|
||||
*/
|
||||
public final static int IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020;
|
||||
/**
|
||||
* Bytes of machine word are reversed.
|
||||
*/
|
||||
public final static int IMAGE_FILE_BYTES_REVERSED_LO = 0x0080;
|
||||
/**
|
||||
* 32 bit word machine.
|
||||
*/
|
||||
public final static int IMAGE_FILE_32BIT_MACHINE = 0x0100;
|
||||
/**
|
||||
* Debugging info stripped from file in .DBG file
|
||||
*/
|
||||
public final static int IMAGE_FILE_DEBUG_STRIPPED = 0x0200;
|
||||
/**
|
||||
* If Image is on removable media, copy and run from the swap file.
|
||||
*/
|
||||
public final static int IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 0x0400;
|
||||
/**
|
||||
* If Image is on Net, copy and run from the swap file.
|
||||
*/
|
||||
public final static int IMAGE_FILE_NET_RUN_FROM_SWAP = 0x0800;
|
||||
/**
|
||||
* System File.
|
||||
*/
|
||||
public final static int IMAGE_FILE_SYSTEM = 0x1000;
|
||||
/**
|
||||
* File is a DLL.
|
||||
*/
|
||||
public final static int IMAGE_FILE_DLL = 0x2000;
|
||||
/**
|
||||
* File should only be run on a UP machine
|
||||
*/
|
||||
public final static int IMAGE_FILE_UP_SYSTEM_ONLY = 0x4000;
|
||||
/**
|
||||
* Bytes of machine word are reversed.
|
||||
*/
|
||||
public final static int IMAGE_FILE_BYTES_REVERSED_HI = 0x8000;
|
||||
public final static int IMAGE_FILE_RELOCS_STRIPPED = 0x0001;
|
||||
/**
|
||||
* File is executable (no unresolved externel references).
|
||||
*/
|
||||
public final static int IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002;
|
||||
/**
|
||||
* Line nunbers stripped from file.
|
||||
*/
|
||||
public final static int IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004;
|
||||
/**
|
||||
* Local symbols stripped from file.
|
||||
*/
|
||||
public final static int IMAGE_FILE_LOCAL_SYMS_STRIPPED = 0x0008;
|
||||
/**
|
||||
* Agressively trim working set
|
||||
*/
|
||||
public final static int IMAGE_FILE_AGGRESIVE_WS_TRIM = 0x0010;
|
||||
/**
|
||||
* App can handle >2gb addresses
|
||||
*/
|
||||
public final static int IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020;
|
||||
/**
|
||||
* Bytes of machine word are reversed.
|
||||
*/
|
||||
public final static int IMAGE_FILE_BYTES_REVERSED_LO = 0x0080;
|
||||
/**
|
||||
* 32 bit word machine.
|
||||
*/
|
||||
public final static int IMAGE_FILE_32BIT_MACHINE = 0x0100;
|
||||
/**
|
||||
* Debugging info stripped from file in .DBG file
|
||||
*/
|
||||
public final static int IMAGE_FILE_DEBUG_STRIPPED = 0x0200;
|
||||
/**
|
||||
* If Image is on removable media, copy and run from the swap file.
|
||||
*/
|
||||
public final static int IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 0x0400;
|
||||
/**
|
||||
* If Image is on Net, copy and run from the swap file.
|
||||
*/
|
||||
public final static int IMAGE_FILE_NET_RUN_FROM_SWAP = 0x0800;
|
||||
/**
|
||||
* System File.
|
||||
*/
|
||||
public final static int IMAGE_FILE_SYSTEM = 0x1000;
|
||||
/**
|
||||
* File is a DLL.
|
||||
*/
|
||||
public final static int IMAGE_FILE_DLL = 0x2000;
|
||||
/**
|
||||
* File should only be run on a UP machine.
|
||||
*/
|
||||
public final static int IMAGE_FILE_UP_SYSTEM_ONLY = 0x4000;
|
||||
/**
|
||||
* Bytes of machine word are reversed.
|
||||
*/
|
||||
public final static int IMAGE_FILE_BYTES_REVERSED_HI = 0x8000;
|
||||
|
||||
public final static String [] CHARACTERISTICS = {
|
||||
"Relocation info stripped from file",
|
||||
"File is executable (i.e. no unresolved externel references)",
|
||||
"Line nunbers stripped from file",
|
||||
"Local symbols stripped from file",
|
||||
"Agressively trim working set",
|
||||
"App can handle >2gb addresses",
|
||||
"Bytes of machine word are reversed",
|
||||
"32 bit word machine",
|
||||
"Debugging info stripped from file in .DBG file",
|
||||
"If Image is on removable media, copy and run from the swap file",
|
||||
"If Image is on Net, copy and run from the swap file",
|
||||
"System file",
|
||||
"File is a DLL",
|
||||
"File should only be run on a UP machine",
|
||||
"Bytes of machine word are reversed"
|
||||
};
|
||||
/**
|
||||
* Magic value in LordPE's Symbol Table pointer field.
|
||||
*/
|
||||
private final static int LORDPE_SYMBOL_TABLE = 0x726F4C5B;
|
||||
/**
|
||||
* Magic value in LordPE's Number of Symbols field.
|
||||
*/
|
||||
private final static int LORDPE_NUMBER_OF_SYMBOLS = 0x5D455064;
|
||||
|
||||
private short machine;
|
||||
private short numberOfSections;
|
||||
private int timeDateStamp;
|
||||
private int pointerToSymbolTable;
|
||||
private int numberOfSymbols;
|
||||
private short sizeOfOptionalHeader; // delta between start of OptionalHeader and start of section table
|
||||
private short characteristics;
|
||||
public final static String[] CHARACTERISTICS = { "Relocation info stripped from file",
|
||||
"File is executable (i.e. no unresolved externel references)",
|
||||
"Line nunbers stripped from file", "Local symbols stripped from file",
|
||||
"Agressively trim working set", "App can handle >2gb addresses",
|
||||
"Bytes of machine word are reversed", "32 bit word machine",
|
||||
"Debugging info stripped from file in .DBG file",
|
||||
"If Image is on removable media, copy and run from the swap file",
|
||||
"If Image is on Net, copy and run from the swap file", "System file", "File is a DLL",
|
||||
"File should only be run on a UP machine", "Bytes of machine word are reversed" };
|
||||
|
||||
private SectionHeader [] sectionHeaders;
|
||||
private List<DebugCOFFSymbol>symbols = new ArrayList<>();
|
||||
private short machine;
|
||||
private short numberOfSections;
|
||||
private int timeDateStamp;
|
||||
private int pointerToSymbolTable;
|
||||
private int numberOfSymbols;
|
||||
private short sizeOfOptionalHeader; // delta between start of OptionalHeader and start of section table
|
||||
private short characteristics;
|
||||
|
||||
private FactoryBundledWithBinaryReader reader;
|
||||
private int startIndex;
|
||||
private NTHeader ntHeader;
|
||||
private SectionHeader[] sectionHeaders;
|
||||
private List<DebugCOFFSymbol> symbols = new ArrayList<>();
|
||||
private List<_IMAGE_RUNTIME_FUNCTION_ENTRY> irfes = new ArrayList<>();
|
||||
|
||||
static FileHeader createFileHeader(
|
||||
FactoryBundledWithBinaryReader reader, int startIndex,
|
||||
NTHeader ntHeader) throws IOException {
|
||||
FileHeader fileHeader = (FileHeader) reader.getFactory().create(FileHeader.class);
|
||||
fileHeader.initFileHeader(reader, startIndex, ntHeader);
|
||||
return fileHeader;
|
||||
}
|
||||
private FactoryBundledWithBinaryReader reader;
|
||||
private int startIndex;
|
||||
private NTHeader ntHeader;
|
||||
|
||||
/**
|
||||
* DO NOT USE THIS CONSTRUCTOR, USE create*(GenericFactory ...) FACTORY METHODS INSTEAD.
|
||||
*/
|
||||
public FileHeader() {}
|
||||
static FileHeader createFileHeader(FactoryBundledWithBinaryReader reader, int startIndex,
|
||||
NTHeader ntHeader) throws IOException {
|
||||
FileHeader fileHeader = (FileHeader) reader.getFactory().create(FileHeader.class);
|
||||
fileHeader.initFileHeader(reader, startIndex, ntHeader);
|
||||
return fileHeader;
|
||||
}
|
||||
|
||||
private void initFileHeader(FactoryBundledWithBinaryReader reader, int startIndex, NTHeader ntHeader) throws IOException {
|
||||
this.reader = reader;
|
||||
this.startIndex = startIndex;
|
||||
this.ntHeader = ntHeader;
|
||||
/**
|
||||
* DO NOT USE THIS CONSTRUCTOR, USE create*(GenericFactory ...) FACTORY METHODS INSTEAD.
|
||||
*/
|
||||
public FileHeader() {
|
||||
}
|
||||
|
||||
private void initFileHeader(FactoryBundledWithBinaryReader reader, int startIndex,
|
||||
NTHeader ntHeader) throws IOException {
|
||||
this.reader = reader;
|
||||
this.startIndex = startIndex;
|
||||
this.ntHeader = ntHeader;
|
||||
|
||||
parse();
|
||||
}
|
||||
|
||||
parse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the architecture type of the computer.
|
||||
* @return the architecture type of the computer
|
||||
*/
|
||||
public short getMachine() {
|
||||
public short getMachine() {
|
||||
return machine;
|
||||
}
|
||||
|
||||
@@ -184,131 +188,137 @@ public class FileHeader implements StructConverter {
|
||||
* Returns a string representation of the architecture type of the computer.
|
||||
* @return a string representation of the architecture type of the computer
|
||||
*/
|
||||
public String getMachineName() {
|
||||
return MachineName.getName(machine);
|
||||
}
|
||||
|
||||
public String getMachineName() {
|
||||
return MachineName.getName(machine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of sections.
|
||||
* Returns the number of sections.
|
||||
* Sections equate to Ghidra memory blocks.
|
||||
* @return the number of sections
|
||||
*/
|
||||
public int getNumberOfSections() {
|
||||
return numberOfSections;
|
||||
}
|
||||
public int getNumberOfSections() {
|
||||
return numberOfSections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array of section headers.
|
||||
* @return the array of section headers
|
||||
*/
|
||||
public SectionHeader [] getSectionHeaders() {
|
||||
if (sectionHeaders == null) {
|
||||
return new SectionHeader[0];
|
||||
}
|
||||
return sectionHeaders;
|
||||
}
|
||||
public SectionHeader[] getSectionHeaders() {
|
||||
if (sectionHeaders == null) {
|
||||
return new SectionHeader[0];
|
||||
}
|
||||
return sectionHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array of symbols.
|
||||
* @return the array of symbols
|
||||
*/
|
||||
public List<DebugCOFFSymbol> getSymbols() {
|
||||
public List<DebugCOFFSymbol> getSymbols() {
|
||||
return symbols;
|
||||
}
|
||||
|
||||
public List<_IMAGE_RUNTIME_FUNCTION_ENTRY> getImageRuntimeFunctionEntries() {
|
||||
return irfes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the section header that contains the specified virtual address.
|
||||
* @param virtualAddr the virtual address
|
||||
* @return the section header that contains the specified virtual address
|
||||
*/
|
||||
public SectionHeader getSectionHeaderContaining(int virtualAddr) {
|
||||
for (SectionHeader sectionHeader : sectionHeaders) {
|
||||
int start = sectionHeader.getVirtualAddress();
|
||||
int end = sectionHeader.getVirtualAddress()+sectionHeader.getVirtualSize()-1;
|
||||
if (virtualAddr >= start && virtualAddr <= end) {
|
||||
return sectionHeader;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public SectionHeader getSectionHeaderContaining(int virtualAddr) {
|
||||
for (SectionHeader sectionHeader : sectionHeaders) {
|
||||
int start = sectionHeader.getVirtualAddress();
|
||||
int end = sectionHeader.getVirtualAddress() + sectionHeader.getVirtualSize() - 1;
|
||||
if (virtualAddr >= start && virtualAddr <= end) {
|
||||
return sectionHeader;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the section header at the specified position in the array.
|
||||
* @param index index of section header to return
|
||||
* @return the section header at the specified position in the array, or null if invalid
|
||||
*/
|
||||
public SectionHeader getSectionHeader(int index) {
|
||||
public SectionHeader getSectionHeader(int index) {
|
||||
if (index >= 0 && index < sectionHeaders.length) {
|
||||
return sectionHeaders[index];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return sectionHeaders[index];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time stamp of the image.
|
||||
* @return the time stamp of the image
|
||||
*/
|
||||
public int getTimeDateStamp() {
|
||||
return timeDateStamp;
|
||||
}
|
||||
public int getTimeDateStamp() {
|
||||
return timeDateStamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file offset of the COFF symbol table
|
||||
* @return the file offset of the COFF symbol table
|
||||
*/
|
||||
public int getPointerToSymbolTable() {
|
||||
return pointerToSymbolTable;
|
||||
}
|
||||
public int getPointerToSymbolTable() {
|
||||
return pointerToSymbolTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of symbols in the COFF symbol table
|
||||
* @return the number of symbols in the COFF symbol table
|
||||
*/
|
||||
public int getNumberOfSymbols() {
|
||||
return numberOfSymbols;
|
||||
}
|
||||
public int getNumberOfSymbols() {
|
||||
return numberOfSymbols;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the optional header data
|
||||
* @return the size of the optional header, in bytes
|
||||
*/
|
||||
public int getSizeOfOptionalHeader() {
|
||||
public int getSizeOfOptionalHeader() {
|
||||
return sizeOfOptionalHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of bit flags indicating attributes of the file.
|
||||
* Returns a set of bit flags indicating attributes of the file.
|
||||
* @return a set of bit flags indicating attributes
|
||||
*/
|
||||
public int getCharacteristics() {
|
||||
return characteristics;
|
||||
}
|
||||
public int getCharacteristics() {
|
||||
return characteristics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file pointer to the section headers.
|
||||
* @return the file pointer to the section headers
|
||||
*/
|
||||
public int getPointerToSections() {
|
||||
short sizeOptHdr = ntHeader.getFileHeader().sizeOfOptionalHeader;
|
||||
public int getPointerToSections() {
|
||||
short sizeOptHdr = ntHeader.getFileHeader().sizeOfOptionalHeader;
|
||||
int ptrToSections = startIndex + IMAGE_SIZEOF_FILE_HEADER + sizeOptHdr;
|
||||
int testSize = ntHeader.getOptionalHeader().is64bit()
|
||||
? Constants.IMAGE_SIZEOF_NT_OPTIONAL64_HEADER
|
||||
: Constants.IMAGE_SIZEOF_NT_OPTIONAL32_HEADER;
|
||||
if (sizeOptHdr != testSize) {
|
||||
int testSize =
|
||||
ntHeader.getOptionalHeader().is64bit() ? Constants.IMAGE_SIZEOF_NT_OPTIONAL64_HEADER
|
||||
: Constants.IMAGE_SIZEOF_NT_OPTIONAL32_HEADER;
|
||||
if (sizeOptHdr != testSize) {
|
||||
Msg.warn(this, "Non-standard optional header size: " + sizeOptHdr + " bytes");
|
||||
}
|
||||
}
|
||||
return ptrToSections;
|
||||
}
|
||||
}
|
||||
|
||||
void processSections(OptionalHeader optHeader) throws IOException {
|
||||
long oldIndex = reader.getPointerIndex();
|
||||
void processSections(OptionalHeader optHeader) throws IOException {
|
||||
long oldIndex = reader.getPointerIndex();
|
||||
|
||||
int tmpIndex = getPointerToSections();
|
||||
if (numberOfSections < 0) {
|
||||
Msg.error(this, "Number of sections = "+numberOfSections);
|
||||
} else if (optHeader.getFileAlignment() == 0) {
|
||||
Msg.error(this, "File alignment == 0: section processing skipped");
|
||||
} else {
|
||||
int tmpIndex = getPointerToSections();
|
||||
if (numberOfSections < 0) {
|
||||
Msg.error(this, "Number of sections = " + numberOfSections);
|
||||
}
|
||||
else if (optHeader.getFileAlignment() == 0) {
|
||||
Msg.error(this, "File alignment == 0: section processing skipped");
|
||||
}
|
||||
else {
|
||||
sectionHeaders = new SectionHeader[numberOfSections];
|
||||
for (int i = 0; i < numberOfSections; ++i) {
|
||||
sectionHeaders[i] = SectionHeader.createSectionHeader(reader, tmpIndex);
|
||||
@@ -330,8 +340,8 @@ public class FileHeader implements StructConverter {
|
||||
optHeader.getSectionAlignment());
|
||||
if (virtualAddress == alignedVirtualAddress) {
|
||||
if (sizeOfRawData > virtualSize) {
|
||||
sectionHeaders[i].setVirtualSize(
|
||||
Math.min(sizeOfRawData, alignedVirtualSize));
|
||||
sectionHeaders[i]
|
||||
.setVirtualSize(Math.min(sizeOfRawData, alignedVirtualSize));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -341,68 +351,101 @@ public class FileHeader implements StructConverter {
|
||||
}
|
||||
}
|
||||
|
||||
reader.setPointerIndex(oldIndex);
|
||||
}
|
||||
reader.setPointerIndex(oldIndex);
|
||||
}
|
||||
|
||||
void processSymbols() throws IOException {
|
||||
if (isLordPE()) {
|
||||
return;
|
||||
}
|
||||
void processImageRuntimeFunctionEntries() throws IOException {
|
||||
FileHeader fh = ntHeader.getFileHeader();
|
||||
SectionHeader[] sections = fh.getSectionHeaders();
|
||||
|
||||
long oldIndex = reader.getPointerIndex();
|
||||
// Look for an exception handler section for an array of
|
||||
// RUNTIME_FUNCTION structures, bail if one isn't found
|
||||
SectionHeader irfeHeader = null;
|
||||
for (SectionHeader header : sections) {
|
||||
if (header.getName().equals(".pdata")) {
|
||||
irfeHeader = header;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int tmpIndex = getPointerToSymbolTable();
|
||||
if (!ntHeader.checkRVA(tmpIndex)) {
|
||||
Msg.error(this, "Invalid file index "+Integer.toHexString(tmpIndex));
|
||||
return;
|
||||
}
|
||||
if (irfeHeader == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( numberOfSymbols < 0 || numberOfSymbols > reader.length()) {
|
||||
Msg.error(this, "Invalid symbol count "+Integer.toHexString(numberOfSymbols));
|
||||
return;
|
||||
}
|
||||
long oldIndex = reader.getPointerIndex();
|
||||
|
||||
int stringTableIndex = tmpIndex + DebugCOFFSymbol.IMAGE_SIZEOF_SYMBOL * numberOfSymbols;
|
||||
|
||||
for (int i = 0; i < numberOfSymbols; ++i) {
|
||||
if (!ntHeader.checkRVA(tmpIndex)) {
|
||||
Msg.error(this, "Invalid file index "+Integer.toHexString(tmpIndex));
|
||||
break;
|
||||
}
|
||||
int start = irfeHeader.getPointerToRawData();
|
||||
reader.setPointerIndex(start);
|
||||
|
||||
DebugCOFFSymbol symbol = DebugCOFFSymbol.createDebugCOFFSymbol(reader, tmpIndex, stringTableIndex);
|
||||
ImageRuntimeFunctionEntries entries =
|
||||
ImageRuntimeFunctionEntries.createImageRuntimeFunctionEntries(reader, start, ntHeader);
|
||||
irfes = entries.getRuntimeFunctionEntries();
|
||||
|
||||
tmpIndex += DebugCOFFSymbol.IMAGE_SIZEOF_SYMBOL;
|
||||
reader.setPointerIndex(oldIndex);
|
||||
}
|
||||
|
||||
tmpIndex += (DebugCOFFSymbolAux.IMAGE_SIZEOF_AUX_SYMBOL * symbol.getNumberOfAuxSymbols());
|
||||
void processSymbols() throws IOException {
|
||||
if (isLordPE()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int numberOfAuxSymbols = symbol.getNumberOfAuxSymbols();
|
||||
long oldIndex = reader.getPointerIndex();
|
||||
|
||||
int tmpIndex = getPointerToSymbolTable();
|
||||
if (!ntHeader.checkRVA(tmpIndex)) {
|
||||
Msg.error(this, "Invalid file index " + Integer.toHexString(tmpIndex));
|
||||
return;
|
||||
}
|
||||
|
||||
if (numberOfSymbols < 0 || numberOfSymbols > reader.length()) {
|
||||
Msg.error(this, "Invalid symbol count " + Integer.toHexString(numberOfSymbols));
|
||||
return;
|
||||
}
|
||||
|
||||
int stringTableIndex = tmpIndex + DebugCOFFSymbol.IMAGE_SIZEOF_SYMBOL * numberOfSymbols;
|
||||
|
||||
for (int i = 0; i < numberOfSymbols; ++i) {
|
||||
if (!ntHeader.checkRVA(tmpIndex)) {
|
||||
Msg.error(this, "Invalid file index " + Integer.toHexString(tmpIndex));
|
||||
break;
|
||||
}
|
||||
|
||||
DebugCOFFSymbol symbol =
|
||||
DebugCOFFSymbol.createDebugCOFFSymbol(reader, tmpIndex, stringTableIndex);
|
||||
|
||||
tmpIndex += DebugCOFFSymbol.IMAGE_SIZEOF_SYMBOL;
|
||||
|
||||
tmpIndex +=
|
||||
(DebugCOFFSymbolAux.IMAGE_SIZEOF_AUX_SYMBOL * symbol.getNumberOfAuxSymbols());
|
||||
|
||||
int numberOfAuxSymbols = symbol.getNumberOfAuxSymbols();
|
||||
i += numberOfAuxSymbols > 0 ? numberOfAuxSymbols : 0;
|
||||
|
||||
symbols.add( symbol );
|
||||
}
|
||||
symbols.add(symbol);
|
||||
}
|
||||
|
||||
reader.setPointerIndex(oldIndex);
|
||||
}
|
||||
reader.setPointerIndex(oldIndex);
|
||||
}
|
||||
|
||||
public boolean isLordPE() {
|
||||
if (getPointerToSymbolTable() == 0x726F4C5B && getNumberOfSymbols() == 0x5D455064) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public boolean isLordPE() {
|
||||
if (getPointerToSymbolTable() == LORDPE_SYMBOL_TABLE &&
|
||||
getNumberOfSymbols() == LORDPE_NUMBER_OF_SYMBOLS) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void parse() throws IOException {
|
||||
reader.setPointerIndex(startIndex);
|
||||
private void parse() throws IOException {
|
||||
reader.setPointerIndex(startIndex);
|
||||
|
||||
machine = reader.readNextShort();
|
||||
numberOfSections = reader.readNextShort();
|
||||
timeDateStamp = reader.readNextInt ();
|
||||
pointerToSymbolTable = reader.readNextInt ();
|
||||
numberOfSymbols = reader.readNextInt ();
|
||||
sizeOfOptionalHeader = reader.readNextShort();
|
||||
characteristics = reader.readNextShort();
|
||||
}
|
||||
machine = reader.readNextShort();
|
||||
numberOfSections = reader.readNextShort();
|
||||
timeDateStamp = reader.readNextInt();
|
||||
pointerToSymbolTable = reader.readNextInt();
|
||||
numberOfSymbols = reader.readNextInt();
|
||||
sizeOfOptionalHeader = reader.readNextShort();
|
||||
characteristics = reader.readNextShort();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.app.util.bin.StructConverter#toDataType()
|
||||
@@ -411,22 +454,22 @@ public class FileHeader implements StructConverter {
|
||||
public DataType toDataType() throws DuplicateNameException {
|
||||
StructureDataType struct = new StructureDataType(NAME, 0);
|
||||
|
||||
struct.add(WORD,2,"Machine",getMachineName());
|
||||
struct.add(WORD,2,"NumberOfSections",null);
|
||||
struct.add(DWORD,4,"TimeDateStamp",null);
|
||||
struct.add(DWORD,4,"PointerToSymbolTable",null);
|
||||
struct.add(DWORD,4,"NumberOfSymbols",null);
|
||||
struct.add(WORD,2,"SizeOfOptionalHeader",null);
|
||||
struct.add(WORD,2,"Characteristics",null);
|
||||
struct.add(WORD, 2, "Machine", getMachineName());
|
||||
struct.add(WORD, 2, "NumberOfSections", null);
|
||||
struct.add(DWORD, 4, "TimeDateStamp", null);
|
||||
struct.add(DWORD, 4, "PointerToSymbolTable", null);
|
||||
struct.add(DWORD, 4, "NumberOfSymbols", null);
|
||||
struct.add(WORD, 2, "SizeOfOptionalHeader", null);
|
||||
struct.add(WORD, 2, "Characteristics", null);
|
||||
|
||||
struct.setCategoryPath(new CategoryPath("/PE"));
|
||||
|
||||
return struct;
|
||||
}
|
||||
|
||||
private void setSectionHeaders(SectionHeader [] sectionHeaders) {
|
||||
private void setSectionHeaders(SectionHeader[] sectionHeaders) {
|
||||
this.sectionHeaders = sectionHeaders;
|
||||
numberOfSections = (short)sectionHeaders.length;
|
||||
numberOfSections = (short) sectionHeaders.length;
|
||||
}
|
||||
|
||||
void writeHeader(RandomAccessFile raf, DataConverter dc) throws IOException {
|
||||
@@ -436,7 +479,7 @@ public class FileHeader implements StructConverter {
|
||||
raf.write(dc.getBytes(pointerToSymbolTable));
|
||||
raf.write(dc.getBytes(numberOfSymbols));
|
||||
raf.write(dc.getBytes(sizeOfOptionalHeader));
|
||||
raf.write(dc.getBytes(characteristics));
|
||||
raf.write(dc.getBytes(characteristics));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -449,61 +492,61 @@ public class FileHeader implements StructConverter {
|
||||
* @throws RuntimeException if the memory block is uninitialized
|
||||
*/
|
||||
public void addSection(MemoryBlock block, OptionalHeader optionalHeader) {
|
||||
DataDirectory [] directories = optionalHeader.getDataDirectories();
|
||||
|
||||
DataDirectory [] dataDirectories = optionalHeader.getDataDirectories();
|
||||
DataDirectory[] directories = optionalHeader.getDataDirectories();
|
||||
|
||||
DataDirectory[] dataDirectories = optionalHeader.getDataDirectories();
|
||||
|
||||
SecurityDataDirectory sdd = null;
|
||||
if (dataDirectories.length > OptionalHeader.IMAGE_DIRECTORY_ENTRY_SECURITY) {
|
||||
sdd = (SecurityDataDirectory)dataDirectories[OptionalHeader.IMAGE_DIRECTORY_ENTRY_SECURITY];
|
||||
sdd =
|
||||
(SecurityDataDirectory) dataDirectories[OptionalHeader.IMAGE_DIRECTORY_ENTRY_SECURITY];
|
||||
if (sdd != null && sdd.getSize() > 0) {
|
||||
sdd.updatePointers( PortableExecutable.computeAlignment( (int)block.getSize( ), optionalHeader.getFileAlignment( ) ) );
|
||||
sdd.updatePointers(PortableExecutable.computeAlignment((int) block.getSize(),
|
||||
optionalHeader.getFileAlignment()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int lastPos = computeAlignedNewPosition( optionalHeader, directories );
|
||||
int lastPos = computeAlignedNewPosition(optionalHeader, directories);
|
||||
|
||||
SectionHeader newSection = new SectionHeader(block, optionalHeader, lastPos);
|
||||
|
||||
SectionHeader [] newSectionHeaders = new SectionHeader[sectionHeaders.length + 1];
|
||||
System.arraycopy(sectionHeaders, 0, newSectionHeaders, 0, sectionHeaders.length);
|
||||
SectionHeader[] newSectionHeaders = new SectionHeader[sectionHeaders.length + 1];
|
||||
System.arraycopy(sectionHeaders, 0, newSectionHeaders, 0, sectionHeaders.length);
|
||||
newSectionHeaders[sectionHeaders.length] = newSection;
|
||||
setSectionHeaders(newSectionHeaders);
|
||||
|
||||
int firstSectionStart = sectionHeaders[0].getPointerToRawData();
|
||||
int lastSectionEnd = sectionHeaders[sectionHeaders.length-1].getPointerToRawData()
|
||||
+sectionHeaders[sectionHeaders.length-1].getSizeOfRawData();
|
||||
int lastSectionEnd = sectionHeaders[sectionHeaders.length - 1].getPointerToRawData() +
|
||||
sectionHeaders[sectionHeaders.length - 1].getSizeOfRawData();
|
||||
|
||||
for (int i = 0 ; i < directories.length ; i++) {
|
||||
if (directories[i] == null ||
|
||||
directories[i].getSize() == 0 ||
|
||||
for (int i = 0; i < directories.length; i++) {
|
||||
if (directories[i] == null || directories[i].getSize() == 0 ||
|
||||
directories[i].isContainedInSection()) {
|
||||
continue;
|
||||
}
|
||||
if (directories[i].getVirtualAddress() < firstSectionStart) {
|
||||
if (i != OptionalHeader.IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT) {
|
||||
throw new RuntimeException("PE - Unexpected directory before sections: "+i);
|
||||
throw new RuntimeException("PE - Unexpected directory before sections: " + i);
|
||||
}
|
||||
}
|
||||
if (directories[i].getVirtualAddress() > lastSectionEnd) {
|
||||
if (i != OptionalHeader.IMAGE_DIRECTORY_ENTRY_SECURITY) {
|
||||
throw new RuntimeException("PE - Unexpected directory after sections: "+i);
|
||||
throw new RuntimeException("PE - Unexpected directory after sections: " + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
|
||||
|
||||
if (dataDirectories.length > OptionalHeader.IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT) {
|
||||
BoundImportDataDirectory bidd = (BoundImportDataDirectory)dataDirectories[OptionalHeader.IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT];
|
||||
BoundImportDataDirectory bidd =
|
||||
(BoundImportDataDirectory) dataDirectories[OptionalHeader.IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT];
|
||||
if (bidd != null && bidd.getSize() > 0) {
|
||||
bidd.updatePointers(SectionHeader.IMAGE_SIZEOF_SECTION_HEADER);
|
||||
int endptr = bidd.getVirtualAddress() + bidd.getSize() - 1;
|
||||
if (endptr >= sectionHeaders[0].getPointerToRawData()) {
|
||||
int alignedPtr = PortableExecutable.computeAlignment(endptr, optionalHeader.getFileAlignment());
|
||||
int alignedPtr = PortableExecutable.computeAlignment(endptr,
|
||||
optionalHeader.getFileAlignment());
|
||||
offset = alignedPtr - sectionHeaders[0].getPointerToRawData();
|
||||
for (SectionHeader sectionHeader : sectionHeaders) {
|
||||
sectionHeader.updatePointers(offset);
|
||||
@@ -514,9 +557,9 @@ public class FileHeader implements StructConverter {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (dataDirectories.length > OptionalHeader.IMAGE_DIRECTORY_ENTRY_DEBUG) {
|
||||
DebugDataDirectory ddd = (DebugDataDirectory)dataDirectories[OptionalHeader.IMAGE_DIRECTORY_ENTRY_DEBUG];
|
||||
DebugDataDirectory ddd =
|
||||
(DebugDataDirectory) dataDirectories[OptionalHeader.IMAGE_DIRECTORY_ENTRY_DEBUG];
|
||||
if (ddd != null && ddd.getSize() > 0) {
|
||||
if (ddd.getVirtualAddress() > newSection.getVirtualAddress()) {
|
||||
if (sdd != null && sdd.getSize() > 0) {
|
||||
@@ -530,12 +573,12 @@ public class FileHeader implements StructConverter {
|
||||
}
|
||||
|
||||
if (block.isExecute()) {
|
||||
optionalHeader.setSizeOfCode(optionalHeader.getSizeOfCode() +
|
||||
newSection.getSizeOfRawData());
|
||||
optionalHeader
|
||||
.setSizeOfCode(optionalHeader.getSizeOfCode() + newSection.getSizeOfRawData());
|
||||
}
|
||||
else {
|
||||
optionalHeader.setSizeOfInitializedData(optionalHeader.getSizeOfInitializedData() +
|
||||
newSection.getSizeOfRawData());
|
||||
optionalHeader.setSizeOfInitializedData(
|
||||
optionalHeader.getSizeOfInitializedData() + newSection.getSizeOfRawData());
|
||||
}
|
||||
|
||||
int soi = newSection.getVirtualAddress() + newSection.getSizeOfRawData();
|
||||
@@ -543,7 +586,8 @@ public class FileHeader implements StructConverter {
|
||||
optionalHeader.setSizeOfImage(soi);
|
||||
}
|
||||
|
||||
private int computeAlignedNewPosition( OptionalHeader optionalHeader, DataDirectory [] directories ) {
|
||||
private int computeAlignedNewPosition(OptionalHeader optionalHeader,
|
||||
DataDirectory[] directories) {
|
||||
int lastPos = 0;
|
||||
for (SectionHeader sectionHeader : sectionHeaders) {
|
||||
if (sectionHeader.getPointerToRawData() + sectionHeader.getSizeOfRawData() > lastPos) {
|
||||
@@ -551,14 +595,13 @@ public class FileHeader implements StructConverter {
|
||||
}
|
||||
}
|
||||
for (DataDirectory directorie : directories) {
|
||||
if (directorie == null ||
|
||||
directorie.getSize() == 0) {
|
||||
if (directorie == null || directorie.getSize() == 0) {
|
||||
continue;
|
||||
}
|
||||
if (directorie.rvaToPointer() + directorie.getSize() > lastPos) {
|
||||
lastPos = directorie.rvaToPointer() + directorie.getSize();
|
||||
}
|
||||
}
|
||||
return PortableExecutable.computeAlignment( lastPos, optionalHeader.getFileAlignment( ) );
|
||||
return PortableExecutable.computeAlignment(lastPos, optionalHeader.getFileAlignment());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,486 @@
|
||||
/* ###
|
||||
* 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 ghidra.app.util.bin.format.pe;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY {
|
||||
* DWORD BeginAddress;
|
||||
* DWORD EndAddress;
|
||||
* union {
|
||||
* DWORD UnwindInfoAddress;
|
||||
* DWORD UnwindData;
|
||||
* } DUMMYUNIONNAME;
|
||||
* } RUNTIME_FUNCTION, *PRUNTIME_FUNCTION, _IMAGE_RUNTIME_FUNCTION_ENTRY, *_PIMAGE_RUNTIME_FUNCTION_ENTRY;
|
||||
*
|
||||
* #define UNW_FLAG_NHANDLER 0x0
|
||||
* #define UNW_FLAG_EHANDLER 0x1
|
||||
* #define UNW_FLAG_UHANDLER 0x2
|
||||
* #define UNW_FLAG_CHAININFO 0x4
|
||||
*
|
||||
* typedef struct _UNWIND_INFO {
|
||||
* UCHAR Version : 3;
|
||||
* UCHAR Flags : 5;
|
||||
* UCHAR SizeOfProlog;
|
||||
* UCHAR CountOfUnwindCodes;
|
||||
* UCHAR FrameRegister : 4;
|
||||
* UCHAR FrameOffset : 4;
|
||||
* UNWIND_CODE UnwindCode[1];
|
||||
*
|
||||
* //
|
||||
* // The unwind codes are followed by an optional DWORD aligned field that
|
||||
* // contains the exception handler address or the address of chained unwind
|
||||
* // information. If an exception handler address is specified, then it is
|
||||
* // followed by the language specified exception handler data.
|
||||
* //
|
||||
* // union {
|
||||
* // ULONG ExceptionHandler;
|
||||
* // ULONG FunctionEntry;
|
||||
* // };
|
||||
* //
|
||||
* // ULONG ExceptionData[];
|
||||
* //
|
||||
* } UNWIND_INFO, *PUNWIND_INFO;
|
||||
*/
|
||||
public class ImageRuntimeFunctionEntries {
|
||||
private final static int UNWIND_INFO_VERSION_BITMASK = 0x07;
|
||||
private final static int UNWIND_INFO_FLAGS_SHIFT = 0x03;
|
||||
private final static int UNWIND_INFO_FRAME_REGISTER_MASK = 0x0F;
|
||||
private final static int UNWIND_INFO_FRAME_OFFSET_SHIFT = 0x04;
|
||||
private final static int UNWIND_INFO_OPCODE_MASK = 0x0F;
|
||||
private final static int UNWIND_INFO_OPCODE_INFO_SHIFT = 0x04;
|
||||
private final static int UNWIND_INFO_SIZE = 0x0C;
|
||||
|
||||
List<_IMAGE_RUNTIME_FUNCTION_ENTRY> functionEntries = new ArrayList<>();
|
||||
|
||||
static ImageRuntimeFunctionEntries createImageRuntimeFunctionEntries(
|
||||
FactoryBundledWithBinaryReader reader, long index, NTHeader ntHeader)
|
||||
throws IOException {
|
||||
ImageRuntimeFunctionEntries imageRuntimeFunctionEntriesSection =
|
||||
(ImageRuntimeFunctionEntries) reader.getFactory()
|
||||
.create(ImageRuntimeFunctionEntries.class);
|
||||
imageRuntimeFunctionEntriesSection.initImageRuntimeFunctionEntries(reader, index, ntHeader);
|
||||
return imageRuntimeFunctionEntriesSection;
|
||||
}
|
||||
|
||||
/**
|
||||
* DO NOT USE THIS CONSTRUCTOR, USE create*(GenericFactory ...) FACTORY METHODS INSTEAD.
|
||||
*/
|
||||
public ImageRuntimeFunctionEntries() {
|
||||
}
|
||||
|
||||
private void initImageRuntimeFunctionEntries(FactoryBundledWithBinaryReader reader, long index,
|
||||
NTHeader ntHeader) throws IOException {
|
||||
|
||||
int entryCount = 0;
|
||||
|
||||
// Find the exception handler data section. This is an unbounded array of
|
||||
// RUNTIME_INFO structures one after another and there's no count field
|
||||
// to tell us how many there are, so get the maximum number there could be
|
||||
// based on the size of the section.
|
||||
FileHeader fh = ntHeader.getFileHeader();
|
||||
for (SectionHeader section : fh.getSectionHeaders()) {
|
||||
if (section.getName().contentEquals(".pdata")) {
|
||||
entryCount = section.getSizeOfRawData() / UNWIND_INFO_SIZE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entryCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
long origIndex = reader.getPointerIndex();
|
||||
|
||||
reader.setPointerIndex(index);
|
||||
|
||||
for (int i = 0; i < entryCount; i++) {
|
||||
_IMAGE_RUNTIME_FUNCTION_ENTRY entry = new _IMAGE_RUNTIME_FUNCTION_ENTRY();
|
||||
entry.beginAddress = reader.readNextUnsignedInt();
|
||||
entry.endAddress = reader.readNextUnsignedInt();
|
||||
entry.unwindInfoAddressOrData = reader.readNextUnsignedInt();
|
||||
|
||||
// When the size of the section is bigger than the number of structures
|
||||
// the structure data fields will all be null, signaling the end of the
|
||||
// array of structures. Break out here.
|
||||
if (entry.beginAddress == 0 && entry.endAddress == 0 &&
|
||||
entry.unwindInfoAddressOrData == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Read and process the UNWIND_INFO structures the RUNTIME_INFO
|
||||
// structures point to
|
||||
entry.unwindInfo = readUnwindInfo(reader, entry.unwindInfoAddressOrData, ntHeader);
|
||||
|
||||
functionEntries.add(entry);
|
||||
}
|
||||
|
||||
reader.setPointerIndex(origIndex);
|
||||
}
|
||||
|
||||
private UNWIND_INFO readUnwindInfo(FactoryBundledWithBinaryReader reader, long offset,
|
||||
NTHeader ntHeader) throws IOException {
|
||||
long origIndex = reader.getPointerIndex();
|
||||
|
||||
long pointer = ntHeader.rvaToPointer(offset);
|
||||
UNWIND_INFO unwindInfo = new UNWIND_INFO(pointer);
|
||||
|
||||
if (pointer < 0) {
|
||||
return unwindInfo;
|
||||
}
|
||||
|
||||
reader.setPointerIndex(pointer);
|
||||
byte splitByte = reader.readNextByte();
|
||||
unwindInfo.version = (byte) (splitByte & UNWIND_INFO_VERSION_BITMASK);
|
||||
unwindInfo.flags = (byte) (splitByte >> UNWIND_INFO_FLAGS_SHIFT);
|
||||
|
||||
unwindInfo.sizeOfProlog = reader.readNextByte();
|
||||
unwindInfo.countOfUnwindCodes = reader.readNextByte();
|
||||
|
||||
splitByte = reader.readNextByte();
|
||||
unwindInfo.frameRegister = (byte) (splitByte & UNWIND_INFO_FRAME_REGISTER_MASK);
|
||||
unwindInfo.frameOffset = (byte) (splitByte >> UNWIND_INFO_FRAME_OFFSET_SHIFT);
|
||||
|
||||
unwindInfo.unwindCodes = new UNWIND_CODE[unwindInfo.countOfUnwindCodes];
|
||||
for (int i = 0; i < unwindInfo.countOfUnwindCodes; i++) {
|
||||
UNWIND_CODE code = new UNWIND_CODE();
|
||||
code.offsetInProlog = reader.readNextByte();
|
||||
|
||||
int opCodeData = reader.readNextUnsignedByte();
|
||||
code.opCode = UNWIND_CODE_OPCODE.fromInt((opCodeData & UNWIND_INFO_OPCODE_MASK));
|
||||
code.opInfoRegister =
|
||||
UNWIND_CODE_OPINFO_REGISTER.fromInt(opCodeData >> UNWIND_INFO_OPCODE_INFO_SHIFT);
|
||||
|
||||
unwindInfo.unwindCodes[i] = code;
|
||||
}
|
||||
|
||||
// You can have an exception handler and/or an unwind handler, or you
|
||||
// can have chained exception handling info only.
|
||||
if (unwindInfo.hasExceptionHandler() || unwindInfo.hasUnwindHandler()) {
|
||||
if (unwindInfo.hasExceptionHandler()) {
|
||||
unwindInfo.exceptionHandlerFunction = reader.readNextInt();
|
||||
}
|
||||
if (unwindInfo.hasUnwindHandler()) {
|
||||
unwindInfo.unwindHandlerFunction = reader.readNextInt();
|
||||
}
|
||||
}
|
||||
else if (unwindInfo.hasChainedUnwindInfo()) {
|
||||
unwindInfo.unwindHandlerChainInfo = new _IMAGE_RUNTIME_FUNCTION_ENTRY();
|
||||
unwindInfo.unwindHandlerChainInfo.beginAddress = reader.readNextInt();
|
||||
unwindInfo.unwindHandlerChainInfo.endAddress = reader.readNextInt();
|
||||
unwindInfo.unwindHandlerChainInfo.unwindInfoAddressOrData = reader.readNextInt();
|
||||
|
||||
// Follow the chain to the referenced UNWIND_INFO structure until we
|
||||
// get to the end
|
||||
unwindInfo.unwindHandlerChainInfo.unwindInfo = readUnwindInfo(reader,
|
||||
unwindInfo.unwindHandlerChainInfo.unwindInfoAddressOrData, ntHeader);
|
||||
}
|
||||
|
||||
reader.setPointerIndex(origIndex);
|
||||
|
||||
return unwindInfo;
|
||||
}
|
||||
|
||||
public List<_IMAGE_RUNTIME_FUNCTION_ENTRY> getRuntimeFunctionEntries() {
|
||||
return functionEntries;
|
||||
}
|
||||
|
||||
public class _IMAGE_RUNTIME_FUNCTION_ENTRY {
|
||||
public long beginAddress;
|
||||
public long endAddress;
|
||||
public long unwindInfoAddressOrData;
|
||||
public UNWIND_INFO unwindInfo;
|
||||
}
|
||||
|
||||
public enum UNWIND_CODE_OPCODE {
|
||||
UWOP_PUSH_NONVOL(0x00),
|
||||
UWOP_ALLOC_LARGE(0x01),
|
||||
UWOP_ALLOC_SMALL(0x02),
|
||||
UWOP_SET_FPREG(0x03),
|
||||
UWOP_SAVE_NONVOL(0x04),
|
||||
UWOP_SAVE_NONVOL_FAR(0x05),
|
||||
UWOP_SAVE_XMM(0x06),
|
||||
UWOP_SAVE_XMM_FAR(0x07),
|
||||
UWOP_SAVE_XMM128(0x08),
|
||||
UWOP_SAVE_XMM128_FAR(0x09),
|
||||
UWOP_PUSH_MACHFRAME(0x0A);
|
||||
|
||||
private final int id;
|
||||
|
||||
UNWIND_CODE_OPCODE(int value) {
|
||||
id = value;
|
||||
}
|
||||
|
||||
public int id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public static UNWIND_CODE_OPCODE fromInt(int id) {
|
||||
UNWIND_CODE_OPCODE[] values = UNWIND_CODE_OPCODE.values();
|
||||
for (UNWIND_CODE_OPCODE value : values) {
|
||||
if (value.id == id) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public enum UNWIND_CODE_OPINFO_REGISTER {
|
||||
UNWIND_OPINFO_REGISTER_RAX(0x00),
|
||||
UNWIND_OPINFO_REGISTER_RCX(0x01),
|
||||
UNWIND_OPINFO_REGISTER_RDX(0x02),
|
||||
UNWIND_OPINFO_REGISTER_RBX(0x03),
|
||||
UNWIND_OPINFO_REGISTER_RSP(0x04),
|
||||
UNWIND_OPINFO_REGISTER_RBP(0x05),
|
||||
UNWIND_OPINFO_REGISTER_RSI(0x06),
|
||||
UNWIND_OPINFO_REGISTER_RDI(0x07),
|
||||
UNWIND_OPINFO_REGISTER_R8(0x08),
|
||||
UNWIND_OPINFO_REGISTER_R9(0x09),
|
||||
UNWIND_OPINFO_REGISTER_R10(0x0A),
|
||||
UNWIND_OPINFO_REGISTER_R11(0x0B),
|
||||
UNWIND_OPINFO_REGISTER_R12(0x0C),
|
||||
UNWIND_OPINFO_REGISTER_R13(0x0D),
|
||||
UNWIND_OPINFO_REGISTER_R14(0x0E),
|
||||
UNWIND_OPINFO_REGISTER_R15(0x0F);
|
||||
|
||||
private final int id;
|
||||
|
||||
UNWIND_CODE_OPINFO_REGISTER(int value) {
|
||||
id = value;
|
||||
}
|
||||
|
||||
public int id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public static UNWIND_CODE_OPINFO_REGISTER fromInt(int id) {
|
||||
UNWIND_CODE_OPINFO_REGISTER[] values = UNWIND_CODE_OPINFO_REGISTER.values();
|
||||
for (UNWIND_CODE_OPINFO_REGISTER value : values) {
|
||||
if (value.id == id) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class UNWIND_CODE {
|
||||
public byte offsetInProlog;
|
||||
public UNWIND_CODE_OPCODE opCode;
|
||||
public UNWIND_CODE_OPINFO_REGISTER opInfoRegister;
|
||||
}
|
||||
|
||||
public class UNWIND_INFO implements StructConverter {
|
||||
private static final String NAME = "UNWIND_INFO";
|
||||
|
||||
private final static int UNW_FLAG_NHANDLER = 0x0;
|
||||
private final static int UNW_FLAG_EHANDLER = 0x1;
|
||||
private final static int UNW_FLAG_UHANDLER = 0x2;
|
||||
private final static int UNW_FLAG_CHAININFO = 0x4;
|
||||
|
||||
private final static int UNWIND_VERSION_FIELD_LENGTH = 0x03;
|
||||
private final static int UNWIND_FLAGS_FIELD_LENGTH = 0x05;
|
||||
private final static int UNWIND_FRAME_REGISTER_LENGTH = 0x04;
|
||||
private final static int UNWIND_OP_FIELD_LENGTH = 0x04;
|
||||
|
||||
byte version;
|
||||
byte flags;
|
||||
byte sizeOfProlog;
|
||||
byte countOfUnwindCodes;
|
||||
byte frameRegister;
|
||||
byte frameOffset;
|
||||
UNWIND_CODE[] unwindCodes;
|
||||
int exceptionHandlerFunction;
|
||||
int unwindHandlerFunction;
|
||||
_IMAGE_RUNTIME_FUNCTION_ENTRY unwindHandlerChainInfo;
|
||||
|
||||
long startOffset;
|
||||
|
||||
public UNWIND_INFO(long offset) {
|
||||
startOffset = offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType(NAME + "_" + startOffset, 0);
|
||||
try {
|
||||
StructureDataType vf = new StructureDataType("VersionFlags", 0);
|
||||
vf.insertBitField(0, 1, 0, BYTE, UNWIND_VERSION_FIELD_LENGTH, "Version", null);
|
||||
vf.insertBitField(0, 1, UNWIND_VERSION_FIELD_LENGTH, defineFlagsField(),
|
||||
UNWIND_FLAGS_FIELD_LENGTH, "Flags", null);
|
||||
|
||||
struct.add(vf, "Version + Flags", null);
|
||||
}
|
||||
catch (InvalidDataTypeException e) {
|
||||
struct.add(BYTE, "Version + Flags", null);
|
||||
}
|
||||
|
||||
struct.add(BYTE, "SizeOfProlog", null);
|
||||
struct.add(BYTE, "CountOfUnwindCodes", null);
|
||||
|
||||
try {
|
||||
StructureDataType fr = new StructureDataType("FrameRegisterAndOffset", 0);
|
||||
fr.insertBitField(0, 1, 0, BYTE, UNWIND_FRAME_REGISTER_LENGTH, "FrameRegister",
|
||||
null);
|
||||
fr.insertBitField(0, 1, UNWIND_FRAME_REGISTER_LENGTH, BYTE,
|
||||
UNWIND_FRAME_REGISTER_LENGTH, "FrameOffset", null);
|
||||
struct.add(fr, "FrameRegister + FrameOffset", null);
|
||||
}
|
||||
catch (InvalidDataTypeException e) {
|
||||
struct.add(BYTE, "FrameRegister + FrameOffset", null);
|
||||
}
|
||||
|
||||
for (int i = 0; i < countOfUnwindCodes; i++) {
|
||||
StructureDataType unwindCode = new StructureDataType("UnwindCode", 0);
|
||||
unwindCode.add(BYTE, "OffsetInProlog", null);
|
||||
|
||||
StructureDataType unwindCodeInfo = new StructureDataType("UnwindCodeInfo", 0);
|
||||
try {
|
||||
if (unwindCodes[i].opCode != null) {
|
||||
unwindCodeInfo.insertBitField(0, 1, 0, defineUnwindOpCodeField(),
|
||||
UNWIND_OP_FIELD_LENGTH, "UnwindOpCode", null);
|
||||
}
|
||||
else {
|
||||
unwindCodeInfo.insertBitField(0, 1, 0, BYTE, UNWIND_OP_FIELD_LENGTH,
|
||||
"UnwindOpCode", null);
|
||||
}
|
||||
|
||||
if (unwindCodes[i].opInfoRegister != null) {
|
||||
unwindCodeInfo.insertBitField(0, 1, UNWIND_OP_FIELD_LENGTH,
|
||||
defineUnwindCodeRegisterField(), UNWIND_OP_FIELD_LENGTH, "OpInfo",
|
||||
null);
|
||||
}
|
||||
else {
|
||||
unwindCodeInfo.insertBitField(0, 1, UNWIND_OP_FIELD_LENGTH, BYTE,
|
||||
UNWIND_OP_FIELD_LENGTH, "OpInfo", null);
|
||||
}
|
||||
}
|
||||
catch (InvalidDataTypeException e) {
|
||||
}
|
||||
unwindCode.add(unwindCodeInfo, "UnwindCodeInfo", null);
|
||||
|
||||
struct.add(unwindCode, "UnwindCode", null);
|
||||
}
|
||||
|
||||
if (hasExceptionHandler() || hasUnwindHandler()) {
|
||||
if (hasExceptionHandler()) {
|
||||
struct.add(IBO32, "ExceptionHandler", null);
|
||||
}
|
||||
if (hasUnwindHandler()) {
|
||||
struct.add(IBO32, "UnwindHandler", null);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (hasChainedUnwindInfo()) {
|
||||
struct.add(IBO32, "FunctionStartAddress", null);
|
||||
struct.add(IBO32, "FunctionEndAddress", null);
|
||||
struct.add(IBO32, "FunctionUnwindInfoAddress", null);
|
||||
}
|
||||
}
|
||||
|
||||
return struct;
|
||||
}
|
||||
|
||||
public boolean hasExceptionHandler() {
|
||||
return (flags & UNW_FLAG_EHANDLER) == UNW_FLAG_EHANDLER;
|
||||
}
|
||||
|
||||
public boolean hasUnwindHandler() {
|
||||
return (flags & UNW_FLAG_UHANDLER) == UNW_FLAG_UHANDLER;
|
||||
}
|
||||
|
||||
public boolean hasChainedUnwindInfo() {
|
||||
return (flags & UNW_FLAG_CHAININFO) == UNW_FLAG_CHAININFO;
|
||||
}
|
||||
|
||||
private EnumDataType defineFlagsField() {
|
||||
EnumDataType flagsField = new EnumDataType("Flags", 5);
|
||||
flagsField.add("UNW_FLAG_NHANDLER", UNW_FLAG_NHANDLER);
|
||||
flagsField.add("UNW_FLAG_EHANDLER", UNW_FLAG_EHANDLER);
|
||||
flagsField.add("UNW_FLAG_UHANDLER", UNW_FLAG_UHANDLER);
|
||||
flagsField.add("UNW_FLAG_CHAININFO", UNW_FLAG_CHAININFO);
|
||||
|
||||
return flagsField;
|
||||
}
|
||||
|
||||
private EnumDataType defineUnwindOpCodeField() {
|
||||
EnumDataType unwindOpCodeField = new EnumDataType("UNWIND_CODE_OPCODE", 4);
|
||||
unwindOpCodeField.add("UWOP_PUSH_NONVOL", UNWIND_CODE_OPCODE.UWOP_PUSH_NONVOL.id);
|
||||
unwindOpCodeField.add("UWOP_ALLOC_LARGE", UNWIND_CODE_OPCODE.UWOP_ALLOC_LARGE.id);
|
||||
unwindOpCodeField.add("UWOP_ALLOC_SMALL", UNWIND_CODE_OPCODE.UWOP_ALLOC_SMALL.id);
|
||||
unwindOpCodeField.add("UWOP_SET_FPREG", UNWIND_CODE_OPCODE.UWOP_SET_FPREG.id);
|
||||
unwindOpCodeField.add("UWOP_SAVE_NONVOL", UNWIND_CODE_OPCODE.UWOP_SAVE_NONVOL.id);
|
||||
unwindOpCodeField.add("UWOP_SAVE_NONVOL_FAR",
|
||||
UNWIND_CODE_OPCODE.UWOP_SAVE_NONVOL_FAR.id);
|
||||
unwindOpCodeField.add("UWOP_SAVE_XMM", UNWIND_CODE_OPCODE.UWOP_SAVE_XMM.id);
|
||||
unwindOpCodeField.add("UWOP_SAVE_XMM_FAR", UNWIND_CODE_OPCODE.UWOP_SAVE_XMM_FAR.id);
|
||||
unwindOpCodeField.add("UWOP_SAVE_XMM128", UNWIND_CODE_OPCODE.UWOP_SAVE_XMM128.id);
|
||||
unwindOpCodeField.add("UWOP_SAVE_XMM128_FAR",
|
||||
UNWIND_CODE_OPCODE.UWOP_SAVE_XMM128_FAR.id);
|
||||
unwindOpCodeField.add("UWOP_PUSH_MACHFRAME", UNWIND_CODE_OPCODE.UWOP_PUSH_MACHFRAME.id);
|
||||
|
||||
return unwindOpCodeField;
|
||||
}
|
||||
|
||||
private EnumDataType defineUnwindCodeRegisterField() {
|
||||
EnumDataType unwindCodeRegisterField =
|
||||
new EnumDataType("UNWIND_CODE_OPINFO_REGISTER", 4);
|
||||
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RAX",
|
||||
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RAX.id);
|
||||
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RCX",
|
||||
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RCX.id);
|
||||
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RDX",
|
||||
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RDX.id);
|
||||
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RBX",
|
||||
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RBX.id);
|
||||
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RSP",
|
||||
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RSP.id);
|
||||
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RBP",
|
||||
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RBP.id);
|
||||
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RSI",
|
||||
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RSI.id);
|
||||
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RDI",
|
||||
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RDI.id);
|
||||
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R8",
|
||||
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R8.id);
|
||||
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R9",
|
||||
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R9.id);
|
||||
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R10",
|
||||
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R10.id);
|
||||
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R11",
|
||||
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R11.id);
|
||||
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R12",
|
||||
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R12.id);
|
||||
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R13",
|
||||
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R13.id);
|
||||
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R14",
|
||||
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R14.id);
|
||||
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R15",
|
||||
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R15.id);
|
||||
|
||||
return unwindCodeRegisterField;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ import ghidra.util.task.TaskMonitorAdapter;
|
||||
|
||||
/**
|
||||
* A class to represent the <b><code>IMAGE_NT_HEADERS32</code></b> and
|
||||
* IMAGE_NT_HEADERS64 structs as defined in
|
||||
* IMAGE_NT_HEADERS64 structs as defined in
|
||||
* <code>winnt.h</code>.
|
||||
* <pre>
|
||||
* typedef struct _IMAGE_NT_HEADERS {
|
||||
@@ -39,8 +39,8 @@ import ghidra.util.task.TaskMonitorAdapter;
|
||||
* IMAGE_OPTIONAL_HEADER32 OptionalHeader;
|
||||
* };
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class NTHeader implements StructConverter, OffsetValidator {
|
||||
/**
|
||||
@@ -82,8 +82,8 @@ public class NTHeader implements StructConverter, OffsetValidator {
|
||||
public NTHeader() {
|
||||
}
|
||||
|
||||
private void initNTHeader(FactoryBundledWithBinaryReader reader, int index, SectionLayout layout,
|
||||
boolean advancedProcess, boolean parseCliHeaders)
|
||||
private void initNTHeader(FactoryBundledWithBinaryReader reader, int index,
|
||||
SectionLayout layout, boolean advancedProcess, boolean parseCliHeaders)
|
||||
throws InvalidNTHeaderException, IOException {
|
||||
this.reader = reader;
|
||||
this.index = index;
|
||||
@@ -172,9 +172,9 @@ public class NTHeader implements StructConverter, OffsetValidator {
|
||||
//low alignment mode?
|
||||
//
|
||||
if (optionalHeader != null) {
|
||||
if (optionalHeader.getFileAlignment() == optionalHeader.getSectionAlignment()
|
||||
&& optionalHeader.getSectionAlignment() < 800
|
||||
&& optionalHeader.getFileAlignment() > 1) {
|
||||
if (optionalHeader.getFileAlignment() == optionalHeader.getSectionAlignment() &&
|
||||
optionalHeader.getSectionAlignment() < 800 &&
|
||||
optionalHeader.getFileAlignment() > 1) {
|
||||
return rva;
|
||||
}
|
||||
}
|
||||
@@ -270,6 +270,7 @@ public class NTHeader implements StructConverter, OffsetValidator {
|
||||
|
||||
fileHeader.processSections(optionalHeader);
|
||||
fileHeader.processSymbols();
|
||||
fileHeader.processImageRuntimeFunctionEntries();
|
||||
|
||||
if (advancedProcess) {
|
||||
optionalHeader.processDataDirectories(TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
@@ -278,7 +279,7 @@ public class NTHeader implements StructConverter, OffsetValidator {
|
||||
|
||||
void writeHeader(RandomAccessFile raf, DataConverter dc) throws IOException {
|
||||
|
||||
raf.seek( index );
|
||||
raf.seek(index);
|
||||
|
||||
raf.write(dc.getBytes(signature));
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.format.mz.DOSHeader;
|
||||
import ghidra.app.util.bin.format.pe.*;
|
||||
import ghidra.app.util.bin.format.pe.ImageCor20Header.ImageCor20Flags;
|
||||
import ghidra.app.util.bin.format.pe.ImageRuntimeFunctionEntries._IMAGE_RUNTIME_FUNCTION_ENTRY;
|
||||
import ghidra.app.util.bin.format.pe.PortableExecutable.SectionLayout;
|
||||
import ghidra.app.util.bin.format.pe.debug.DebugCOFFSymbol;
|
||||
import ghidra.app.util.bin.format.pe.debug.DebugDirectoryParser;
|
||||
@@ -148,6 +149,7 @@ public class PeLoader extends AbstractPeDebugLoader {
|
||||
processProperties(optionalHeader, program, monitor);
|
||||
processComments(program.getListing(), monitor);
|
||||
processSymbols(fileHeader, sectionToAddress, program, monitor, log);
|
||||
processImageRuntimeFunctionEntries(fileHeader, program, monitor, log);
|
||||
|
||||
processEntryPoints(ntHeader, program, monitor);
|
||||
String compiler = CompilerOpinion.getOpinion(pe, provider).toString();
|
||||
@@ -248,24 +250,74 @@ public class PeLoader extends AbstractPeDebugLoader {
|
||||
setComment(CodeUnit.EOL_COMMENT, start, section.getName());
|
||||
start = start.add(dt.getLength());
|
||||
}
|
||||
|
||||
// for (int i = 0; i < datadirs.length; ++i) {
|
||||
// if (datadirs[i] == null || datadirs[i].getSize() == 0) {
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// if (datadirs[i].hasParsedCorrectly()) {
|
||||
// start = datadirs[i].getMarkupAddress(program, true);
|
||||
// dt = datadirs[i].toDataType();
|
||||
// DataUtilities.createData(program, start, dt, true, DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
catch (Exception e1) {
|
||||
Msg.error(this, "Error laying down header structures " + e1);
|
||||
}
|
||||
}
|
||||
|
||||
private void processImageRuntimeFunctionEntries(FileHeader fileHeader, Program program,
|
||||
TaskMonitor monitor, MessageLog log) {
|
||||
|
||||
// Check to see that we have exception data to process
|
||||
SectionHeader irfeHeader = null;
|
||||
for (SectionHeader header : fileHeader.getSectionHeaders()) {
|
||||
if (header.getName().contains(".pdata")) {
|
||||
irfeHeader = header;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (irfeHeader == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Address start = program.getImageBase().add(irfeHeader.getVirtualAddress());
|
||||
|
||||
List<_IMAGE_RUNTIME_FUNCTION_ENTRY> irfes = fileHeader.getImageRuntimeFunctionEntries();
|
||||
if (irfes == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
StructureDataType dt = new StructureDataType(".PDATA", 0);
|
||||
dt.setCategoryPath(new CategoryPath("/PE"));
|
||||
|
||||
// Lay an array of RUNTIME_INFO structure out over the data
|
||||
StructureDataType irfeStruct = new StructureDataType("_IMAGE_RUNTIME_FUNCTION_ENTRY", 0);
|
||||
irfeStruct.add(ghidra.app.util.bin.StructConverter.IBO32, "BeginAddress", null);
|
||||
irfeStruct.add(ghidra.app.util.bin.StructConverter.IBO32, "EndAddress", null);
|
||||
irfeStruct.add(ghidra.app.util.bin.StructConverter.IBO32, "UnwindInfoAddressOrData", null);
|
||||
|
||||
ArrayDataType irfeArray =
|
||||
new ArrayDataType(irfeStruct, irfes.size(), irfeStruct.getLength());
|
||||
|
||||
try {
|
||||
DataUtilities.createData(program, start, irfeArray, irfeArray.getLength(), true,
|
||||
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
}
|
||||
catch (CodeUnitInsertionException e) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Each RUNTIME_INFO contains an address to an UNWIND_INFO structure
|
||||
// which also needs to be laid out. When they contain chaining data
|
||||
// they're recursive but the toDataType() function handles that.
|
||||
for (_IMAGE_RUNTIME_FUNCTION_ENTRY entry : irfes) {
|
||||
if (entry.unwindInfoAddressOrData > 0) {
|
||||
try {
|
||||
dt = (StructureDataType) entry.unwindInfo.toDataType();
|
||||
start = program.getImageBase().add(entry.unwindInfoAddressOrData);
|
||||
|
||||
DataUtilities.createData(program, start, dt, dt.getLength(), true,
|
||||
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
}
|
||||
catch (CodeUnitInsertionException | DuplicateNameException | IOException e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processSymbols(FileHeader fileHeader, Map<SectionHeader, Address> sectionToAddress,
|
||||
Program program, TaskMonitor monitor, MessageLog log) {
|
||||
List<DebugCOFFSymbol> symbols = fileHeader.getSymbols();
|
||||
@@ -493,7 +545,7 @@ public class PeLoader extends AbstractPeDebugLoader {
|
||||
break;
|
||||
}
|
||||
|
||||
// Get address of current position in the import address table
|
||||
// Get address of current position in the import address table
|
||||
Address iatAddr = iatBaseAddr.add(offset);
|
||||
Data iatData = listing.getDataAt(iatAddr);
|
||||
if (iatData == null || !(iatData.getValue() instanceof Address)) {
|
||||
@@ -506,8 +558,7 @@ public class PeLoader extends AbstractPeDebugLoader {
|
||||
importInfo.getName(), null, SourceType.IMPORTED, 0, RefType.DATA);
|
||||
}
|
||||
catch (DuplicateNameException | InvalidInputException e) {
|
||||
log.appendMsg(
|
||||
"Failed to create Delay Load external function at: " + iatAddr);
|
||||
log.appendMsg("Failed to create Delay Load external function at: " + iatAddr);
|
||||
}
|
||||
|
||||
// Create delay load proxy function
|
||||
|
||||
Reference in New Issue
Block a user