diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/Writeable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/Writeable.java
index 97140f586d..51cbe16fc6 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/Writeable.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/Writeable.java
@@ -16,19 +16,19 @@
*/
package ghidra.app.util.bin.format;
-import ghidra.util.DataConverter;
-
import java.io.IOException;
import java.io.RandomAccessFile;
+import ghidra.util.DataConverter;
+
/**
- * An interface for writing out class state information.
- *
+ * An interface for writing out class state information
*/
public interface Writeable {
/**
- * Writes this object to the specified random access file using
- * the data converter to handle endianness.
+ * Writes this object to the specified random access file using the data converter to handle
+ * endianness
+ *
* @param raf the random access file
* @param dc the data converter
* @throws IOException if an I/O error occurs
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/FileHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/FileHeader.java
index 65a3275d5a..951d13198f 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/FileHeader.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/FileHeader.java
@@ -17,11 +17,11 @@ package ghidra.app.util.bin.format.pe;
import java.io.IOException;
import java.io.RandomAccessFile;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
+import ghidra.app.util.bin.format.Writeable;
import ghidra.app.util.bin.format.pe.debug.DebugCOFFSymbol;
import ghidra.app.util.bin.format.pe.debug.DebugCOFFSymbolAux;
import ghidra.program.model.data.*;
@@ -30,101 +30,75 @@ import ghidra.util.DataConverter;
import ghidra.util.Msg;
import ghidra.util.exception.DuplicateNameException;
-/**
- * A class to represent the IMAGE_FILE_HEADER struct as
- * defined in winnt.h.
- *
- *
- * typedef struct _IMAGE_FILE_HEADER {
- * WORD Machine; // MANDATORY
- * WORD NumberOfSections; // USED
- * DWORD TimeDateStamp;
- * DWORD PointerToSymbolTable;
- * DWORD NumberOfSymbols;
- * WORD SizeOfOptionalHeader; // USED
- * WORD Characteristics; // MANDATORY
- * } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
- *
- *
- */
-public class FileHeader implements StructConverter {
- /**
- * The name to use when converting into a structure data type.
- */
+/// A class to represent the `IMAGE_FILE_HEADER` struct as defined in `winnt.h`
+///
+/// ```c
+/// typedef struct _IMAGE_FILE_HEADER {
+/// WORD Machine; // MANDATORY
+/// WORD NumberOfSections; // USED
+/// DWORD TimeDateStamp;
+/// DWORD PointerToSymbolTable;
+/// DWORD NumberOfSymbols;
+/// WORD SizeOfOptionalHeader; // USED
+/// WORD Characteristics; // MANDATORY
+/// } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
+/// ```
+public class FileHeader implements StructConverter, Writeable {
+ /// The name to use when converting into a structure data type
public final static String NAME = "IMAGE_FILE_HEADER";
- /**
- * The size of the IMAGE_FILE_HEADER in bytes.
- */
+
+ /// The size of the {@code IMAGE_FILE_HEADER} in bytes
public final static int IMAGE_SIZEOF_FILE_HEADER = 20;
- /**
- * Relocation info stripped from file.
- */
+ /// Relocation info stripped from file
public final static int IMAGE_FILE_RELOCS_STRIPPED = 0x0001;
- /**
- * File is executable (no unresolved externel references).
- */
+
+ /// File is executable (no unresolved external references)
public final static int IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002;
- /**
- * Line nunbers stripped from file.
- */
+
+ /// Line numbers stripped from file
public final static int IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004;
- /**
- * Local symbols stripped from file.
- */
+
+ /// Local symbols stripped from file
public final static int IMAGE_FILE_LOCAL_SYMS_STRIPPED = 0x0008;
- /**
- * Agressively trim working set
- */
+
+ /// Aggressively trim working set
public final static int IMAGE_FILE_AGGRESIVE_WS_TRIM = 0x0010;
- /**
- * App can handle >2gb addresses
- */
+
+ /// App can handle >2gb addresses
public final static int IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020;
- /**
- * Bytes of machine word are reversed.
- */
+
+ /// Bytes of machine word are reversed
public final static int IMAGE_FILE_BYTES_REVERSED_LO = 0x0080;
- /**
- * 32 bit word machine.
- */
+
+ /// 32 bit word machine
public final static int IMAGE_FILE_32BIT_MACHINE = 0x0100;
- /**
- * Debugging info stripped from file in .DBG file
- */
+
+ /// 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.
- */
+
+ /// 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.
- */
+
+ /// 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.
- */
+
+ /// System File
public final static int IMAGE_FILE_SYSTEM = 0x1000;
- /**
- * File is a DLL.
- */
+
+ /// File is a DLL
public final static int IMAGE_FILE_DLL = 0x2000;
- /**
- * File should only be run on a UP machine.
- */
+
+ /// 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.
- */
+
+ /// Bytes of machine word are reversed
public final static int IMAGE_FILE_BYTES_REVERSED_HI = 0x8000;
- /**
- * Magic value in LordPE's Symbol Table pointer field.
- */
+ /// 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.
- */
+
+ /// Magic value in LordPE's Number of Symbols field
private final static int LORDPE_NUMBER_OF_SYMBOLS = 0x5D455064;
public final static String[] CHARACTERISTICS = { "Relocation info stripped from file",
@@ -137,9 +111,7 @@ public class FileHeader implements StructConverter {
"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" };
- /**
- * Values for the Machine field indicating the intended processor architecture
- */
+ // Values for the Machine field indicating the intended processor architecture
public final static int IMAGE_FILE_MACHINE_MASK = 0xFFFF;
public final static int IMAGE_FILE_MACHINE_UNKNOWN = 0x0; // The content of this field is assumed to be applicable to any machine type
public final static int IMAGE_FILE_MACHINE_AM33 = 0x1d3; // Matsushita AM33
@@ -182,25 +154,39 @@ public class FileHeader implements StructConverter {
private int startIndex;
private NTHeader ntHeader;
+ /**
+ * Creates a new {@link FileHeader}
+ *
+ * @param reader A {@link BinaryReader}
+ * @param startIndex The {@link BinaryReader} index of the start of the header
+ * @param ntHeader The associated {@link NTHeader}
+ * @throws IOException if an IO-related error occurred
+ */
FileHeader(BinaryReader reader, int startIndex, NTHeader ntHeader) throws IOException {
this.reader = reader;
this.startIndex = startIndex;
this.ntHeader = ntHeader;
- parse();
+ reader.setPointerIndex(startIndex);
+
+ machine = reader.readNextShort();
+ numberOfSections = reader.readNextUnsignedShort();
+ timeDateStamp = reader.readNextInt();
+ pointerToSymbolTable = reader.readNextInt();
+ numberOfSymbols = reader.readNextInt();
+ sizeOfOptionalHeader = reader.readNextShort();
+ characteristics = reader.readNextShort();
}
/**
- * Returns the architecture type of the computer.
- * @return the architecture type of the computer
+ * {@return the architecture type of the computer}
*/
public short getMachine() {
return machine;
}
/**
- * Returns a string representation of the architecture type of the computer.
- * @return 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);
@@ -234,118 +220,97 @@ public class FileHeader implements StructConverter {
}
/**
- * Returns the number of sections.
- * Sections equate to Ghidra memory blocks.
- * @return the number of sections
+ * {@return the number of sections}
*/
public int getNumberOfSections() {
return numberOfSections;
}
/**
- * Returns the array of section headers.
- * @return the array of section headers
+ * {@return the array of section headers}
*/
public SectionHeader[] getSectionHeaders() {
- if (sectionHeaders == null) {
- return new SectionHeader[0];
- }
- return sectionHeaders;
+ return sectionHeaders != null ? sectionHeaders : new SectionHeader[0];
}
/**
- * Returns the array of symbols.
- * @return the array of symbols
+ * {@return the array of symbols}
*/
public List{@code
- * typedef struct _IMAGE_NT_HEADERS {
- * DWORD Signature;
- * IMAGE_FILE_HEADER FileHeader;
- * IMAGE_OPTIONAL_HEADER32 OptionalHeader;
- * };
- * }
- */
-public class NTHeader implements StructConverter, OffsetValidator {
- /**
- * The size of the NT header signature.
- */
+/// A class to represent the `IMAGE_NT_HEADERS32` and `IMAGE_NT_HEADERS64` structures as defined in
+/// `winnt.h`
+/// ```c
+/// typedef struct _IMAGE_NT_HEADERS {
+/// DWORD Signature;
+/// IMAGE_FILE_HEADER FileHeader;
+/// IMAGE_OPTIONAL_HEADER32 OptionalHeader;
+/// };
+/// ```
+public class NTHeader implements StructConverter, OffsetValidator, Writeable {
+
+ /// The size of the NT header signature.
public final static int SIZEOF_SIGNATURE = BinaryReader.SIZEOF_INT;
+
public final static int MAX_SANE_COUNT = 0x10000;
private int signature;
private FileHeader fileHeader;
private OptionalHeader optionalHeader;
- private BinaryReader reader;
private int index;
private boolean parseCliHeaders = false;
private SectionLayout layout = SectionLayout.FILE;
/**
- * Constructs a new NT header.
+ * Constructs a new NT header
*
* @param reader the binary reader
* @param index the index into the reader to the start of the NT header
@@ -63,16 +60,50 @@ public class NTHeader implements StructConverter, OffsetValidator {
* @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 parseCliHeaders)
throws InvalidNTHeaderException, IOException {
- this.reader = reader;
this.index = index;
this.layout = layout;
this.parseCliHeaders = parseCliHeaders;
- parse();
+ int tmpIndex = index;
+
+ try {
+ signature = reader.readInt(tmpIndex);
+ }
+ catch (IndexOutOfBoundsException ioobe) {
+ // Handled below
+ }
+
+ // if not correct signature, then return...
+ if (signature != Constants.IMAGE_NT_SIGNATURE) {
+ throw new InvalidNTHeaderException();
+ }
+
+ tmpIndex += 4;
+
+ fileHeader = new FileHeader(reader, tmpIndex, this);
+ if (fileHeader.getSizeOfOptionalHeader() == 0) {
+ Msg.warn(this, "Section headers overlap optional header");
+ }
+ tmpIndex += FileHeader.IMAGE_SIZEOF_FILE_HEADER;
+
+ optionalHeader = new OptionalHeader(this, reader, tmpIndex);
+
+ // Process symbols. Allow parsing to continue on failure.
+ boolean symbolsProcessed = false;
+ try {
+ fileHeader.processSymbols();
+ symbolsProcessed = true;
+ }
+ catch (Exception e) {
+ Msg.error(this, "Failed to process symbols: " + e.getMessage());
+ }
+
+ // Process sections. Resolving some sections names (i.e., "/21") requires symbols to have
+ // been successfully processed. Resolving is optional though.
+ fileHeader.processSections(optionalHeader, symbolsProcessed);
}
/**
@@ -205,8 +236,8 @@ public class NTHeader implements StructConverter, OffsetValidator {
}
/**
- * {@return the given virtual address (VA) converted into a pointer into the binary
- * image, or -1 if not valid}
+ * {@return the given virtual address (VA) converted into a pointer into the binary image, or -1
+ * if not valid}
*
* @param va the virtual address
*/
@@ -215,8 +246,8 @@ public class NTHeader implements StructConverter, OffsetValidator {
}
/**
- * {@return the given virtual address (VA) converted into a pointer into the binary
- * image, or -1 if not valid}
+ * {@return the given virtual address (VA) converted into a pointer into the binary image, or
+ * -1 if not valid}
*
* @param va the virtual address
*/
@@ -224,62 +255,26 @@ public class NTHeader implements StructConverter, OffsetValidator {
return rvaToPointer(va - getOptionalHeader().getImageBase());
}
- private void parse() throws InvalidNTHeaderException, IOException {
- int tmpIndex = index;
-
- try {
- signature = reader.readInt(tmpIndex);
- }
- catch (IndexOutOfBoundsException ioobe) {
- // Handled below
- }
-
- // if not correct signature, then return...
- if (signature != Constants.IMAGE_NT_SIGNATURE) {
- throw new InvalidNTHeaderException();
- }
-
- tmpIndex += 4;
-
- fileHeader = new FileHeader(reader, tmpIndex, this);
- if (fileHeader.getSizeOfOptionalHeader() == 0) {
- Msg.warn(this, "Section headers overlap optional header");
- }
- tmpIndex += FileHeader.IMAGE_SIZEOF_FILE_HEADER;
-
- optionalHeader = new OptionalHeader(this, reader, tmpIndex);
-
- // Process symbols. Allow parsing to continue on failure.
- boolean symbolsProcessed = false;
- try {
- fileHeader.processSymbols();
- symbolsProcessed = true;
- }
- catch (Exception e) {
- Msg.error(this, "Failed to process symbols: " + e.getMessage());
- }
-
- // Process sections. Resolving some sections names (i.e., "/21") requires symbols to have
- // been successfully processed. Resolving is optional though.
- fileHeader.processSections(optionalHeader, symbolsProcessed);
- }
-
- void writeHeader(RandomAccessFile raf, DataConverter dc) throws IOException {
+ @Override
+ public void write(RandomAccessFile raf, DataConverter dc) throws IOException {
raf.seek(index);
raf.write(dc.getBytes(signature));
- fileHeader.writeHeader(raf, dc);
+ fileHeader.write(raf, dc);
optionalHeader.writeHeader(raf, dc);
SectionHeader[] sections = fileHeader.getSectionHeaders();
for (SectionHeader section : sections) {
- section.writeHeader(raf, dc);
+ section.write(raf, dc);
}
}
+ /**
+ * {@return whether or not CLI headers should be parsed}
+ */
boolean shouldParseCliHeaders() {
return parseCliHeaders;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/OptionalHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/OptionalHeader.java
index b71c838922..5f3aaf3207 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/OptionalHeader.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/OptionalHeader.java
@@ -105,129 +105,88 @@ import ghidra.util.task.TaskMonitor;
*/
public class OptionalHeader implements StructConverter {
- /**
- * ASLR with 64 bit address space.
- */
+ /// ASLR with 64 bit address space
public final static int IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020;
- /**
- * The DLL can be relocated at load time.
- */
+ /// The DLL can be relocated at load time
public final static int IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040;
- /**
- * Code integrity checks are forced.
- */
+ /// Code integrity checks are forced
public final static int IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = 0x0080;
- /**
- * The image is compatible with data execution prevention (DEP)
- */
+ /// The image is compatible with data execution prevention (DEP)
public final static int IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100;
- /**
- * The image is isolation aware, but should not be isolated.
- */
+ /// The image is isolation aware, but should not be isolated
public final static int IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200;
- /**
- * The image does not use structured exception handling (SEH).
- */
+ /// The image does not use structured exception handling (SEH)
public final static int IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400;
- /**
- * Do not bind the image.
- */
+ /// Do not bind the image
public final static int IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800;
- /**
- * Image should execute in an AppContainer.
- */
+ /// Image should execute in an AppContainer
public final static int IMAGE_DLLCHARACTERISTICS_APPCONTAINER = 0x1000;
- /**
- * A WDM driver.
- */
+ /// A WDM driver
public final static int IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000;
- /**
- * Image supports Control Flow Guard.
- */
+ /// Image supports Control Flow Guard
public final static int IMAGE_DLLCHARACTERISTICS_GUARD_CF = 0x4000;
- /**
- * The image is terminal server aware.
- */
+ /// The image is terminal server aware
public final static int IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000;
- /**
- * The count of data directories in the optional header.
- */
+ /// The count of data directories in the optional header
public final static byte IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
- /**
- * Export directory index
- */
+ /// Export directory index
public final static byte IMAGE_DIRECTORY_ENTRY_EXPORT = 0;
- /**
- * Import directory index
- */
+
+ /// Import directory index
public final static byte IMAGE_DIRECTORY_ENTRY_IMPORT = 1;
- /**
- * Resource directory index
- */
+
+ /// Resource directory index
public final static byte IMAGE_DIRECTORY_ENTRY_RESOURCE = 2;
- /**
- * Exception directory index
- */
+
+ /// Exception directory index
public final static byte IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3;
- /**
- * Security directory index
- */
+
+ /// Security directory index
public final static byte IMAGE_DIRECTORY_ENTRY_SECURITY = 4;
- /**
- * Base Relocation Table directory index
- */
+
+ /// Base Relocation Table directory index
public final static byte IMAGE_DIRECTORY_ENTRY_BASERELOC = 5;
- /**
- * Debug directory index
- */
+
+ /// Debug directory index
public final static byte IMAGE_DIRECTORY_ENTRY_DEBUG = 6;
- /**
- * Architecture Specific Data directory index
- */
+
+ /// Architecture Specific Data directory index
public final static byte IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7;
- /**
- * Global Pointer directory index
- */
- public final static byte IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8;//RVA of GP
- /**
- * TLS directory index
- */
+
+ /// Global Pointer directory index
+ public final static byte IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8; //RVA of GP
+
+ /// TLS directory index
public final static byte IMAGE_DIRECTORY_ENTRY_TLS = 9;
- /**
- * Load Configuration directory index
- */
+
+ /// Load Configuration directory index
public final static byte IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10;
- /**
- * Bound Import directory index
- */
+
+ /// Bound Import directory index
public final static byte IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11;
- /**
- * Import Address Table directory index
- */
+
+ /// Import Address Table directory index
public final static byte IMAGE_DIRECTORY_ENTRY_IAT = 12;
- /**
- * Delay Load Import Descriptors directory index
- */
+
+ /// Delay Load Import Descriptors directory index
public final static byte IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13;
- /**
- * COM Runtime Descriptor directory index
- */
+
+ /// COM Runtime Descriptor directory index
public final static byte IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14;
- /**
- * New name for the COM Descriptor directory index
- */
+
+ /// New name for the COM Descriptor directory index
public final static byte IMAGE_DIRECTORY_ENTRY_COMHEADER = 14;
protected short magic;
@@ -272,10 +231,6 @@ public class OptionalHeader implements StructConverter {
this.reader = reader;
this.startIndex = startIndex;
- parse();
- }
-
- protected void parse() throws IOException {
reader.setPointerIndex(startIndex);
magic = reader.readNextShort();
@@ -620,35 +575,35 @@ public class OptionalHeader implements StructConverter {
}
/**
- * {@return true of this optional header is 64-bit.}
+ * {@return true of this optional header is 64-bit}
*/
public boolean is64bit() {
return magic == Constants.IMAGE_NT_OPTIONAL_HDR64_MAGIC;
}
/**
- * {@return the major version number of the linker that built this binary.}
+ * {@return the major version number of the linker that built this binary}
*/
public byte getMajorLinkerVersion() {
return majorLinkerVersion;
}
/**
- * {@return the minor version number of the linker that built this binary.}
+ * {@return the minor version number of the linker that built this binary}
*/
public byte getMinorLinkerVersion() {
return minorLinkerVersion;
}
/**
- * {@return the combined total size of all sections with IMAGE_SCN_CNT_CODE attribute.}
+ * {@return the combined total size of all sections with IMAGE_SCN_CNT_CODE attribute}
*/
public long getSizeOfCode() {
return sizeOfCode;
}
/**
- * Sets the combined total size of all sections with the IMAGE_SCN_CNT_CODE attribute.
+ * Sets the combined total size of all sections with the IMAGE_SCN_CNT_CODE attribute
*
* @param size The size to set
*/
@@ -657,7 +612,7 @@ public class OptionalHeader implements StructConverter {
}
/**
- * {@return the combined size of all initialized data sections.}
+ * {@return the combined size of all initialized data sections}
*/
public long getSizeOfInitializedData() {
return Integer.toUnsignedLong(sizeOfInitializedData);
@@ -673,14 +628,14 @@ public class OptionalHeader implements StructConverter {
}
/**
- * {@return the size of all sections with the uninitialized data attributes.}
+ * {@return the size of all sections with the uninitialized data attributes}
*/
public long getSizeOfUninitializedData() {
return Integer.toUnsignedLong(sizeOfUninitializedData);
}
/**
- * Sets the size of all sections with the uninitialized data attributes.}
+ * Sets the size of all sections with the uninitialized data attributes}
*
* @param size The size to set
*/
@@ -696,14 +651,14 @@ public class OptionalHeader implements StructConverter {
}
/**
- * {@return the RVA of the first byte of code when loaded in memory.}
+ * {@return the RVA of the first byte of code when loaded in memory}
*/
public long getBaseOfCode() {
return Integer.toUnsignedLong(baseOfCode);
}
/**
- * {@return the RVA of the first byte of data when loaded into memory.}
+ * {@return the RVA of the first byte of data when loaded into memory}
*/
public long getBaseOfData() {
return Integer.toUnsignedLong(baseOfData);
@@ -731,42 +686,42 @@ public class OptionalHeader implements StructConverter {
}
/**
- * {@return the major version number of the required operating system.}
+ * {@return the major version number of the required operating system}
*/
public short getMajorOperatingSystemVersion() {
return majorOperatingSystemVersion;
}
/**
- * {@return the minor version number of the required operating system.}
+ * {@return the minor version number of the required operating system}
*/
public short getMinorOperatingSystemVersion() {
return minorOperatingSystemVersion;
}
/**
- * {@return the major version number of the image.}
+ * {@return the major version number of the image}
*/
public short getMajorImageVersion() {
return majorImageVersion;
}
/**
- * {@return the minor version number of the image.}
+ * {@return the minor version number of the image}
*/
public short getMinorImageVersion() {
return minorImageVersion;
}
/**
- * {@return the major version number of the subsystem.}
+ * {@return the major version number of the subsystem}
*/
public short getMajorSubsystemVersion() {
return majorSubsystemVersion;
}
/**
- * {@return the minor version number of the subsystem.}
+ * {@return the minor version number of the subsystem}
*/
public short getMinorSubsystemVersion() {
return minorSubsystemVersion;
@@ -812,22 +767,21 @@ public class OptionalHeader implements StructConverter {
}
/**
- * {@return the image file checksum.}
+ * {@return the image file checksum}
*/
public int getChecksum() {
return checkSum;
}
/**
- * {@return the subsystem that is required to run this image.}
+ * {@return the subsystem that is required to run this image}
*/
public int getSubsystem() {
return subsystem;
}
/**
- * {@return the flags that describe properties of and features of this binary.}
- * @see ghidra.app.util.bin.format.pe.DllCharacteristics
+ * {@return the flags that describe properties of and features of this binary}
*/
public short getDllCharacteristics() {
return dllCharacteristics;
@@ -862,21 +816,21 @@ public class OptionalHeader implements StructConverter {
}
/**
- * {@return the flags passed to the loader. Obsolete.}
+ * {@return the flags passed to the loader (obsolete)}
*/
public int getLoaderFlags() {
return loaderFlags;
}
/**
- * {@return the number of data-directory entries in the remainder of the optional header.}
+ * {@return the number of data-directory entries in the remainder of the optional header}
*/
public long getNumberOfRvaAndSizes() {
return Integer.toUnsignedLong(numberOfRvaAndSizes);
}
/**
- * {@return the array of data directories.}
+ * {@return the array of data directories}
*/
public DataDirectory[] getDataDirectories() {
return dataDirectory;
@@ -911,7 +865,8 @@ public class OptionalHeader implements StructConverter {
ddstruct.add(DWORD, "Size", null);
ddstruct.setCategoryPath(new CategoryPath("/PE"));
- StructureDataType struct = new StructureDataType(getName(), 0);
+ String name = "IMAGE_OPTIONAL_HEADER" + (is64bit() ? "64" : "32");
+ StructureDataType struct = new StructureDataType(name, 0);
struct.add(WORD, "Magic", null);
struct.add(BYTE, "MajorLinkerVersion", null);
@@ -970,7 +925,6 @@ public class OptionalHeader implements StructConverter {
*
* @param raf the random access file
* @param dc the data converter
- *
* @throws IOException if an IO-related error occurred
*/
public void writeHeader(RandomAccessFile raf, DataConverter dc) throws IOException {
@@ -1066,7 +1020,7 @@ public class OptionalHeader implements StructConverter {
}
/**
- * {@return true if the PE uses predominantly CLI code; otherwise, false.}
+ * {@return true if the PE uses predominantly CLI code; otherwise, false}
*
* @throws IOException if an IO-related error occurred
*/
@@ -1089,8 +1043,4 @@ public class OptionalHeader implements StructConverter {
return intermediateLanguageOnly && cor20.getManagedNativeHeader().getVirtualAddress() == 0;
}
-
- private String getName() {
- return "IMAGE_OPTIONAL_HEADER" + (is64bit() ? "64" : "32");
- }
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PeUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PeUtils.java
index ec17b7bf1d..fe8e6b5853 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PeUtils.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PeUtils.java
@@ -78,4 +78,17 @@ public class PeUtils {
}
}
+ /**
+ * {@return the given value rounded up to the nearest given alignment}
+ *
+ * @param value the value to align
+ * @param alignment the alignment value
+ */
+ public static int align(int value, int alignment) {
+ if (alignment == 0) {
+ return value;
+ }
+ return Math.ceilDiv(value, alignment) * alignment;
+ }
+
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PortableExecutable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PortableExecutable.java
index 6cc66a8f13..92e074162c 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PortableExecutable.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PortableExecutable.java
@@ -20,6 +20,7 @@ import java.io.RandomAccessFile;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider;
+import ghidra.app.util.bin.format.Writeable;
import ghidra.app.util.bin.format.mz.DOSHeader;
import ghidra.app.util.importer.MessageLog;
import ghidra.util.DataConverter;
@@ -28,23 +29,18 @@ import ghidra.util.task.TaskMonitor;
/**
* A class to manage loading Portable Executables (PE).
- *
- *
*/
-public class PortableExecutable {
+public class PortableExecutable implements Writeable {
public static final String NAME = "PORTABLE_EXECUTABLE";
public static boolean DEBUG = false;
/**
- * Indicates how sections of this PE are laid out in the underlying ByteProvider.
- * Use {@link SectionLayout#FILE} when loading from a file, and {@link SectionLayout#MEMORY} when
- * loading from a memory model (like an already-loaded program in Ghidra).
+ * Indicates how sections of this PE are laid out in the underlying {@link ByteProvider}.
+ * Use {@link SectionLayout#FILE} when loading from a file, and {@link SectionLayout#MEMORY}
+ * when loading from a memory model (like an already-loaded program in Ghidra).
*/
public static enum SectionLayout {
- /** Indicates the sections of this PE are laid out as stored in a file. **/
- FILE,
- /** Indicates the sections of this PE are laid out as loaded into memory **/
- MEMORY
+ FILE, MEMORY
}
private BinaryReader reader;
@@ -52,28 +48,25 @@ public class PortableExecutable {
private RichHeader richHeader;
private NTHeader ntHeader;
- //private FileHeader fileHeader;
-
/**
- * Constructs a new Portable Executable using the specified byte provider and layout.
- *
- * Same as calling createFileAlignedPortableExecutable(factory, bp, layout, true, false)
- * @param bp the byte provider
+ * Constructs a new {@link PortableExecutable} using the specified byte provider and layout
+ *
+ * @param bp the {@link ByteProvider}
* @param layout specifies the layout of the underlying provider and governs RVA resolution
- * @throws IOException if an I/O error occurs.
- * @see #PortableExecutable(ByteProvider, SectionLayout, boolean, boolean)
- **/
+ * @throws IOException if an I/O error occurs
+ */
public PortableExecutable(ByteProvider bp, SectionLayout layout) throws IOException {
this(bp, layout, true, false);
}
/**
- * Constructs a new Portable Executable using the specified byte provider and layout.
- * @param bp the byte provider
+ * Constructs a new {@link PortableExecutable} using the specified byte provider and layout
+ *
+ * @param bp the {@link ByteProvider}
* @param layout specifies the layout of the underlying provider and governs RVA resolution
* @param advancedProcess if true, the data directories are also processed
* @param parseCliHeaders if true, CLI headers are parsed (if present)
- * @throws IOException if an I/O error occurs.
+ * @throws IOException if an I/O error occurs
*/
public PortableExecutable(ByteProvider bp, SectionLayout layout, boolean advancedProcess,
boolean parseCliHeaders) throws IOException {
@@ -101,56 +94,38 @@ public class PortableExecutable {
}
return;
}
-
- //fileHeader = new FileHeader(reader);
- //
- //if (fileHeader.getMachineName() != null) {
- // if (fileHeader.getSizeOfOptionalHeader() == 0) {
- // Err.debug(this, "This is a .OBJ file...");
- // }
- // else if (fileHeader.getSizeOfOptionalHeader() == Constants.IMAGE_SIZEOF_ROM_OPTIONAL_HEADER) {
- // Err.debug(this, "This is a ROM image...");
- // }
- //}
- //if (isValidLibrary(reader)) {
- // Err.debug(this, "This is a library/archive file...");
- //}
}
/**
- * Returns the DOS header from the PE image.
- * @return the DOS header from the PE image
+ * {@return the DOS header from the PE image}
*/
public DOSHeader getDOSHeader() {
return dosHeader;
}
/**
- * Returns the Rich header from the PE image.
- * @return the Rich header from the PE image
+ * {@return the rich header from the PE image}
*/
public RichHeader getRichHeader() {
return richHeader;
}
/**
- * Returns the NT header from the PE image.
- * @return the NT header from the PE image
+ * {@return the NT header from the PE image}
*/
public NTHeader getNTHeader() {
return ntHeader;
}
- //private boolean isValidLibrary(BinaryReader reader) throws IOException {
- // String s = reader.readAsciiString(0);
- // if (s != null && s.length() >= Constants.IMAGE_ARCHIVE_START_SIZE) {
- // return s.substring(0, Constants.IMAGE_ARCHIVE_START_SIZE).equals(Constants.IMAGE_ARCHIVE_START);
- // }
- // return false;
- //}
-
- public void writeHeader(RandomAccessFile raf, DataConverter dc) throws IOException {
+ /**
+ * {@return the length of the {@link PortableExecutable} file in bytes
+ */
+ public long getFileLength() {
+ return reader != null ? reader.length() : 0;
+ }
+ @Override
+ public void write(RandomAccessFile raf, DataConverter dc) throws IOException {
raf.seek(0);
if (dosHeader != null) {
dosHeader.write(raf, dc);
@@ -159,19 +134,7 @@ public class PortableExecutable {
richHeader.write(raf, dc);
}
if (ntHeader != null) {
- ntHeader.writeHeader(raf, dc);
+ ntHeader.write(raf, dc);
}
}
-
- public static int computeAlignment(int value, int alignment) {
- if (alignment == 0 || (value % alignment) == 0) {
- return value;
- }
- int a = ((value + alignment) / alignment) * alignment;
- return a;
- }
-
- public long getFileLength() {
- return reader != null ? reader.length() : 0;
- }
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/SectionHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/SectionHeader.java
index 74a311c189..4d5358e7a1 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/SectionHeader.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/SectionHeader.java
@@ -18,211 +18,179 @@ package ghidra.app.util.bin.format.pe;
import java.io.*;
import ghidra.app.util.bin.*;
+import ghidra.app.util.bin.format.Writeable;
import ghidra.program.model.data.*;
import ghidra.program.model.mem.*;
import ghidra.util.DataConverter;
import ghidra.util.exception.DuplicateNameException;
-/**
- * A class to the represent the IMAGE_SECTION_HEADER
- * struct as defined in winnt.h.
- *
- *
- * typedef struct _IMAGE_SECTION_HEADER {
- * BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
- * union {
- * DWORD PhysicalAddress;
- * DWORD VirtualSize; // MANDATORY
- * } Misc;
- * DWORD VirtualAddress; // MANDATORY
- * DWORD SizeOfRawData; // MANDATORY
- * DWORD PointerToRawData; // MANDATORY
- * DWORD PointerToRelocations;
- * DWORD PointerToLinenumbers;
- * WORD NumberOfRelocations;
- * WORD NumberOfLinenumbers;
- * DWORD Characteristics; // MANDATORY
- * } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; *
- *
- * #define IMAGE_SIZEOF_SECTION_HEADER 40 *
- *
- *
- */
-public class SectionHeader implements StructConverter, ByteArrayConverter {
- /**
- * The name to use when converting into a structure data type.
- */
+/// A class to the represent the `IMAGE_SECTION_HEADER` struct as defined in `winnt.h`
+///
+/// ```c
+/// typedef struct _IMAGE_SECTION_HEADER {
+/// BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
+/// union {
+/// DWORD PhysicalAddress;
+/// DWORD VirtualSize; // MANDATORY
+/// } Misc;
+/// DWORD VirtualAddress; // MANDATORY
+/// DWORD SizeOfRawData; // MANDATORY
+/// DWORD PointerToRawData; // MANDATORY
+/// DWORD PointerToRelocations;
+/// DWORD PointerToLinenumbers;
+/// WORD NumberOfRelocations;
+/// WORD NumberOfLinenumbers;
+/// DWORD Characteristics; // MANDATORY
+/// } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
+///
+/// #define IMAGE_SIZEOF_SECTION_HEADER 40
+/// ```
+public class SectionHeader implements StructConverter, ByteArrayConverter, Writeable {
+ /// The name to use when converting into a structure data type
public final static String NAME = "IMAGE_SECTION_HEADER";
- /**
- * The size of the section header short name.
- */
+
+ /// The size of the section header short name
public final static int IMAGE_SIZEOF_SHORT_NAME = 8;
- /**
- * The size of the section header.
- */
+
+ /// The size of the section header
public final static int IMAGE_SIZEOF_SECTION_HEADER = 40;
-// public final static int IMAGE_SCN_TYPE_REG = 0x00000000;
-// public final static int IMAGE_SCN_TYPE_DSECT = 0x00000001;
-// public final static int IMAGE_SCN_TYPE_NOLOAD = 0x00000002;
-// public final static int IMAGE_SCN_TYPE_GROUP = 0x00000004;
-// public final static int IMAGE_SCN_TYPE_NO_PAD = 0x00000008;
-// public final static int IMAGE_SCN_TYPE_COPY = 0x00000010;
- /**
- * Section contains code.
- */
- public final static int IMAGE_SCN_CNT_CODE = 0x00000020;
- /**
- * Section contains initialized data.
- */
- public final static int IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040;
- /**
- * Section contains uninitialized data.
- */
- public final static int IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080;
-// public final static int IMAGE_SCN_LNK_OTHER = 0x00000100;
- /**
- * Section contains information for use by the linker.
- * Only exists in OBJs.
- */
- public final static int IMAGE_SCN_LNK_INFO = 0x00000200;
-// public final static int IMAGE_SCN_TYPE_OVER = 0x00000400;
- /**
- * Section contents will not become part of the image.
- * This only appears in OBJ files.
- */
- public final static int IMAGE_SCN_LNK_REMOVE = 0x00000800;
- /**
- * Section contents is communal data (comdat).
- * Communal data is data (or code) that can be
- * defined in multiple OBJs. The linker will select
- * one copy to include in the executable. Comdats
- * are vital for support of C++ template functions
- * and function-level linking. Comdat sections only
- * appear in OBJ files.
- */
- public final static int IMAGE_SCN_LNK_COMDAT = 0x00001000;
-// Reserved. = 0x00002000;
-// public final static int IMAGE_SCN_MEM_PROTECTED - Obsolete = 0x00004000;
- /**
- * Reset speculative exceptions handling bits in the TLB entries for this section.
- */
- public final static int IMAGE_SCN_NO_DEFER_SPEC_EXC = 0x00004000;
- /**
- * Section content can be accessed relative to GP.
- */
- public final static int IMAGE_SCN_GPREL = 0x00008000;
-// public final static int IMAGE_SCN_MEM_FARDATA = 0x00008000;
-// public final static int IMAGE_SCN_MEM_SYSHEAP - Obsolete = 0x00010000;
-// public final static int IMAGE_SCN_MEM_PURGEABLE = 0x00020000;
-// public final static int IMAGE_SCN_MEM_16BIT = 0x00020000;
-// public final static int IMAGE_SCN_MEM_LOCKED = 0x00040000;
-// public final static int IMAGE_SCN_MEM_PRELOAD = 0x00080000;
- /**
- * Align on 1-byte boundary.
- */
- public final static int IMAGE_SCN_ALIGN_1BYTES = 0x00100000;
- /**
- * Align on 2-byte boundary.
- */
- public final static int IMAGE_SCN_ALIGN_2BYTES = 0x00200000;
- /**
- * Align on 4-byte boundary.
- */
- public final static int IMAGE_SCN_ALIGN_4BYTES = 0x00300000;
- /**
- * Align on 8-byte boundary.
- */
- public final static int IMAGE_SCN_ALIGN_8BYTES = 0x00400000;
- /**
- * Align on 16-byte boundary.
- */
- public final static int IMAGE_SCN_ALIGN_16BYTES = 0x00500000;
- /**
- * Align on 32-byte boundary.
- */
- public final static int IMAGE_SCN_ALIGN_32BYTES = 0x00600000;
- /**
- * Align on 64-byte boundary.
- */
- public final static int IMAGE_SCN_ALIGN_64BYTES = 0x00700000;
- /**
- * Align on 128-byte boundary.
- */
- public final static int IMAGE_SCN_ALIGN_128BYTES = 0x00800000;
- /**
- * Align on 256-byte boundary.
- */
- public final static int IMAGE_SCN_ALIGN_256BYTES = 0x00900000;
- /**
- * Align on 512-byte boundary.
- */
- public final static int IMAGE_SCN_ALIGN_512BYTES = 0x00A00000;
- /**
- * Align on 1024-byte boundary.
- */
- public final static int IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000;
- /**
- * Align on 2048-byte boundary.
- */
- public final static int IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000;
- /**
- * Align on 4096-byte boundary.
- */
- public final static int IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000;
- /**
- * Align on 8192-byte boundary.
- */
- public final static int IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000;
- /**
- * Mask for alignment flags
- */
- public final static int IMAGE_SCN_ALIGN_MASK = 0x00F00000;
- /**
- * Section contains extended relocations.
- */
- public final static int IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000;
- /**
- * The section can be discarded from the final executable.
- * Used to hold information for the linker's use,
- * including the .debug$ sections.
- */
- public final static int IMAGE_SCN_MEM_DISCARDABLE = 0x02000000;
- /**
- * Section is not cachable.
- */
- public final static int IMAGE_SCN_MEM_NOT_CACHED = 0x04000000;
- /**
- * The section is not pageable, so it should
- * always be physically present in memory.
- * Often used for kernel-mode drivers.
- */
- public final static int IMAGE_SCN_MEM_NOT_PAGED = 0x08000000;
- /**
- * Section is shareable. The physical pages containing this
- * section's data will be shared between all processes
- * that have this executable loaded. Thus, every process
- * will see the exact same values for data in this section.
- * Useful for making global variables shared between all
- * instances of a process. To make a section shared,
- * use the /section:name,S linker switch.
- */
- public final static int IMAGE_SCN_MEM_SHARED = 0x10000000;
- /**
- * Section is executable.
- */
- public final static int IMAGE_SCN_MEM_EXECUTE = 0x20000000;
- /**
- * Section is readable.
- */
- public final static int IMAGE_SCN_MEM_READ = 0x40000000;
- /**
- * Section is writeable.
- */
- public final static int IMAGE_SCN_MEM_WRITE = 0x80000000;
+ /// Reserved for future use
+ public final static int IMAGE_SCN_RESERVED1 = 0x00000000;
- public final static int NOT_SET = -1;
+ /// Reserved for future use
+ public final static int IMAGE_SCN_RESERVED2 = 0x00000001;
+
+ /// Reserved for future use
+ public final static int IMAGE_SCN_RESERVED3 = 0x00000002;
+
+ /// Reserved for future use
+ public final static int IMAGE_SCN_RESERVED4 = 0x00000004;
+
+ public final static int IMAGE_SCN_TYPE_NO_PAD = 0x00000008;
+
+ /// Reserved for future use
+ public final static int IMAGE_SCN_RESERVED5 = 0x00000010;
+
+ /// Section contains code
+ public final static int IMAGE_SCN_CNT_CODE = 0x00000020;
+
+ /// Section contains initialized data
+ public final static int IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040;
+
+ /// Section contains uninitialized data
+ public final static int IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080;
+
+ /// Reserved for future use
+ public final static int IMAGE_SCN_LNK_OTHER = 0x00000100;
+
+ /// Section contains information for use by the linker (only exists in OBJs)
+ public final static int IMAGE_SCN_LNK_INFO = 0x00000200;
+
+ /// Reserved for future use
+ public final static int IMAGE_SCN_RESERVED6 = 0x00000400;
+
+ /// Section contents will not become part of the image (this only appears in OBJ files)
+ public final static int IMAGE_SCN_LNK_REMOVE = 0x00000800;
+
+ /// Section contents is communal data (comdat). Communal data is data (or code) that can be
+ /// defined in multiple OBJs. The linker will select one copy to include in the executable.
+ /// Comdats are vital for support of C++ template functions and function-level linking. Comdat
+ /// sections only appear in OBJ files.
+ public final static int IMAGE_SCN_LNK_COMDAT = 0x00001000;
+
+ /// Reset speculative exceptions handling bits in the TLB entries for this section
+ public final static int IMAGE_SCN_NO_DEFER_SPEC_EXC = 0x00004000;
+
+ /// Section content can be accessed relative to GP
+ public final static int IMAGE_SCN_GPREL = 0x00008000;
+
+ /// Reserved for future use
+ public final static int IMAGE_SCN_MEM_PURGEABLE = 0x00020000;
+
+ /// Reserved for future use
+ public final static int IMAGE_SCN_MEM_16BIT = 0x00020000;
+
+ /// Reserved for future use
+ public final static int IMAGE_SCN_MEM_LOCKED = 0x00040000;
+
+ /// Reserved for future use
+ public final static int IMAGE_SCN_MEM_PRELOAD = 0x00080000;
+
+ /// Align on 1-byte boundary
+ public final static int IMAGE_SCN_ALIGN_1BYTES = 0x00100000;
+
+ /// Align on 2-byte boundary
+ public final static int IMAGE_SCN_ALIGN_2BYTES = 0x00200000;
+
+ /// Align on 4-byte boundary
+ public final static int IMAGE_SCN_ALIGN_4BYTES = 0x00300000;
+
+ /// Align on 8-byte boundary
+ public final static int IMAGE_SCN_ALIGN_8BYTES = 0x00400000;
+
+ /// Align on 16-byte boundary
+ public final static int IMAGE_SCN_ALIGN_16BYTES = 0x00500000;
+
+ /// Align on 32-byte boundary
+ public final static int IMAGE_SCN_ALIGN_32BYTES = 0x00600000;
+
+ /// Align on 64-byte boundary
+ public final static int IMAGE_SCN_ALIGN_64BYTES = 0x00700000;
+
+ /// Align on 128-byte boundary
+ public final static int IMAGE_SCN_ALIGN_128BYTES = 0x00800000;
+
+ /// Align on 256-byte boundary
+ public final static int IMAGE_SCN_ALIGN_256BYTES = 0x00900000;
+
+ /// Align on 512-byte boundary
+ public final static int IMAGE_SCN_ALIGN_512BYTES = 0x00A00000;
+
+ /// Align on 1024-byte boundary
+ public final static int IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000;
+
+ /// Align on 2048-byte boundary
+ public final static int IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000;
+
+ /// Align on 4096-byte boundary
+ public final static int IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000;
+
+ /// Align on 8192-byte boundary
+ public final static int IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000;
+
+ /// Mask for alignment flags
+ public final static int IMAGE_SCN_ALIGN_MASK = 0x00F00000;
+
+ /// Section contains extended relocations
+ public final static int IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000;
+
+ /// The section can be discarded from the final executable. Used to hold information for the
+ /// linker's use, including the .debug$ sections.
+ public final static int IMAGE_SCN_MEM_DISCARDABLE = 0x02000000;
+
+ /// Section is not cachable
+ public final static int IMAGE_SCN_MEM_NOT_CACHED = 0x04000000;
+
+ /// The section is not pageable, so it should always be physically present in memory. Often used
+ /// for kernel-mode drivers.
+ public final static int IMAGE_SCN_MEM_NOT_PAGED = 0x08000000;
+
+ /// Section is shareable. The physical pages containing this section's data will be shared
+ /// between all processes that have this executable loaded. Thus, every process will see the
+ /// exact same values for data in this section. Useful for making global variables shared
+ /// between all instances of a process. To make a section shared, use the /section:name,S
+ /// linker switch.
+ public final static int IMAGE_SCN_MEM_SHARED = 0x10000000;
+
+ /// Section is executable
+ public final static int IMAGE_SCN_MEM_EXECUTE = 0x20000000;
+
+ /// Section is readable
+ public final static int IMAGE_SCN_MEM_READ = 0x40000000;
+
+ /// Section is writeable
+ public final static int IMAGE_SCN_MEM_WRITE = 0x80000000;
private String name;
private int physicalAddress;
@@ -239,58 +207,55 @@ public class SectionHeader implements StructConverter, ByteArrayConverter {
private BinaryReader reader;
/**
- * Read a {@link SectionHeader} from the specified stream starting at {@code index}.
+ * Creates a new {@link SectionHeader} from the specified stream starting at {@code index}
*
* @param reader {@link BinaryReader} to read from
* @param index long offset in the reader where the section header starts
* @param stringTableOffset offset of the string table, or -1 if not available
- * @return new {@link SectionHeader}
* @throws IOException if error reading data
*/
- public static SectionHeader readSectionHeader(BinaryReader reader, long index,
- long stringTableOffset) throws IOException {
- SectionHeader result = new SectionHeader();
+ public SectionHeader(BinaryReader reader, long index, long stringTableOffset)
+ throws IOException {
+ this.reader = reader;
- result.reader = reader;
-
- result.name = reader.readAsciiString(index, IMAGE_SIZEOF_SHORT_NAME).trim();
- if (result.name.startsWith("/") && stringTableOffset != -1) {
+ name = reader.readAsciiString(index, IMAGE_SIZEOF_SHORT_NAME).trim();
+ if (name.startsWith("/") && stringTableOffset != -1) {
try {
- int nameOffset = Integer.parseInt(result.name.substring(1));
- result.name = reader.readAsciiString(stringTableOffset + nameOffset);
+ int nameOffset = Integer.parseInt(name.substring(1));
+ name = reader.readAsciiString(stringTableOffset + nameOffset);
}
catch (NumberFormatException | IOException nfe) {
// ignore format or out-of-bounds errors...section name will remain as it was
}
}
- // we need to skip IMAGE_SIZEOF_SHORT_NAME chars no matter what,
- // since those bytes are always allocated
+ // We need to skip IMAGE_SIZEOF_SHORT_NAME chars no matter what since those bytes are always
+ // allocated
reader.setPointerIndex(index + IMAGE_SIZEOF_SHORT_NAME);
- result.physicalAddress = result.virtualSize = reader.readNextInt();
- result.virtualAddress = reader.readNextInt();
- result.sizeOfRawData = reader.readNextInt();
- result.pointerToRawData = reader.readNextInt();
- result.pointerToRelocations = reader.readNextInt();
- result.pointerToLinenumbers = reader.readNextInt();
- result.numberOfRelocations = reader.readNextShort();
- result.numberOfLinenumbers = reader.readNextShort();
- result.characteristics = reader.readNextInt();
-
- return result;
- }
-
- private SectionHeader() {
- // empty
+ physicalAddress = virtualSize = reader.readNextInt();
+ virtualAddress = reader.readNextInt();
+ sizeOfRawData = reader.readNextInt();
+ pointerToRawData = reader.readNextInt();
+ pointerToRelocations = reader.readNextInt();
+ pointerToLinenumbers = reader.readNextInt();
+ numberOfRelocations = reader.readNextShort();
+ numberOfLinenumbers = reader.readNextShort();
+ characteristics = reader.readNextInt();
}
+ /**
+ * Creates a new {@link SectionHeader} from the given {@link MemoryBlock}
+ *
+ * @param block The {@link MemoryBlock}
+ * @param optHeader The {@link OptionalHeader}
+ * @param ptr The pointer to raw data
+ */
SectionHeader(MemoryBlock block, OptionalHeader optHeader, int ptr) {
name = block.getName();
physicalAddress = virtualSize = (int) block.getSize();
virtualAddress = (int) block.getStart().getOffset() - (int) optHeader.getImageBase();
- sizeOfRawData =
- PortableExecutable.computeAlignment(virtualSize, optHeader.getFileAlignment());
+ sizeOfRawData = PeUtils.align(virtualSize, optHeader.getFileAlignment());
pointerToRawData = ptr;
pointerToLinenumbers = 0;
pointerToRelocations = 0;
@@ -308,8 +273,7 @@ public class SectionHeader implements StructConverter, ByteArrayConverter {
SectionFlags.IMAGE_SCN_CNT_CODE.getMask();
}
if (block.isExecute()) {
- characteristics |=
- SectionHeader.IMAGE_SCN_MEM_EXECUTE | SectionHeader.IMAGE_SCN_CNT_CODE;
+ characteristics |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE;
}
else if (block.getType() == MemoryBlockType.DEFAULT) {//not executable, then must be data...
if (block.isInitialized()) {
@@ -322,91 +286,67 @@ public class SectionHeader implements StructConverter, ByteArrayConverter {
}
/**
- * Returns the ASCII name of the section. A
- * section name is not guaranteed to be
- * null-terminated. If you specify a section name
- * longer than eight characters, the linker
- * truncates it to eight characters in the
- * executable. A mechanism exists for allowing
- * longer section names in OBJ files. Section
- * names often start with a period, but this is
- * not a requirement. Section names with a $ in
- * the name get special treatment from the linker.
- * Sections with identical names prior to the $
- * character are merged. The characters following
- * the $ provide an alphabetic ordering for how the
- * merged sections appear in the final section.
- * There's quite a bit more to the subject of sections
- * with $ in the name and how they're combined, but
- * the details are outside the scope of this article
- *
- * @return the ASCII name of the section
+ * {@return the ASCII name of the section}
+ * + * A section name is not guaranteed to be null-terminated. If you specify a section name + * longer than eight characters, the linker truncates it to eight characters in the executable. + * A mechanism exists for allowing longer section names in OBJ files. Section names often start + * with a period, but this is not a requirement. Section names with a $ in the name get special + * treatment from the linker. Sections with identical names prior to the $ character are merged. + * The characters following the $ provide an alphabetic ordering for how the merged sections + * appear in the final section. There's quite a bit more to the subject of sections with $ in + * the name and how they're combined, but the details are outside the scope of this article. */ public String getName() { return name; } /** - * Returns a readable ascii version of the name. - * All non-readable characters - * are replaced with underscores. - * @return a readable ascii version of the name + * {@return a readable ascii version of the name (all non-readable characters are replaced with + * underscores} */ public String getReadableName() { - StringBuffer buffer = new StringBuffer(); + StringBuilder sb = new StringBuilder(); for (int i = 0; i < name.length(); ++i) { char ch = name.charAt(i); if (ch >= 0x20 && ch <= 0x7e) {//is readable ascii? - buffer.append(ch); + sb.append(ch); } else { - buffer.append('_'); + sb.append('_'); } } - return buffer.toString(); + return sb.toString(); } /** - * Returns the physical (file) address of this section. - * @return the physical (file) address of this section + * {@return the physical (file) address of this section} */ public int getPhysicalAddress() { return physicalAddress; } /** - * In executables, returns the RVA where - * the section begins in memory. Should be set to 0 in OBJs. - * this section should be loaded into memory. - * @return the RVA where the section begins in memory. + * {@return the RVA where the section begins in memory} */ public int getVirtualAddress() { return virtualAddress; } /** - * Returns the actual, used size of the section. - * This field may be larger or - * smaller than the SizeOfRawData field. - * If the VirtualSize is larger, the - * SizeOfRawData field is the size of the - * initialized data from the executable, - * and the remaining bytes up to the VirtualSize - * should be zero-padded. This field is set - * to 0 in OBJ files. - * @return the actual, used size of the section + * {@return the actual, used size of the section} + *
+ * This field may be larger or smaller than the SizeOfRawData field. If the VirtualSize is
+ * larger, the SizeOfRawData field is the size of the initialized data from the executable, and
+ * the remaining bytes up to the VirtualSize should be zero-padded. This field is set to 0 in
+ * OBJ files.
*/
public int getVirtualSize() {
- if (virtualSize == 0) {
- return sizeOfRawData;
- }
- return virtualSize;
+ return virtualSize != 0 ? virtualSize : sizeOfRawData;
}
/**
- * Returns the size (in bytes) of data stored for the section
- * in the executable or OBJ.
- * @return the size (in bytes) of data stored for the section
+ * {@return the size (in bytes) of data stored for the section}
*/
public int getSizeOfRawData() {
return sizeOfRawData;
@@ -438,28 +378,22 @@ public class SectionHeader implements StructConverter, ByteArrayConverter {
return pointerToRawData;
}
-
/**
- * Returns the file offset of relocations for this section.
- * @return the file offset of relocations for this section
+ * {@return the file offset of relocations for this section}
*/
public int getPointerToRelocations() {
return pointerToRelocations;
}
/**
- * Returns the number of relocations pointed
- * to by the PointerToRelocations field.
- * @return the number of relocations
+ * {@return the number of relocations pointed to by the {@code PointerToRelocations} field}
*/
public short getNumberOfRelocations() {
return numberOfRelocations;
}
/**
- * Return the file offset for COFF-style line
- * numbers for this section.
- * @return the file offset for COFF-style line numbers for this section
+ * {@return the file offset for COFF-style line numbers for this section}
*/
public int getPointerToLinenumbers() {
return pointerToLinenumbers;
@@ -477,9 +411,7 @@ public class SectionHeader implements StructConverter, ByteArrayConverter {
}
/**
- * Returns the number of line numbers pointed to by the
- * NumberOfRelocations field.
- * @return the number of line numbers
+ * {@return the number of line numbers pointed to by the {@code NumberOfRelocations} field
*/
public short getNumberOfLinenumbers() {
return numberOfLinenumbers;
@@ -491,26 +423,22 @@ public class SectionHeader implements StructConverter, ByteArrayConverter {
}
/**
- * Returns an input stream to underlying bytes of this section.
- * @return an input stream to underlying bytes of this section
- * @throws IOException if an i/o error occurs.
+ * {@return an {@link InputStream} to underlying bytes of this section}
+ *
+ * @throws IOException if an IO-related error occurred
*/
public InputStream getDataStream() throws IOException {
return reader.getByteProvider().getInputStream(getPointerToRawData());
}
/**
- * Returns a ByteProvider to underlying bytes of this section.
- * @return a ByteProvider to underlying bytes of this section
+ * {@return a {@link ByteProvider} to underlying bytes of this section}
*/
- public ByteProvider getDataByteProvider() {
+ public ByteProvider getDataByteProvider() {
return new ByteProviderWrapper(reader.getByteProvider(), getPointerToRawData(),
getSizeOfRawData());
}
- /**
- * @see java.lang.Object#toString()
- */
@Override
public String toString() {
StringBuffer buff = new StringBuffer();
@@ -562,13 +490,8 @@ public class SectionHeader implements StructConverter, ByteArrayConverter {
return struct;
}
- /**
- * Writes this section header to the specified random access file.
- * @param raf the random access file
- * @param dc the data converter
- * @throws IOException if an I/O error occurs
- */
- public void writeHeader(RandomAccessFile raf, DataConverter dc) throws IOException {
+ @Override
+ public void write(RandomAccessFile raf, DataConverter dc) throws IOException {
byte[] paddedName = new byte[IMAGE_SIZEOF_SHORT_NAME];
byte[] nameBytes = name.getBytes();
System.arraycopy(nameBytes, 0, paddedName, 0,
@@ -587,17 +510,15 @@ public class SectionHeader implements StructConverter, ByteArrayConverter {
}
/**
- * Writes the bytes from this section into the specified random access file.
- * The bytes will be written starting at the byte position
- * specified by getPointerToRawData().
+ * Writes the bytes from this section into the specified random access file. The bytes will be
+ * written starting at the byte position specified by {@link #getPointerToRawData()}
*
- * @param raf the random access file
- * @param rafIndex the index into the RAF where the bytes will be written
- * @param dc the data converter
- * @param block the memory block corresponding to this section
- * @param useBlockBytes if true, then use the bytes from the memory block,
- * otherwise use the bytes from this section.
- *
+ * @param raf the random access file
+ * @param rafIndex the index into the RAF where the bytes will be written
+ * @param dc the data converter
+ * @param block the memory block corresponding to this section
+ * @param useBlockBytes if true, then use the bytes from the memory block, otherwise use the
+ * bytes from this section.
* @throws IOException if there are errors writing to the file
* @throws MemoryAccessException if the byte from the memory block cannot be accesses
*/
@@ -610,8 +531,6 @@ public class SectionHeader implements StructConverter, ByteArrayConverter {
raf.seek(rafIndex);
- //if ((block.getType() == MemoryBlock.INITIALIZED) || (block.getType() == MemoryBlock.LIVE)) {
-
if (useBlockBytes) {
byte[] blockBytes = new byte[(int) block.getSize()];
block.getBytes(block.getStart(), blockBytes);
@@ -625,7 +544,6 @@ public class SectionHeader implements StructConverter, ByteArrayConverter {
if (padLength > 0) {
raf.write(new byte[padLength]);
}
- //}
}
void updatePointers(int offset) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/SeparateDebugHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/SeparateDebugHeader.java
index ee0200b5e7..4961595e57 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/SeparateDebugHeader.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/SeparateDebugHeader.java
@@ -110,7 +110,7 @@ public class SeparateDebugHeader implements OffsetValidator {
sections = new SectionHeader[numberOfSections];
for (int i = 0; i < numberOfSections; ++i) {
- sections[i] = SectionHeader.readSectionHeader(reader, ptr, -1);
+ sections[i] = new SectionHeader(reader, ptr, -1);
ptr += SectionHeader.IMAGE_SIZEOF_SECTION_HEADER;
}