Merge remote-tracking branch 'origin/GP-729_jmlagor_Process_the_.pdata_section_to_parse_exception_handling_data--SQUASHED'

This commit is contained in:
ghidra1
2021-03-10 12:24:40 -05:00
4 changed files with 860 additions and 279 deletions

View File

@@ -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 &gt;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 &gt;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());
}
}

View File

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

View File

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

View File

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