mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-25 20:18:23 +08:00
Merge branch 'GP-6991_ryanmkurtz_mz-fix'
This commit is contained in:
@@ -19,11 +19,6 @@ import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.ne.InvalidWindowsHeaderException;
|
||||
import ghidra.app.util.bin.format.ne.WindowsHeader;
|
||||
import ghidra.app.util.bin.format.pe.InvalidNTHeaderException;
|
||||
import ghidra.app.util.bin.format.pe.NTHeader;
|
||||
import ghidra.app.util.bin.format.pe.PortableExecutable.SectionLayout;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.DataConverter;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
@@ -62,7 +57,8 @@ import ghidra.util.exception.DuplicateNameException;
|
||||
public class DOSHeader extends OldDOSHeader {
|
||||
|
||||
/** The name to use when converting into a structure data type. */
|
||||
public final static String NAME = "IMAGE_DOS_HEADER";
|
||||
@SuppressWarnings("hiding")
|
||||
public final static String NAME = "IMAGE_DOS_HEADER";
|
||||
|
||||
public final static int SIZEOF_DOS_HEADER = 64;
|
||||
|
||||
@@ -75,7 +71,8 @@ public class DOSHeader extends OldDOSHeader {
|
||||
private byte [] stubBytes;
|
||||
|
||||
/**
|
||||
* Constructs a new DOS header.
|
||||
* Constructs a new {@link DOSHeader}
|
||||
*
|
||||
* @param reader the binary reader
|
||||
* @throws IOException if there was an IO-related error
|
||||
*/
|
||||
@@ -84,87 +81,40 @@ public class DOSHeader extends OldDOSHeader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reserved words.
|
||||
* @return the reserved words
|
||||
*/
|
||||
* {@return the reserved words}
|
||||
*/
|
||||
public short [] e_res() {
|
||||
return e_res;
|
||||
}
|
||||
/**
|
||||
* Returns the OEM identifier (for e_oeminfo).
|
||||
* @return the OEM identifier (for e_oeminfo)
|
||||
*/
|
||||
|
||||
/**
|
||||
* {@return the OEM identifier (for e_oeminfo)}
|
||||
*/
|
||||
public short e_oemid() {
|
||||
return e_oemid;
|
||||
}
|
||||
/**
|
||||
* Returns the OEM information; e_oemid specific.
|
||||
* @return the OEM information; e_oemid specific
|
||||
*/
|
||||
|
||||
/**
|
||||
* {@return the OEM information; e_oemid specific}
|
||||
*/
|
||||
public short e_oeminfo() {
|
||||
return e_oeminfo;
|
||||
}
|
||||
/**
|
||||
* Returns the reserved words (2).
|
||||
* @return the reserved words (2)
|
||||
*/
|
||||
|
||||
/**
|
||||
* {@return the reserved words (2)}
|
||||
*/
|
||||
public short [] e_res2() {
|
||||
return e_res2;
|
||||
}
|
||||
/**
|
||||
* Returns the file address of new EXE header.
|
||||
* @return the file address of new EXE header
|
||||
*/
|
||||
|
||||
/**
|
||||
* {@return the file address of new EXE header}
|
||||
*/
|
||||
public int e_lfanew() {
|
||||
return e_lfanew;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a new EXE header exists.
|
||||
* @return true if a new EXE header exists
|
||||
*/
|
||||
@Override
|
||||
public boolean hasNewExeHeader() {
|
||||
if (e_lfanew >= 0 && e_lfanew <= 0x10000) {
|
||||
if (e_lfarlc() == 0x40) {
|
||||
// There are some non-NE files out there than may have e_lfarlc == 0x40, so we need
|
||||
// to actually read the bytes at e_lfanew and check for the required NE signature.
|
||||
try {
|
||||
new WindowsHeader(reader, null, (short) e_lfanew);
|
||||
return true;
|
||||
}
|
||||
catch (InvalidWindowsHeaderException | IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a PE header exists.
|
||||
* @return true if a PE header exists
|
||||
*/
|
||||
@Override
|
||||
public boolean hasPeHeader() {
|
||||
if (e_lfanew >= 0 && e_lfanew <= 0x1000000) {
|
||||
try {
|
||||
NTHeader ntHeader =
|
||||
new NTHeader(reader, e_lfanew, SectionLayout.FILE, false);
|
||||
if (ntHeader.getOptionalHeader() != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (InvalidNTHeaderException | IOException e) {
|
||||
// Fall through and return false
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.app.util.bin.StructConverter#toDataType()
|
||||
*/
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException {
|
||||
StructureDataType struct = (StructureDataType)super.toDataType();
|
||||
@@ -199,24 +149,16 @@ public class DOSHeader extends OldDOSHeader {
|
||||
return struct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to override the value of name
|
||||
* @return The name of the header
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length (in bytes) of the DOS
|
||||
* program.
|
||||
* <p>
|
||||
* In other words:
|
||||
* <code>e_lfanew() - SIZEOF_DOS_HEADER</code>
|
||||
*
|
||||
* @return the length (in bytes)
|
||||
*/
|
||||
* {@return the length (in bytes) of the DOS program}
|
||||
* <p>
|
||||
* In other words: {@code e_lfanew() - SIZEOF_DOS_HEADER}
|
||||
*/
|
||||
public int getProgramLen() {
|
||||
return stubBytes == null ? 0 : stubBytes.length;
|
||||
}
|
||||
@@ -261,9 +203,6 @@ public class DOSHeader extends OldDOSHeader {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.app.util.bin.format.Writeable#write(java.io.RandomAccessFile, ghidra.util.DataConverter)
|
||||
*/
|
||||
@Override
|
||||
public void write(RandomAccessFile raf, DataConverter dc) throws IOException {
|
||||
super.write(raf, dc);
|
||||
|
||||
+19
-54
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -72,7 +72,8 @@ public class OldDOSHeader implements StructConverter, Writeable {
|
||||
protected BinaryReader reader;
|
||||
|
||||
/**
|
||||
* Constructs a new DOS header.
|
||||
* Constructs a new {@link OldDOSHeader}
|
||||
*
|
||||
* @param reader the binary reader
|
||||
* @throws IOException if there was an IO-related error
|
||||
*/
|
||||
@@ -82,32 +83,28 @@ public class OldDOSHeader implements StructConverter, Writeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the processor name.
|
||||
* @return the processor name
|
||||
* {@return the processor name}
|
||||
*/
|
||||
public String getProcessorName() {
|
||||
return "x86";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the magic number.
|
||||
* @return the magic number
|
||||
* {@return the magic number}
|
||||
*/
|
||||
public short e_magic() {
|
||||
return e_magic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes on the last page of file.
|
||||
* @return the number of bytes on the last page of the file
|
||||
* {@return the number of bytes on the last page of the file}
|
||||
*/
|
||||
public short e_cblp() {
|
||||
return e_cblp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of pages in the file.
|
||||
* @return the number of pages in the file
|
||||
* {@return the number of pages in the file}
|
||||
*/
|
||||
public short e_cp() {
|
||||
return e_cp;
|
||||
@@ -122,104 +119,77 @@ public class OldDOSHeader implements StructConverter, Writeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of header in paragraphs.
|
||||
* @return the size of header in paragraphs
|
||||
* {@return the size of header in paragraphs}
|
||||
*/
|
||||
public short e_cparhdr() {
|
||||
return e_cparhdr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum extra paragraphs needed.
|
||||
* @return the minimum extra paragraphs needed
|
||||
* {@return the minimum extra paragraphs needed}
|
||||
*/
|
||||
public short e_minalloc() {
|
||||
return e_minalloc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum extra paragraphs needed.
|
||||
* @return the maximum extra paragraphs needed
|
||||
* {@return the maximum extra paragraphs needed}
|
||||
*/
|
||||
public short e_maxalloc() {
|
||||
return e_maxalloc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the initial (relative) SS value.
|
||||
* @return the initial (relative) SS value
|
||||
* {@return the initial (relative) SS value}
|
||||
*/
|
||||
public short e_ss() {
|
||||
return e_ss;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the initial SP value.
|
||||
* @return the initial SP value
|
||||
* {@return the initial SP value}
|
||||
*/
|
||||
public short e_sp() {
|
||||
return e_sp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the checksum.
|
||||
* @return the checksum
|
||||
* {@return the checksum}
|
||||
*/
|
||||
public short e_csum() {
|
||||
return e_csum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the initial IP value.
|
||||
* @return the initial IP value
|
||||
* {@return the initial IP value}
|
||||
*/
|
||||
public short e_ip() {
|
||||
return e_ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the initial (relative) CS value.
|
||||
* @return the initial (relative) CS value
|
||||
* {@return the initial (relative) CS value}
|
||||
*/
|
||||
public short e_cs() {
|
||||
return e_cs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file address of relocation table.
|
||||
* @return the file address of relocation table
|
||||
* {@return the file address of relocation table}
|
||||
*/
|
||||
public short e_lfarlc() {
|
||||
return e_lfarlc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the overlay number.
|
||||
* @return the overlay number
|
||||
* {@return the overlay number}
|
||||
*/
|
||||
public short e_ovno() {
|
||||
return e_ovno;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a new EXE header exists.
|
||||
* @return true if a new EXE header exists
|
||||
*/
|
||||
public boolean hasNewExeHeader() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a PE header exists.
|
||||
* @return true if a PE header exists
|
||||
*/
|
||||
public boolean hasPeHeader() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the DOS magic number is correct
|
||||
* @return true if the DOS magic number is correct
|
||||
* {@return true if the DOS magic number is correct}
|
||||
*/
|
||||
public boolean isDosSignature() {
|
||||
return e_magic == IMAGE_DOS_SIGNATURE;
|
||||
@@ -268,10 +238,6 @@ public class OldDOSHeader implements StructConverter, Writeable {
|
||||
return struct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to override the value of name
|
||||
* @return The name of the header
|
||||
*/
|
||||
protected String getName() {
|
||||
return NAME;
|
||||
}
|
||||
@@ -317,5 +283,4 @@ public class OldDOSHeader implements StructConverter, Writeable {
|
||||
raf.write(dc.getBytes(e_lfarlc));
|
||||
raf.write(dc.getBytes(e_ovno));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,18 +27,16 @@ import ghidra.util.Msg;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* A class to represent the <b><code>IMAGE_NT_HEADERS32</code></b> and
|
||||
* IMAGE_NT_HEADERS64 structs as defined in
|
||||
* <code>winnt.h</code>.
|
||||
* <pre>
|
||||
* A class to represent the {@code IMAGE_NT_HEADERS32} and {@code IMAGE_NT_HEADERS64} structs as
|
||||
* defined in {@code winnt.h}
|
||||
*
|
||||
* <pre>{@code
|
||||
* typedef struct _IMAGE_NT_HEADERS {
|
||||
* DWORD Signature;
|
||||
* IMAGE_FILE_HEADER FileHeader;
|
||||
* IMAGE_OPTIONAL_HEADER32 OptionalHeader;
|
||||
* };
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public class NTHeader implements StructConverter, OffsetValidator {
|
||||
/**
|
||||
@@ -58,13 +56,14 @@ 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 layout The {@link SectionLayout}
|
||||
* @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.
|
||||
* do not constitute an accurate NT header.
|
||||
*/
|
||||
public NTHeader(BinaryReader reader, int index, SectionLayout layout, boolean parseCliHeaders)
|
||||
throws InvalidNTHeaderException, IOException {
|
||||
@@ -77,8 +76,7 @@ public class NTHeader implements StructConverter, OffsetValidator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name to use when converting into a structure data type.
|
||||
* @return the name to use when converting into a structure data type
|
||||
* {@return the name to use when converting into a structure data type}
|
||||
*/
|
||||
public String getName() {
|
||||
return "IMAGE_NT_HEADERS" + (optionalHeader.is64bit() ? "64" : "32");
|
||||
@@ -89,24 +87,19 @@ public class NTHeader implements StructConverter, OffsetValidator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file header.
|
||||
* @return the file header
|
||||
* {@return the file header}
|
||||
*/
|
||||
public FileHeader getFileHeader() {
|
||||
return fileHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the optional header.
|
||||
* @return the optional header
|
||||
* {@return the optional header}
|
||||
*/
|
||||
public OptionalHeader getOptionalHeader() {
|
||||
return optionalHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.app.util.bin.StructConverter#toDataType()
|
||||
*/
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType(getName(), 0);
|
||||
@@ -121,20 +114,20 @@ public class NTHeader implements StructConverter, OffsetValidator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a relative virtual address (RVA) into a pointer.
|
||||
* {@return the given relative virtual address (RVA) converted into a pointer into the binary
|
||||
* image, or -1 if not valid}
|
||||
*
|
||||
* @param rva the relative virtual address
|
||||
* @return the pointer into binary image, 0 if not valid
|
||||
*/
|
||||
public int rvaToPointer(int rva) {
|
||||
return (int) rvaToPointer(Integer.toUnsignedLong(rva));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a relative virtual address (RVA) into a pointer.
|
||||
* {@return the given relative virtual address (RVA) converted into a pointer into the binary
|
||||
* image, or -1 if not valid}
|
||||
|
||||
* @param rva the relative virtual address
|
||||
* @return the pointer into binary image, -1 if not valid
|
||||
*/
|
||||
public long rvaToPointer(long rva) {
|
||||
SectionHeader[] sections = fileHeader.getSectionHeaders();
|
||||
@@ -212,31 +205,26 @@ public class NTHeader implements StructConverter, OffsetValidator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a virtual address (VA) into a pointer.
|
||||
* {@return the given virtual address (VA) converted into a pointer into the binary
|
||||
* image, or -1 if not valid}
|
||||
*
|
||||
* @param va the virtual address
|
||||
* @return the pointer into binary image, 0 if not valid
|
||||
*/
|
||||
public int vaToPointer(int va) {
|
||||
return (int) vaToPointer(Integer.toUnsignedLong(va));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a virtual address (VA) into a pointer.
|
||||
* {@return the given virtual address (VA) converted into a pointer into the binary
|
||||
* image, or -1 if not valid}
|
||||
*
|
||||
* @param va the virtual address
|
||||
* @return the pointer into binary image, 0 if not valid
|
||||
*/
|
||||
public long vaToPointer(long va) {
|
||||
return rvaToPointer(va - getOptionalHeader().getImageBase());
|
||||
}
|
||||
|
||||
private void parse() throws InvalidNTHeaderException, IOException {
|
||||
|
||||
if (index < 0 || index > reader.length()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int tmpIndex = index;
|
||||
|
||||
try {
|
||||
|
||||
@@ -23,6 +23,9 @@ import ghidra.app.util.MemoryBlockUtils;
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.format.mz.*;
|
||||
import ghidra.app.util.bin.format.ne.NewExecutable;
|
||||
import ghidra.app.util.bin.format.pe.PortableExecutable;
|
||||
import ghidra.app.util.bin.format.pe.PortableExecutable.SectionLayout;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.program.database.mem.FileBytes;
|
||||
import ghidra.program.database.module.TreeManager;
|
||||
@@ -65,7 +68,7 @@ public class MzLoader extends AbstractLibrarySupportLoader {
|
||||
}
|
||||
MzExecutable mz = new MzExecutable(provider);
|
||||
OldDOSHeader header = mz.getHeader();
|
||||
if (header.isDosSignature() && !header.hasNewExeHeader() && !header.hasPeHeader()) {
|
||||
if (header.isDosSignature() && !isPeOrNe(provider)) {
|
||||
List<QueryResult> results =
|
||||
QueryOpinionService.query(getName(), "" + header.e_magic(), null);
|
||||
for (QueryResult result : results) {
|
||||
@@ -127,6 +130,28 @@ public class MzLoader extends AbstractLibrarySupportLoader {
|
||||
return 60; // we are less priority than PE! Important for ProgramLoader
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return true if the given {@link ByteProvider} contains a PE or NE binary}
|
||||
*
|
||||
* @param provider The {@link ByteProvider} to check
|
||||
*/
|
||||
private boolean isPeOrNe(ByteProvider provider) {
|
||||
try {
|
||||
new PortableExecutable(provider, SectionLayout.FILE, false, false);
|
||||
return true;
|
||||
}
|
||||
catch (IOException e) {
|
||||
try {
|
||||
new NewExecutable(provider, null);
|
||||
return true;
|
||||
}
|
||||
catch (IOException e2) {
|
||||
// fall through
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a relocation's fixup information
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user