Created
November 18, 2017 14:36
-
-
Save marcin-chwedczuk/bc050b8feddb50f29cd5bf83e5f843c4 to your computer and use it in GitHub Desktop.
Display values of MS-DOS Portable Executable header
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Needs Guava to compile: | |
// | |
// compile group: 'com.google.guava', name: 'guava', version: '23.4-jre' | |
// | |
import com.google.common.io.LittleEndianDataInputStream; | |
import java.io.FileInputStream; | |
import java.io.IOException; | |
import java.util.Arrays; | |
import java.util.List; | |
import java.util.stream.IntStream; | |
import static java.util.stream.Collectors.joining; | |
public class Main { | |
// from: http://www.ntcore.com/files/inject2exe.htm#TheMSDOSdata2_1 | |
private final static List<HeaderField> msdosHeaderFields = Arrays.asList( | |
new HeaderField("e_magic", "c2", "Magic number 'MZ'"), | |
new HeaderField("e_cblp", "s", "Bytes on last page of file"), | |
new HeaderField("e_cp", "s", "Pages in file"), | |
new HeaderField("e_crlc", "s", "Relocations"), | |
new HeaderField("e_cparhdr", "s", "Size of header in paragraphs"), | |
new HeaderField("e_minalloc", "s", "Minimum extra paragraphs needed"), | |
new HeaderField("e_maxalloc", "s", "Maximum extra paragraphs needed"), | |
new HeaderField("e_ss", "s", "Initial (relative) SS value"), | |
new HeaderField("e_sp", "s", "Initial SP value"), | |
new HeaderField("e_csum", "s", "Checksum"), | |
new HeaderField("e_ip", "s", "Initial IP value"), | |
new HeaderField("e_cs", "s", "Initial (relative) CS value"), | |
new HeaderField("e_lfarlc", "s", "File address of relocation table"), | |
new HeaderField("e_ovno", "s", "Overlay number"), | |
new HeaderField("e_res", "c8", "Reserved ss"), | |
new HeaderField("e_oemid", "s", "OEM identifier (for e_oeminfo)"), | |
new HeaderField("e_oeminfo", "s", "OEM information; e_oemid specific"), | |
new HeaderField("e_res2", "c20", "Reserved ss"), | |
new HeaderField("e_lfanew", "l", "File address of the new exe header") | |
); | |
public static void main(String[] args) throws IOException { | |
if (args.length != 1) { | |
System.err.println("usage: " + System.getProperty("sun.java.command") + " program.com"); | |
System.exit(1); | |
} | |
String comProgramFilename = args[0]; | |
// Data in COM and PE file headers is always stored using little-endian convention. | |
// This means that an int whose value is 0x11223344 will | |
// be represented with bytes 0x44 0x33 0x22 0x11 in exactly that order. | |
// In other words little-endian conventions tell us that we should store | |
// LSB first and MSB last. | |
// Here we use LittleEndianDataInputStream from Guava library. | |
try (LittleEndianDataInputStream dataInputStream = | |
new LittleEndianDataInputStream(new FileInputStream(comProgramFilename))) { | |
for (HeaderField field : msdosHeaderFields) { | |
switch (field.type) { | |
case "s": | |
print(field.name, String.format("0x%04x", | |
Short.toUnsignedInt(dataInputStream.readShort())), | |
field.comment); | |
break; | |
case "l": | |
print(field.name, | |
String.format("0x%08x", dataInputStream.readInt()), | |
field.comment); | |
break; | |
default: // cN - format | |
int numberOfBytes = Integer.parseInt(field.type.substring(1)); | |
String hexString = IntStream.range(0, numberOfBytes) | |
.mapToObj(i -> { | |
try { | |
byte c = dataInputStream.readByte(); | |
return String.format("%02x", Byte.toUnsignedInt(c)); | |
} catch (IOException e) { | |
throw new RuntimeException(e); | |
} | |
}) | |
.collect(joining(" ")); | |
print(field.name, hexString, field.comment); | |
break; | |
} | |
} | |
} | |
} | |
private static void print(String fieldName, String fieldValue, String comment) { | |
System.out.printf("%16s: %-16s // %s%n", fieldName, fieldValue, comment); | |
} | |
private static class HeaderField { | |
public final String name; | |
/** s - short, l - long, cN - N characters */ | |
public final String type; | |
public final String comment; | |
public HeaderField(String fieldName, String fieldSize, String comment) { | |
this.name = fieldName; | |
this.type = fieldSize; | |
this.comment = comment; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment