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());
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ImageRuntimeFunctionEntries.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ImageRuntimeFunctionEntries.java
new file mode 100644
index 0000000000..7a372d9d19
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ImageRuntimeFunctionEntries.java
@@ -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;
+ }
+ }
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/NTHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/NTHeader.java
index 0912d75484..e88d1fe976 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/NTHeader.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/NTHeader.java
@@ -30,7 +30,7 @@ import ghidra.util.task.TaskMonitorAdapter;
/**
* A class to represent the IMAGE_NT_HEADERS32 and
- * IMAGE_NT_HEADERS64 structs as defined in
+ * IMAGE_NT_HEADERS64 structs as defined in
* winnt.h.
*
* typedef struct _IMAGE_NT_HEADERS {
@@ -39,8 +39,8 @@ import ghidra.util.task.TaskMonitorAdapter;
* IMAGE_OPTIONAL_HEADER32 OptionalHeader;
* };
*
- *
- *
+ *
+ *
*/
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));
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java
index f7f1141135..ad4317876c 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java
@@ -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 sectionToAddress,
Program program, TaskMonitor monitor, MessageLog log) {
List 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