diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/mz/DOSHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/mz/DOSHeader.java index f4cabc88ed..07e8c9e526 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/mz/DOSHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/mz/DOSHeader.java @@ -19,8 +19,6 @@ import java.io.IOException; import java.io.RandomAccessFile; 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.ne.InvalidWindowsHeaderException; import ghidra.app.util.bin.format.ne.WindowsHeader; import ghidra.app.util.bin.format.pe.InvalidNTHeaderException; @@ -61,26 +59,13 @@ import ghidra.util.exception.DuplicateNameException; * * */ -public class DOSHeader implements StructConverter, Writeable { +public class DOSHeader extends OldDOSHeader { + /** The name to use when converting into a structure data type. */ public final static String NAME = "IMAGE_DOS_HEADER"; - public final static int IMAGE_DOS_SIGNATURE = 0x5A4D; // MZ - public final static int SIZEOF_DOS_HEADER = 64; + + public final static int SIZEOF_DOS_HEADER = 64; - private short e_magic; // Magic number - private short e_cblp; // Bytes on last page of file - private short e_cp; // Pages in file - private short e_crlc; // Relocations - private short e_cparhdr; // Size of header in paragraphs - private short e_minalloc; // Minimum extra paragraphs needed - private short e_maxalloc; // Maximum extra paragraphs needed - private short e_ss; // Initial (relative) SS value - private short e_sp; // Initial SP value - private short e_csum; // Checksum - private short e_ip; // Initial IP value - private short e_cs; // Initial (relative) CS value - private short e_lfarlc; // File address of relocation table - private short e_ovno; // Overlay number private short [] e_res = new short[4]; // Reserved words private short e_oemid; // OEM identifier (for e_oeminfo) private short e_oeminfo; // OEM information; e_oemid specific @@ -89,123 +74,16 @@ public class DOSHeader implements StructConverter, Writeable { private byte [] stubBytes; - private BinaryReader reader; - /** - * Constructs a new DOS header. - * @param reader the binary reader - */ + * Constructs a new DOS header. + * @param reader the binary reader + * @throws IOException if there was an IO-related error + */ public DOSHeader(BinaryReader reader) throws IOException { - this.reader = reader; - parse(); + super(reader); } - /** - * Returns the processor name. - * @return the processor name - */ - public String getProcessorName() { - return "x86"; - } - /** - * Returns 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 - */ - public short e_cblp() { - return e_cblp; - } - /** - * Returns the number of pages in the file. - * @return the number of pages in the file - */ - public short e_cp() { - return e_cp; - } - /** - * Returns the number of relocations. - * @return the number of relocations - */ - public short e_crlc() { - return e_crlc; - } - /** - * Returns 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 - */ - public short e_minalloc() { - return e_minalloc; - } - /** - * Returns 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 - */ - public short e_ss() { - return e_ss; - } - /** - * Returns the initial SP value. - * @return the initial SP value - */ - public short e_sp() { - return e_sp; - } - /** - * Returns the checksum. - * @return the checksum - */ - public short e_csum() { - return e_csum; - } - /** - * Returns 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 - */ - public short e_cs() { - return e_cs; - } - /** - * Returns 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 - */ - public short e_ovno() { - return e_ovno; - } - /** + /** * Returns the reserved words. * @return the reserved words */ @@ -245,9 +123,10 @@ public class DOSHeader implements StructConverter, Writeable { * 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) { + 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 { @@ -266,6 +145,7 @@ public class DOSHeader implements StructConverter, Writeable { * 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 { @@ -282,24 +162,13 @@ public class DOSHeader implements StructConverter, Writeable { return false; } - /** - * Returns 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; - } - /** * @see ghidra.app.util.bin.StructConverter#toDataType() */ @Override public DataType toDataType() throws DuplicateNameException { - StructureDataType struct = new StructureDataType(NAME, 0); - struct.add(new ArrayDataType(ASCII,2,1)); - for (int i=1; i <= 13; i++) { - struct.add(WORD); - } + StructureDataType struct = (StructureDataType)super.toDataType(); + struct.add(new ArrayDataType(WORD,4,2)); struct.add(WORD); struct.add(WORD); @@ -309,20 +178,6 @@ public class DOSHeader implements StructConverter, Writeable { struct.add(new ArrayDataType(BYTE, getProgramLen(), 1)); } - struct.getComponent( 0).setFieldName("e_magic"); - struct.getComponent( 1).setFieldName("e_cblp"); - struct.getComponent( 2).setFieldName("e_cp"); - struct.getComponent( 3).setFieldName("e_crlc"); - struct.getComponent( 4).setFieldName("e_cparhdr"); - struct.getComponent( 5).setFieldName("e_minalloc"); - struct.getComponent( 6).setFieldName("e_maxalloc"); - struct.getComponent( 7).setFieldName("e_ss"); - struct.getComponent( 8).setFieldName("e_sp"); - struct.getComponent( 9).setFieldName("e_csum"); - struct.getComponent(10).setFieldName("e_ip"); - struct.getComponent(11).setFieldName("e_cs"); - struct.getComponent(12).setFieldName("e_lfarlc"); - struct.getComponent(13).setFieldName("e_ovno"); struct.getComponent(14).setFieldName("e_res[4]"); struct.getComponent(15).setFieldName("e_oemid"); struct.getComponent(16).setFieldName("e_oeminfo"); @@ -332,20 +187,6 @@ public class DOSHeader implements StructConverter, Writeable { struct.getComponent(19).setFieldName("e_program"); } - struct.getComponent( 0).setComment("Magic number"); - struct.getComponent( 1).setComment("Bytes of last page"); - struct.getComponent( 2).setComment("Pages in file"); - struct.getComponent( 3).setComment("Relocations"); - struct.getComponent( 4).setComment("Size of header in paragraphs"); - struct.getComponent( 5).setComment("Minimum extra paragraphs needed"); - struct.getComponent( 6).setComment("Maximum extra paragraphs needed"); - struct.getComponent( 7).setComment("Initial (relative) SS value"); - struct.getComponent( 8).setComment("Initial SP value"); - struct.getComponent( 9).setComment("Checksum"); - struct.getComponent(10).setComment("Initial IP value"); - struct.getComponent(11).setComment("Initial (relative) CS value"); - struct.getComponent(12).setComment("File address of relocation table"); - struct.getComponent(13).setComment("Overlay number"); struct.getComponent(14).setComment("Reserved words"); struct.getComponent(15).setComment("OEM identifier (for e_oeminfo)"); struct.getComponent(16).setComment("OEM information; e_oemid specific"); @@ -355,10 +196,17 @@ public class DOSHeader implements StructConverter, Writeable { struct.getComponent(19).setComment("Actual DOS program"); } - struct.setCategoryPath(new CategoryPath("/DOS")); - 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 @@ -373,35 +221,21 @@ public class DOSHeader implements StructConverter, Writeable { return stubBytes == null ? 0 : stubBytes.length; } - private void parse() throws IOException { - reader.setPointerIndex(0); - - e_magic = reader.readNextShort(); - - if (e_magic != IMAGE_DOS_SIGNATURE) { + @Override + protected void parse() throws IOException { + super.parse(); + + if (!isDosSignature()) { return; } - - e_cblp = reader.readNextShort(); - e_cp = reader.readNextShort(); - e_crlc = reader.readNextShort(); - e_cparhdr = reader.readNextShort(); - e_minalloc = reader.readNextShort(); - e_maxalloc = reader.readNextShort(); - e_ss = reader.readNextShort(); - e_sp = reader.readNextShort(); - e_csum = reader.readNextShort(); - e_ip = reader.readNextShort(); - e_cs = reader.readNextShort(); - e_lfarlc = reader.readNextShort(); - e_ovno = reader.readNextShort(); + e_res = reader.readNextShortArray(4); e_oemid = reader.readNextShort(); e_oeminfo = reader.readNextShort(); e_res2 = reader.readNextShortArray(10); e_lfanew = reader.readNextInt(); - if (isDosSignature() && e_lfanew < 0x10000) { + if (e_lfanew < 0x10000) { try { stubBytes = e_lfanew > SIZEOF_DOS_HEADER ? reader.readByteArray(SIZEOF_DOS_HEADER, e_lfanew - SIZEOF_DOS_HEADER) : new byte[0]; @@ -432,20 +266,7 @@ public class DOSHeader implements StructConverter, Writeable { */ @Override public void write(RandomAccessFile raf, DataConverter dc) throws IOException { - raf.write(dc.getBytes(e_magic)); - raf.write(dc.getBytes(e_cblp)); - raf.write(dc.getBytes(e_cp)); - raf.write(dc.getBytes(e_crlc)); - raf.write(dc.getBytes(e_cparhdr)); - raf.write(dc.getBytes(e_minalloc)); - raf.write(dc.getBytes(e_maxalloc)); - raf.write(dc.getBytes(e_ss)); - raf.write(dc.getBytes(e_sp)); - raf.write(dc.getBytes(e_csum)); - raf.write(dc.getBytes(e_ip)); - raf.write(dc.getBytes(e_cs)); - raf.write(dc.getBytes(e_lfarlc)); - raf.write(dc.getBytes(e_ovno)); + super.write(raf, dc); for (short e_re : e_res) { raf.write(dc.getBytes(e_re)); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/mz/MzExecutable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/mz/MzExecutable.java new file mode 100644 index 0000000000..b1011910be --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/mz/MzExecutable.java @@ -0,0 +1,75 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.bin.format.mz; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.ByteProvider; + +/** + * A class to manage loading old-style DOS MZ executables + */ +public class MzExecutable { + + private BinaryReader reader; + private OldDOSHeader header; + private List relocations = new ArrayList<>(); + + /** + * Constructs a new instance of an old-style MZ executable + * + * @param provider The bytes + * @throws IOException if an I/O error occurs + */ + public MzExecutable(ByteProvider provider) throws IOException { + reader = new BinaryReader(provider, true); + header = new OldDOSHeader(reader); + reader.setPointerIndex(header.e_lfarlc()); + for (int i = 0; i < header.e_crlc(); i++) { + relocations.add(new MzRelocation(reader)); + } + } + + /** + * Returns the underlying binary reader + * + * @return the underlying binary reader + */ + public BinaryReader getBinaryReader() { + return reader; + } + + /** + * Returns the DOS Header from this old-style MZ executable + * + * @return the DOS Header from this old-style MZ executable + */ + public OldDOSHeader getHeader() { + return header; + } + + /** + * Returns the old-style MZ relocations + * + * @return the old-style MZ relocations + */ + public List getRelocations() { + return relocations; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/mz/MzRelocation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/mz/MzRelocation.java new file mode 100644 index 0000000000..a06c0f420a --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/mz/MzRelocation.java @@ -0,0 +1,75 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.bin.format.mz; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +public class MzRelocation implements StructConverter { + + /** The name to use when converting into a structure data type. */ + public static final String NAME = "OLD_IMAGE_DOS_RELOC"; + + private int segment; + private int offset; + + /** + * Constructs a new old-style MZ relocation + * + * @param reader A {@link BinaryReader} positioned at the start of the relocation + * @throws IOException if there was an IO-related error + */ + public MzRelocation(BinaryReader reader) throws IOException { + offset = Short.toUnsignedInt(reader.readNextShort()); + segment = Short.toUnsignedInt(reader.readNextShort()); + } + + /** + * Gets the segment + * + * @return The segment + */ + public int getSegment() { + return segment; + } + + /** + * Gets the offset + * + * @return The offset + */ + public int getOffset() { + return offset; + } + + @Override + public DataType toDataType() throws DuplicateNameException { + StructureDataType struct = new StructureDataType(NAME, 0); + struct.add(WORD, "offset", null); + struct.add(WORD, "segment", null); + struct.setCategoryPath(new CategoryPath("/DOS")); + return struct; + } + + @Override + public String toString() { + return String.format("%04x:%04x", segment, offset); + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/mz/OldDOSHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/mz/OldDOSHeader.java new file mode 100644 index 0000000000..d484fce451 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/mz/OldDOSHeader.java @@ -0,0 +1,321 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.bin.format.mz; + +import java.io.IOException; +import java.io.RandomAccessFile; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.Writeable; +import ghidra.program.model.data.*; +import ghidra.util.DataConverter; +import ghidra.util.exception.DuplicateNameException; + +/** + * This class represents a DOS Header + *
+ *
+ *     WORD   e_magic;                     // Magic number								// MANDATORY
+ *     WORD   e_cblp;                      // Bytes on last page of file
+ *     WORD   e_cp;                        // Pages in file
+ *     WORD   e_crlc;                      // Relocations
+ *     WORD   e_cparhdr;                   // Size of header in paragraphs
+ *     WORD   e_minalloc;                  // Minimum extra paragraphs needed
+ *     WORD   e_maxalloc;                  // Maximum extra paragraphs needed
+ *     WORD   e_ss;                        // Initial (relative) SS value
+ *     WORD   e_sp;                        // Initial SP value
+ *     WORD   e_csum;                      // Checksum
+ *     WORD   e_ip;                        // Initial IP value
+ *     WORD   e_cs;                        // Initial (relative) CS value
+ *     WORD   e_lfarlc;                    // File address of relocation table
+ *     WORD   e_ovno;                      // Overlay number
+ *     
+ * 
+ */ + +public class OldDOSHeader implements StructConverter, Writeable { + + /** The name to use when converting into a structure data type. */ + public static final String NAME = "OLD_IMAGE_DOS_HEADER"; + + public static final int IMAGE_DOS_SIGNATURE = 0x5A4D; + + private short e_magic; + private short e_cblp; + private short e_cp; + private short e_crlc; + private short e_cparhdr; + private short e_minalloc; + private short e_maxalloc; + private short e_ss; + private short e_sp; + private short e_csum; + private short e_ip; + private short e_cs; + private short e_lfarlc; + private short e_ovno; + + protected BinaryReader reader; + + /** + * Constructs a new DOS header. + * @param reader the binary reader + * @throws IOException if there was an IO-related error + */ + public OldDOSHeader(BinaryReader reader) throws IOException { + this.reader = reader; + parse(); + } + + /** + * Returns the processor name. + * @return the processor name + */ + public String getProcessorName() { + return "x86"; + } + + /** + * Returns 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 + */ + public short e_cblp() { + return e_cblp; + } + + /** + * Returns the number of pages in the file. + * @return the number of pages in the file + */ + public short e_cp() { + return e_cp; + } + + /** + * Returns the number of relocations. + * @return the number of relocations + */ + public short e_crlc() { + return e_crlc; + } + + /** + * Returns 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 + */ + public short e_minalloc() { + return e_minalloc; + } + + /** + * Returns 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 + */ + public short e_ss() { + return e_ss; + } + + /** + * Returns the initial SP value. + * @return the initial SP value + */ + public short e_sp() { + return e_sp; + } + + /** + * Returns the checksum. + * @return the checksum + */ + public short e_csum() { + return e_csum; + } + + /** + * Returns 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 + */ + public short e_cs() { + return e_cs; + } + + /** + * Returns 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 + */ + 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 + */ + public boolean isDosSignature() { + return e_magic == IMAGE_DOS_SIGNATURE; + } + + @Override + public DataType toDataType() throws DuplicateNameException { + StructureDataType struct = new StructureDataType(getName(), 0); + struct.add(new ArrayDataType(ASCII,2,1)); + for (int i=1; i <= 13; i++) { + struct.add(WORD); + } + + struct.getComponent( 0).setFieldName("e_magic"); + struct.getComponent( 1).setFieldName("e_cblp"); + struct.getComponent( 2).setFieldName("e_cp"); + struct.getComponent( 3).setFieldName("e_crlc"); + struct.getComponent( 4).setFieldName("e_cparhdr"); + struct.getComponent( 5).setFieldName("e_minalloc"); + struct.getComponent( 6).setFieldName("e_maxalloc"); + struct.getComponent( 7).setFieldName("e_ss"); + struct.getComponent( 8).setFieldName("e_sp"); + struct.getComponent( 9).setFieldName("e_csum"); + struct.getComponent(10).setFieldName("e_ip"); + struct.getComponent(11).setFieldName("e_cs"); + struct.getComponent(12).setFieldName("e_lfarlc"); + struct.getComponent(13).setFieldName("e_ovno"); + + struct.getComponent( 0).setComment("Magic number"); + struct.getComponent( 1).setComment("Bytes of last page"); + struct.getComponent( 2).setComment("Pages in file"); + struct.getComponent( 3).setComment("Relocations"); + struct.getComponent( 4).setComment("Size of header in paragraphs"); + struct.getComponent( 5).setComment("Minimum extra paragraphs needed"); + struct.getComponent( 6).setComment("Maximum extra paragraphs needed"); + struct.getComponent( 7).setComment("Initial (relative) SS value"); + struct.getComponent( 8).setComment("Initial SP value"); + struct.getComponent( 9).setComment("Checksum"); + struct.getComponent(10).setComment("Initial IP value"); + struct.getComponent(11).setComment("Initial (relative) CS value"); + struct.getComponent(12).setComment("File address of relocation table"); + struct.getComponent(13).setComment("Overlay number"); + + struct.setCategoryPath(new CategoryPath("/DOS")); + + return struct; + } + + /** + * Helper to override the value of name + * @return The name of the header + */ + protected String getName() { + return NAME; + } + + protected void parse() throws IOException { + reader.setPointerIndex(0); + + e_magic = reader.readNextShort(); + + if (!isDosSignature()) { + return; + } + + e_cblp = reader.readNextShort(); + e_cp = reader.readNextShort(); + e_crlc = reader.readNextShort(); + e_cparhdr = reader.readNextShort(); + e_minalloc = reader.readNextShort(); + e_maxalloc = reader.readNextShort(); + e_ss = reader.readNextShort(); + e_sp = reader.readNextShort(); + e_csum = reader.readNextShort(); + e_ip = reader.readNextShort(); + e_cs = reader.readNextShort(); + e_lfarlc = reader.readNextShort(); + e_ovno = reader.readNextShort(); + } + + @Override + public void write(RandomAccessFile raf, DataConverter dc) throws IOException { + raf.write(dc.getBytes(e_magic)); + raf.write(dc.getBytes(e_cblp)); + raf.write(dc.getBytes(e_cp)); + raf.write(dc.getBytes(e_crlc)); + raf.write(dc.getBytes(e_cparhdr)); + raf.write(dc.getBytes(e_minalloc)); + raf.write(dc.getBytes(e_maxalloc)); + raf.write(dc.getBytes(e_ss)); + raf.write(dc.getBytes(e_sp)); + raf.write(dc.getBytes(e_csum)); + raf.write(dc.getBytes(e_ip)); + raf.write(dc.getBytes(e_cs)); + raf.write(dc.getBytes(e_lfarlc)); + raf.write(dc.getBytes(e_ovno)); + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/mz/OldStyleExecutable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/mz/OldStyleExecutable.java deleted file mode 100644 index c1ba05d63f..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/mz/OldStyleExecutable.java +++ /dev/null @@ -1,57 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.app.util.bin.format.mz; - -import java.io.IOException; - -import ghidra.app.util.bin.BinaryReader; -import ghidra.app.util.bin.ByteProvider; - -/** - * A class to manage loading Old-style (MZ) Executables. - * - * - */ -public class OldStyleExecutable { - private BinaryReader reader; - private DOSHeader dosHeader; - - /** - * Constructs a new instance of an old-style executable - * @param bp the byte provider - * @throws IOException if an I/O error occurs - */ - public OldStyleExecutable(ByteProvider bp) throws IOException { - reader = new BinaryReader(bp, true); - dosHeader = new DOSHeader(reader); - } - - /** - * Returns the underlying binary reader. - * @return the underlying binary reader - */ - public BinaryReader getBinaryReader() { - return reader; - } - - /** - * Returns the DOS Header from this old-style executable. - * @return the DOS Header from this old-style executable - */ - public DOSHeader getDOSHeader() { - return dosHeader; - } -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MzLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MzLoader.java index ea8150c0cb..a38b4af8da 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MzLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MzLoader.java @@ -18,47 +18,50 @@ package ghidra.app.util.opinion; import java.io.IOException; import java.math.BigInteger; import java.util.*; +import java.util.Map.Entry; import ghidra.app.util.MemoryBlockUtils; import ghidra.app.util.Option; import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.ByteProvider; -import ghidra.app.util.bin.format.mz.DOSHeader; -import ghidra.app.util.bin.format.mz.OldStyleExecutable; +import ghidra.app.util.bin.format.mz.*; import ghidra.app.util.importer.MessageLog; -import ghidra.framework.store.LockException; +import ghidra.framework.model.DomainObject; import ghidra.program.database.mem.FileBytes; import ghidra.program.model.address.*; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.DataUtilities; import ghidra.program.model.lang.Register; import ghidra.program.model.listing.*; import ghidra.program.model.mem.*; import ghidra.program.model.symbol.*; -import ghidra.util.*; -import ghidra.util.exception.*; +import ghidra.util.DataConverter; +import ghidra.util.LittleEndianDataConverter; +import ghidra.util.exception.CancelledException; +import ghidra.util.exception.InvalidInputException; import ghidra.util.task.TaskMonitor; /** - * A {@link Loader} for processing Microsoft DOS MZ files. + * A {@link Loader} for processing old-style DOS MZ executables + * + * @see OSDev.org MZ + * @see Notes on the format of DOS .EXE files + * @see Removing the Mystery from SEGMENT : OFFSET Addressing */ public class MzLoader extends AbstractLibrarySupportLoader { public final static String MZ_NAME = "Old-style DOS Executable (MZ)"; + /** Option to control how memory blocks are formed */ + public static final String CREATE_BLOCKS_FROM_RELOC_SEGS_OPTION_NAME = + "Create memory blocks from relocation segments"; + static final boolean CREATE_BLOCKS_FROM_RELOC_SEGS_OPTION_DEFAULT = true; + private final static String ENTRY_NAME = "entry"; private final static int INITIAL_SEGMENT_VAL = 0x1000; private final static int FAR_RETURN_OPCODE = 0xCB; private final static byte MOVW_DS_OPCODE = (byte) 0xba; private static final long MIN_BYTE_LENGTH = 4; - private DataConverter converter = LittleEndianDataConverter.INSTANCE; - - @Override - public int getTierPriority() { - return 60; // we are less priority than PE! Important for AutoImporter - } - - public MzLoader() { - } - @Override public Collection findSupportedLoadSpecs(ByteProvider provider) throws IOException { List loadSpecs = new ArrayList<>(); @@ -66,11 +69,11 @@ public class MzLoader extends AbstractLibrarySupportLoader { if (provider.length() < MIN_BYTE_LENGTH) { return loadSpecs; } - OldStyleExecutable ose = new OldStyleExecutable(provider); - DOSHeader dos = ose.getDOSHeader(); - if (dos.isDosSignature() && !dos.hasNewExeHeader() && !dos.hasPeHeader()) { + MzExecutable mz = new MzExecutable(provider); + OldDOSHeader header = mz.getHeader(); + if (header.isDosSignature() && !header.hasNewExeHeader() && !header.hasPeHeader()) { List results = - QueryOpinionService.query(getName(), "" + dos.e_magic(), null); + QueryOpinionService.query(getName(), "" + header.e_magic(), null); for (QueryResult result : results) { loadSpecs.add(new LoadSpec(this, 0, result)); } @@ -83,71 +86,330 @@ public class MzLoader extends AbstractLibrarySupportLoader { } @Override - public void load(ByteProvider provider, LoadSpec loadSpec, List