GP-2826: PeLoader now handles sections partially or fully outside of the

file better
This commit is contained in:
Ryan Kurtz
2022-11-14 03:39:34 -05:00
parent 81fd59389d
commit 322a4e81a8
4 changed files with 56 additions and 41 deletions
@@ -332,32 +332,43 @@ public class FileHeader implements StructConverter {
long stringTableOffset = getStringTableOffset(); long stringTableOffset = getStringTableOffset();
sectionHeaders = new SectionHeader[numberOfSections]; sectionHeaders = new SectionHeader[numberOfSections];
for (int i = 0; i < numberOfSections; ++i) { for (int i = 0; i < numberOfSections; ++i) {
sectionHeaders[i] = SectionHeader section =
SectionHeader.readSectionHeader(reader, tmpIndex, stringTableOffset); SectionHeader.readSectionHeader(reader, tmpIndex, stringTableOffset);
sectionHeaders[i] = section;
int pointerToRawData = section.getPointerToRawData();
int sizeOfRawData = section.getSizeOfRawData();
// Ensure PointerToRawData + SizeOfRawData doesn't exceed the length of the file // Ensure PointerToRawData + SizeOfRawData doesn't exceed the length of the file
int pointerToRawData = sectionHeaders[i].getPointerToRawData(); if (pointerToRawData >= reader.length()) {
int sizeOfRawData = (int) Math.min(reader.length() - pointerToRawData, sizeOfRawData = 0;
sectionHeaders[i].getSizeOfRawData()); Msg.warn(this, "Section " + section.getName() + " begins after end of file!");
}
else if (pointerToRawData + sizeOfRawData > reader.length()) {
sizeOfRawData = (int) (reader.length() - pointerToRawData);
Msg.warn(this,
String.format("Section %s exceeds file length...truncating from %d to %d",
section.getName(), section.getSizeOfRawData(), sizeOfRawData));
}
section.setSizeOfRawData(sizeOfRawData);
// Ensure VirtualSize is large enough to accommodate SizeOfRawData, but do not // Ensure VirtualSize is large enough to accommodate SizeOfRawData, but do not
// exceed the next alignment boundary. We can only do this if the VirtualAddress is // exceed the next alignment boundary. We can only do this if the VirtualAddress is
// already properly aligned, since we currently don't support moving sections to // already properly aligned, since we currently don't support moving sections to
// different addresses to enforce alignment. // different addresses to enforce alignment.
int virtualAddress = sectionHeaders[i].getVirtualAddress(); int virtualAddress = section.getVirtualAddress();
int virtualSize = sectionHeaders[i].getVirtualSize(); int virtualSize = section.getVirtualSize();
int alignedVirtualAddress = PortableExecutable.computeAlignment(virtualAddress, int alignedVirtualAddress = PortableExecutable.computeAlignment(virtualAddress,
optHeader.getSectionAlignment()); optHeader.getSectionAlignment());
int alignedVirtualSize = PortableExecutable.computeAlignment(virtualSize, int alignedVirtualSize = PortableExecutable.computeAlignment(virtualSize,
optHeader.getSectionAlignment()); optHeader.getSectionAlignment());
if (virtualAddress == alignedVirtualAddress) { if (virtualAddress == alignedVirtualAddress) {
if (sizeOfRawData > virtualSize) { if (sizeOfRawData > virtualSize) {
sectionHeaders[i] section.setVirtualSize(Math.min(sizeOfRawData, alignedVirtualSize));
.setVirtualSize(Math.min(sizeOfRawData, alignedVirtualSize));
} }
} }
else { else {
Msg.warn(this, "Section " + sectionHeaders[i].getName() + " is not aligned!"); Msg.warn(this, "Section " + section.getName() + " is not aligned!");
} }
tmpIndex += SectionHeader.IMAGE_SIZEOF_SECTION_HEADER; tmpIndex += SectionHeader.IMAGE_SIZEOF_SECTION_HEADER;
} }
@@ -22,10 +22,11 @@ import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter; import ghidra.app.util.bin.StructConverter;
import ghidra.app.util.bin.format.pe.PortableExecutable.SectionLayout; import ghidra.app.util.bin.format.pe.PortableExecutable.SectionLayout;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.util.*; import ghidra.util.DataConverter;
import ghidra.util.Msg;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.NotYetImplementedException; import ghidra.util.exception.NotYetImplementedException;
import ghidra.util.task.TaskMonitorAdapter; import ghidra.util.task.TaskMonitor;
/** /**
* A class to represent the <b><code>IMAGE_NT_HEADERS32</code></b> and * A class to represent the <b><code>IMAGE_NT_HEADERS32</code></b> and
@@ -62,9 +63,11 @@ public class NTHeader implements StructConverter, OffsetValidator {
* Constructs a new NT header. * Constructs a new NT header.
* @param reader the binary reader * @param reader the binary reader
* @param index the index into the reader to the start of the NT header * @param index the index into the reader to the start of the NT header
* @param advancedProcess if true, information rafside of the base header will be processed * @param layout The {@link SectionLayout}
* @param advancedProcess if true, information outside of the base header will be processed
* @param parseCliHeaders if true, CLI headers are parsed (if present) * @param parseCliHeaders if true, CLI headers are parsed (if present)
* @throws InvalidNTHeaderException if the bytes the specified index * @throws InvalidNTHeaderException if the bytes the specified index
* @throws IOException if an IO-related exception occurred
* do not constitute an accurate NT header. * do not constitute an accurate NT header.
*/ */
public NTHeader(BinaryReader reader, int index, SectionLayout layout, boolean advancedProcess, public NTHeader(BinaryReader reader, int index, SectionLayout layout, boolean advancedProcess,
@@ -124,22 +127,26 @@ public class NTHeader implements StructConverter, OffsetValidator {
/** /**
* Converts a relative virtual address (RVA) into a pointer. * Converts a relative virtual address (RVA) into a pointer.
* @see #rvaToPointer(long) *
* @param rva the relative virtual address
* @return the pointer into binary image, 0 if not valid
*/ */
public int rvaToPointer(int rva) { public int rvaToPointer(int rva) {
return (int) rvaToPointer(rva & Conv.INT_MASK); return (int) rvaToPointer(Integer.toUnsignedLong(rva));
} }
/** /**
* Converts a relative virtual address (RVA) into a pointer.
* @param rva the relative virtual address * @param rva the relative virtual address
* @return the pointer into binary image, 0 if not valid * @return the pointer into binary image, 0 if not valid
*/ */
public long rvaToPointer(long rva) { public long rvaToPointer(long rva) {
SectionHeader[] sections = fileHeader.getSectionHeaders(); SectionHeader[] sections = fileHeader.getSectionHeaders();
for (SectionHeader section : sections) { for (SectionHeader section : sections) {
long sectionVA = section.getVirtualAddress() & Conv.INT_MASK; long sectionVA = Integer.toUnsignedLong(section.getVirtualAddress());
long rawSize = section.getSizeOfRawData() & Conv.INT_MASK; long rawSize = Integer.toUnsignedLong(section.getSizeOfRawData());
long rawPtr = section.getPointerToRawData() & Conv.INT_MASK; long rawPtr = Integer.toUnsignedLong(section.getPointerToRawData());
switch (layout) { switch (layout) {
case MEMORY: case MEMORY:
@@ -169,10 +176,10 @@ public class NTHeader implements StructConverter, OffsetValidator {
public boolean checkPointer(long ptr) { public boolean checkPointer(long ptr) {
SectionHeader[] sections = fileHeader.getSectionHeaders(); SectionHeader[] sections = fileHeader.getSectionHeaders();
for (SectionHeader section : sections) { for (SectionHeader section : sections) {
long virtPtr = section.getVirtualAddress() & Conv.INT_MASK; long virtPtr = Integer.toUnsignedLong(section.getVirtualAddress());
long virtSize = section.getVirtualSize() & Conv.INT_MASK; long virtSize = Integer.toUnsignedLong(section.getVirtualSize());
long rawSize = section.getSizeOfRawData() & Conv.INT_MASK; long rawSize = Integer.toUnsignedLong(section.getSizeOfRawData());
long rawPtr = section.getPointerToRawData() & Conv.INT_MASK; long rawPtr = Integer.toUnsignedLong(section.getPointerToRawData());
long sectionBasePtr = layout == SectionLayout.MEMORY ? virtPtr : rawPtr; long sectionBasePtr = layout == SectionLayout.MEMORY ? virtPtr : rawPtr;
long sectionSize = layout == SectionLayout.MEMORY ? virtSize : rawSize; long sectionSize = layout == SectionLayout.MEMORY ? virtSize : rawSize;
@@ -199,13 +206,17 @@ public class NTHeader implements StructConverter, OffsetValidator {
/** /**
* Converts a virtual address (VA) into a pointer. * Converts a virtual address (VA) into a pointer.
* @see #vaToPointer(long) *
* @param va the virtual address
* @return the pointer into binary image, 0 if not valid
*/ */
public int vaToPointer(int va) { public int vaToPointer(int va) {
return (int) vaToPointer(va & Conv.INT_MASK); return (int) vaToPointer(Integer.toUnsignedLong(va));
} }
/** /**
* Converts a virtual address (VA) into a pointer.
*
* @param va the virtual address * @param va the virtual address
* @return the pointer into binary image, 0 if not valid * @return the pointer into binary image, 0 if not valid
*/ */
@@ -213,10 +224,6 @@ public class NTHeader implements StructConverter, OffsetValidator {
return rvaToPointer(va - getOptionalHeader().getImageBase()); return rvaToPointer(va - getOptionalHeader().getImageBase());
} }
/**
* @throws InvalidNTHeaderException
* @throws IOException
*/
private void parse() throws InvalidNTHeaderException, IOException { private void parse() throws InvalidNTHeaderException, IOException {
if (index < 0 || index > reader.length()) { if (index < 0 || index > reader.length()) {
@@ -229,6 +236,7 @@ public class NTHeader implements StructConverter, OffsetValidator {
signature = reader.readInt(tmpIndex); signature = reader.readInt(tmpIndex);
} }
catch (IndexOutOfBoundsException ioobe) { catch (IndexOutOfBoundsException ioobe) {
// Handled below
} }
// if not correct signature, then return... // if not correct signature, then return...
@@ -256,7 +264,7 @@ public class NTHeader implements StructConverter, OffsetValidator {
fileHeader.processSymbols(); fileHeader.processSymbols();
if (advancedProcess) { if (advancedProcess) {
optionalHeader.processDataDirectories(TaskMonitorAdapter.DUMMY_MONITOR); optionalHeader.processDataDirectories(TaskMonitor.DUMMY);
} }
} }
@@ -20,7 +20,6 @@ import java.io.*;
import ghidra.app.util.bin.*; import ghidra.app.util.bin.*;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
import ghidra.util.Conv;
import ghidra.util.DataConverter; import ghidra.util.DataConverter;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
@@ -535,7 +534,7 @@ public class SectionHeader implements StructConverter, ByteArrayConverter {
EnumDataType characteristicsEnum = new EnumDataType("SectionFlags", 4); EnumDataType characteristicsEnum = new EnumDataType("SectionFlags", 4);
characteristicsEnum.setCategoryPath(new CategoryPath("/PE")); characteristicsEnum.setCategoryPath(new CategoryPath("/PE"));
for (SectionFlags flag : SectionFlags.values()) { for (SectionFlags flag : SectionFlags.values()) {
characteristicsEnum.add(flag.name(), Conv.intToLong(flag.getMask())); characteristicsEnum.add(flag.name(), Integer.toUnsignedLong(flag.getMask()));
} }
struct.add(characteristicsEnum, "Characteristics", null); struct.add(characteristicsEnum, "Characteristics", null);
struct.setCategoryPath(new CategoryPath("/PE")); struct.setCategoryPath(new CategoryPath("/PE"));
@@ -16,7 +16,6 @@
package ghidra.app.util.opinion; package ghidra.app.util.opinion;
import java.io.IOException; import java.io.IOException;
import java.math.BigInteger;
import java.util.*; import java.util.*;
import ghidra.app.util.MemoryBlockUtils; import ghidra.app.util.MemoryBlockUtils;
@@ -36,8 +35,6 @@ import ghidra.program.database.function.OverlappingFunctionException;
import ghidra.program.database.mem.FileBytes; import ghidra.program.database.mem.FileBytes;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.mem.Memory; import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.mem.MemoryAccessException;
@@ -109,7 +106,6 @@ public class PeLoader extends AbstractPeDebugLoader {
return; return;
} }
OptionalHeader optionalHeader = ntHeader.getOptionalHeader(); OptionalHeader optionalHeader = ntHeader.getOptionalHeader();
FileHeader fileHeader = ntHeader.getFileHeader();
monitor.setMessage("Completing PE header parsing..."); monitor.setMessage("Completing PE header parsing...");
FileBytes fileBytes = createFileBytes(provider, program, monitor); FileBytes fileBytes = createFileBytes(provider, program, monitor);
@@ -406,7 +402,7 @@ public class PeLoader extends AbstractPeDebugLoader {
//than 32bit. On WindowsCE some sections are //than 32bit. On WindowsCE some sections are
//declared to roll over. //declared to roll over.
if (!optionalHeader.is64bit()) { if (!optionalHeader.is64bit()) {
addr &= Conv.INT_MASK; addr &= 0x00000000ffffffffL;
} }
Address address = space.getAddress(addr); Address address = space.getAddress(addr);
@@ -686,6 +682,11 @@ public class PeLoader extends AbstractPeDebugLoader {
address = space.getAddress(addr); address = space.getAddress(addr);
String sectionName = sections[i].getReadableName();
if (sectionName.isBlank()) {
sectionName = "SECTION." + i;
}
r = ((sections[i].getCharacteristics() & r = ((sections[i].getCharacteristics() &
SectionFlags.IMAGE_SCN_MEM_READ.getMask()) != 0x0); SectionFlags.IMAGE_SCN_MEM_READ.getMask()) != 0x0);
w = ((sections[i].getCharacteristics() & w = ((sections[i].getCharacteristics() &
@@ -707,10 +708,6 @@ public class PeLoader extends AbstractPeDebugLoader {
Msg.warn(this, "OptionalHeader.SizeOfImage < size of " + Msg.warn(this, "OptionalHeader.SizeOfImage < size of " +
sections[i].getName() + " section"); sections[i].getName() + " section");
} }
String sectionName = sections[i].getReadableName();
if (sectionName.isBlank()) {
sectionName = "SECTION." + i;
}
MemoryBlockUtils.createInitializedBlock(prog, false, sectionName, address, MemoryBlockUtils.createInitializedBlock(prog, false, sectionName, address,
fileBytes, rawDataPtr, dataSize, "", "", r, w, x, log); fileBytes, rawDataPtr, dataSize, "", "", r, w, x, log);
sectionToAddress.put(sections[i], address); sectionToAddress.put(sections[i], address);
@@ -740,8 +737,8 @@ public class PeLoader extends AbstractPeDebugLoader {
else { else {
int dataSize = (virtualSize > 0 || rawDataSize < 0) ? virtualSize : 0; int dataSize = (virtualSize > 0 || rawDataSize < 0) ? virtualSize : 0;
if (dataSize > 0) { if (dataSize > 0) {
MemoryBlockUtils.createUninitializedBlock(prog, false, MemoryBlockUtils.createUninitializedBlock(prog, false, sectionName, address,
sections[i].getReadableName(), address, dataSize, "", "", r, w, x, log); dataSize, "", "", r, w, x, log);
sectionToAddress.put(sections[i], address); sectionToAddress.put(sections[i], address);
} }
} }