Microsoft PE (Portable Executable) file format: Java parsing library

Application

Microsoft Windows

File extension

["exe", "dll", "sys"]

KS implementation details

License: CC0-1.0
Minimal Kaitai Struct required: 0.7

References

This page hosts a formal specification of Microsoft PE (Portable Executable) file format using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Usage

Runtime library

All parsing code for Java generated by Kaitai Struct depends on the Java runtime library. You have to install it before you can parse data.

The Java runtime library is published in the Maven Central Repository. Refer to the artifact page for instructions how to add it into your project with the build tool that you use.

Code

Parse a local file and get structure in memory:

MicrosoftPe data = MicrosoftPe.fromFile("path/to/local/file.exe");

Or parse structure from a byte array:

byte[] someArray = new byte[] { ... };
MicrosoftPe data = new MicrosoftPe(new ByteBufferKaitaiStream(someArray));

After that, one can get various attributes from the structure by invoking getter methods like:

data.mz() // => get mz

Java source code to parse Microsoft PE (Portable Executable) file format

MicrosoftPe.java

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

import io.kaitai.struct.ByteBufferKaitaiStream;
import io.kaitai.struct.KaitaiStruct;
import io.kaitai.struct.KaitaiStream;
import java.io.IOException;
import java.util.Map;
import java.util.HashMap;
import java.util.Arrays;
import java.util.ArrayList;
import java.nio.charset.Charset;


/**
 * @see <a href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format">Source</a>
 */
public class MicrosoftPe extends KaitaiStruct {
    public static MicrosoftPe fromFile(String fileName) throws IOException {
        return new MicrosoftPe(new ByteBufferKaitaiStream(fileName));
    }

    public enum PeFormat {
        ROM_IMAGE(263),
        PE32(267),
        PE32_PLUS(523);

        private final long id;
        PeFormat(long id) { this.id = id; }
        public long id() { return id; }
        private static final Map<Long, PeFormat> byId = new HashMap<Long, PeFormat>(3);
        static {
            for (PeFormat e : PeFormat.values())
                byId.put(e.id(), e);
        }
        public static PeFormat byId(long id) { return byId.get(id); }
    }

    public MicrosoftPe(KaitaiStream _io) {
        this(_io, null, null);
    }

    public MicrosoftPe(KaitaiStream _io, KaitaiStruct _parent) {
        this(_io, _parent, null);
    }

    public MicrosoftPe(KaitaiStream _io, KaitaiStruct _parent, MicrosoftPe _root) {
        super(_io);
        this._parent = _parent;
        this._root = _root == null ? this : _root;
        _read();
    }
    private void _read() {
        this.mz = new MzPlaceholder(this._io, this, _root);
    }

    /**
     * @see <a href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#the-attribute-certificate-table-image-only">Source</a>
     */
    public static class CertificateEntry extends KaitaiStruct {
        public static CertificateEntry fromFile(String fileName) throws IOException {
            return new CertificateEntry(new ByteBufferKaitaiStream(fileName));
        }

        public enum CertificateRevision {
            REVISION_1_0(256),
            REVISION_2_0(512);

            private final long id;
            CertificateRevision(long id) { this.id = id; }
            public long id() { return id; }
            private static final Map<Long, CertificateRevision> byId = new HashMap<Long, CertificateRevision>(2);
            static {
                for (CertificateRevision e : CertificateRevision.values())
                    byId.put(e.id(), e);
            }
            public static CertificateRevision byId(long id) { return byId.get(id); }
        }

        public enum CertificateTypeEnum {
            X509(1),
            PKCS_SIGNED_DATA(2),
            RESERVED_1(3),
            TS_STACK_SIGNED(4);

            private final long id;
            CertificateTypeEnum(long id) { this.id = id; }
            public long id() { return id; }
            private static final Map<Long, CertificateTypeEnum> byId = new HashMap<Long, CertificateTypeEnum>(4);
            static {
                for (CertificateTypeEnum e : CertificateTypeEnum.values())
                    byId.put(e.id(), e);
            }
            public static CertificateTypeEnum byId(long id) { return byId.get(id); }
        }

        public CertificateEntry(KaitaiStream _io) {
            this(_io, null, null);
        }

        public CertificateEntry(KaitaiStream _io, MicrosoftPe.CertificateTable _parent) {
            this(_io, _parent, null);
        }

        public CertificateEntry(KaitaiStream _io, MicrosoftPe.CertificateTable _parent, MicrosoftPe _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this.length = this._io.readU4le();
            this.revision = CertificateRevision.byId(this._io.readU2le());
            this.certificateType = CertificateTypeEnum.byId(this._io.readU2le());
            this.certificateBytes = this._io.readBytes((length() - 8));
        }
        private long length;
        private CertificateRevision revision;
        private CertificateTypeEnum certificateType;
        private byte[] certificateBytes;
        private MicrosoftPe _root;
        private MicrosoftPe.CertificateTable _parent;

        /**
         * Specifies the length of the attribute certificate entry.
         */
        public long length() { return length; }

        /**
         * Contains the certificate version number.
         */
        public CertificateRevision revision() { return revision; }

        /**
         * Specifies the type of content in bCertificate
         */
        public CertificateTypeEnum certificateType() { return certificateType; }

        /**
         * Contains a certificate, such as an Authenticode signature.
         */
        public byte[] certificateBytes() { return certificateBytes; }
        public MicrosoftPe _root() { return _root; }
        public MicrosoftPe.CertificateTable _parent() { return _parent; }
    }
    public static class OptionalHeaderWindows extends KaitaiStruct {
        public static OptionalHeaderWindows fromFile(String fileName) throws IOException {
            return new OptionalHeaderWindows(new ByteBufferKaitaiStream(fileName));
        }

        public enum SubsystemEnum {
            UNKNOWN(0),
            NATIVE(1),
            WINDOWS_GUI(2),
            WINDOWS_CUI(3),
            POSIX_CUI(7),
            WINDOWS_CE_GUI(9),
            EFI_APPLICATION(10),
            EFI_BOOT_SERVICE_DRIVER(11),
            EFI_RUNTIME_DRIVER(12),
            EFI_ROM(13),
            XBOX(14),
            WINDOWS_BOOT_APPLICATION(16);

            private final long id;
            SubsystemEnum(long id) { this.id = id; }
            public long id() { return id; }
            private static final Map<Long, SubsystemEnum> byId = new HashMap<Long, SubsystemEnum>(12);
            static {
                for (SubsystemEnum e : SubsystemEnum.values())
                    byId.put(e.id(), e);
            }
            public static SubsystemEnum byId(long id) { return byId.get(id); }
        }

        public OptionalHeaderWindows(KaitaiStream _io) {
            this(_io, null, null);
        }

        public OptionalHeaderWindows(KaitaiStream _io, MicrosoftPe.OptionalHeader _parent) {
            this(_io, _parent, null);
        }

        public OptionalHeaderWindows(KaitaiStream _io, MicrosoftPe.OptionalHeader _parent, MicrosoftPe _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            if (_parent().std().format() == MicrosoftPe.PeFormat.PE32) {
                this.imageBase32 = this._io.readU4le();
            }
            if (_parent().std().format() == MicrosoftPe.PeFormat.PE32_PLUS) {
                this.imageBase64 = this._io.readU8le();
            }
            this.sectionAlignment = this._io.readU4le();
            this.fileAlignment = this._io.readU4le();
            this.majorOperatingSystemVersion = this._io.readU2le();
            this.minorOperatingSystemVersion = this._io.readU2le();
            this.majorImageVersion = this._io.readU2le();
            this.minorImageVersion = this._io.readU2le();
            this.majorSubsystemVersion = this._io.readU2le();
            this.minorSubsystemVersion = this._io.readU2le();
            this.win32VersionValue = this._io.readU4le();
            this.sizeOfImage = this._io.readU4le();
            this.sizeOfHeaders = this._io.readU4le();
            this.checkSum = this._io.readU4le();
            this.subsystem = SubsystemEnum.byId(this._io.readU2le());
            this.dllCharacteristics = this._io.readU2le();
            if (_parent().std().format() == MicrosoftPe.PeFormat.PE32) {
                this.sizeOfStackReserve32 = this._io.readU4le();
            }
            if (_parent().std().format() == MicrosoftPe.PeFormat.PE32_PLUS) {
                this.sizeOfStackReserve64 = this._io.readU8le();
            }
            if (_parent().std().format() == MicrosoftPe.PeFormat.PE32) {
                this.sizeOfStackCommit32 = this._io.readU4le();
            }
            if (_parent().std().format() == MicrosoftPe.PeFormat.PE32_PLUS) {
                this.sizeOfStackCommit64 = this._io.readU8le();
            }
            if (_parent().std().format() == MicrosoftPe.PeFormat.PE32) {
                this.sizeOfHeapReserve32 = this._io.readU4le();
            }
            if (_parent().std().format() == MicrosoftPe.PeFormat.PE32_PLUS) {
                this.sizeOfHeapReserve64 = this._io.readU8le();
            }
            if (_parent().std().format() == MicrosoftPe.PeFormat.PE32) {
                this.sizeOfHeapCommit32 = this._io.readU4le();
            }
            if (_parent().std().format() == MicrosoftPe.PeFormat.PE32_PLUS) {
                this.sizeOfHeapCommit64 = this._io.readU8le();
            }
            this.loaderFlags = this._io.readU4le();
            this.numberOfRvaAndSizes = this._io.readU4le();
        }
        private Long imageBase32;
        private Long imageBase64;
        private long sectionAlignment;
        private long fileAlignment;
        private int majorOperatingSystemVersion;
        private int minorOperatingSystemVersion;
        private int majorImageVersion;
        private int minorImageVersion;
        private int majorSubsystemVersion;
        private int minorSubsystemVersion;
        private long win32VersionValue;
        private long sizeOfImage;
        private long sizeOfHeaders;
        private long checkSum;
        private SubsystemEnum subsystem;
        private int dllCharacteristics;
        private Long sizeOfStackReserve32;
        private Long sizeOfStackReserve64;
        private Long sizeOfStackCommit32;
        private Long sizeOfStackCommit64;
        private Long sizeOfHeapReserve32;
        private Long sizeOfHeapReserve64;
        private Long sizeOfHeapCommit32;
        private Long sizeOfHeapCommit64;
        private long loaderFlags;
        private long numberOfRvaAndSizes;
        private MicrosoftPe _root;
        private MicrosoftPe.OptionalHeader _parent;
        public Long imageBase32() { return imageBase32; }
        public Long imageBase64() { return imageBase64; }
        public long sectionAlignment() { return sectionAlignment; }
        public long fileAlignment() { return fileAlignment; }
        public int majorOperatingSystemVersion() { return majorOperatingSystemVersion; }
        public int minorOperatingSystemVersion() { return minorOperatingSystemVersion; }
        public int majorImageVersion() { return majorImageVersion; }
        public int minorImageVersion() { return minorImageVersion; }
        public int majorSubsystemVersion() { return majorSubsystemVersion; }
        public int minorSubsystemVersion() { return minorSubsystemVersion; }
        public long win32VersionValue() { return win32VersionValue; }
        public long sizeOfImage() { return sizeOfImage; }
        public long sizeOfHeaders() { return sizeOfHeaders; }
        public long checkSum() { return checkSum; }
        public SubsystemEnum subsystem() { return subsystem; }
        public int dllCharacteristics() { return dllCharacteristics; }
        public Long sizeOfStackReserve32() { return sizeOfStackReserve32; }
        public Long sizeOfStackReserve64() { return sizeOfStackReserve64; }
        public Long sizeOfStackCommit32() { return sizeOfStackCommit32; }
        public Long sizeOfStackCommit64() { return sizeOfStackCommit64; }
        public Long sizeOfHeapReserve32() { return sizeOfHeapReserve32; }
        public Long sizeOfHeapReserve64() { return sizeOfHeapReserve64; }
        public Long sizeOfHeapCommit32() { return sizeOfHeapCommit32; }
        public Long sizeOfHeapCommit64() { return sizeOfHeapCommit64; }
        public long loaderFlags() { return loaderFlags; }
        public long numberOfRvaAndSizes() { return numberOfRvaAndSizes; }
        public MicrosoftPe _root() { return _root; }
        public MicrosoftPe.OptionalHeader _parent() { return _parent; }
    }
    public static class OptionalHeaderDataDirs extends KaitaiStruct {
        public static OptionalHeaderDataDirs fromFile(String fileName) throws IOException {
            return new OptionalHeaderDataDirs(new ByteBufferKaitaiStream(fileName));
        }

        public OptionalHeaderDataDirs(KaitaiStream _io) {
            this(_io, null, null);
        }

        public OptionalHeaderDataDirs(KaitaiStream _io, MicrosoftPe.OptionalHeader _parent) {
            this(_io, _parent, null);
        }

        public OptionalHeaderDataDirs(KaitaiStream _io, MicrosoftPe.OptionalHeader _parent, MicrosoftPe _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this.exportTable = new DataDir(this._io, this, _root);
            this.importTable = new DataDir(this._io, this, _root);
            this.resourceTable = new DataDir(this._io, this, _root);
            this.exceptionTable = new DataDir(this._io, this, _root);
            this.certificateTable = new DataDir(this._io, this, _root);
            this.baseRelocationTable = new DataDir(this._io, this, _root);
            this.debug = new DataDir(this._io, this, _root);
            this.architecture = new DataDir(this._io, this, _root);
            this.globalPtr = new DataDir(this._io, this, _root);
            this.tlsTable = new DataDir(this._io, this, _root);
            this.loadConfigTable = new DataDir(this._io, this, _root);
            this.boundImport = new DataDir(this._io, this, _root);
            this.iat = new DataDir(this._io, this, _root);
            this.delayImportDescriptor = new DataDir(this._io, this, _root);
            this.clrRuntimeHeader = new DataDir(this._io, this, _root);
        }
        private DataDir exportTable;
        private DataDir importTable;
        private DataDir resourceTable;
        private DataDir exceptionTable;
        private DataDir certificateTable;
        private DataDir baseRelocationTable;
        private DataDir debug;
        private DataDir architecture;
        private DataDir globalPtr;
        private DataDir tlsTable;
        private DataDir loadConfigTable;
        private DataDir boundImport;
        private DataDir iat;
        private DataDir delayImportDescriptor;
        private DataDir clrRuntimeHeader;
        private MicrosoftPe _root;
        private MicrosoftPe.OptionalHeader _parent;
        public DataDir exportTable() { return exportTable; }
        public DataDir importTable() { return importTable; }
        public DataDir resourceTable() { return resourceTable; }
        public DataDir exceptionTable() { return exceptionTable; }
        public DataDir certificateTable() { return certificateTable; }
        public DataDir baseRelocationTable() { return baseRelocationTable; }
        public DataDir debug() { return debug; }
        public DataDir architecture() { return architecture; }
        public DataDir globalPtr() { return globalPtr; }
        public DataDir tlsTable() { return tlsTable; }
        public DataDir loadConfigTable() { return loadConfigTable; }
        public DataDir boundImport() { return boundImport; }
        public DataDir iat() { return iat; }
        public DataDir delayImportDescriptor() { return delayImportDescriptor; }
        public DataDir clrRuntimeHeader() { return clrRuntimeHeader; }
        public MicrosoftPe _root() { return _root; }
        public MicrosoftPe.OptionalHeader _parent() { return _parent; }
    }
    public static class DataDir extends KaitaiStruct {
        public static DataDir fromFile(String fileName) throws IOException {
            return new DataDir(new ByteBufferKaitaiStream(fileName));
        }

        public DataDir(KaitaiStream _io) {
            this(_io, null, null);
        }

        public DataDir(KaitaiStream _io, MicrosoftPe.OptionalHeaderDataDirs _parent) {
            this(_io, _parent, null);
        }

        public DataDir(KaitaiStream _io, MicrosoftPe.OptionalHeaderDataDirs _parent, MicrosoftPe _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this.virtualAddress = this._io.readU4le();
            this.size = this._io.readU4le();
        }
        private long virtualAddress;
        private long size;
        private MicrosoftPe _root;
        private MicrosoftPe.OptionalHeaderDataDirs _parent;
        public long virtualAddress() { return virtualAddress; }
        public long size() { return size; }
        public MicrosoftPe _root() { return _root; }
        public MicrosoftPe.OptionalHeaderDataDirs _parent() { return _parent; }
    }
    public static class CoffSymbol extends KaitaiStruct {
        public static CoffSymbol fromFile(String fileName) throws IOException {
            return new CoffSymbol(new ByteBufferKaitaiStream(fileName));
        }

        public CoffSymbol(KaitaiStream _io) {
            this(_io, null, null);
        }

        public CoffSymbol(KaitaiStream _io, MicrosoftPe.CoffHeader _parent) {
            this(_io, _parent, null);
        }

        public CoffSymbol(KaitaiStream _io, MicrosoftPe.CoffHeader _parent, MicrosoftPe _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this._raw_nameAnnoying = this._io.readBytes(8);
            KaitaiStream _io__raw_nameAnnoying = new ByteBufferKaitaiStream(_raw_nameAnnoying);
            this.nameAnnoying = new Annoyingstring(_io__raw_nameAnnoying, this, _root);
            this.value = this._io.readU4le();
            this.sectionNumber = this._io.readU2le();
            this.type = this._io.readU2le();
            this.storageClass = this._io.readU1();
            this.numberOfAuxSymbols = this._io.readU1();
        }
        private Section section;
        public Section section() {
            if (this.section != null)
                return this.section;
            this.section = _root().pe().sections().get((int) (sectionNumber() - 1));
            return this.section;
        }
        private byte[] data;
        public byte[] data() {
            if (this.data != null)
                return this.data;
            long _pos = this._io.pos();
            this._io.seek((section().pointerToRawData() + value()));
            this.data = this._io.readBytes(1);
            this._io.seek(_pos);
            return this.data;
        }
        private Annoyingstring nameAnnoying;
        private long value;
        private int sectionNumber;
        private int type;
        private int storageClass;
        private int numberOfAuxSymbols;
        private MicrosoftPe _root;
        private MicrosoftPe.CoffHeader _parent;
        private byte[] _raw_nameAnnoying;
        public Annoyingstring nameAnnoying() { return nameAnnoying; }
        public long value() { return value; }
        public int sectionNumber() { return sectionNumber; }
        public int type() { return type; }
        public int storageClass() { return storageClass; }
        public int numberOfAuxSymbols() { return numberOfAuxSymbols; }
        public MicrosoftPe _root() { return _root; }
        public MicrosoftPe.CoffHeader _parent() { return _parent; }
        public byte[] _raw_nameAnnoying() { return _raw_nameAnnoying; }
    }
    public static class PeHeader extends KaitaiStruct {
        public static PeHeader fromFile(String fileName) throws IOException {
            return new PeHeader(new ByteBufferKaitaiStream(fileName));
        }

        public PeHeader(KaitaiStream _io) {
            this(_io, null, null);
        }

        public PeHeader(KaitaiStream _io, MicrosoftPe _parent) {
            this(_io, _parent, null);
        }

        public PeHeader(KaitaiStream _io, MicrosoftPe _parent, MicrosoftPe _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this.peSignature = this._io.readBytes(4);
            if (!(Arrays.equals(peSignature(), new byte[] { 80, 69, 0, 0 }))) {
                throw new KaitaiStream.ValidationNotEqualError(new byte[] { 80, 69, 0, 0 }, peSignature(), _io(), "/types/pe_header/seq/0");
            }
            this.coffHdr = new CoffHeader(this._io, this, _root);
            this._raw_optionalHdr = this._io.readBytes(coffHdr().sizeOfOptionalHeader());
            KaitaiStream _io__raw_optionalHdr = new ByteBufferKaitaiStream(_raw_optionalHdr);
            this.optionalHdr = new OptionalHeader(_io__raw_optionalHdr, this, _root);
            this.sections = new ArrayList<Section>();
            for (int i = 0; i < coffHdr().numberOfSections(); i++) {
                this.sections.add(new Section(this._io, this, _root));
            }
        }
        private CertificateTable certificateTable;
        public CertificateTable certificateTable() {
            if (this.certificateTable != null)
                return this.certificateTable;
            if (optionalHdr().dataDirs().certificateTable().virtualAddress() != 0) {
                long _pos = this._io.pos();
                this._io.seek(optionalHdr().dataDirs().certificateTable().virtualAddress());
                this._raw_certificateTable = this._io.readBytes(optionalHdr().dataDirs().certificateTable().size());
                KaitaiStream _io__raw_certificateTable = new ByteBufferKaitaiStream(_raw_certificateTable);
                this.certificateTable = new CertificateTable(_io__raw_certificateTable, this, _root);
                this._io.seek(_pos);
            }
            return this.certificateTable;
        }
        private byte[] peSignature;
        private CoffHeader coffHdr;
        private OptionalHeader optionalHdr;
        private ArrayList<Section> sections;
        private MicrosoftPe _root;
        private MicrosoftPe _parent;
        private byte[] _raw_optionalHdr;
        private byte[] _raw_certificateTable;
        public byte[] peSignature() { return peSignature; }
        public CoffHeader coffHdr() { return coffHdr; }
        public OptionalHeader optionalHdr() { return optionalHdr; }
        public ArrayList<Section> sections() { return sections; }
        public MicrosoftPe _root() { return _root; }
        public MicrosoftPe _parent() { return _parent; }
        public byte[] _raw_optionalHdr() { return _raw_optionalHdr; }
        public byte[] _raw_certificateTable() { return _raw_certificateTable; }
    }
    public static class OptionalHeader extends KaitaiStruct {
        public static OptionalHeader fromFile(String fileName) throws IOException {
            return new OptionalHeader(new ByteBufferKaitaiStream(fileName));
        }

        public OptionalHeader(KaitaiStream _io) {
            this(_io, null, null);
        }

        public OptionalHeader(KaitaiStream _io, MicrosoftPe.PeHeader _parent) {
            this(_io, _parent, null);
        }

        public OptionalHeader(KaitaiStream _io, MicrosoftPe.PeHeader _parent, MicrosoftPe _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this.std = new OptionalHeaderStd(this._io, this, _root);
            this.windows = new OptionalHeaderWindows(this._io, this, _root);
            this.dataDirs = new OptionalHeaderDataDirs(this._io, this, _root);
        }
        private OptionalHeaderStd std;
        private OptionalHeaderWindows windows;
        private OptionalHeaderDataDirs dataDirs;
        private MicrosoftPe _root;
        private MicrosoftPe.PeHeader _parent;
        public OptionalHeaderStd std() { return std; }
        public OptionalHeaderWindows windows() { return windows; }
        public OptionalHeaderDataDirs dataDirs() { return dataDirs; }
        public MicrosoftPe _root() { return _root; }
        public MicrosoftPe.PeHeader _parent() { return _parent; }
    }
    public static class Section extends KaitaiStruct {
        public static Section fromFile(String fileName) throws IOException {
            return new Section(new ByteBufferKaitaiStream(fileName));
        }

        public Section(KaitaiStream _io) {
            this(_io, null, null);
        }

        public Section(KaitaiStream _io, MicrosoftPe.PeHeader _parent) {
            this(_io, _parent, null);
        }

        public Section(KaitaiStream _io, MicrosoftPe.PeHeader _parent, MicrosoftPe _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this.name = new String(KaitaiStream.bytesStripRight(this._io.readBytes(8), (byte) 0), Charset.forName("UTF-8"));
            this.virtualSize = this._io.readU4le();
            this.virtualAddress = this._io.readU4le();
            this.sizeOfRawData = this._io.readU4le();
            this.pointerToRawData = this._io.readU4le();
            this.pointerToRelocations = this._io.readU4le();
            this.pointerToLinenumbers = this._io.readU4le();
            this.numberOfRelocations = this._io.readU2le();
            this.numberOfLinenumbers = this._io.readU2le();
            this.characteristics = this._io.readU4le();
        }
        private byte[] body;
        public byte[] body() {
            if (this.body != null)
                return this.body;
            long _pos = this._io.pos();
            this._io.seek(pointerToRawData());
            this.body = this._io.readBytes(sizeOfRawData());
            this._io.seek(_pos);
            return this.body;
        }
        private String name;
        private long virtualSize;
        private long virtualAddress;
        private long sizeOfRawData;
        private long pointerToRawData;
        private long pointerToRelocations;
        private long pointerToLinenumbers;
        private int numberOfRelocations;
        private int numberOfLinenumbers;
        private long characteristics;
        private MicrosoftPe _root;
        private MicrosoftPe.PeHeader _parent;
        public String name() { return name; }
        public long virtualSize() { return virtualSize; }
        public long virtualAddress() { return virtualAddress; }
        public long sizeOfRawData() { return sizeOfRawData; }
        public long pointerToRawData() { return pointerToRawData; }
        public long pointerToRelocations() { return pointerToRelocations; }
        public long pointerToLinenumbers() { return pointerToLinenumbers; }
        public int numberOfRelocations() { return numberOfRelocations; }
        public int numberOfLinenumbers() { return numberOfLinenumbers; }
        public long characteristics() { return characteristics; }
        public MicrosoftPe _root() { return _root; }
        public MicrosoftPe.PeHeader _parent() { return _parent; }
    }
    public static class CertificateTable extends KaitaiStruct {
        public static CertificateTable fromFile(String fileName) throws IOException {
            return new CertificateTable(new ByteBufferKaitaiStream(fileName));
        }

        public CertificateTable(KaitaiStream _io) {
            this(_io, null, null);
        }

        public CertificateTable(KaitaiStream _io, MicrosoftPe.PeHeader _parent) {
            this(_io, _parent, null);
        }

        public CertificateTable(KaitaiStream _io, MicrosoftPe.PeHeader _parent, MicrosoftPe _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this.items = new ArrayList<CertificateEntry>();
            {
                int i = 0;
                while (!this._io.isEof()) {
                    this.items.add(new CertificateEntry(this._io, this, _root));
                    i++;
                }
            }
        }
        private ArrayList<CertificateEntry> items;
        private MicrosoftPe _root;
        private MicrosoftPe.PeHeader _parent;
        public ArrayList<CertificateEntry> items() { return items; }
        public MicrosoftPe _root() { return _root; }
        public MicrosoftPe.PeHeader _parent() { return _parent; }
    }
    public static class MzPlaceholder extends KaitaiStruct {
        public static MzPlaceholder fromFile(String fileName) throws IOException {
            return new MzPlaceholder(new ByteBufferKaitaiStream(fileName));
        }

        public MzPlaceholder(KaitaiStream _io) {
            this(_io, null, null);
        }

        public MzPlaceholder(KaitaiStream _io, MicrosoftPe _parent) {
            this(_io, _parent, null);
        }

        public MzPlaceholder(KaitaiStream _io, MicrosoftPe _parent, MicrosoftPe _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this.magic = this._io.readBytes(2);
            if (!(Arrays.equals(magic(), new byte[] { 77, 90 }))) {
                throw new KaitaiStream.ValidationNotEqualError(new byte[] { 77, 90 }, magic(), _io(), "/types/mz_placeholder/seq/0");
            }
            this.data1 = this._io.readBytes(58);
            this.ofsPe = this._io.readU4le();
        }
        private byte[] magic;
        private byte[] data1;
        private long ofsPe;
        private MicrosoftPe _root;
        private MicrosoftPe _parent;
        public byte[] magic() { return magic; }
        public byte[] data1() { return data1; }

        /**
         * In PE file, an offset to PE header
         */
        public long ofsPe() { return ofsPe; }
        public MicrosoftPe _root() { return _root; }
        public MicrosoftPe _parent() { return _parent; }
    }
    public static class OptionalHeaderStd extends KaitaiStruct {
        public static OptionalHeaderStd fromFile(String fileName) throws IOException {
            return new OptionalHeaderStd(new ByteBufferKaitaiStream(fileName));
        }

        public OptionalHeaderStd(KaitaiStream _io) {
            this(_io, null, null);
        }

        public OptionalHeaderStd(KaitaiStream _io, MicrosoftPe.OptionalHeader _parent) {
            this(_io, _parent, null);
        }

        public OptionalHeaderStd(KaitaiStream _io, MicrosoftPe.OptionalHeader _parent, MicrosoftPe _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this.format = MicrosoftPe.PeFormat.byId(this._io.readU2le());
            this.majorLinkerVersion = this._io.readU1();
            this.minorLinkerVersion = this._io.readU1();
            this.sizeOfCode = this._io.readU4le();
            this.sizeOfInitializedData = this._io.readU4le();
            this.sizeOfUninitializedData = this._io.readU4le();
            this.addressOfEntryPoint = this._io.readU4le();
            this.baseOfCode = this._io.readU4le();
            if (format() == MicrosoftPe.PeFormat.PE32) {
                this.baseOfData = this._io.readU4le();
            }
        }
        private PeFormat format;
        private int majorLinkerVersion;
        private int minorLinkerVersion;
        private long sizeOfCode;
        private long sizeOfInitializedData;
        private long sizeOfUninitializedData;
        private long addressOfEntryPoint;
        private long baseOfCode;
        private Long baseOfData;
        private MicrosoftPe _root;
        private MicrosoftPe.OptionalHeader _parent;
        public PeFormat format() { return format; }
        public int majorLinkerVersion() { return majorLinkerVersion; }
        public int minorLinkerVersion() { return minorLinkerVersion; }
        public long sizeOfCode() { return sizeOfCode; }
        public long sizeOfInitializedData() { return sizeOfInitializedData; }
        public long sizeOfUninitializedData() { return sizeOfUninitializedData; }
        public long addressOfEntryPoint() { return addressOfEntryPoint; }
        public long baseOfCode() { return baseOfCode; }
        public Long baseOfData() { return baseOfData; }
        public MicrosoftPe _root() { return _root; }
        public MicrosoftPe.OptionalHeader _parent() { return _parent; }
    }

    /**
     * @see "3.3. COFF File Header (Object and Image)"
     */
    public static class CoffHeader extends KaitaiStruct {
        public static CoffHeader fromFile(String fileName) throws IOException {
            return new CoffHeader(new ByteBufferKaitaiStream(fileName));
        }

        public enum MachineType {
            UNKNOWN(0),
            I386(332),
            R4000(358),
            WCE_MIPS_V2(361),
            ALPHA(388),
            SH3(418),
            SH3_DSP(419),
            SH4(422),
            SH5(424),
            ARM(448),
            THUMB(450),
            ARM_NT(452),
            AM33(467),
            POWERPC(496),
            POWERPC_FP(497),
            IA64(512),
            MIPS16(614),
            ALPHA64_OR_AXP64(644),
            MIPS_FPU(870),
            MIPS16_FPU(1126),
            EBC(3772),
            RISCV32(20530),
            RISCV64(20580),
            RISCV128(20776),
            LOONGARCH32(25138),
            LOONGARCH64(25188),
            AMD64(34404),
            M32R(36929),
            ARM64(43620);

            private final long id;
            MachineType(long id) { this.id = id; }
            public long id() { return id; }
            private static final Map<Long, MachineType> byId = new HashMap<Long, MachineType>(29);
            static {
                for (MachineType e : MachineType.values())
                    byId.put(e.id(), e);
            }
            public static MachineType byId(long id) { return byId.get(id); }
        }

        public CoffHeader(KaitaiStream _io) {
            this(_io, null, null);
        }

        public CoffHeader(KaitaiStream _io, MicrosoftPe.PeHeader _parent) {
            this(_io, _parent, null);
        }

        public CoffHeader(KaitaiStream _io, MicrosoftPe.PeHeader _parent, MicrosoftPe _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this.machine = MachineType.byId(this._io.readU2le());
            this.numberOfSections = this._io.readU2le();
            this.timeDateStamp = this._io.readU4le();
            this.pointerToSymbolTable = this._io.readU4le();
            this.numberOfSymbols = this._io.readU4le();
            this.sizeOfOptionalHeader = this._io.readU2le();
            this.characteristics = this._io.readU2le();
        }
        private Integer symbolTableSize;
        public Integer symbolTableSize() {
            if (this.symbolTableSize != null)
                return this.symbolTableSize;
            int _tmp = (int) ((numberOfSymbols() * 18));
            this.symbolTableSize = _tmp;
            return this.symbolTableSize;
        }
        private Integer symbolNameTableOffset;
        public Integer symbolNameTableOffset() {
            if (this.symbolNameTableOffset != null)
                return this.symbolNameTableOffset;
            int _tmp = (int) ((pointerToSymbolTable() + symbolTableSize()));
            this.symbolNameTableOffset = _tmp;
            return this.symbolNameTableOffset;
        }
        private Long symbolNameTableSize;
        public Long symbolNameTableSize() {
            if (this.symbolNameTableSize != null)
                return this.symbolNameTableSize;
            long _pos = this._io.pos();
            this._io.seek(symbolNameTableOffset());
            this.symbolNameTableSize = this._io.readU4le();
            this._io.seek(_pos);
            return this.symbolNameTableSize;
        }
        private ArrayList<CoffSymbol> symbolTable;
        public ArrayList<CoffSymbol> symbolTable() {
            if (this.symbolTable != null)
                return this.symbolTable;
            long _pos = this._io.pos();
            this._io.seek(pointerToSymbolTable());
            this.symbolTable = new ArrayList<CoffSymbol>();
            for (int i = 0; i < numberOfSymbols(); i++) {
                this.symbolTable.add(new CoffSymbol(this._io, this, _root));
            }
            this._io.seek(_pos);
            return this.symbolTable;
        }
        private MachineType machine;
        private int numberOfSections;
        private long timeDateStamp;
        private long pointerToSymbolTable;
        private long numberOfSymbols;
        private int sizeOfOptionalHeader;
        private int characteristics;
        private MicrosoftPe _root;
        private MicrosoftPe.PeHeader _parent;
        public MachineType machine() { return machine; }
        public int numberOfSections() { return numberOfSections; }
        public long timeDateStamp() { return timeDateStamp; }
        public long pointerToSymbolTable() { return pointerToSymbolTable; }
        public long numberOfSymbols() { return numberOfSymbols; }
        public int sizeOfOptionalHeader() { return sizeOfOptionalHeader; }
        public int characteristics() { return characteristics; }
        public MicrosoftPe _root() { return _root; }
        public MicrosoftPe.PeHeader _parent() { return _parent; }
    }
    public static class Annoyingstring extends KaitaiStruct {
        public static Annoyingstring fromFile(String fileName) throws IOException {
            return new Annoyingstring(new ByteBufferKaitaiStream(fileName));
        }

        public Annoyingstring(KaitaiStream _io) {
            this(_io, null, null);
        }

        public Annoyingstring(KaitaiStream _io, MicrosoftPe.CoffSymbol _parent) {
            this(_io, _parent, null);
        }

        public Annoyingstring(KaitaiStream _io, MicrosoftPe.CoffSymbol _parent, MicrosoftPe _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
        }
        private String nameFromOffset;
        public String nameFromOffset() {
            if (this.nameFromOffset != null)
                return this.nameFromOffset;
            if (nameZeroes() == 0) {
                KaitaiStream io = _root()._io();
                long _pos = io.pos();
                io.seek((nameZeroes() == 0 ? (_parent()._parent().symbolNameTableOffset() + nameOffset()) : 0));
                this.nameFromOffset = new String(io.readBytesTerm((byte) 0, false, true, false), Charset.forName("ascii"));
                io.seek(_pos);
            }
            return this.nameFromOffset;
        }
        private Long nameOffset;
        public Long nameOffset() {
            if (this.nameOffset != null)
                return this.nameOffset;
            long _pos = this._io.pos();
            this._io.seek(4);
            this.nameOffset = this._io.readU4le();
            this._io.seek(_pos);
            return this.nameOffset;
        }
        private String name;
        public String name() {
            if (this.name != null)
                return this.name;
            this.name = (nameZeroes() == 0 ? nameFromOffset() : nameFromShort());
            return this.name;
        }
        private Long nameZeroes;
        public Long nameZeroes() {
            if (this.nameZeroes != null)
                return this.nameZeroes;
            long _pos = this._io.pos();
            this._io.seek(0);
            this.nameZeroes = this._io.readU4le();
            this._io.seek(_pos);
            return this.nameZeroes;
        }
        private String nameFromShort;
        public String nameFromShort() {
            if (this.nameFromShort != null)
                return this.nameFromShort;
            if (nameZeroes() != 0) {
                long _pos = this._io.pos();
                this._io.seek(0);
                this.nameFromShort = new String(this._io.readBytesTerm((byte) 0, false, true, false), Charset.forName("ascii"));
                this._io.seek(_pos);
            }
            return this.nameFromShort;
        }
        private MicrosoftPe _root;
        private MicrosoftPe.CoffSymbol _parent;
        public MicrosoftPe _root() { return _root; }
        public MicrosoftPe.CoffSymbol _parent() { return _parent; }
    }
    private PeHeader pe;
    public PeHeader pe() {
        if (this.pe != null)
            return this.pe;
        long _pos = this._io.pos();
        this._io.seek(mz().ofsPe());
        this.pe = new PeHeader(this._io, this, _root);
        this._io.seek(_pos);
        return this.pe;
    }
    private MzPlaceholder mz;
    private MicrosoftPe _root;
    private KaitaiStruct _parent;
    public MzPlaceholder mz() { return mz; }
    public MicrosoftPe _root() { return _root; }
    public KaitaiStruct _parent() { return _parent; }
}