From 8797fcfbeaa2bf61bb73a6014312014871e189c8 Mon Sep 17 00:00:00 2001 From: Lukas Kempf Date: Tue, 19 May 2020 17:20:34 +0200 Subject: [PATCH] 1876 Improved support for MZ executables - Fixed incorrect header - Gracefully handle segment overflows - Added missing segment relocations - Create uninitiallized memory according to header --- .../app/util/bin/format/mz/DOSHeader.java | 228 ++---------- .../app/util/bin/format/mz/OldDOSHeader.java | 325 ++++++++++++++++++ .../bin/format/mz/OldStyleExecutable.java | 6 +- .../ghidra/app/util/opinion/MzLoader.java | 68 ++-- 4 files changed, 388 insertions(+), 239 deletions(-) create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/mz/OldDOSHeader.java 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..9d475e686d 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 @@ -61,26 +61,11 @@ import ghidra.util.exception.DuplicateNameException; * * */ -public class DOSHeader implements StructConverter, Writeable { +public class DOSHeader extends OldDOSHeader implements StructConverter, Writeable { /** 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; - 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 @@ -96,116 +81,10 @@ public class DOSHeader implements StructConverter, Writeable { * @param reader the binary reader */ 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 +124,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 +146,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 +163,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 +179,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 +188,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 +197,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 +222,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 +267,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/OldDOSHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/mz/OldDOSHeader.java new file mode 100644 index 0000000000..32d05c5159 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/mz/OldDOSHeader.java @@ -0,0 +1,325 @@ +/* ### + * 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; + public static final int SIZEOF_DOS_HEADER = 28; + + 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 + */ + 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; + } + + /** + * @see ghidra.app.util.bin.StructConverter#toDataType() + */ + @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(); + } + + /** + * @see ghidra.app.util.bin.format.Writeable#write(java.io.RandomAccessFile, ghidra.util.DataConverter) + */ + @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 index c1ba05d63f..1c3787c685 100644 --- 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 @@ -27,7 +27,7 @@ import ghidra.app.util.bin.ByteProvider; */ public class OldStyleExecutable { private BinaryReader reader; - private DOSHeader dosHeader; + private OldDOSHeader dosHeader; /** * Constructs a new instance of an old-style executable @@ -36,7 +36,7 @@ public class OldStyleExecutable { */ public OldStyleExecutable(ByteProvider bp) throws IOException { reader = new BinaryReader(bp, true); - dosHeader = new DOSHeader(reader); + dosHeader = new OldDOSHeader(reader); } /** @@ -51,7 +51,7 @@ public class OldStyleExecutable { * Returns the DOS Header from this old-style executable. * @return the DOS Header from this old-style executable */ - public DOSHeader getDOSHeader() { + public OldDOSHeader getOldDOSHeader() { 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..00f76870b8 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 @@ -23,7 +23,7 @@ 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.OldDOSHeader; import ghidra.app.util.bin.format.mz.OldStyleExecutable; import ghidra.app.util.importer.MessageLog; import ghidra.framework.store.LockException; @@ -67,7 +67,7 @@ public class MzLoader extends AbstractLibrarySupportLoader { return loadSpecs; } OldStyleExecutable ose = new OldStyleExecutable(provider); - DOSHeader dos = ose.getDOSHeader(); + OldDOSHeader dos = ose.getOldDOSHeader(); if (dos.isDosSignature() && !dos.hasNewExeHeader() && !dos.hasPeHeader()) { List results = QueryOpinionService.query(getName(), "" + dos.e_magic(), null); @@ -98,7 +98,7 @@ public class MzLoader extends AbstractLibrarySupportLoader { Memory memory = prog.getMemory(); OldStyleExecutable ose = new OldStyleExecutable(provider); - DOSHeader dos = ose.getDOSHeader(); + OldDOSHeader dos = ose.getOldDOSHeader(); BinaryReader reader = ose.getBinaryReader(); if (monitor.isCancelled()) { @@ -117,7 +117,7 @@ public class MzLoader extends AbstractLibrarySupportLoader { return; } monitor.setMessage("Processing relocations..."); - doRelocations(prog, reader, dos); + doRelocations(prog, reader, dos, log); if (monitor.isCancelled()) { return; @@ -137,7 +137,7 @@ public class MzLoader extends AbstractLibrarySupportLoader { } private void setRegisters(ProgramContext context, Symbol entry, MemoryBlock[] blocks, - DOSHeader dos) { + OldDOSHeader dos) { if (entry == null) { return; } @@ -170,7 +170,7 @@ public class MzLoader extends AbstractLibrarySupportLoader { context.setValue(sp, entry.getAddress(), entry.getAddress(), BigInteger.valueOf(Conv.shortToLong(dos.e_sp()))); context.setValue(ss, entry.getAddress(), entry.getAddress(), - BigInteger.valueOf(Conv.shortToLong(dos.e_ss()))); + BigInteger.valueOf(Conv.intToLong((dos.e_ss() + INITIAL_SEGMENT_VAL) & Conv.SHORT_MASK))); BigInteger csValue = BigInteger.valueOf( Conv.intToLong(((SegmentedAddress) entry.getAddress()).getSegment())); @@ -245,15 +245,16 @@ public class MzLoader extends AbstractLibrarySupportLoader { } private void processSegments(Program program, FileBytes fileBytes, SegmentedAddressSpace space, - BinaryReader reader, DOSHeader dos, MessageLog log, TaskMonitor monitor) { + BinaryReader reader, OldDOSHeader dos, MessageLog log, TaskMonitor monitor) { try { int relocationTableOffset = Conv.shortToInt(dos.e_lfarlc()); int csStart = INITIAL_SEGMENT_VAL; int dataStart = dos.e_cparhdr() << 4; HashMap segMap = new HashMap(); + // Handle overflow SegmentedAddress codeAddress = - space.getAddress(Conv.shortToInt(dos.e_cs()) + csStart, 0); + space.getAddress((Conv.shortToInt((dos.e_cs())) + csStart) & Conv.SHORT_MASK, 0); segMap.put(codeAddress, codeAddress); codeAddress = space.getAddress(csStart, 0); segMap.put(codeAddress, codeAddress); // This is there data starts loading @@ -264,7 +265,7 @@ public class MzLoader extends AbstractLibrarySupportLoader { int seg = Conv.shortToInt(reader.readNextShort()); // compute the new segment referenced at the location - SegmentedAddress segStartAddr = space.getAddress(seg + csStart, 0); + SegmentedAddress segStartAddr = space.getAddress((seg + csStart) & Conv.SHORT_MASK, 0); segMap.put(segStartAddr, segStartAddr); int location = (seg << 4) + off; @@ -331,6 +332,13 @@ public class MzLoader extends AbstractLibrarySupportLoader { " extra bytes starting at file offset 0x" + Integer.toHexString(exeEndOffset)); } + // create the allocated memory + Memory mem = program.getMemory(); + Address end = mem.getMaxAddress().add(1); + // TODO: Handle overflow, consider minalloc + MemoryBlockUtils.createUninitializedBlock(program, false, "Alloc", end, + dos.e_maxalloc() * 16, "", "mz", true, true, false, log); + // // create the stack segment // SegmentedAddress stackStart = space.getAddress((dos.e_ss() + csStart), 0); // mbu.createUninitializedBlock(false, "Stack", stackStart, dos.e_sp(), "", "", true, true, false); @@ -344,7 +352,7 @@ public class MzLoader extends AbstractLibrarySupportLoader { } } - private void doRelocations(Program prog, BinaryReader reader, DOSHeader dos) { + private void doRelocations(Program prog, BinaryReader reader, OldDOSHeader dos, MessageLog log) { try { Memory mem = prog.getMemory(); SegmentedAddressSpace space = @@ -360,40 +368,34 @@ public class MzLoader extends AbstractLibrarySupportLoader { int off = Conv.shortToInt(reader.readNextShort()); int seg = Conv.shortToInt(reader.readNextShort()); - //SegmentedAddress segStartAddr = space.getAddress(seg + csStart, 0); - - int location = (seg << 4) + off; + int location = ((seg << 4) + off) & Conv.SHORT_MASK; int locOffset = location + dataStart; - // compute the new segment referenced at the location - SegmentedAddress fixupAddr = space.getAddress(seg + csStart, off); - int value = Conv.shortToInt(reader.readShort(locOffset)); - int fixupAddrSeg = (value + csStart) & Conv.SHORT_MASK; - mem.setShort(fixupAddr, (short) fixupAddrSeg); + try { + // compute the new segment referenced at the location + SegmentedAddress fixupAddr = space.getAddress((seg + csStart) & Conv.SHORT_MASK, off); + int value = Conv.shortToInt(reader.readShort(locOffset)); + int fixupAddrSeg = (value + csStart) & Conv.SHORT_MASK; + mem.setShort(fixupAddr, (short) fixupAddrSeg); - // Add to relocation table - prog.getRelocationTable() - .add(fixupAddr, 0, new long[] { off, seg }, null, null); + // Add to relocation table + prog.getRelocationTable() + .add(fixupAddr, 0, new long[] { off, seg }, null, null); + } + catch (AddressOutOfBoundsException|IOException|MemoryAccessException e) { + log.error("MzLoader", "Failed to process relocation " + i + ": " + e.getMessage()); + } } } catch (IOException e) { - throw new RuntimeException(e); - } - catch (MemoryAccessException e) { - throw new RuntimeException(e); + log.error("MzLoader", "Failed to process relocation table: " + e.getMessage()); } } private void createSymbols(SegmentedAddressSpace space, SymbolTable symbolTable, - DOSHeader dos) { + OldDOSHeader dos) { int ipValue = Conv.shortToInt(dos.e_ip()); - int codeSegment = Conv.shortToInt(dos.e_cs()) + INITIAL_SEGMENT_VAL; - - if (codeSegment > Conv.SHORT_MASK) { - System.out.println("Invalid entry point location: " + Integer.toHexString(codeSegment) + - ":" + Integer.toHexString(ipValue)); - return; - } + int codeSegment = (Conv.shortToInt(dos.e_cs()) + INITIAL_SEGMENT_VAL) & Conv.SHORT_MASK; Address addr = space.getAddress(codeSegment, ipValue);