mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-21 18:51:34 +08:00
GP-2826: PeLoader now handles sections partially or fully outside of the
file better
This commit is contained in:
@@ -332,32 +332,43 @@ public class FileHeader implements StructConverter {
|
||||
long stringTableOffset = getStringTableOffset();
|
||||
sectionHeaders = new SectionHeader[numberOfSections];
|
||||
for (int i = 0; i < numberOfSections; ++i) {
|
||||
sectionHeaders[i] =
|
||||
SectionHeader section =
|
||||
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
|
||||
int pointerToRawData = sectionHeaders[i].getPointerToRawData();
|
||||
int sizeOfRawData = (int) Math.min(reader.length() - pointerToRawData,
|
||||
sectionHeaders[i].getSizeOfRawData());
|
||||
if (pointerToRawData >= reader.length()) {
|
||||
sizeOfRawData = 0;
|
||||
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
|
||||
// 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
|
||||
// different addresses to enforce alignment.
|
||||
int virtualAddress = sectionHeaders[i].getVirtualAddress();
|
||||
int virtualSize = sectionHeaders[i].getVirtualSize();
|
||||
int virtualAddress = section.getVirtualAddress();
|
||||
int virtualSize = section.getVirtualSize();
|
||||
int alignedVirtualAddress = PortableExecutable.computeAlignment(virtualAddress,
|
||||
optHeader.getSectionAlignment());
|
||||
int alignedVirtualSize = PortableExecutable.computeAlignment(virtualSize,
|
||||
optHeader.getSectionAlignment());
|
||||
if (virtualAddress == alignedVirtualAddress) {
|
||||
if (sizeOfRawData > virtualSize) {
|
||||
sectionHeaders[i]
|
||||
.setVirtualSize(Math.min(sizeOfRawData, alignedVirtualSize));
|
||||
section.setVirtualSize(Math.min(sizeOfRawData, alignedVirtualSize));
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -22,10 +22,11 @@ import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.pe.PortableExecutable.SectionLayout;
|
||||
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.NotYetImplementedException;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param reader the binary reader
|
||||
* @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)
|
||||
* @throws InvalidNTHeaderException if the bytes the specified index
|
||||
* @throws IOException if an IO-related exception occurred
|
||||
* do not constitute an accurate NT header.
|
||||
*/
|
||||
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.
|
||||
* @see #rvaToPointer(long)
|
||||
*
|
||||
* @param rva the relative virtual address
|
||||
* @return the pointer into binary image, 0 if not valid
|
||||
*/
|
||||
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
|
||||
* @return the pointer into binary image, 0 if not valid
|
||||
*/
|
||||
public long rvaToPointer(long rva) {
|
||||
SectionHeader[] sections = fileHeader.getSectionHeaders();
|
||||
for (SectionHeader section : sections) {
|
||||
long sectionVA = section.getVirtualAddress() & Conv.INT_MASK;
|
||||
long rawSize = section.getSizeOfRawData() & Conv.INT_MASK;
|
||||
long rawPtr = section.getPointerToRawData() & Conv.INT_MASK;
|
||||
long sectionVA = Integer.toUnsignedLong(section.getVirtualAddress());
|
||||
long rawSize = Integer.toUnsignedLong(section.getSizeOfRawData());
|
||||
long rawPtr = Integer.toUnsignedLong(section.getPointerToRawData());
|
||||
|
||||
switch (layout) {
|
||||
case MEMORY:
|
||||
@@ -169,10 +176,10 @@ public class NTHeader implements StructConverter, OffsetValidator {
|
||||
public boolean checkPointer(long ptr) {
|
||||
SectionHeader[] sections = fileHeader.getSectionHeaders();
|
||||
for (SectionHeader section : sections) {
|
||||
long virtPtr = section.getVirtualAddress() & Conv.INT_MASK;
|
||||
long virtSize = section.getVirtualSize() & Conv.INT_MASK;
|
||||
long rawSize = section.getSizeOfRawData() & Conv.INT_MASK;
|
||||
long rawPtr = section.getPointerToRawData() & Conv.INT_MASK;
|
||||
long virtPtr = Integer.toUnsignedLong(section.getVirtualAddress());
|
||||
long virtSize = Integer.toUnsignedLong(section.getVirtualSize());
|
||||
long rawSize = Integer.toUnsignedLong(section.getSizeOfRawData());
|
||||
long rawPtr = Integer.toUnsignedLong(section.getPointerToRawData());
|
||||
|
||||
long sectionBasePtr = layout == SectionLayout.MEMORY ? virtPtr : rawPtr;
|
||||
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.
|
||||
* @see #vaToPointer(long)
|
||||
*
|
||||
* @param va the virtual address
|
||||
* @return the pointer into binary image, 0 if not valid
|
||||
*/
|
||||
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
|
||||
* @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());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidNTHeaderException
|
||||
* @throws IOException
|
||||
*/
|
||||
private void parse() throws InvalidNTHeaderException, IOException {
|
||||
|
||||
if (index < 0 || index > reader.length()) {
|
||||
@@ -229,6 +236,7 @@ public class NTHeader implements StructConverter, OffsetValidator {
|
||||
signature = reader.readInt(tmpIndex);
|
||||
}
|
||||
catch (IndexOutOfBoundsException ioobe) {
|
||||
// Handled below
|
||||
}
|
||||
|
||||
// if not correct signature, then return...
|
||||
@@ -256,7 +264,7 @@ public class NTHeader implements StructConverter, OffsetValidator {
|
||||
fileHeader.processSymbols();
|
||||
|
||||
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.program.model.data.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.util.Conv;
|
||||
import ghidra.util.DataConverter;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
@@ -535,7 +534,7 @@ public class SectionHeader implements StructConverter, ByteArrayConverter {
|
||||
EnumDataType characteristicsEnum = new EnumDataType("SectionFlags", 4);
|
||||
characteristicsEnum.setCategoryPath(new CategoryPath("/PE"));
|
||||
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.setCategoryPath(new CategoryPath("/PE"));
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package ghidra.app.util.opinion;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.util.MemoryBlockUtils;
|
||||
@@ -36,8 +35,6 @@ import ghidra.program.database.function.OverlappingFunctionException;
|
||||
import ghidra.program.database.mem.FileBytes;
|
||||
import ghidra.program.model.address.*;
|
||||
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.mem.Memory;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
@@ -109,7 +106,6 @@ public class PeLoader extends AbstractPeDebugLoader {
|
||||
return;
|
||||
}
|
||||
OptionalHeader optionalHeader = ntHeader.getOptionalHeader();
|
||||
FileHeader fileHeader = ntHeader.getFileHeader();
|
||||
|
||||
monitor.setMessage("Completing PE header parsing...");
|
||||
FileBytes fileBytes = createFileBytes(provider, program, monitor);
|
||||
@@ -406,7 +402,7 @@ public class PeLoader extends AbstractPeDebugLoader {
|
||||
//than 32bit. On WindowsCE some sections are
|
||||
//declared to roll over.
|
||||
if (!optionalHeader.is64bit()) {
|
||||
addr &= Conv.INT_MASK;
|
||||
addr &= 0x00000000ffffffffL;
|
||||
}
|
||||
|
||||
Address address = space.getAddress(addr);
|
||||
@@ -686,6 +682,11 @@ public class PeLoader extends AbstractPeDebugLoader {
|
||||
|
||||
address = space.getAddress(addr);
|
||||
|
||||
String sectionName = sections[i].getReadableName();
|
||||
if (sectionName.isBlank()) {
|
||||
sectionName = "SECTION." + i;
|
||||
}
|
||||
|
||||
r = ((sections[i].getCharacteristics() &
|
||||
SectionFlags.IMAGE_SCN_MEM_READ.getMask()) != 0x0);
|
||||
w = ((sections[i].getCharacteristics() &
|
||||
@@ -707,10 +708,6 @@ public class PeLoader extends AbstractPeDebugLoader {
|
||||
Msg.warn(this, "OptionalHeader.SizeOfImage < size of " +
|
||||
sections[i].getName() + " section");
|
||||
}
|
||||
String sectionName = sections[i].getReadableName();
|
||||
if (sectionName.isBlank()) {
|
||||
sectionName = "SECTION." + i;
|
||||
}
|
||||
MemoryBlockUtils.createInitializedBlock(prog, false, sectionName, address,
|
||||
fileBytes, rawDataPtr, dataSize, "", "", r, w, x, log);
|
||||
sectionToAddress.put(sections[i], address);
|
||||
@@ -740,8 +737,8 @@ public class PeLoader extends AbstractPeDebugLoader {
|
||||
else {
|
||||
int dataSize = (virtualSize > 0 || rawDataSize < 0) ? virtualSize : 0;
|
||||
if (dataSize > 0) {
|
||||
MemoryBlockUtils.createUninitializedBlock(prog, false,
|
||||
sections[i].getReadableName(), address, dataSize, "", "", r, w, x, log);
|
||||
MemoryBlockUtils.createUninitializedBlock(prog, false, sectionName, address,
|
||||
dataSize, "", "", r, w, x, log);
|
||||
sectionToAddress.put(sections[i], address);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user