unit Pirate_PE;

interface

uses
  Windows, SysUtils, Classes, Graphics, Messages;

type
  EPEException = class(Exception);

const
  SDotTextSectionTag = '.text';
  SCODESectionTag = 'CODE';
  SUPXSectionTag = 'UPX0';
  DFM_Signature = $30465054;
  NB10_Signature = $3031424E;
  RSDS_Signature = $53445352;

  {$IFNDEF D9PLUS}
  IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT      = 13;  { Delay Load Import Descriptors }
  IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR    = 14;  { COM Runtime descriptor }
  {$ENDIF}

  RT_HTML       = MAKEINTRESOURCE(23);
  RT_MANIFEST   = MAKEINTRESOURCE(24);
  RT_REGISTRY   = MAKEINTRESOURCE(125);
  RT_TYPELIB    = MAKEINTRESOURCE(126);
  RT_AVI        = MAKEINTRESOURCE(127);

  rtCURSOR           = 1;
  rtBITMAP           = 2;
  rtICON             = 3;
  rtMENU             = 4;
  rtDIALOG           = 5;
  rtSTRING           = 6;
  rtFONTDIR          = 7;
  rtFONT             = 8;
  rtACCELERATOR      = 9;
  rtRCDATA           = 10;
  rtMESSAGETABLE     = 11;
  rtGROUP_CURSOR     = 12;
  rtGROUP_ICON       = 13;
  rtVERSION          = 16;
  rtDLGINCLUDE       = 17;
  rtPLUGPLAY         = 19;
  rtVXD              = 20;
  rtANICURSOR        = 21;
  rtANIICON          = 22;
  rtHTML             = 23;
  rtMANIFEST         = 24;
  rtREGISTRY         = 125;
  rtTYPELIB          = 126;
  rtAVI              = 127;

  cResources: array[0..23] of record
                                ID: PAnsiChar;
                                Name: shortstring;
                              end = ((ID:RT_CURSOR; Name:'CURSOR'),
                                     (ID:RT_BITMAP; Name:'BITMAP'),
                                     (ID:RT_ICON; Name:'ICON'),
                                     (ID:RT_MENU; Name:'MENU'),
                                     (ID:RT_DIALOG; Name:'DIALOG'),
                                     (ID:RT_STRING; Name:'STRING'),
                                     (ID:RT_FONTDIR; Name:'FONTDIR'),
                                     (ID:RT_FONT; Name:'FONT'),
                                     (ID:RT_ACCELERATOR; Name:'ACCELERATOR'),
                                     (ID:RT_RCDATA; Name:'RCDATA'),
                                     (ID:RT_MESSAGETABLE; Name:'MESSAGETABLE'),
                                     (ID:RT_GROUP_CURSOR; Name:'GROUP_CURSOR'),
                                     (ID:RT_GROUP_ICON; Name:'GROUP_ICON'),
                                     (ID:RT_VERSION; Name:'VERSION'),
                                     (ID:RT_DLGINCLUDE; Name:'DLGINCLUDE'),
                                     (ID:RT_PLUGPLAY; Name:'PLUGPLAY'),
                                     (ID:RT_VXD; Name:'VXD'),
                                     (ID:RT_ANICURSOR; Name:'ANICURSOR'),
                                     (ID:RT_ANIICON; Name:'ANIICON'),
                                     (ID:RT_HTML; Name:'HTML'),
                                     (ID:RT_MANIFEST; Name:'MANIFEST'),
                                     (ID:RT_REGISTRY; Name:'REGISTRY'),
                                     (ID:RT_TYPELIB; Name:'TYPELIB'),
                                     (ID:RT_AVI; Name:'AVI'));

  IMAGE_FILE_MACHINE_IA64      = $0200; // Intel 64
  IMAGE_FILE_MACHINE_AMD64     = $8664; // AMD64 (K8)

  IMAGE_RESOURCE_NAME_IS_STRING    = Cardinal($80000000);
  IMAGE_RESOURCE_DATA_IS_DIRECTORY = Cardinal($80000000);

  IMAGE_NT_OPTIONAL_HDR32_MAGIC = $010B;
  IMAGE_NT_OPTIONAL_HDR64_MAGIC = $020B;

  IMAGE_ORDINAL_FLAG32 = Cardinal($80000000);
  IMAGE_ORDINAL_FLAG64 = int64($8000000000000000);

  IMAGE_DEBUG_TYPE_BORLAND    = 9;
  IMAGE_DEBUG_TYPE_RESERVED10 = 10;
  IMAGE_DEBUG_TYPE_CLSID      = 11;

  MNU_GRAYED         =$0001;   // 'GRAYED' keyword
  MNU_INACTIVE       =$0002;   // 'INACTIVE' keyword
  MNU_BITMAP         =$0004;   // 'BITMAP' keyword
  MNU_OWNERDRAW      =$0100;   // 'OWNERDRAW' keyword
  MNU_CHECKED        =$0008;   // 'CHECKED' keyword
  MNU_POPUP          =$0010;   // Used internally
  MNU_MENUBARBREAK   =$0020;   // 'MENUBARBREAK' keyword
  MNU_MENUBREAK      =$0040;   // 'MENUBREAK' keyword
  MNU_ENDMENU        =$0080;   // Used internally

  cMetadataTables: array[0..63] of string = ('00 - Module',
                                              '01 - TypeRef',
                                              '02 - TypeDef',
                                              '',
                                              '04 - Field',
                                              '',
                                              '06 - MethodDef',
                                              '',
                                              '08 - Param',
                                              '09 - InterfaceImpl',
                                              '10 - MemberRef',
                                              '11 - Constant',
                                              '12 - CustomAttribute',
                                              '13 - FieldMarshal',
                                              '14 - DeclSecurity',
                                              '15 - ClassLayout',
                                              '16 - FieldLayout',
                                              '17 - StandAloneSig',
                                              '18 - EventMap',
                                              '',
                                              '20 - Event',
                                              '21 - PropertyMap',
                                              '',
                                              '23 - Property',
                                              '24 - MethodSemantics',
                                              '25 - MethodImpl',
                                              '26 - ModuleRef',
                                              '27 - TypeSpec',
                                              '28 - ImplMap',
                                              '29 - FieldRVA',
                                              '',
                                              '',
                                              '32 - Assembly',
                                              '33 - AssemblyProcessor',
                                              '34 - AssemblyOS',
                                              '35 - AssemblyRef',
                                              '36 - AssemblyRefProcessor',
                                              '37 - AssemblyRefOS',
                                              '38 - File',
                                              '39 - ExportedType',
                                              '40 - ManifestResource',
                                              '41 - NestedClass',
                                               '','','','','','','','','','','',
                                               '','','','','','','','','','','');

type
  {$IFNDEF D6PLUS}
  PCardinal = ^Cardinal;
  {$ENDIF}

  TImageOs2Header = record
    ne_magic: Word;        // Magic number
    ne_ver: CHAR;          // Version number
    ne_rev: CHAR;          // Revision number
    ne_enttab: Word;       // Offset of Entry Table
    ne_cbenttab: Word;     // Number of bytes in Entry Table
    ne_crc: Longint;       // Checksum of whole file
    ne_flags: Word;        // Flag word
    ne_autodata: Word;     // Automatic data segment number
    ne_heap: Word;         // Initial heap allocation
    ne_stack: Word;        // Initial stack allocation
    ne_csip: Longint;      // Initial CS:IP setting
    ne_sssp: Longint;      // Initial SS:SP setting
    ne_cseg: Word;         // Count of file segments
    ne_cmod: Word;         // Entries in Module Reference Table
    ne_cbnrestab: Word;    // Size of non-resident name table
    ne_segtab: Word;       // Offset of Segment Table
    ne_rsrctab: Word;      // Offset of Resource Table
    ne_restab: Word;       // Offset of resident name table
    ne_modtab: Word;       // Offset of Module Reference Table
    ne_imptab: Word;       // Offset of Imported Names Table
    ne_nrestab: Longint;   // Offset of Non-resident Names Table
    ne_cmovent: Word;      // Count of movable entries
    ne_align: Word;        // Segment alignment shift count
    ne_cres: Word;         // Count of resource segments
    ne_exetyp: Byte;       // Target Operating system
    ne_flagsothers: Byte;  // Other .EXE flags
    ne_pretthunks: Word;   // offset to return thunks
    ne_psegrefbytes: Word; // offset to segment ref. bytes
    ne_swaparea: Word;     // Minimum code swap area size
    ne_expver: Word;       // Expected Windows version number
  end;
  PImageOs2Header = ^TImageOs2Header;

  TImageVxdHeader = record
    e32_magic: Word;         // Magic number
    e32_border: Byte;        // The byte ordering for the VXD
    e32_worder: Byte;        // The word ordering for the VXD
    e32_level: cardinal;        // The EXE format level for now = 0
    e32_cpu: Word;           // The CPU type
    e32_os: Word;            // The OS type
    e32_ver: cardinal;          // Module version
    e32_mflags: cardinal;       // Module flags
    e32_mpages: cardinal;       // Module # pages
    e32_startobj: cardinal;     // Object # for instruction pointer
    e32_eip: cardinal;          // Extended instruction pointer
    e32_stackobj: cardinal;     // Object # for stack pointer
    e32_esp: cardinal;          // Extended stack pointer
    e32_pagesize: cardinal;     // VXD page size
    e32_lastpagesize: cardinal; // Last page size in VXD
    e32_fixupsize: cardinal;    // Fixup section size
    e32_fixupsum: cardinal;     // Fixup section checksum
    e32_ldrsize: cardinal;      // Loader section size
    e32_ldrsum: cardinal;       // Loader section checksum
    e32_objtab: cardinal;       // Object table offset
    e32_objcnt: cardinal;       // Number of objects in module
    e32_objmap: cardinal;       // Object page map offset
    e32_itermap: cardinal;      // Object iterated data map offset
    e32_rsrctab: cardinal;      // Offset of Resource Table
    e32_rsrccnt: cardinal;      // Number of resource entries
    e32_restab: cardinal;       // Offset of resident name table
    e32_enttab: cardinal;       // Offset of Entry Table
    e32_dirtab: cardinal;       // Offset of Module Directive Table
    e32_dircnt: cardinal;       // Number of module directives
    e32_fpagetab: cardinal;     // Offset of Fixup Page Table
    e32_frectab: cardinal;      // Offset of Fixup Record Table
    e32_impmod: cardinal;       // Offset of Import Module Name Table
    e32_impmodcnt: cardinal;    // Number of entries in Import Module Name Table
    e32_impproc: cardinal;      // Offset of Import Procedure Name Table
    e32_pagesum: cardinal;      // Offset of Per-Page Checksum Table
    e32_datapage: cardinal;     // Offset of Enumerated Data Pages
    e32_preload: cardinal;      // Number of preload pages
    e32_nrestab: cardinal;      // Offset of Non-resident Names Table
    e32_cbnrestab: cardinal;    // Size of Non-resident Name Table
    e32_nressum: cardinal;      // Non-resident Name Table Checksum
    e32_autodata: cardinal;     // Object # for automatic data object
    e32_debuginfo: cardinal;    // Offset of the debugging information
    e32_debuglen: cardinal;     // The length of the debugging info. in bytes
    e32_instpreload: cardinal;  // Number of instance pages in preload section of VXD file
    e32_instdemand: cardinal;   // Number of instance pages in demand load section of VXD file
    e32_heapsize: cardinal;     // Size of heap - for 16-bit apps
    e32_res3: array [0..11] of Byte;      // Reserved words
    e32_winresoff: cardinal;
    e32_winreslen: cardinal;
    e32_devid: Word;         // Device ID for VxD
    e32_ddkver: Word;        // DDK version for VxD
  end;
  PImageVxdHeader = ^TImageVxdHeader;

  PImageOptionalHeader64 = ^TImageOptionalHeader64;
  TImageOptionalHeader64 = packed record
    { Standard fields. }
    Magic: Word;
    MajorLinkerVersion: Byte;
    MinorLinkerVersion: Byte;
    SizeOfCode: Cardinal;
    SizeOfInitializedData: Cardinal;
    SizeOfUninitializedData: Cardinal;
    AddressOfEntryPoint: Cardinal;
    BaseOfCode: Cardinal;
    { NT additional fields. }
    ImageBase: Int64;
    SectionAlignment: Cardinal;
    FileAlignment: Cardinal;
    MajorOperatingSystemVersion: Word;
    MinorOperatingSystemVersion: Word;
    MajorImageVersion: Word;
    MinorImageVersion: Word;
    MajorSubsystemVersion: Word;
    MinorSubsystemVersion: Word;
    Win32VersionValue: Cardinal;
    SizeOfImage: Cardinal;
    SizeOfHeaders: Cardinal;
    CheckSum: Cardinal;
    Subsystem: Word;
    DllCharacteristics: Word;
    SizeOfStackReserve: Int64;
    SizeOfStackCommit: Int64;
    SizeOfHeapReserve: Int64;
    SizeOfHeapCommit: Int64;
    LoaderFlags: Cardinal;
    NumberOfRvaAndSizes: Cardinal;
    DataDirectory: packed array[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1] of TImageDataDirectory;
  end;

  PImageNtHeaders = ^TImageNtHeaders;
  TImageNtHeaders = packed record
    Signature: Cardinal;
    FileHeader: TImageFileHeader;
    Magic: Word;
  end;

  TImageLoadConfigDirectory32 = record
    Size: cardinal;
    TimeDateStamp: cardinal;
    MajorVersion: WORD;
    MinorVersion: WORD;
    GlobalFlagsClear: cardinal;
    GlobalFlagsSet: cardinal;
    CriticalSectionDefaultTimeout: cardinal;
    DeCommitFreeBlockThreshold: cardinal;
    DeCommitTotalFreeThreshold: cardinal;
    LockPrefixTable: cardinal;            // VA
    MaximumAllocationSize: cardinal;
    VirtualMemoryThreshold: cardinal;
    ProcessHeapFlags: cardinal;
    ProcessAffinityMask: cardinal;
    CSDVersion: WORD;
    Reserved1: WORD;
    EditList: cardinal;                   // VA
    SecurityCookie: cardinal;             // VA
    SEHandlerTable: cardinal;             // VA
    SEHandlerCount: cardinal;
  end;
  PImageLoadConfigDirectory32 = ^TImageLoadConfigDirectory32;

  TImageLoadConfigDirectory64 = record
    Size: Cardinal;
    TimeDateStamp: Cardinal;
    MajorVersion: WORD;
    MinorVersion: WORD;
    GlobalFlagsClear: Cardinal;
    GlobalFlagsSet: Cardinal;
    CriticalSectionDefaultTimeout: Cardinal;
    DeCommitFreeBlockThreshold: int64;
    DeCommitTotalFreeThreshold: int64;
    LockPrefixTable: int64;         // VA
    MaximumAllocationSize: int64;
    VirtualMemoryThreshold: int64;
    ProcessAffinityMask: int64;
    ProcessHeapFlags: Cardinal;
    CSDVersion: WORD;
    Reserved1: WORD;
    EditList: int64;                // VA
    SecurityCookie: int64;             // VA
    SEHandlerTable: int64;             // VA
    SEHandlerCount: int64;
  end;
  PImageLoadConfigDirectory64 = ^TImageLoadConfigDirectory64;

  TImageCOR20Header = record
    // Header versioning
    cb: Cardinal;
    MajorRuntimeVersion: word;
    MinorRuntimeVersion: word;
    // Symbol table and startup information
    MetaData: TImageDataDirectory;
    Flags: Cardinal;
// DDBLD - Added next section to replace following lin
// DDBLD - Still verifying, since not in NT SDK
// Cardinal EntryPointToken;

    // If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is not set, EntryPointToken represents a managed entrypoint.
    // If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is set, EntryPointRVA represents an RVA to a native entrypoint.
    EntryPointToken: cardinal;
    EntryPointRVA: cardinal;

// DDBLD - End of Added Area

    // Binding information
    Resources: TImageDataDirectory;
    StrongNameSignature: TImageDataDirectory;

    // Regular fixup and binding information
    CodeManagerTable: TImageDataDirectory;
    VTableFixups: TImageDataDirectory;
    ExportAddressTableJumps: TImageDataDirectory;

    // Precompiled image info (internal use only - set to zero)
    ManagedNativeHeader: TImageDataDirectory;
  end;
  PImageCOR20Header = ^TImageCOR20Header;

  TIIDUnion = record
    case Integer of
      0: (Characteristics: Cardinal);         // 0 for terminating null import descriptor
      1: (OriginalFirstThunk: Cardinal);      // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
  end;

  TImageImportDescriptor = record
    Union: TIIDUnion;
    TimeDateStamp: Cardinal;                  // 0 if not bound,
                                           // -1 if bound, and real date\time stamp
                                           //     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
                                           // O.W. date/time stamp of DLL bound to (Old BIND)

    ForwarderChain: Cardinal;                 // -1 if no forwarders
    Name: Cardinal;
    FirstThunk: Cardinal;                     // RVA to IAT (if bound this IAT has actual addresses)
  end;
  PImageImportDescriptor = ^TImageImportDescriptor;

  TImageThunkData = record
    case Integer of
      0: (ForwarderString: Cardinal);   // PBYTE
      1: (Function_: Cardinal);         // PCardinal
      2: (Ordinal: Cardinal);
      3: (AddressOfData: Cardinal);     // PIMAGE_IMPORT_BY_NAME
  end;
  PImageThunkData = ^TImageThunkData;

  TImageThunkData64 = record
    case Integer of
      0: (ForwarderString: int64);   // PBYTE
      1: (Function_: int64);         // PCardinal
      2: (Ordinal: int64);
      3: (AddressOfData: int64);     // PIMAGE_IMPORT_BY_NAME
  end;
  PImageThunkData64 = ^TImageThunkData64;

  TImgDelayDescr = packed record
    grAttrs: Cardinal;                 // attributes
    szName: Cardinal;                  // pointer to dll name
    phmod: PCardinal;                  // address of module handle
    { TODO : probably wrong declaration }
    pIAT: TImageThunkData;          // address of the IAT
    { TODO : probably wrong declaration }
    pINT: TImageThunkData;          // address of the INT
    { TODO : probably wrong declaration }
    pBoundIAT: TImageThunkData;     // address of the optional bound IAT
    { TODO : probably wrong declaration }
    pUnloadIAT: TImageThunkData;    // address of optional copy of original IAT
    dwTimeStamp: Cardinal;             // 0 if not bound,
                                    // O.W. date/time stamp of DLL bound to (Old BIND)
  end;
  PImgDelayDescr = ^TImgDelayDescr;

  TImageBoundImportDescriptor = record
    TimeDateStamp: Cardinal;
    OffsetModuleName: Word;
    NumberOfModuleForwarderRefs: Word;
    // Array of zero or more IMAGE_BOUND_FORWARDER_REF follows
  end;
  PImageBoundImportDescriptor = ^TImageBoundImportDescriptor;

  TImageBoundForwarderRef = record
    TimeDateStamp: Cardinal;
    OffsetModuleName: Word;
    Reserved: Word;
  end;
  PImageBoundForwarderRef = ^TImageBoundForwarderRef;

  TImageImportByName = record
    Hint: Word;
    Name: array [0..0] of AnsiChar;
  end;
  PImageImportByName = ^TImageImportByName;

  TImageResourceDirectory = record
    Characteristics: cardinal;
    TimeDateStamp: cardinal;
    MajorVersion: Word;
    MinorVersion: Word;
    NumberOfNamedEntries: Word;
    NumberOfIdEntries: Word;
  end;
  PImageResourceDirectory = ^TImageResourceDirectory;

  TImageResourceDirectoryEntry = record
    case Integer of
      0: (
        // Cardinal NameOffset:31;
        // Cardinal NameIsString:1;
        NameOffset: Cardinal;
        OffsetToData: Cardinal
      );
      1: (
        Name: Cardinal;
        // Cardinal OffsetToDirectory:31;
        // Cardinal DataIsDirectory:1;
        OffsetToDirectory: Cardinal;
      );
      2: (
        Id: WORD;
      );
  end;
  PImageResourceDirectoryEntry = ^TImageResourceDirectoryEntry;

  TImageResourceDataEntry = record
    OffsetToData: Cardinal;
    Size: Cardinal;
    CodePage: Cardinal;
    Reserved: Cardinal;
  end;
  PImageResourceDataEntry = ^TImageResourceDataEntry;

  TImageResourceDirectoryString = record
    Length: Word;
    NameString: array [0..0] of CHAR;
  end;
  PImageResourceDirectoryString = ^TImageResourceDirectoryString;

  TImageResourceDirStringU = record
    Length: Word;
    NameString: array [0..0] of WCHAR;
  end;
  PImageResourceDirStringU = ^TImageResourceDirStringU;

  PAccelTableEntry = ^TAccelTableEntry;
  TAccelTableEntry = packed record
    fFlags: Word;
    wAnsi: Word;
    wId: Word;
    padding: Word;
  end;

  PMessageResourceBlock = ^TMessageResourceBlock;
  TMessageResourceBlock = packed record
    LowId: ULONG;
    HighId: ULONG;
    OffsetToEntries: ULONG;
  end;

  PMessageResourceData = ^TMessageResourceData;
  TMessageResourceData = packed record
    NumberOfBlocks: ULONG;
    // Blocks: array[0..0] of TMessageResourceBlock;
  end;

  PMessageResourceEntry = ^TMessageResourceEntry;
  TMessageResourceEntry = packed record
    Length: Word;
    Flags: Word;
    // Text: array[0..0] of Char;
  end;

  TImageFunctionEntry = record
    StartingAddress: cardinal;
    EndingAddress: cardinal;
    EndOfPrologue: cardinal;
  end;
  PImageFunctionEntry = ^TImageFunctionEntry;

  TImageFunctionEntry64 = record
    StartingAddress: int64;
    EndingAddress: int64;
    case Integer of
      0: (EndOfPrologue: int64);
      1: (UnwindInfoAddress: int64);
  end;
  PImageFunctionEntry64 = ^TImageFunctionEntry64;

  TImageTLSDirectory = record
    StartAddressOfRawData: cardinal;
    EndAddressOfRawData: cardinal;
    AddressOfIndex: cardinal;
    AddressOfCallbacks: Cardinal;
    SizeOfZeroFill: Cardinal;
    Characteristics: Cardinal;
  end;
  PImageTLSDirectory = ^TImageTLSDirectory;

  TImageTLSDirectory64 = record
    StartAddressOfRawData: int64;
    EndAddressOfRawData: int64;
    AddressOfIndex: int64;
    AddressOfCallbacks: int64;
    SizeOfZeroFill: Cardinal;
    Characteristics: Cardinal;
  end;
  PImageTLSDirectory64 = ^TImageTLSDirectory64;

  PDlgTemplateEx = ^TDlgTemplateEx;
  TDlgTemplateEx = packed record
    wDlgVer: word;           // use 1
    wSignature: word;        // use 0xFFFF
    dwHelpID: cardinal;         // Dialog's context help ID
    dwExtendedStyle: Cardinal;
    style: Cardinal;
    cdit: Word;
    x: SHORT;
    y: SHORT;
    cx: SHORT;
    cy: SHORT;
  end;

  PDlgItemTemplateEx = ^TDlgItemTemplateEx;
  TDlgItemTemplateEx = packed record
    dwHelpID: cardinal;
    dwExtendedStyle: Cardinal;
    style: Cardinal;
    x: SHORT;
    y: SHORT;
    cx: SHORT;
    cy: SHORT;
    id: Cardinal;
  end;

  PResourceItem = ^TResourceItem;
  TResourceItem = record
    Typ: Longint;
    TypeName,
    Name: string;
    Lang: string;
    CodePage: Cardinal;
    RawDataAddress: Pointer;
    RawDataOffset: Cardinal;
    RawDataSize: Cardinal;
  end;

  PResourceData = ^TResourceData;
  TResourceData = array of TResourceItem;

  TSectionItem = record
    Name: string;
    Data: TImageSectionHeader;
  end;

  TDirectoryItem = record
    Name: string;
    Section: string;
    Data: TImageDataDirectory;
  end;

  TExportItem = record
    Name: string;
    Ordinal: Word;
    Address: Cardinal;
  end;

  TExportData = array of TExportItem;

  TImportItem = record
    Name: string;
    Functions: TExportData;
  end;

  TImportData = array of TImportItem;

  // CodeView header 
  TCVHeader = record
    CvSignature: Cardinal; // NBxx
    Offset: Cardinal;      // Always 0 for NB10
  end;
  PCVHeader = ^TCVHeader;

  // CodeView NB10 debug information 
  // (used when debug information is stored in a PDB 2.00 file) 
  TCVInfoPDB20 = record
    Header: TCVHeader;
    Signature: Cardinal;       // seconds since 01.01.1970
    Age: cardinal;             // an always-incrementing value 
    PdbFileName: array[0..0] of byte;  // zero terminated string with the name of the PDB file 
  end;
  PCVInfoPDB20 = ^TCVInfoPDB20;

// CodeView RSDS debug information 
// (used when debug information is stored in a PDB 7.00 file) 
  TCVInfoPDB70 = record
    CvSignature: Cardinal; 
    Signature: TGUID;       // unique identifier 
    Age: Cardinal;             // an always-incrementing value 
    PdbFileName: array[0..0] of Byte;  // zero terminated string with the name of the PDB file 
  end;
  PCVInfoPDB70 = ^TCVInfoPDB70;

  TDebugItem = record
    Typ: Cardinal;
    Characteristics: Cardinal;
    TimeStamp: TDateTime;
    MajorVersion: Word;
    MinorVersion: Word;
    TypeName: Shortstring;
    SizeOfData: Cardinal;
    AddressOfRawData: Cardinal;
    PointerToRawData: Cardinal;

    Signature: Cardinal;
    GUID: TGUID;
    Age: Cardinal;
    PDBFilename: string;
  end;

  TDebugData = array of TDebugItem;

  TMetadataStream = record
    Name: string;
    Address: Cardinal;
    Size: Cardinal;
  end;

  TMetadataStreams = array of TMetadataStream;

  TMetadataTable = record
    Name: string;
    Members: array of shortstring;
  end;

  TMetadataTables = array of TMetadataTable;

  TResourceRawStream = class(TCustomMemoryStream)
  public
    constructor Create(AItem: TResourceItem);
    function Write(const Buffer; Count: Longint): Longint; override;
  end;

  TExceptionItem = record
    StartingAddress,
    EndingAddress,
    EndOfPrologue: int64;
  end;
  TExceptionData = array of TExceptionItem;

  TCertItem = record
    Data: Pointer;
    Header: TWinCertificate;
  end;
  TCertData = array of TCertItem;

  TPirate_PE = class
  private
    FMFB: Pointer;
    FET: TExportData;
    FIT: TImportData;
    FDT: TDebugData;
    FXD: TExceptionData;
    FCD: TCertData;
    FCL: TList;
    FMDS: TMetadataStreams;
    FMDT: TMetadataTables;
    FRP,FCU,FDFM,FDOS,FHDR,
    FOPT,FVER,FCLR,FCLRMD,FLC,FTLS: TStringList;
    FRD: TResourceData;
    FH,FM,FLH: THandle;
    FFilename: string;
    FDesc: string;
    FFlags: Integer;
    FKeep: Boolean;
    FSize: Int64;
    FLinker: string;
    FHeadersAddress, FHeadersSize: Cardinal;
    FIs64: Boolean;
    FSig: Word;
    FIPI: Boolean;
    procedure SetFilename(const Value: string);
    procedure ReadInfo;
    procedure CreateExportList;
    procedure CreateImportList;
    procedure CreateImportList64;
    procedure CreateDebugList;
    procedure CreateResList;
    procedure CreateFormList;
    procedure CreateLoadConfigList;
    procedure CreateLoadConfigList64;
    procedure CreateTLSList;
    procedure CreateTLSList64;
    procedure CreateClassList;
    procedure CreateVerList;
    procedure CreateExcList;
    procedure CreateExcList64;
    procedure CreateCertList;
    procedure ReadCLRData;
    procedure ReadHeaders;
    function ResOfsToRawData(Ofs: Cardinal): Cardinal;
    function RvaToVa(Rva: Cardinal; Correct: boolean = True): Pointer;
    function RvaToVaEx(Rva: Cardinal): Pointer;
    function DirectoryEntryToData(Directory: Word): Pointer;
    function ValidMSEXEModule: Boolean;
    function ValidReadableNTPEModule: Boolean;
    function GetDataDirectory(ADirectory: Word): TImagedataDirectory;

    function GetClassCount: Cardinal;
    function GetClassItem(Index: cardinal): TClass;
    function GetPkgCount: Cardinal;
    function GetPkgItem(Index: Cardinal): string;
    function GetUnitCount: Cardinal;
    function GetUnitItem(Index: Cardinal): string;
    function GetFormCount: Cardinal;
    function GetFormItem(Index: Cardinal): string;
    function GetResCount: Cardinal;
    function GetResItem(Index: Cardinal): TResourceItem;
    function GetSecCount: Cardinal;
    function GetSecItem(Index: Cardinal): TSectionItem;
    function GetDirCount: Cardinal;
    function GetDirItem(Index: Cardinal): TDirectoryItem;
    function GetExpCount: Cardinal;
    function GetExpItem(Index: Cardinal): TExportItem;
    function GetImpCount: Cardinal;
    function GetImpItem(Index: Cardinal): TImportItem;
    function GetHeadCount: Cardinal;
    function GetHeadName(Index: Cardinal): string;
    function GetHeadValue(Index: Cardinal): string;
    function GetVerCount: Cardinal;
    function GetVerName(Index: Cardinal): string;
    function GetVerValue(Index: Cardinal): string;
    function GetCLRCount: Cardinal;
    function GetCLRName(Index: Cardinal): string;
    function GetCLRValue(Index: Cardinal): string;
    function GetDOSCount: Cardinal;
    function GetDOSName(Index: Cardinal): string;
    function GetDOSValue(Index: Cardinal): string;
    function GetOptCount: Cardinal;
    function GetOptName(Index: Cardinal): string;
    function GetOptValue(Index: Cardinal): string;
    function GetCLRMDCount: Cardinal;
    function GetCLRMDName(Index: Cardinal): string;
    function GetCLRMDValue(Index: Cardinal): string;
    function GetDebugCount: Cardinal;
    function GetDebugItem(Index: Cardinal): TDebugItem;
    function GetLoadConfigCount: Cardinal;
    function GetLoadConfigName(Index: Cardinal): string;
    function GetLoadConfigValue(Index: Cardinal): string;
    function GetMDSCount: Cardinal;
    function GetMDSItem(Index: Cardinal): TMetadataStream;
    function GetMDTCount: Cardinal;
    function GetMDTItem(Index: Cardinal): TMetadataTable;
    function GetExcCount: Cardinal;
    function GetExcItem(Index: Cardinal): TExceptionItem;
    function GetTLSCount: Cardinal;
    function GetTLSName(Index: Cardinal): string;
    function GetTLSValue(Index: Cardinal): string;
    function GetCertCount: Cardinal;
    function GetCertItem(Index: Cardinal): TCertItem;
    function GetResItemByName(Name: string): TResourceItem;
  public
    ImageNTHeaders: PImageNtHeaders;
    OptionalHeader: PImageOptionalHeader;
    OptionalHeader64: PImageOptionalHeader64;
    OS2Header: PImageOs2Header;
    VxdHeader: PImageVxdHeader;

    constructor Create;
    destructor Destroy; override;

    procedure Close;

    function SectionExists(ASectionName: string; var AHeader: Pointer): Boolean;
    procedure GetFormSource(Index: Cardinal; ADest: TStrings);

    property Is64bit: Boolean read FIs64;
    property Signature: Word read FSig;

    property FileName: string read FFilename write SetFilename;
    property FileHandle: THandle read FH;

    property ClassCount: Cardinal read GetClassCount;
    property Classes[Index: Cardinal]: TClass read GetClassItem;

    property PackageCount: Cardinal read GetPkgCount;
    property Packages[Index: Cardinal]: string read GetPkgItem;

    property UnitCount: Cardinal read GetUnitCount;
    property Units[Index: Cardinal]: string read GetUnitItem;

    property FormCount: Cardinal read GetFormCount;
    property Forms[Index: Cardinal]: string read GetFormItem;

    property ResourceCount: Cardinal read GetResCount;
    property Resources[Index: Cardinal]: TResourceItem read GetResItem;
    property ResourceByName[Name: string]: TResourceItem read GetResItemByName;

    property DebugCount: Cardinal read GetDebugCount;
    property Debugs[Index: Cardinal]: TDebugItem read GetDebugItem;

    property ExceptionCount: Cardinal read GetExcCount;
    property Exceptions[Index: Cardinal]: TExceptionItem read GetExcItem;

    property SectionCount: Cardinal read GetSecCount;
    property Sections[Index: Cardinal]: TSectionItem read GetSecItem;

    property DirectoryCount: Cardinal read GetDirCount;
    property Directories[Index: Cardinal]: TDirectoryItem read GetDirItem;

    property ExportCount: Cardinal read GetExpCount;
    property ExportItems[Index: Cardinal]: TExportItem read GetExpItem;

    property ImportCount: Cardinal read GetImpCount;
    property ImportItems[Index: Cardinal]: TImportItem read GetImpItem;

    property DOSHeaderCount: Cardinal read GetDOSCount;
    property DOSHeaderNames[Index: Cardinal]: string read GetDOSName;
    property DOSHeaderValues[Index: Cardinal]: string read GetDOSValue;

    property FileHeaderCount: Cardinal read GetHeadCount;
    property FileHeaderNames[Index: Cardinal]: string read GetHeadName;
    property FileHeaderValues[Index: Cardinal]: string read GetHeadValue;

    property OptionaHeaderCount: Cardinal read GetOptCount;
    property OptionalHeaderNames[Index: Cardinal]: string read GetOptName;
    property OptionalHeaderValues[Index: Cardinal]: string read GetOptValue;

    property CLRHeaderCount: Cardinal read GetCLRCount;
    property CLRHeaderNames[Index: Cardinal]: string read GetCLRName;
    property CLRHeaderValues[Index: Cardinal]: string read GetCLRValue;

    property MetadataHeaderCount: Cardinal read GetCLRMDCount;
    property MetadataHeaderNames[Index: Cardinal]: string read GetCLRMDName;
    property MetadataHeaderValues[Index: Cardinal]: string read GetCLRMDValue;

    property MetadataStreamCount: Cardinal read GetMDSCount;
    property MetadataStreams[Index: Cardinal]: TMetadataStream read GetMDSItem;

    property MetadataTableCount: Cardinal read GetMDTCount;
    property MetadataTables[Index: Cardinal]: TMetadataTable read GetMDTItem;

    property VersionCount: Cardinal read GetVerCount;
    property VersionNames[Index: Cardinal]: string read GetVerName;
    property VersionValues[Index: Cardinal]: string read GetVerValue;

    property LoadConfigCount: Cardinal read GetLoadConfigCount;
    property LoadConfigNames[Index: Cardinal]: string read GetLoadConfigName;
    property LoadConfigValues[Index: Cardinal]: string read GetLoadConfigValue;

    property TLSCount: Cardinal read GetTLSCount;
    property TLSs[Index: Cardinal]: string read GetTLSName;
    property TLSValues[Index: Cardinal]: string read GetTLSValue;

    property CertificateCount: Cardinal read GetCertCount;
    property Certificates[Index: Cardinal]: TCertItem read GetCertItem;

    property IsPackageInfo: Boolean read FIPI;
    property PackageDescription: string read FDesc;
    property PackageFlags: Integer read FFlags;
    property LinkerProdurer: string read FLinker;
    property Size: Int64 read FSize;
  end;

procedure SaveResourceAsJPEG(ResItem: TResourceItem; ADest: TStream);
procedure SaveResourceAsBitmap(ResItem: TResourceItem; ADest: TStream);
procedure SaveResourceAsCursor(ResItem: TResourceItem; ADest: TStream);
procedure SaveResourceAsIcon(ResItem: TResourceItem; ADest: TStream);
procedure SaveResourceAsStrings(ResItem: TResourceItem; ADest: TStrings);
procedure SaveResourceAsAccelerators(ResItem: TResourceItem; ADest: TStrings);
procedure SaveResourceAsMessageTable(ResItem: TResourceItem; ADest: TStrings);
procedure SaveResourceAsDFM(ResItem: TResourceItem; ADest: TStrings);
procedure SaveResourceAsText(ResItem: TResourceItem; ADest: TStrings);
procedure SaveResourceAsMenu(ResItem: TResourceItem; ADest: TStrings);
procedure SaveResourceAsDialog(ResItem: TResourceItem; ADest: TStrings);

function CanShowResourceAsDialog(ResItem: TResourceItem): Boolean;
function ShowResourceAsDialog(ResItem: TResourceItem): Integer;
function GetResourceTypeName(ATyp: PAnsiChar): string;
function GetSignatureString(ASig: Cardinal): string;
function GetMagicString(AMagic: word): string;
function GetSubsystemString(ASubsystem: Word): string;
function GetMachineString(AMachine: Word): string;

implementation

uses Math;

function _ReadWideString(ARS: TResourceRawStream): string;
var
  c: Word;
  n: Integer;
begin
  Result:='';
  repeat
    n:=ARS.Read(c,SizeOf(word));
    Result:=Result+Copy(WideCharToString(PWideChar(@c)),1,1);
  until (c=0) or (n=0);
end;

function UNIX32ToDatetime(ADate: Cardinal): TDateTime;
begin
  Result:=Int(Encodedate(1970,1,1));
  Result:=((Result*SecsPerDay)+ADate)/SecsPerDay;
end;

function GetFileSize(const AFilename: string): Integer;
var
  FI :TBYHANDLEFILEINFORMATION;
  h :THandle;
begin
  Result:=-1;
  FileMode:=0;
  h:=FileOpen(AFilename,fmOpenRead or fmShareDenyNone);
  if h<>Cardinal(-1) then begin
    GetFileInformationByHandle(h,FI);
    FileClose(h);
    Result:=FI.nFileSizelow+256*FI.nFileSizehigh;
  end;
end;

procedure SaveResourceAsJPEG;
var
  rs: TResourceRawStream;
begin
  rs:=TResourceRawStream.Create(ResItem);
  try
    ADest.Position:=0;
    ADest.CopyFrom(rs,rs.Size);
  finally
    rs.Free;
  end;
end;

procedure SaveResourceAsBitmap;

  function GetDInColors(BitCount: Word): Integer;
  begin
    case BitCount of
      1, 4, 8: Result:=1 shl BitCount;
    else
      Result:=0;
    end;
  end;

var
  rs: TResourceRawStream;
  BH: TBitmapFileHeader;
  BI: PBitmapInfoHeader;
  BC: PBitmapCoreHeader;
  ClrUsed: Integer;
begin
  rs:=TResourceRawStream.Create(ResItem);
  try
    FillChar(BH,sizeof(BH), #0);
    BH.bfType:=$4D42;
    BH.bfSize:=rs.Size+SizeOf(BH);
    BI:=PBitmapInfoHeader(rs.Memory);
    if BI.biSize=SizeOf(TBitmapInfoHeader) then begin
      ClrUsed:=BI.biClrUsed;
      if ClrUsed=0 then
        ClrUsed:=GetDInColors(BI.biBitCount);
      BH.bfOffBits:=ClrUsed*SizeOf(TRgbQuad)+SizeOf(TBitmapInfoHeader)+SizeOf(BH);
    end else begin
      BC:=PBitmapCoreHeader(rs.Memory);
      ClrUsed:=GetDInColors(BC.bcBitCount);
      BH.bfOffBits:=ClrUsed*SizeOf(TRGBTriple)+SizeOf(TBitmapCoreHeader)+SizeOf(BH);
    end;
    rs.Position:=0;
    ADest.Position:=0;
    ADest.Write(BH,SizeOf(BH));
    ADest.Write(rs.Memory^,rs.Size);
    ADest.Position:=0;
  finally
    rs.Free;
  end;
end;

procedure SaveResourceAsCursor;
var
  rs: TResourceRawStream;
begin
  rs:=TResourceRawStream.Create(ResItem);
  try
    with TIcon.Create do
      try
        Handle:=CreateIconFromResource(rs.Memory,rs.Size,False,$30000);
        SaveToStream(ADest);
        ADest.Position:=0;
      finally
        Free;
      end;
  finally
    rs.Free;
  end;
end;

function CanShowResourceAsDialog;
var
  rs: TResourceRawStream;
begin
  rs:=TResourceRawStream.Create(ResItem);
  try
    Result:=Windows.PDlgTemplate(rs.Memory)^.style and DS_CONTROL=0;
  finally
    rs.Free;
  end;
end;

function ShowResourceAsDialog;
var
  rs: TResourceRawStream;
  LastFocus: HWND;
  MemHandle: THandle;
  P: Windows.PDlgTemplate;

  function DialogProc(hwndDlg: HWND; uMsg: UINT; W: WPARAM; L: LPARAM): BOOL; stdcall;
  begin
    Result := False;
    case uMsg of
      WM_INITDIALOG: Result:=True;
      WM_LBUTTONDBLCLK: EndDialog(hwndDlg,0);
      WM_RBUTTONUP: EndDialog(hwndDlg,1);
      WM_SYSCOMMAND: if W and $FFF0 = SC_CLOSE then
                        EndDialog(hwndDlg, 0);
    end;
  end;

begin
  rs:=TResourceRawStream.Create(ResItem);
  try
    LastFocus:=GetFocus;
    MemHandle:=GlobalAlloc(GMEM_ZEROINIT,rs.Size);
    P:=GlobalLock(MemHandle);
    Move(rs.Memory^,P^,rs.Size);
    GlobalUnlock(MemHandle);
    Result:=DialogBoxIndirect(hinstance,Windows.PDlgTemplate(MemHandle)^,0,@DialogProc);
    GlobalFree(MemHandle);
    SetFocus(LastFocus);
  finally
    rs.Free;
  end;
end;

procedure SaveResourceAsStrings;
var
  rs: TResourceRawStream;
  P: PWChar;
  Cnt: Cardinal;
  Len: Word;
  S: string;
  id: Cardinal;
begin
  ADest.Clear;
  rs:=TResourceRawStream.Create(ResItem);
  id:=(StrToIntDef(ResItem.Name,1)-1) shl 4;
  try
    ADest.Add('STRINGTABLE');
    ADest.Add('BEGIN');
    P:=rs.Memory;
    Cnt:=0;
    while Cnt<16 do begin
      Len:=Word(P^);
      if Len>0 then begin
        Inc(P);
        S:=Trim(WideCharLenToString(P,Len));
        ADest.Add(Format('  %d, "%s"',[id+Cnt,S]));
        Inc(P,Len);
      end else
        Inc(P);
      Inc(Cnt);
    end;
    ADest.Add('END');
  finally
    rs.Free;
  end;
end;

procedure SaveResourceAsAccelerators;
var
  rs: TResourceRawStream;
  TableEntry: PAccelTableEntry;
  IsLast: Boolean;
  S: string;

  function AnsiToChar(A: Word): string;
  begin
    if A>=32 then
      Result:=Chr(A)
    else
      Result:='';
  end;

  function VirtualKeyNameFromCode(KeyCode: Byte): string;
  const
  KN002F: array[$00..$2F] of PChar = (
    nil,
    'LBUTTON',
    'RBUTTON',
    'CANCEL',
    'MBUTTON',
    nil, nil, nil, // 05..07
    'BACK',
    'TAB',
    nil, nil, // 0A..0B
    'CLEAR',
    'RETURN',
    nil, nil, // 0E..0F
    'SHIFT ',
    'CONTROL',
    'MENU',
    'PAUSE',
    'CAPITAL',
    'KANA',
    'HANGUL',
    'JUNJA',
    'FINAL',
    'HANJA',
    'KANJI',
    'ESCAPE',
    'CONVERT',
    'NONCONVERT',
    'ACCEPT',
    'MODECHANGE',
    'SPACE',
    'PRIOR',
    'NEXT',
    'END',
    'HOME',
    'LEFT',
    'UP',
    'RIGHT',
    'DOWN',
    'SELECT',
    'PRINT',
    'EXECUTE',
    'SNAPSHOT',
    'INSERT',
    'DELETE',
    'HELP'
    );
  KN5B5D: array[$5B..$5D] of PChar = (
    'LWIN',
    'RWIN',
    'APPS'
    );
  KN6A6F: array[$6A..$6F] of PChar = (
    'MULTIPLY',
    'ADD',
    'SEPARATOR',
    'SUBTRACT',
    'DECIMAL',
    'DIVIDE'
    );
  KNA0A5: array[$A0..$A5] of PChar = (
    'LSHIFT',
    'RSHIFT',
    'LCONTROL',
    'RCONTROL',
    'LMENU',
    'RMENU'
    );
  KNF6FE: array[$F6..$FE] of PChar = (
    'ATTN',
    'CRSEL',
    'EXSEL',
    'EREOF',
    'PLAY',
    'ZOOM',
    'NONAME',
    'PA1',
    'OEM_CLEAR'
    );
begin
  case KeyCode of
    $00..$2F:
      Result := KN002F[KeyCode];
    $30..$39, $41..$5A:
      Result := Chr(KeyCode);
    $5B..$5D:
      Result := KN5B5D[KeyCode];
    $60..$69:
      Result := Format('NUMPAD%d', [KeyCode - $60]);
    $6A..$6F:
      Result := KN6A6F[KeyCode];
    $70..$87:
      Result := Format('F%d', [KeyCode - $6F]);
    $90:
      Result := 'NUMLOCK';
    $91:
      Result := 'SCROLL';
    $A0..$A5:
      Result := KNA0A5[KeyCode];
    $E5:
      Result := 'PROCESSKEY';
    $F6..$FE:
      Result := KNF6FE[KeyCode];
  else
    Result := '';
  end;
  if Result <> '' then Result := 'VK_' + Result;
end;

begin
  rs:=TResourceRawStream.Create(ResItem);
  ADest.BeginUpdate;
  try
    ADest.Clear;
    ADest.Add(Format('%s ACCELERATORS',[ResItem.Name]));
    ADest.Add('BEGIN');
    TableEntry:=rs.Memory;
    repeat
      with TableEntry^ do  begin
        IsLast:=fFlags and $80<>0;
        if fFlags and FVIRTKEY<>0 then begin
          S:=Format('  %s, %d, VIRTKEY, ',[VirtualKeyNameFromCode(wAnsi),wId]);
          if fFlags and FSHIFT<>0 then
            S:=S+'SHIFT, ';
          if fFlags and FCONTROL<>0 then
            S:=S+'CONTROL, ';
          if fFlags and FALT<>0 then
            S:=S+'ALT, ';
        end else
          S:=Format('  "%s", %d, ',[AnsiToChar(wAnsi),wId]);
        if fFlags and FNOINVERT<>0 then
          S:=S+'NOINVERT, ';
        SetLength(S,Length(S)-2);
      end;
      ADest.Add(TrimRight(S));
      Inc(TableEntry);
    until IsLast;
    ADest.Add('END');
  finally
    ADest.EndUpdate;
    rs.Free;
  end;
end;

procedure SaveResourceAsMessageTable;
var
  rs: TResourceRawStream;
  Count,I: Integer;
  E: Cardinal;
  Block: PMessageResourceBlock;
  Entry: PMessageResourceEntry;
  S: string;
  Text: PChar;
  Data: Pointer;
begin
  rs:=TResourceRawStream.Create(ResItem);
  try
    Data:=rs.Memory;
    Count:=PMessageResourceData(Data)^.NumberOfBlocks;
    Block:=Data;
    Inc(PMessageResourceData(Block));
    for I:=1 to Count do begin
      Entry:=PMessageResourceEntry(Cardinal(Data) + Block^.OffsetToEntries);
      for E:=Block^.LowId to Block^.HighId do begin
        with Entry^ do begin
          Text:=PChar(Entry)+Sizeof(TMessageResourceEntry);
          if Flags=1 then
            S:=WideCharLenToString(PWideChar(Text),lstrlenW(PWideChar(Text)))
          else
            SetString(S,PAnsiChar(Text),StrLen(Text));
          S:=Trim(S);
          ADest.Add(S);
        end;
        Entry:=Pointer(PChar(Entry)+Entry^.Length);
      end;
      Inc(Block);
    end;
  finally
    rs.Free;
  end;
end;

procedure SaveResourceAsDFM;
var
  rs: TResourceRawStream;
  MemStream: TMemoryStream;
  Buf: Cardinal;
begin
  MemStream:=TMemoryStream.Create;
  rs:=TResourceRawStream.Create(ResItem);
  ADest.Clear;
  try
    rs.Seek(0,soFromBeginning);
    if (rs.Read(Buf,4)=4) and (Buf=DFM_Signature) then begin
      rs.Seek(0,soFromBeginning);
      ObjectBinaryToText(rs,MemStream);
      MemStream.Seek(0,soFromBeginning);
      ADest.LoadFromStream(MemStream);
    end;
  finally
    MemStream.Free;
    rs.Free;
  end;
end;

procedure SaveResourceAsText;
var
  rs: TResourceRawStream;
begin
  rs:=TResourceRawStream.Create(ResItem);
  try
    ADest.LoadFromStream(rs);
  finally
    rs.Free;
  end;
end;

procedure SaveResourceAsMenu;

function GetFlagString(AFlag: Word): string;
begin
  Result:=', ';
  if AFlag and MNU_GRAYED<>0 then
    Result:=Result+'GRAYED, ';
  if AFlag and MNU_INACTIVE<>0 then
    Result:=Result+'INACTIVE, ';
  if AFlag and MNU_BITMAP<>0 then
    Result:=Result+'BITMAP, ';
  if AFlag and MNU_OWNERDRAW<>0 then
    Result:=Result+'OWNERDRAW, ';
  if AFlag and MNU_CHECKED<>0 then
    Result:=Result+'CHECKED, ';
  if AFlag and MNU_MENUBARBREAK<>0 then
    Result:=Result+'MENUBARBREAK, ';
  if AFlag and MNU_MENUBREAK<>0 then
    Result:=Result+'MENUBREAK, ';
  SetLength(Result,Length(Result)-2);
end;

var
  rs: TResourceRawStream;
  i: Integer;
  w,c,f: Word;
  s: string;
begin
  rs:=TResourceRawStream.Create(ResItem);
  try
    i:=-1;
    ADest.Clear;
    ADest.Add(Format('%s MENU',[ResItem.Name]));
    rs.Seek(SizeOf(Cardinal),soFromBeginning);
    repeat
      if rs.read(f,SizeOf(Word))<>SizeOf(Word) then
        Break;
      if (f and MNU_POPUP=0) then
        rs.Read(c,SizeOf(Word));
      s:=_ReadWideString(rs);
      if (f and MNU_POPUP<>0) then begin
        if (s<>'') then begin
          Inc(i);
          ADest.Add(Format('%sPOPUP "%s"',[StringOfChar(' ',i*2),s]));
          ADest.Add(Format('%sBEGIN',[StringOfChar(' ',i*2)]));
        end;
      end else begin
        if (c=0) and (s='') then
          ADest.Add(Format('%sMENUITEM SEPARATOR',[StringOfChar(' ',(i+1)*2)]))
        else
          ADest.Add(Format('%sMENUITEM "%s", %d%s',[StringOfChar(' ',(i+1)*2),s,c,GetFlagString(f)]));
        if (f and MNU_ENDMENU<>0) then begin
          Dec(i);
          ADest.Add(Format('%sEND',[StringOfChar(' ',i*2)]));
        end;
      end;
    until rs.Position>=rs.Size;
  finally
    rs.Free;
  end;
end;

procedure SaveResourceAsDialog;

function GetStyleString(AStyle,AExStyle: Cardinal): string;
begin
  Result:='  ';
  if AStyle and DS_ABSALIGN<>0 then
    Result:=Result+'DS_ABSALIGN | ';
  if AStyle and DS_SYSMODAL<>0 then
    Result:=Result+'DS_SYSMODAL | ';
  if AStyle and DS_LOCALEDIT<>0 then
    Result:=Result+'DS_LOCALEDIT | ';
  if AStyle and DS_SETFONT<>0 then
    Result:=Result+'DS_SETFONT | ';
  if AStyle and DS_MODALFRAME<>0 then
    Result:=Result+'DS_MODALFRAME | ';
  if AStyle and DS_NOIDLEMSG<>0 then
    Result:=Result+'DS_NOIDLEMSG | ';
  if AStyle and DS_SETFOREGROUND<>0 then
    Result:=Result+'DS_SETFOREGROUND | ';
  if AStyle and DS_3DLOOK<>0 then
    Result:=Result+'DS_3DLOOK | ';
  if AStyle and DS_FIXEDSYS<>0 then
    Result:=Result+'DS_FIXEDSYS | ';
  if AStyle and DS_NOFAILCREATE<>0 then
    Result:=Result+'DS_NOFAILCREATE | ';
  if AStyle and DS_CONTROL<>0 then
    Result:=Result+'DS_CONTROL | ';
  if AStyle and DS_CENTER<>0 then
    Result:=Result+'DS_CENTER | ';
  if AStyle and DS_CENTERMOUSE<>0 then
    Result:=Result+'DS_CENTERMOUSE | ';
  if AStyle and DS_CONTEXTHELP<>0 then
    Result:=Result+'DS_CONTEXTHELP | ';

  if AStyle and WS_BORDER<>0 then
    Result:=Result+'WS_BORDER | ';
  if AStyle and WS_CHILD<>0 then
    Result:=Result+'WS_CHILD | ';
  if AStyle and WS_CLIPCHILDREN<>0 then
    Result:=Result+'WS_CLIPCHILDREN | ';
  if AStyle and WS_CLIPSIBLINGS<>0 then
    Result:=Result+'WS_CLIPSIBLINGS | ';
  if AStyle and WS_DISABLED<>0 then
    Result:=Result+'WS_DISABLED | ';
  if AStyle and WS_DLGFRAME<>0 then
    Result:=Result+'WS_DLGFRAME | ';
  if AStyle and WS_GROUP<>0 then
    Result:=Result+'WS_GROUP | ';
  if AStyle and WS_HSCROLL<>0 then
    Result:=Result+'WS_HSCROLL | ';
  if AStyle and WS_MAXIMIZE<>0 then
    Result:=Result+'WS_MAXIMIZE | ';
  if AStyle and WS_MAXIMIZEBOX<>0 then
    Result:=Result+'WS_MAXIMIZEBOX | ';
  if AStyle and WS_MINIMIZE<>0 then
    Result:=Result+'WS_MINIMIZE | ';
  if AStyle and WS_MINIMIZEBOX<>0 then
    Result:=Result+'WS_MINIMIZEBOX | ';
  if AStyle and WS_OVERLAPPED<>0 then
    Result:=Result+'WS_OVERLAPPED | ';
  if AStyle and WS_POPUP<>0 then
    Result:=Result+'WS_POPUP | ';
  if AStyle and WS_SYSMENU<>0 then
    Result:=Result+'WS_SYSMENU | ';
  if AStyle and WS_TABSTOP<>0 then
    Result:=Result+'WS_TABSTOP | ';
  if AStyle and WS_THICKFRAME<>0 then
    Result:=Result+'WS_THICKFRAME | ';
  if AStyle and WS_VISIBLE<>0 then
    Result:=Result+'WS_VISIBLE | ';
  if AStyle and WS_VSCROLL<>0 then
    Result:=Result+'WS_VSCROLL | ';

  if AExStyle>0 then begin
    if AExStyle and WS_EX_ACCEPTFILES<>0 then
      Result:=Result+'WS_EX_ACCEPTFILES | ';
    if AExStyle and WS_EX_DLGMODALFRAME<>0 then
      Result:=Result+'WS_EX_DLGMODALFRAME | ';
    if AExStyle and WS_EX_NOPARENTNOTIFY<>0 then
      Result:=Result+'WS_EX_NOPARENTNOTIFY | ';
    if AExStyle and WS_EX_TOPMOST<>0 then
      Result:=Result+'WS_EX_TOPMOST | ';
    if AExStyle and WS_EX_TRANSPARENT<>0 then
      Result:=Result+'WS_EX_TRANSPARENT | ';
    if AExStyle and WS_EX_MDICHILD<>0 then
      Result:=Result+'WS_EX_MDICHILD | ';
    if AExStyle and WS_EX_TOOLWINDOW<>0 then
      Result:=Result+'WS_EX_TOOLWINDOW | ';
    if AExStyle and WS_EX_WINDOWEDGE<>0 then
      Result:=Result+'WS_EX_WINDOWEDGE | ';
    if AExStyle and WS_EX_CLIENTEDGE <>0 then
      Result:=Result+'WS_EX_CLIENTEDGE | ';
    if AExStyle and WS_EX_CONTEXTHELP<>0 then
      Result:=Result+'WS_EX_CONTEXTHELP | ';
    if AExStyle and WS_EX_RIGHT<>0 then
      Result:=Result+'WS_EX_RIGHT | '
    else
      Result:=Result+'WS_EX_LEFT | ';
    if AExStyle and WS_EX_RTLREADING<>0 then
      Result:=Result+'WS_EX_RTLREADING | '
    else
      Result:=Result+'WS_EX_LTRREADING | ';
    if AExStyle and WS_EX_LEFTSCROLLBAR<>0 then
      Result:=Result+'WS_EX_LEFTSCROLLBAR | '
    else
      Result:=Result+'WS_EX_RIGHTSCROLLBAR | ';
    if AExStyle and WS_EX_CONTROLPARENT<>0 then
      Result:=Result+'WS_EX_CONTROLPARENT | ';
    if AExStyle and WS_EX_STATICEDGE <>0 then
      Result:=Result+'WS_EX_STATICEDGE | ';
    if AExStyle and WS_EX_APPWINDOW<>0 then
      Result:=Result+'WS_EX_APPWINDOW | ';
  end;    
  SetLength(Result,Length(Result)-3);
  Result:=Trim(Result)
end;

function GetClassIdString(ACID: Word): string;
begin
  case ACID of
    $80: Result:='BUTTON';
    $81: Result:='EDIT';
    $82: Result:='STATIC';
    $83: Result:='LISTBOX';
    $84: Result:='SCROLLBAR';
    $85: Result:='COMBOBOX';
  end;
end;

var
  i: Integer;
  rs: TResourceRawStream;
  dex: Boolean;
  s,cn: string;
  w,w1,n: Word;
  d,p: Cardinal;
  dstyle,dexstyle: Cardinal;
  item: TDlgItemTemplate;
  itemex: TDlgItemTemplateEx;
begin
  rs:=TResourceRawStream.Create(ResItem);
  try
    ADest.Clear;
    dex:=(PDlgTemplateEx(rs.Memory)^.wDlgVer=1) and (PDlgTemplateEx(rs.Memory)^.wSignature=$FFFF);
    if dex then
      with PDlgTemplateEx(rs.Memory)^ do begin
        dstyle:=Style;
        dexstyle:=dwExtendedStyle;
        n:=cdit;
        s:='DIALOGEX';
        ADest.Add(Format('%s %s %d, %d, %d, %d',[ResItem.Name,s,x,y,cx,cy]));
        ADest.Add(Format('STYLE %s',[GetStyleString(dStyle,dexStyle)]));
        rs.Seek(SizeOf(TDlgTemplateEx),soFromBeginning);
      end
    else
      with Windows.PDlgTemplate(rs.Memory)^ do begin
        dstyle:=Style;
        dexstyle:=dwExtendedStyle;
        n:=cdit;
        s:='DIALOG';
        ADest.Add(Format('%s %s %d, %d, %d, %d',[ResItem.Name,s,x,y,cx,cy]));
        ADest.Add(Format('STYLE %s',[GetStyleString(dStyle,dexStyle)]));
        rs.Seek(SizeOf(TDlgTemplate),soFromBeginning);
      end;

    rs.Read(w,SizeOf(Word));
    if w<>0 then begin
      if w=$FFFF then
        rs.Read(w,SizeOf(Word))
      else
        s:=_ReadWideString(rs);
    end;
    rs.Read(w,SizeOf(Word));
    if w<>0 then begin
      if w=$FFFF then
        rs.Read(w,SizeOf(Word))
      else
        s:=_ReadWideString(rs);
    end;
    s:=_ReadWideString(rs);
    if s<>'' then
      ADest.Add(Format('CAPTION "%s"',[s]));
    if dStyle and DS_SETFONT<>0 then begin
      rs.Read(w,SizeOf(Word));
      if dex then
        rs.read(d,SizeOf(Cardinal));
      s:=_ReadWideString(rs);
      if dex then
        ADest.Add(Format('FONT %d, "%s", %d, %d',[w,s,LoWord(d),Swap(HiWord(d))]))
      else
        ADest.Add(Format('FONT %d, "%s"',[w,s]));
    end;
    ADest.Add('BEGIN');
    w:=rs.Position;
    rs.Seek(w mod 4,soFromCurrent);

    for i:=0 to n-1 do begin
      p:=rs.Position;
      if p>=rs.Size then
        Break;
      if dex then begin
        rs.read(itemex,SizeOf(TDlgItemTemplateEx));
      end else begin
        rs.read(item,SizeOf(TDlgItemTemplate));
      end;
      rs.Read(w,SizeOf(Word));
      if w<>0 then begin
        if w=$FFFF then begin
          rs.Read(w,SizeOf(Word));
          cn:=GetClassIDString(w);
        end else begin
          rs.Seek(-SizeOf(Word),soFromCurrent);
          cn:=_ReadWideString(rs);
        end;
      end;
      rs.Read(w,SizeOf(Word));
      if w<>0 then begin
        if w=$FFFF then begin
          rs.Read(w,SizeOf(Word));
          s:=IntToStr(w);
        end else begin
          rs.Seek(-SizeOf(Word),soFromCurrent);
          s:=_ReadWideString(rs);
        end;
      end;
      if dex then
        ADest.Add(Format('  CONTROL "%s", %d, %s, %s, %d, %d, %d, %d, %d',[s,itemex.id,cn,GetStyleString(itemex.Style,itemex.dwExtendedStyle),itemex.x,itemex.y,itemex.cx,itemex.cy,itemex.dwHelpID]))
      else
        ADest.Add(Format('  CONTROL "%s", %d, %s, %s, %d, %d, %d, %d',[s,item.id,cn,GetStyleString(item.Style,item.dwExtendedStyle),item.x,item.y,item.cx,item.cy]));
      rs.Read(w,SizeOf(Word));
      if w>0 then
        rs.Seek(w,soFromCurrent);  // extra stuff
      rs.Seek((rs.Position-p) mod 4,soFromCurrent);
    end;

    ADest.Add('END');
  finally
    rs.Free;
  end;
end;

procedure SaveResourceAsIcon;
var
  rs: TResourceRawStream;
begin
  rs:=TResourceRawStream.Create(ResItem);
  try
    with TIcon.Create do
      try
        Handle:=CreateIconFromResource(rs.Memory,rs.Size,True,$30000);
        SaveToStream(ADest);
        ADest.Position:=0;
      finally
        Free;
      end;
  finally
    rs.Free;
  end;
end;

function IMAGE_ORDINAL(Ordinal: Cardinal): Cardinal;
begin
  Result:=(Ordinal and $0000FFFF);
end;

function IMAGE_ORDINAL64(Ordinal: int64): int64;
begin
  Result := (Ordinal and $ffff);
end;

function GetResourceTypeName;
var
  i: Integer;
begin
  Result:='';
  for i:=0 to High(cResources) do
    if Longint(cResources[i].ID)=Longint(ATyp) then begin
      Result:=cResources[i].Name;
      Break;
    end;
  if Result='' then
    Result:=string(ATyp);
end;

function GetSignatureString;
begin
  case ASig of
    IMAGE_DOS_SIGNATURE: Result:='DOS executable';
    IMAGE_OS2_SIGNATURE: Result:='New executable (Win 3.1)';
    IMAGE_VXD_SIGNATURE: Result:='VxD';
    LoWord(IMAGE_NT_SIGNATURE): Result:='Portable Executable';
  end;
end;

function GetMagicString;
begin
  case AMagic of
    IMAGE_NT_OPTIONAL_HDR32_MAGIC: Result:='PE32';
    IMAGE_NT_OPTIONAL_HDR64_MAGIC: Result:='PE32+ (64bit)';
  end;
end;

function GetSubsystemString;
begin
  case ASubsystem of
    IMAGE_SUBSYSTEM_UNKNOWN: Result:='unknown';
    IMAGE_SUBSYSTEM_NATIVE: Result:='Native';
    IMAGE_SUBSYSTEM_WINDOWS_GUI: Result:='Windows GUI';
    IMAGE_SUBSYSTEM_WINDOWS_CUI: Result:='Console';
    IMAGE_SUBSYSTEM_OS2_CUI: Result:='OS/2';
    IMAGE_SUBSYSTEM_POSIX_CUI: Result:='Posix';
    IMAGE_SUBSYSTEM_RESERVED8: Result:='Reserved 8';
    else Result:=Format('0x%4.4x',[ASubsystem]);
  end;
end;

function GetMachineString;
begin
  case AMachine of
    IMAGE_FILE_MACHINE_I386: Result:='32-bit Intel';
    IMAGE_FILE_MACHINE_IA64: Result:='64-bit Intel';
    IMAGE_FILE_MACHINE_AMD64: Result:='64-bit AMD';
    IMAGE_FILE_MACHINE_ALPHA: Result:='DEC Alpha';
    IMAGE_FILE_MACHINE_POWERPC: Result:='Power PC';
    else Result:=Format('0x%4.4x',[AMachine]);
  end;
end;

function DirectoryNames(Directory: Word): string;
begin
  case Directory of
    IMAGE_DIRECTORY_ENTRY_EXPORT:
      Result := 'Exports';
    IMAGE_DIRECTORY_ENTRY_IMPORT:
      Result := 'Imports';
    IMAGE_DIRECTORY_ENTRY_RESOURCE:
      Result := 'Resources';
    IMAGE_DIRECTORY_ENTRY_EXCEPTION:
      Result := 'Exceptions';
    IMAGE_DIRECTORY_ENTRY_SECURITY:
      Result := 'Security';
    IMAGE_DIRECTORY_ENTRY_BASERELOC:
      Result := 'Base Relocations';
    IMAGE_DIRECTORY_ENTRY_DEBUG:
      Result := 'Debug';
    IMAGE_DIRECTORY_ENTRY_COPYRIGHT:
      Result := 'Description';
    IMAGE_DIRECTORY_ENTRY_GLOBALPTR:
      Result := 'Machine Value';
    IMAGE_DIRECTORY_ENTRY_TLS:
      Result := 'Thread Local Storage';
    IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG:
      Result := 'Load Configuration';
    IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT:
      Result := 'Bound Import';
    IMAGE_DIRECTORY_ENTRY_IAT:
      Result := 'Import Address Table';
    IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT:
      Result := 'Delay Load Import';
    IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR:
      Result := 'CLR Header';
  else
    Result := Format('reserved [%.2d]', [Directory]);
  end;
end;


{ TPirate_PE }

procedure GetPackageInfoProc1(const Name: string; NameType: TNameType; Flags: Byte; Param: Pointer);
begin
  with TStringList(Param) do
    case NameType of
      ntRequiresPackage: Add(Name);
    end;
end;

procedure GetPackageInfoProc2(const Name: string; NameType: TNameType; Flags: Byte; Param: Pointer);
begin
  with TStringlist(Param) do
    case NameType of
      ntContainsUnit: Add(Name);
    end;
end;

procedure TPirate_PE.Close;
begin
  UnmapViewOfFile(FMFB);
  CloseHandle(FM);
  Closehandle(FH);
  FreeLibrary(FLH);
  FFilename:='';
  FCL.Clear;
  FRP.Clear;
  FCU.Clear;
  FDFM.Clear;
  FHDR.Clear;
  FDOS.Clear;
  FOPT.Clear;
  FCLR.Clear;
  FCLRMD.Clear;
  FLC.Clear;
  FTLS.Clear;
  FVER.Clear;
  Finalize(FRD);
  Finalize(FET);
  Finalize(FIT);
  Finalize(FDT);
  Finalize(FXD);
  Finalize(FCD);
  Finalize(FMDS);
  Finalize(FMDT);
  FDesc:='';
  FH:=0;
  FLH:=0;
end;

constructor TPirate_PE.Create;
begin
  FKeep:=False;
  FH:=0;
  FCL:=TList.Create;
  FRP:=TStringList.Create;
  FCU:=TStringList.Create;
  FDFM:=TStringList.Create;
  FHDR:=TStringList.Create;
  FDOS:=TStringList.Create;
  FOPT:=TStringList.Create;
  FCLR:=TStringList.Create;
  FCLRMD:=TStringList.Create;
  FLC:=TStringList.Create;
  FTLS:=TStringList.Create;
  FVER:=TStringList.Create;
end;

procedure TPirate_PE.CreateCertList;
var
  Dir: PImageDataDirectory;
  CertPtr: PWinCertificate;
  TotalSize: Integer;
begin
  if GetDataDirectory(IMAGE_DIRECTORY_ENTRY_SECURITY).Size=0 then
    Exit;

  Dir:=PImageDataDirectory(DirectoryEntryToData(IMAGE_DIRECTORY_ENTRY_SECURITY));
  
  CertPtr:=PWinCertificate(RvaToVa(Dir^.VirtualAddress));
  TotalSize:=Dir^.Size;
  while TotalSize>=SizeOf(TWinCertificate) do begin
    SetLength(FCD,Length(FCD)+1);
    with FCD[High(FCD)] do begin
      Header:=CertPtr^;
      Data:=PChar(CertPtr)+SizeOf(TWinCertificate);
      Dec(TotalSize,Header.dwLength);
    end;
  end;
end;

procedure TPirate_PE.CreateClassList;
var
  pStart,pEnd,p: Pointer;

  function InRangeOrNil(APointer, pMin, pMax: Pointer): Boolean;
  begin
    Result:= (APointer=nil) or
             ((Integer(Apointer)>=Integer(pMin)) and
              (Integer(Apointer)<=Integer(pMax)))
  end;

  function IsIdent(p: PChar): Boolean;
  var
    i: Integer;
  begin
    Result:= False;
    i:=1;
    if (Ord(p^)>0) and ((p+1)^ in ['A'..'Z', 'a'..'z', '_']) then
      while (i<Ord(p^)) do begin
        Inc(i);
        Result:=((p+I)^ in ['0'..'9', 'A'..'Z', 'a'..'z', '_']);
      end;
  end;

  function isVirtualMethodTable: Boolean;
  begin
    Result:=Integer(p^)=Integer(p)-vmtSelfPtr;
  end;

  function InRangeOrNilTableElements: Boolean;

    function Sub_InRangeOrNilTableElements(Elements: Array of Integer; pMin: Pointer): Boolean;
    var
      i: Integer;
    begin
      Result:= True;
      i:=0;
      while (Result and (i<High(Elements))) do begin
        Result:=InRangeOrNil(Pointer(Pointer(Integer(p^)+Elements[i])^),pMin,pEnd);
        Inc(i);
      end;
    end;

  const
    ElementsFurtherInCode: Array[0..3] of Integer = (vmtClassName, vmtDynamicTable, vmtMethodTable, vmtFieldTable);
    ElementsAnyPartOfCode: Array[0..3] of Integer = (vmtTypeInfo, vmtInitTable, vmtAutoTable, vmtIntfTable);

  begin
    Result:=Sub_InRangeOrNilTableElements(ElementsFurtherInCode, Pointer(p^)) and
            Sub_InRangeOrNilTableElements(ElementsAnyPartOfCode, pStart);
  end;

  function isClassIdent: Boolean;
  begin
    Result:= IsIdent(PChar(Pointer(Integer(p^)+vmtClassName)^));
  end;

begin
  if SectionExists(SCODESectionTag,pStart) or SectionExists(SDotTextSectionTag,pStart) then begin
    pEnd:=Pointer(PChar(FLH)+PImageSectionHeader(pStart)^.VirtualAddress+(PImageSectionHeader(pStart)^.SizeOfRawData-SizeOf(Pointer)));
    pStart:=Pointer(PChar(FLH)+PImageSectionHeader(pStart)^.VirtualAddress);
    p:=pStart;
    while Integer(p)<Integer(pEnd) do begin
      if isVirtualMethodTable and InRangeOrNilTableElements and isClassIdent then
        FCL.Add(TClass(p^));
      Inc(Integer(p), SizeOf(Pointer));
    end;
  end;
end;

procedure TPirate_PE.CreateDebugList;
var
  FDebugDir: PImageDebugDirectory;
  i,n: Integer;
  p: PChar;
  g: Cardinal;
  b: Byte;
begin
  if GetDataDirectory(IMAGE_DIRECTORY_ENTRY_DEBUG).Size=0 then
    Exit;

  FDebugDir:=PImageDebugDirectory(DirectoryEntryToData(IMAGE_DIRECTORY_ENTRY_DEBUG));
  n:=GetDataDirectory(IMAGE_DIRECTORY_ENTRY_DEBUG).Size div SizeOf(TImageDebugDirectory);
  for i:=0 to n-1 do begin
    if FDebugDir._Type<>0 then begin
      
    SetLength(FDT,Length(FDT)+1);
    with FDT[High(FDT)] do begin
      Characteristics:=FDebugDir.Characteristics;
      Timestamp:=UNIX32ToDatetime(FDebugDir.TimeDateStamp);
      MajorVersion:=FDebugDir.MajorVersion;
      MinorVersion:=FDebugDir.MinorVersion;
      SizeOfData:=FDebugDir.SizeOfData;
      PointerToRawData:=FDebugDir.PointerToRawData;
      AddressOfRawData:=FDebugDir.AddressOfRawData;
      Typ:=FDebugDir._Type;
      case FDebugDir._Type of
        IMAGE_DEBUG_TYPE_COFF: TypeName:='COFF';
        IMAGE_DEBUG_TYPE_CODEVIEW: begin
          TypeName:='CodeView';
          p:=PChar(RvaToVA(FDebugDir.PointerToRawData,False));
          if PCVHeader(p).CvSignature=NB10_Signature then begin
            Signature:=PCVInfoPDB20(p).Header.CvSignature;
            Age:=PCVInfoPDB20(p).Age;
            PDBFilename:=string(PChar(Addr(PCVInfoPDB20(p).PdbFileName)));
          end else
          if PCVHeader(p).CvSignature=RSDS_Signature then begin
            Signature:=PCVInfoPDB70(p).CvSignature;
            Age:=PCVInfoPDB70(p).Age;
            GUID:=PCVInfoPDB70(p).Signature;
            g:=GUID.D3;
            GUID.D3:=GUID.D2;
            GUID.D2:=g;
            b:=GUID.D4[0];
            GUID.D4[0]:=GUID.D4[3];
            GUID.D4[3]:=b;
            b:=GUID.D4[1];
            GUID.D4[1]:=GUID.D4[2];
            GUID.D4[2]:=b;

            b:=GUID.D4[4];
            GUID.D4[4]:=GUID.D4[7];
            GUID.D4[7]:=b;
            b:=GUID.D4[5];
            GUID.D4[5]:=GUID.D4[6];
            GUID.D4[6]:=b;
            PDBFilename:=string(PChar(Addr(PCVInfoPDB70(p).PdbFileName)));
          end;
        end;
        IMAGE_DEBUG_TYPE_FPO: TypeName:='FPO';
        IMAGE_DEBUG_TYPE_MISC: begin
          TypeName:='Misc';
          p:=PChar(RvaToVA(FDebugDir.PointerToRawData,False));
          PDBFilename:=string(PChar(Addr(PImageDebugMisc(p).Data)));
        end;
        IMAGE_DEBUG_TYPE_EXCEPTION: TypeName:='Exception';
        IMAGE_DEBUG_TYPE_FIXUP: TypeName:='Fixup';
        IMAGE_DEBUG_TYPE_BORLAND: TypeName:='Borland';
        IMAGE_DEBUG_TYPE_RESERVED10: TypeName:='Reserved10';
        else TypeName:=Format('unknown 0x%8.8x',[FDebugDir._Type]);
      end;
    end;
    end;
    FDebugDir:=PImageDebugDirectory(PChar(FDebugDir)+SizeOf(TImageDebugDirectory));
  end;
end;

procedure TPirate_PE.CreateExcList;
var
  FDir: PImageFunctionEntry;
  i,n: Integer;
begin
  if GetDataDirectory(IMAGE_DIRECTORY_ENTRY_EXCEPTION).Size=0 then
    Exit;

  FDir:=PImageFunctionEntry(DirectoryEntryToData(IMAGE_DIRECTORY_ENTRY_EXCEPTION));
  n:=GetDataDirectory(IMAGE_DIRECTORY_ENTRY_EXCEPTION).Size div SizeOf(TImageFunctionEntry);
  for i:=0 to n-1 do begin
    SetLength(FXD,Length(FXD)+1);
    with FXD[High(FXD)] do begin
      StartingAddress:=FDir.StartingAddress;
      EndingAddress:=FDir.EndingAddress;
      EndOfPrologue:=FDir.EndOfPrologue;
    end;
    Inc(FDir);
  end;
end;

procedure TPirate_PE.CreateExcList64;
var
  FDir: PImageFunctionEntry64;
  i,n: Integer;
begin
  if GetDataDirectory(IMAGE_DIRECTORY_ENTRY_EXCEPTION).Size=0 then
    Exit;

  FDir:=PImageFunctionEntry64(DirectoryEntryToData(IMAGE_DIRECTORY_ENTRY_EXCEPTION));
  n:=GetDataDirectory(IMAGE_DIRECTORY_ENTRY_EXCEPTION).Size div SizeOf(TImageFunctionEntry64);
  for i:=0 to n-1 do begin
    SetLength(FXD,Length(FXD)+1);
    with FXD[High(FXD)] do begin
      StartingAddress:=FDir.StartingAddress;
      EndingAddress:=FDir.EndingAddress;
      EndOfPrologue:=FDir.EndOfPrologue;
    end;
    Inc(FDir);
  end;
end;

procedure TPirate_PE.CreateExportList;
var
  FExportDir: PImageExportDirectory;
  i: Integer;
  Names: PCardinal;
  NameOrdinals: PWORD;
  Functions,a: Cardinal;
begin
  if GetDataDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT).Size=0 then
    Exit;
  FExportDir:=PImageExportDirectory(DirectoryEntryToData(IMAGE_DIRECTORY_ENTRY_EXPORT));
  Names:=RvaToVa(Cardinal(FExportDir.AddressOfNames));
  NameOrdinals:=RvaToVa(Cardinal(FExportDir^.AddressOfNameOrdinals));
  Functions:=Cardinal(RvaToVa(Cardinal(FExportDir^.AddressOfFunctions)));
  for i:=0 to FExportDir.NumberOfFunctions-1 do begin
    a:=PCardinal(Functions+{NameOrdinals^}i*SizeOf(Cardinal))^;
    if a=0 then
      Continue;
    SetLength(FET,Length(FET)+1);
    with FET[High(FET)] do begin
      Ordinal:=i{NameOrdinals^}+FExportDir^.Base;
      Address:=a;
      try 
        Name:=string(PChar(RvaToVA(Cardinal(Names^)))); 
      except 
        Name:=IntToStr(i+1);
      end;
    end;
    Inc(Names);
    Inc(NameOrdinals);
  end;
end;

procedure TPirate_PE.CreateFormList;
var
  i: Integer;
  rs: TResourceRawStream;
  Buf: Cardinal;
begin
  for i:=0 to High(FRD) do
    if (FRD[i].Typ=Cardinal(RT_RCDATA)) then begin
      rs:=TResourceRawStream.Create(FRD[i]);
      try
        if (rs.Read(Buf,4)=4) and (Buf=DFM_Signature) then
          FDFM.Add(FRD[i].Name);
      finally
        rs.Free;
      end;
    end;
end;

procedure TPirate_PE.CreateImportList;

function AddItem(Aname: string; AThunk: PImageThunkData): integer;
var
  idx,i: Integer;
  r: TExportItem;
begin
  Result:=-1;
  idx:=-1;
  for i:=0 to High(FIT) do
    if SameText(FIT[i].Name,AName) then begin
      idx:=i;
      Break;
    end;
  if idx=-1 then begin
    SetLength(FIT,Length(FIT)+1);
    with FIT[High(FIT)] do begin
      Name:=AName;
    end;

    Result:=High(FIT);

    while AThunk.Function_<>0 do begin
      Finalize(r);
      ZeroMemory(@r,SizeOf(r));
      if (AThunk.Ordinal and IMAGE_ORDINAL_FLAG32<>0) then begin
        r.Ordinal:=IMAGE_ORDINAL(AThunk.Ordinal);
        r.Name:='';
      end else begin
        r.Address:=Cardinal(PImageImportByName(RvaToVa(Cardinal(AThunk.AddressOfData))));
        try
          r.Name:=PChar(@PImageImportByName(r.Address).Name);
          r.Ordinal:=PImageImportByName(r.Address).Hint;
        except
        end;
      end;
      with FIT[Result] do begin
        SetLength(Functions,Length(Functions)+1);
        Functions[High(Functions)]:=r;
      end;
      Inc(AThunk);
    end;
  end;
end;

var
  ImportDesc: PImageImportDescriptor;
  s: string;
  BoundImports, BoundImport: PImageBoundImportDescriptor;
  DelayImportDesc: PImgDelayDescr;
  Thunk: PImageThunkData;
begin
  if GetDataDirectory(IMAGE_DIRECTORY_ENTRY_IMPORT).Size>0 then begin
    ImportDesc:=PImageImportDescriptor(DirectoryEntryToData(IMAGE_DIRECTORY_ENTRY_IMPORT));
    while ImportDesc^.Name<>0 do begin
      s:=string(PChar(RvaToVA(ImportDesc^.Name)));
      if ImportDesc^.Union.Characteristics=0 then begin
        Thunk:=PImageThunkData(RvaToVa(ImportDesc^.FirstThunk));
        FLinker:='Borland';
      end else begin
        Thunk:=PImageThunkData(RvaToVa(ImportDesc^.Union.Characteristics));
        FLinker:='Microsoft';
      end;
      AddItem(s,Thunk);

      Inc(ImportDesc);
    end;
  end;

  if GetDataDirectory(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT).Size>0 then begin
    DelayImportDesc:=PImgDelayDescr(DirectoryEntryToData(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT));
    while DelayImportDesc^.szName<>0 do begin
      s:=string(PChar(RvaToVa(DelayImportDesc^.szName)));
      Thunk:=PImageThunkData(RvaToVaEx(DelayImportDesc^.pINT.AddressOfData));
      AddItem(s,Thunk);
      Inc(DelayImportDesc);
    end;
  end;

  {if ImageNTHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size>0 then begin
    BoundImports:=PImageBoundImportDescriptor(DirectoryEntryTodata(IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT));
    BoundImport:=BoundImports;
    while (BoundImport^.OffsetModuleName<>0) do begin
      s:=string(PChar(Cardinal(BoundImports)+BoundImport^.OffsetModuleName));
      ...search for name and if found then change import type to bound...
      for i:=1 to BoundImport^.NumberOfModuleForwarderRefs do
        Inc(PImageBoundForwarderRef(BoundImport)); // skip forward information
      Inc(BoundImport);
    end;
  end;}
end;

procedure TPirate_PE.CreateImportList64;

function AddItem(Aname: string; AThunk: PImageThunkData64): integer;
var
  idx,i: Integer;
  r: TExportItem;
begin
  Result:=-1;
  idx:=-1;
  for i:=0 to High(FIT) do
    if SameText(FIT[i].Name,AName) then begin
      idx:=i;
      Break;
    end;
  if idx=-1 then begin
    SetLength(FIT,Length(FIT)+1);
    with FIT[High(FIT)] do begin
      Name:=AName;
    end;

    Result:=High(FIT);

    while AThunk.Function_<>0 do begin
      Finalize(r);
      ZeroMemory(@r,SizeOf(r));
      if (AThunk.Ordinal and IMAGE_ORDINAL_FLAG64<>0) then begin
        r.Ordinal:=IMAGE_ORDINAL64(AThunk.Ordinal);
        r.Name:='';
      end else begin
        r.Address:=Cardinal(PImageImportByName(RvaToVa(Cardinal(AThunk.AddressOfData))));
        try
          r.Name:=PChar(@PImageImportByName(r.Address).Name);
          r.Ordinal:=PImageImportByName(r.Address).Hint;
        except
        end;
      end;
      with FIT[Result] do begin
        SetLength(Functions,Length(Functions)+1);
        Functions[High(Functions)]:=r;
      end;
      Inc(AThunk);
    end;
  end;
end;

var
  ImportDesc: PImageImportDescriptor;
  s: string;
  BoundImports, BoundImport: PImageBoundImportDescriptor;
  DelayImportDesc: PImgDelayDescr;
  Thunk: PImageThunkData64;
begin
  if GetDataDirectory(IMAGE_DIRECTORY_ENTRY_IMPORT).Size>0 then begin
    ImportDesc:=PImageImportDescriptor(DirectoryEntryToData(IMAGE_DIRECTORY_ENTRY_IMPORT));
    while ImportDesc^.Name<>0 do begin
      s:=string(PChar(RvaToVAEx(ImportDesc^.Name)));
      if ImportDesc^.Union.Characteristics=0 then begin
        Thunk:=PImageThunkData64(RvaToVa(ImportDesc^.FirstThunk));
        FLinker:='Borland';
      end else begin
        Thunk:=PImageThunkData64(RvaToVa(ImportDesc^.Union.Characteristics));
        FLinker:='Microsoft';
      end;
      AddItem(s,Thunk);

      Inc(ImportDesc);
    end;
  end;

  if GetDataDirectory(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT).Size>0 then begin
    DelayImportDesc:=PImgDelayDescr(DirectoryEntryToData(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT));
    while DelayImportDesc^.szName<>0 do begin
      s:=string(PChar(RvaToVaEx(DelayImportDesc^.szName)));
      Thunk:=PImageThunkData64(RvaToVaEx(DelayImportDesc^.pINT.AddressOfData));
      AddItem(s,Thunk);
      Inc(DelayImportDesc);
    end;
  end;
end;

procedure TPirate_PE.CreateLoadConfigList;
begin
  if GetDataDirectory(IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG).Size=0 then
    Exit;
  with PImageLoadConfigDirectory32(DirectoryEntryToData(IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG))^ do begin
    FLC.Add(Format('%s=%s',['Timestamp',DateTimeToStr(UNIX32ToDateTime(TimeDateStamp))]));
    FLC.Add(Format('%s=%d.%d',['Version',MajorVersion,MinorVersion]));
    FLC.Add(Format('%s=0x%8.8x',['Global flags clear',GlobalFlagsClear]));
    FLC.Add(Format('%s=0x%8.8x',['Global flags set',GlobalFlagsSet]));
    FLC.Add(Format('%s=0x%8.8x',['Critical section default timeout',CriticalSectionDefaultTimeout]));
    FLC.Add(Format('%s=0x%8.8x',['DeCommit free block threshold',DeCommitFreeBlockThreshold]));
    FLC.Add(Format('%s=0x%8.8x',['DeCommit total free threshold',DeCommitTotalFreeThreshold]));
    FLC.Add(Format('%s=0x%8.8x',['Lock prefix table',Cardinal(LockPrefixTable)]));
    FLC.Add(Format('%s=0x%8.8x',['Maximum allocation size',MaximumAllocationSize]));
    FLC.Add(Format('%s=0x%8.8x',['Virtual memory threshold',VirtualMemoryThreshold]));
    FLC.Add(Format('%s=0x%8.8x',['Process heap flags',ProcessHeapFlags]));
    FLC.Add(Format('%s=0x%8.8x',['Process affinity mask',ProcessAffinityMask]));
    FLC.Add(Format('%s=0x%4.4x',['CSD version',CSDVersion]));
    FLC.Add(Format('%s=0x%4.4x',['Reserved1',Reserved1]));
    FLC.Add(Format('%s=0x%8.8x',['Edit list',Editlist]));
    FLC.Add(Format('%s=0x%8.8x',['Security cookie',Editlist]));
    FLC.Add(Format('%s=0x%8.8x',['SE handler table',Editlist]));
    FLC.Add(Format('%s=0x%8.8x',['SE handler count',Editlist]));
  end;
end;

procedure TPirate_PE.CreateLoadConfigList64;
begin
  if GetDataDirectory(IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG).Size=0 then
    Exit;
  with PImageLoadConfigDirectory64(DirectoryEntryToData(IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG))^ do begin
    FLC.Add(Format('%s=%s',['Timestamp',DateTimeToStr(UNIX32ToDateTime(TimeDateStamp))]));
    FLC.Add(Format('%s=%d.%d',['Version',MajorVersion,MinorVersion]));
    FLC.Add(Format('%s=0x%8.8x',['Global flags clear',GlobalFlagsClear]));
    FLC.Add(Format('%s=0x%8.8x',['Global flags set',GlobalFlagsSet]));
    FLC.Add(Format('%s=0x%8.8x',['Critical section default timeout',CriticalSectionDefaultTimeout]));
    FLC.Add(Format('%s=0x%16.16x',['DeCommit free block threshold',DeCommitFreeBlockThreshold]));
    FLC.Add(Format('%s=0x%16.16x',['DeCommit total free threshold',DeCommitTotalFreeThreshold]));
    FLC.Add(Format('%s=0x%16.16x',['Lock prefix table',Cardinal(LockPrefixTable)]));
    FLC.Add(Format('%s=0x%16.16x',['Maximum allocation size',MaximumAllocationSize]));
    FLC.Add(Format('%s=0x%16.16x',['Virtual memory threshold',VirtualMemoryThreshold]));
    FLC.Add(Format('%s=0x%8.8x',['Process heap flags',ProcessHeapFlags]));
    FLC.Add(Format('%s=0x%8.8x',['Process affinity mask',ProcessAffinityMask]));
    FLC.Add(Format('%s=0x%4.4x',['CSD version',CSDVersion]));
    FLC.Add(Format('%s=0x%4.4x',['Reserved1',Reserved1]));
    FLC.Add(Format('%s=0x%16.16x',['Edit list',Editlist]));
    FLC.Add(Format('%s=0x%16.16x',['Security cookie',Editlist]));
    FLC.Add(Format('%s=0x%16.16x',['SE handler table',Editlist]));
    FLC.Add(Format('%s=0x%16.16x',['SE handler count',Editlist]));
  end;
end;

function TPirate_PE.ResOfsToRawData(Ofs: Cardinal): Cardinal;
begin
  Result:=(Ofs and $7FFFFFFF)+Cardinal(RvaToVA(GetDataDirectory(IMAGE_DIRECTORY_ENTRY_RESOURCE).VirtualAddress));
end;

procedure TPirate_PE.CreateResList;

procedure ReadSubDir(AEntry: PImageResourceDirectoryEntry; AType: Cardinal; ATypename: string);
var
  i: Integer;
  s,n: string;
  rd: PImageResourceDirectory;
  e: PImageResourceDirectoryEntry;
  de: PImageResourceDataEntry;
begin
  if AEntry^.Name and IMAGE_RESOURCE_NAME_IS_STRING<>0 then begin
    with PImageResourceDirStringU(ResOfsToRawData(AEntry^.Name))^ do
      n:=WideCharLenToString(NameString,Length);
    SetLength(n,Length(n));
  end else
    n:=IntToStr(AEntry^.Name and $FFFF);
  rd:=PImageResourceDirectory(ResOfsToRawData(AEntry.OffsetToDirectory));
  e:=Pointer(Cardinal(rd)+SizeOf(TImageResourceDirectory));
  for i:=0 to rd.NumberOfNamedEntries+rd.NumberOfIdEntries-1 do begin
    if e^.OffsetToData and IMAGE_RESOURCE_DATA_IS_DIRECTORY<>0 then
      ReadSubDir(e,AType,ATypename)
    else begin
      de:=PImageResourceDataEntry(ResOfsToRawData(e^.OffsetToData));
      if e^.Name and IMAGE_RESOURCE_NAME_IS_STRING<>0 then begin
        with PImageResourceDirStringU(ResOfsToRawData(e^.Name))^ do
          s:=WideCharLenToString(NameString,Length);
        SetLength(s,Length(s));
      end else
        s:=IntToStr(e^.Name and $FFFF);
      SetLength(FRD,Length(FRD)+1);
      with FRD[High(FRD)] do begin
        Name:=n;
        if not(AType in [rtCursor..rtManifest]) then begin
          if SameText(ATypename,'REGISTRY') then
            AType:=rtRegistry
          else
          if SameText(ATypename,'TYPELIB') then
            AType:=rtTypelib
          else
          if SameText(ATypename,'AVI') then
            AType:=rtAVI;
        end;
        Typ:=AType;
        try
          Typename:=GetResourceTypeName(MakeIntResource(AType));
        except
          Typename:=Format('"%s"',[ATypename]);
        end;
        Lang:=s;
        CodePage:=de.CodePage;
        RawDataAddress:=RvaToVa(de.OffsetToData);
        RawDataOffset:=de.OffsetToData;
        RawDataSize:=de.Size;
      end;
    end;
    Inc(e);
  end;
end;

var
  FResDir,frd1,frd2: PImageResourceDirectory;
  re,e: PImageResourceDirectoryEntry;
  i,j,k,n,t: Integer;
  p: PChar;
  s: string;
begin
  if GetDataDirectory(IMAGE_DIRECTORY_ENTRY_RESOURCE).Size=0 then
    Exit;
  FResDir:=PImageResourceDirectory(DirectoryEntryToData(IMAGE_DIRECTORY_ENTRY_RESOURCE));
  re:=Pointer(Cardinal(FResDir)+SizeOf(TImageResourceDirectory));
  for i:=0 to FResDir.NumberOfNamedEntries+FResDir.NumberOfIdEntries-1 do begin
    if re^.Name and IMAGE_RESOURCE_NAME_IS_STRING<>0 then begin
      with PImageResourceDirStringU(ResOfsToRawData(re^.Name))^ do
        s:=WideCharLenToString(NameString,Length);
      SetLength(s,Length(s));
    end else
      s:=IntToStr(re^.Name and $FFFF);
    ReadSubDir(re,re^.Name,s);
    Inc(re);
  end;

  for i:=0 to High(FRD) do
    if (FRD[i].Typ=rtRCDATA) and SameText(FRD[i].Name,'PACKAGEINFO') then begin
      FIPI:=True;
      Break;
    end;
end;

procedure TPirate_PE.CreateTLSList;
begin
  if GetDataDirectory(IMAGE_DIRECTORY_ENTRY_TLS).Size=0 then
    Exit;
  with PImageTLSDirectory(DirectoryEntryToData(IMAGE_DIRECTORY_ENTRY_TLS))^ do begin
    FTLS.Add(Format('%s=0x%8.8x',['Start address of raw data',StartAddressOfRawData]));
    FTLS.Add(Format('%s=0x%8.8x',['End address of raw data',EndAddressOfRawData]));
    FTLS.Add(Format('%s=0x%8.8x',['Address of index',AddressOfIndex]));
    FTLS.Add(Format('%s=0x%8.8x',['Address of callbacks',AddressOfCallbacks]));
    FTLS.Add(Format('%s=%d',['Size of zero fill',SizeOfZeroFill]));
    FTLS.Add(Format('%s=0x%8.8x',['Characteristics',Characteristics]));
  end;
end;

procedure TPirate_PE.CreateTLSList64;
begin
  if GetDataDirectory(IMAGE_DIRECTORY_ENTRY_TLS).Size=0 then
    Exit;
  with PImageTLSDirectory64(DirectoryEntryToData(IMAGE_DIRECTORY_ENTRY_TLS))^ do begin
    FTLS.Add(Format('%s=0x%16.16x',['Start address of raw data',StartAddressOfRawData]));
    FTLS.Add(Format('%s=0x%16.16x',['End address of raw data',EndAddressOfRawData]));
    FTLS.Add(Format('%s=0x%16.16x',['Address of index',AddressOfIndex]));
    FTLS.Add(Format('%s=0x%16.16x',['Address of callbacks',AddressOfCallbacks]));
    FTLS.Add(Format('%s=%d',['Size of zero fill',SizeOfZeroFill]));
    FTLS.Add(Format('%s=0x%8.8x',['Characteristics',Characteristics]));
  end;
end;

procedure TPirate_PE.CreateVerList;
var
  translation: string;
  pd: PDWORD;
  pc: PChar;
  Handle: Cardinal;
  Len,Size: Cardinal;
  FBuffer: PChar;
  FixedFileInfo :PVSFixedFileInfo;
  s: string;
begin
  Size:=GetFileVersionInfoSize(PChar(FFilename),Handle);
  if Size>0 then begin
    GetMem(FBuffer,Size);
    try
      if GetFileVersionInfo(PChar(FFilename),Handle,Size,FBuffer) then begin
        if VerQueryValue(FBuffer,'\',Pointer(FixedFileInfo),Len) then begin
          {FVER.Add(Format('%s=%d.%d.%d.%d',['Full file version',
                                            hiword(fixedfileinfo^.dwfileversionms),
                                            loword(fixedfileinfo^.dwfileversionms),
                                            hiword(fixedfileinfo^.dwfileversionls),
                                            loword(fixedfileinfo^.dwfileversionls)]));
          FVER.Add(Format('%s=%d.%d.%d.%d',['Full product version',
                                            hiword(fixedfileinfo^.dwProductVersionMS),
                                            loword(fixedfileinfo^.dwProductVersionMS),
                                            hiword(fixedfileinfo^.dwProductVersionLS),
                                            loword(fixedfileinfo^.dwProductVersionLS)]));}
          if verqueryvalue(FBuffer,pchar('\VarFileInfo\Translation'),Pointer(pd),Len) then begin
            translation:=IntToHex(pd^,8);
            s:=Copy(translation,5,4);
            if StrToIntDef('$'+s,0)=0 then
              s:=IntToHex(1033,4);
            translation:=s+Copy(translation,1,4);
          end else
            translation:='040904E4';

          if verqueryvalue(FBuffer,pchar('\StringFileInfo\'+translation+'\ProductVersion'),Pointer(pc),Len) then
            FVER.Add(Format('%s=%s',['Product version',string(pc)]));
          if verqueryvalue(FBuffer,pchar('\StringFileInfo\'+translation+'\FileVersion'),Pointer(pc),Len) then
            FVER.Add(Format('%s=%s',['File version',string(pc)]));
          if verqueryvalue(FBuffer,pchar('\StringFileInfo\'+translation+'\FileDescription'),Pointer(pc),Len) then
            FVER.Add(Format('%s=%s',['Description',string(pc)]));
          if verqueryvalue(FBuffer,pchar('\StringFileInfo\'+translation+'\LegalCopyright'),Pointer(pc),Len) then
            FVER.Add(Format('%s=%s',['Copyright',string(pc)]));
          if verqueryvalue(FBuffer,pchar('\StringFileInfo\'+translation+'\Comments'),Pointer(pc),Len) then
            FVER.Add(Format('%s=%s',['Comments',string(pc)]));
          if verqueryvalue(FBuffer,pchar('\StringFileInfo\'+translation+'\SpecialBuild'),Pointer(pc),Len) then
            FVER.Add(Format('%s=%s',['Special build',string(pc)]));
          if verqueryvalue(FBuffer,pchar('\StringFileInfo\'+translation+'\ProductName'),Pointer(pc),Len) then
            FVER.Add(Format('%s=%s',['Product name',string(pc)]));
          if verqueryvalue(FBuffer,pchar('\StringFileInfo\'+translation+'\CompanyName'),Pointer(pc),Len) then
            FVER.Add(Format('%s=%s',['Company name',string(pc)]));
          if verqueryvalue(FBuffer,pchar('\StringFileInfo\'+translation+'\InternalName'),Pointer(pc),Len) then
            FVER.Add(Format('%s=%s',['Internal name',string(pc)]));
        end;
      end;
    finally
      FreeMem(FBuffer);
    end;
  end;
end;

destructor TPirate_PE.Destroy;
begin
  Close;
  Finalize(FRD);
  FCL.Free;
  FRP.Free;
  FCU.Free;
  FDFM.Free;
  FHDR.Free;
  FDOS.Free;
  FOPT.Free;
  FCLR.Free;
  FCLRMD.Free;
  FLC.Free;
  FTLS.Free;
  FVER.Free;
  inherited;
end;

function TPirate_PE.DirectoryEntryToData(Directory: Word): Pointer;
begin
  Result:=RvaToVA(GetDataDirectory(Directory).VirtualAddress);
end;

function TPirate_PE.GetCertCount: Cardinal;
begin
  Result:=Length(FCD);
end;

function TPirate_PE.GetCertItem(Index: Cardinal): TCertItem;
begin
  Result:=FCD[Index];
end;

function TPirate_PE.GetClassCount: Cardinal;
begin
  Result:=FCL.Count;
end;

function TPirate_PE.GetClassItem(Index: cardinal): TClass;
begin
  Result:=TClass(FCL[Index]);
end;

function TPirate_PE.GetCLRCount: Cardinal;
begin
  Result:=FCLR.Count;
end;

function TPirate_PE.GetCLRMDCount: Cardinal;
begin
  Result:=FCLRMD.Count;
end;

function TPirate_PE.GetCLRMDName(Index: Cardinal): string;
begin
  Result:=FCLRMD.Names[Index];
end;

function TPirate_PE.GetCLRMDValue(Index: Cardinal): string;
begin
  Result:=FCLRMD.Values[FCLRMD.Names[Index]];
end;

function TPirate_PE.GetCLRName(Index: Cardinal): string;
begin
  Result:=FCLR.Names[Index];
end;

function TPirate_PE.GetCLRValue(Index: Cardinal): string;
begin
  Result:=FCLR.Values[FCLR.Names[Index]];
end;

function TPirate_PE.GetDataDirectory;
begin
  if FIs64 then
    Result:=TImageDataDirectory(OptionalHeader64.DataDirectory[ADirectory])
  else
    Result:=TImageDataDirectory(OptionalHeader.DataDirectory[ADirectory])
end;

function TPirate_PE.GetDebugCount: Cardinal;
begin
  Result:=Length(FDT);
end;

function TPirate_PE.GetDebugItem(Index: Cardinal): TDebugItem;
begin
  Result:=FDT[Index];
end;

function TPirate_PE.GetDirCount: Cardinal;
begin
  Result:=IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
end;

function TPirate_PE.GetDirItem(Index: Cardinal): TDirectoryItem;
var
  i: Integer;
  EndRVA: Cardinal;
begin
  Finalize(Result);
  ZeroMemory(@Result,SizeOf(Result));
  Result.Data:=GetDataDirectory(Index);
  Result.Name:=DirectoryNames(Index);

  for i:=0 to SectionCount-1 do
    with Sections[i] do begin
      if Data.SizeOfRawData=0 then
        EndRVA:=Data.Misc.VirtualSize
      else
        EndRVA:=Data.SizeOfRawData;
      Inc(EndRVA,Data.VirtualAddress);
      if (Data.VirtualAddress<=Result.Data.VirtualAddress) and (EndRVA>=Result.Data.VirtualAddress) then  begin
        Result.Section:=Name;
        Break;
      end;
    end;
end;

function TPirate_PE.GetDOSCount: Cardinal;
begin
  Result:=FDOS.Count;
end;

function TPirate_PE.GetDOSName(Index: Cardinal): string;
begin
  Result:=FDOS.Names[Index];
end;

function TPirate_PE.GetDOSValue(Index: Cardinal): string;
begin
  Result:=FDOS.Values[FDOS.Names[Index]];
end;

function TPirate_PE.GetExcCount: Cardinal;
begin
  Result:=Length(FXD);
end;

function TPirate_PE.GetExcItem(Index: Cardinal): TExceptionItem;
begin
  Result:=FXD[Index];
end;

function TPirate_PE.GetExpCount: Cardinal;
begin
  Result:=Length(FET);
end;

function TPirate_PE.GetExpItem(Index: Cardinal): TExportItem;
begin
  Result:=FET[Index];
end;

function TPirate_PE.GetFormCount: Cardinal;
begin
  Result:=FDFM.Count;
end;

function TPirate_PE.GetFormItem(Index: Cardinal): string;
begin
  Result:=FDFM[Index];
end;

procedure TPirate_PE.GetFormSource(Index: Cardinal; ADest: TStrings);
var
  i: Integer;
begin
  for i:=0 to High(FRD) do
    if SameText(FRD[i].Name,FDFM[Index]) and (FRD[i].Typ=Cardinal(RT_RCDATA)) then begin
      SaveResourceAsDFM(FRD[i],ADest);
      Break;
    end;
end;

function TPirate_PE.GetHeadCount: Cardinal;
begin
  Result:=FHDR.Count;
end;

function TPirate_PE.GetHeadName(Index: Cardinal): string;
begin
  Result:=FHDR.Names[Index];
end;

function TPirate_PE.GetHeadValue(Index: Cardinal): string;
begin
  Result:=FHDR.Values[FHDR.Names[Index]];
end;

function TPirate_PE.GetImpCount: Cardinal;
begin
  Result:=Length(FIT);
end;

function TPirate_PE.GetImpItem(Index: Cardinal): TImportItem;
begin
  Result:=FIT[Index];
end;

function TPirate_PE.GetLoadConfigCount: Cardinal;
begin
  Result:=FLC.Count;
end;

function TPirate_PE.GetLoadConfigName(Index: Cardinal): string;
begin
  Result:=FLC.Names[Index];
end;

function TPirate_PE.GetLoadConfigValue(Index: Cardinal): string;
begin
  Result:=FLC.Values[FLC.Names[Index]];
end;

function TPirate_PE.GetMDSCount: Cardinal;
begin
  Result:=Length(FMDS);
end;

function TPirate_PE.GetMDSItem(Index: Cardinal): TMetadataStream;
begin
  Result:=FMDS[Index];
end;

function TPirate_PE.GetMDTCount: Cardinal;
begin
  Result:=Length(FMDT)
end;

function TPirate_PE.GetMDTItem(Index: Cardinal): TMetadataTable;
begin
  Result:=FMDT[Index];
end;

function TPirate_PE.GetOptCount: Cardinal;
begin
  Result:=FOPT.Count;
end;

function TPirate_PE.GetOptName(Index: Cardinal): string;
begin
  Result:=FOPT.Names[Index];
end;

function TPirate_PE.GetOptValue(Index: Cardinal): string;
begin
  Result:=FOPT.Values[FOPT.Names[Index]];
end;

function TPirate_PE.GetPkgCount: Cardinal;
begin
  Result:=FRP.Count;
end;

function TPirate_PE.GetPkgItem(Index: Cardinal): string;
begin
  Result:=FRP[Index];
end;

function TPirate_PE.GetResCount: Cardinal;
begin
  Result:=Length(FRD);
end;

function TPirate_PE.GetResItem(Index: Cardinal): TResourceItem;
begin
  Result:=FRD[Index];
end;

function TPirate_PE.GetResItemByName(Name: string): TResourceItem;
var
  i,idx: Integer;
begin
  idx:=-1;
  for i:=0 to High(FRD) do
    if SameText(FRD[i].Name,Name) then begin
      idx:=i;
      Break;
    end;
  if idx>-1 then
    Result:=FRD[idx]
  else
    EPEException.CreateFmt('Cannot retrieve resource by name "%s"',[Name]);
end;

function TPirate_PE.GetSecCount: Cardinal;
begin
  Result:=0;
  try
    if FSig=LoWord(IMAGE_NT_SIGNATURE) then
      Result:=ImageNTHeaders^.FileHeader.NumberOfSections;
  except
  end;
end;

function TPirate_PE.GetSecItem(Index: Cardinal): TSectionItem;
begin
  Finalize(Result);
  ZeroMemory(@Result,SizeOf(Result));
  Result.Data:=PImageSectionHeader(FHeadersAddress+FHeadersSize+Index*SizeOf(TImageSectionHeader))^;
  Result.Name:=string(PChar(@Result.Data.Name));
end;

function TPirate_PE.GetTLSCount: Cardinal;
begin
  Result:=FTLS.Count;
end;

function TPirate_PE.GetTLSName(Index: Cardinal): string;
begin
  Result:=FTLS.Names[Index];
end;

function TPirate_PE.GetTLSValue(Index: Cardinal): string;
begin
  Result:=FTLS.Values[FTLS.Names[Index]];
end;

function TPirate_PE.GetUnitCount: Cardinal;
begin
  Result:=FCU.Count;
end;

function TPirate_PE.GetUnitItem(Index: Cardinal): string;
begin
  Result:=FCU[Index];
end;

function TPirate_PE.GetVerCount: Cardinal;
begin
  Result:=FVER.Count;
end;

function TPirate_PE.GetVerName(Index: Cardinal): string;
begin
  Result:=FVER.Names[Index];
end;

function TPirate_PE.GetVerValue(Index: Cardinal): string;
begin
  Result:=FVER.Values[FVER.Names[Index]];
end;

procedure TPirate_PE.ReadCLRData;
var
  CLRHeader: PImageCOR20Header;
  i: Integer;
  c,l,n,ofs,sz,mdofs,usofs,strofs: Cardinal;
  hos: Byte;
  p,s,mdp,strp: PChar;
  t: string;
  q: Int64;
begin
  if GetDataDirectory(IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR).Size>0 then begin
    CLRHeader:=PImageCOR20Header(DirectoryEntryToData(IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR));
    FCLR.Add(Format('%s=%d.%d',['Version',CLRHeader^.MajorRuntimeVersion,CLRHeader^.MinorRuntimeVersion]));
    FCLR.Add(Format('%s=0x%8.8x',['Metadata virtual address',CLRHeader^.MetaData.VirtualAddress]));
    FCLR.Add(Format('%s=0x%8.8x',['Metadata size',CLRHeader^.MetaData.Size]));
    FCLR.Add(Format('%s=0x%8.8x',['Flags',CLRHeader^.Flags]));
    FCLR.Add(Format('%s=0x%8.8x',['Entry point token',CLRHeader^.EntryPointToken]));
    FCLR.Add(Format('%s=0x%8.8x',['Entry point RVA',CLRHeader^.EntryPointRVA]));
    FCLR.Add(Format('%s=0x%8.8x',['Resources virtual address',CLRHeader^.Resources.VirtualAddress]));
    FCLR.Add(Format('%s=0x%8.8x',['Resources size',CLRHeader^.Resources.Size]));
    FCLR.Add(Format('%s=0x%8.8x',['StrongNameSignature virtual address',CLRHeader^.StrongNameSignature.VirtualAddress]));
    FCLR.Add(Format('%s=0x%8.8x',['StrongNameSignature size',CLRHeader^.StrongNameSignature.Size]));
    FCLR.Add(Format('%s=0x%8.8x',['CodeManagerTable virtual address',CLRHeader^.CodeManagerTable.VirtualAddress]));
    FCLR.Add(Format('%s=0x%8.8x',['CodeManagerTable size',CLRHeader^.CodeManagerTable.Size]));
    FCLR.Add(Format('%s=0x%8.8x',['VTableFixups virtual address',CLRHeader^.VTableFixups.VirtualAddress]));
    FCLR.Add(Format('%s=0x%8.8x',['VTableFixups size',CLRHeader^.VTableFixups.Size]));
    FCLR.Add(Format('%s=0x%8.8x',['ExportAddressTableJumps virtual address',CLRHeader^.ExportAddressTableJumps.VirtualAddress]));
    FCLR.Add(Format('%s=0x%8.8x',['ExportAddressTableJumps size',CLRHeader^.ExportAddressTableJumps.Size]));
    FCLR.Add(Format('%s=0x%8.8x',['ManagedNativeHeader virtual address',CLRHeader^.ManagedNativeHeader.VirtualAddress]));
    if CLRHeader^.ManagedNativeHeader.VirtualAddress=0 then
      FCLR.Add(Format('%s=0x%8.8x',['ManagedNativeHeader size',0]))
    else
      FCLR.Add(Format('%s=0x%8.8x',['ManagedNativeHeader size',CLRHeader^.ManagedNativeHeader.Size]));
    FCLR.Add(Format('%s=0x%8.8x',['EEInfoTable virtual address',PImageDataDirectory(PChar(CLRHeader)+64)^.VirtualAddress]));
    FCLR.Add(Format('%s=0x%8.8x',['EEInfoTable size',PImageDataDirectory(PChar(CLRHeader)+64)^.Size]));
    {FCLR.Add(Format('%s=0x%8.8x',['HelperTable virtual address',PImageDataDirectory(PChar(CLRHeader)+72)^.VirtualAddress]));
    FCLR.Add(Format('%s=0x%8.8x',['HelperTable size',PImageDataDirectory(PChar(CLRHeader)+72)^.Size]));
    FCLR.Add(Format('%s=0x%8.8x',['DynamicInfo virtual address',PImageDataDirectory(PChar(CLRHeader)+80)^.VirtualAddress]));
    FCLR.Add(Format('%s=0x%8.8x',['DynamicInfo size',PImageDataDirectory(PChar(CLRHeader)+80)^.Size]));
    FCLR.Add(Format('%s=0x%8.8x',['DelayLoadInfo virtual address',PImageDataDirectory(PChar(CLRHeader)+88)^.VirtualAddress]));
    FCLR.Add(Format('%s=0x%8.8x',['DelayLoadInfo size',PImageDataDirectory(PChar(CLRHeader)+88)^.Size]));
    FCLR.Add(Format('%s=0x%8.8x',['ModuleImage virtual address',PImageDataDirectory(PChar(CLRHeader)+96)^.VirtualAddress]));
    FCLR.Add(Format('%s=0x%8.8x',['ModuleImage size',PImageDataDirectory(PChar(CLRHeader)+96)^.Size]));
    FCLR.Add(Format('%s=0x%8.8x',['ExternalFixup virtual address',PImageDataDirectory(PChar(CLRHeader)+104)^.VirtualAddress]));
    FCLR.Add(Format('%s=0x%8.8x',['ExternalFixup size',PImageDataDirectory(PChar(CLRHeader)+104)^.Size]));
    FCLR.Add(Format('%s=0x%8.8x',['RidMap virtual address',PImageDataDirectory(PChar(CLRHeader)+112)^.VirtualAddress]));
    FCLR.Add(Format('%s=0x%8.8x',['RidMap size',PImageDataDirectory(PChar(CLRHeader)+112)^.Size]));
    FCLR.Add(Format('%s=0x%8.8x',['DebugMap virtual address',PImageDataDirectory(PChar(CLRHeader)+120)^.VirtualAddress]));
    FCLR.Add(Format('%s=0x%8.8x',['DebugMap size',PImageDataDirectory(PChar(CLRHeader)+120)^.Size]));
    FCLR.Add(Format('%s=0x%8.8x',['IPMap virtual address',PImageDataDirectory(PChar(CLRHeader)+128)^.VirtualAddress]));
    FCLR.Add(Format('%s=0x%8.8x',['IPMap size',PImageDataDirectory(PChar(CLRHeader)+128)^.Size]));}

    p:=PChar(RvaToVA(CLRHeader^.MetaData.VirtualAddress));
    Move(p[0],c,SizeOf(Cardinal));
    FCLRMD.Add(Format('%s=0x%8.8x',['Signature',c]));
    Move(p[SizeOf(Cardinal)],c,SizeOf(Cardinal));
    FCLRMD.Add(Format('%s=%d.%d',['Version',HiWord(c),LoWord(c)]));
    Move(p[3*SizeOf(Cardinal)],l,SizeOf(Cardinal));
    s:=StrAlloc(l);
    try
      StrPCopy(s,PChar(p+4*SizeOf(Cardinal)));
      FCLRMD.Add(Format('%s=%s',['Version string',string(s)]));
      Move(p[4*SizeOf(Cardinal)+l],c,SizeOf(Cardinal));
      n:=HiWord(c);
      FCLRMD.Add(Format('%s=%d',['Streams',n]));
    finally
      StrDispose(s);
    end;

    p:=PChar(p+5*SizeOf(Cardinal)+l);
    for i:=0 to n-1 do begin
      Move(p[0],ofs,SizeOf(Cardinal));
      Move(p[SizeOf(Cardinal)],sz,SizeOf(Cardinal));
      p:=PChar(p+2*SizeOf(Cardinal));
      t:=string(p);
      c:=(Length(t)+1) mod 4;
      if c<>0 then
        c:=4-c;
      p:=PChar(p+Length(t)+1+c);

      SetLength(FMDS,Length(FMDS)+1);
      with FMDS[High(FMDS)] do begin
        Name:=t;
        Address:=Ofs;
        Size:=sz;
      end;
    end;

    ofs:=0;
    for i:=0 to High(FMDS) do begin
      if SameText(FMDS[i].Name,'#~') then
        mdofs:=FMDS[i].Address;
      if SameText(FMDS[i].Name,'#US') then
        usofs:=FMDS[i].Address;
      if SameText(FMDS[i].Name,'#Strings') then
        strofs:=FMDS[i].Address;
    end;

    p:=PChar(RvaToVA(CLRHeader^.MetaData.VirtualAddress));

    if mdofs>0 then begin
      mdp:=PChar(p+mdofs);
      strp:=PChar(p+strofs);

      p:=PChar(mdp+6);
      Move(p[0],hos,SizeOf(hos));

      p:=PChar(mdp+8);
      Move(p[0],q,SizeOf(int64));

      for i:=0 to 63-1 do
        if (q and Round(Power(2,i)))<>0 then begin
          SetLength(FMDT,Length(FMDT)+1);
          with FMDT[High(FMDT)] do
            Name:=cMetadataTables[i];
        end;
    end;
  end;
end;

procedure TPirate_PE.ReadHeaders;
begin
  FDOS.Add(Format('%s=0x%4.4x',['Magic number',PImageDosHeader(FMFB)^.e_magic]));
  FDOS.Add(Format('%s=0x%4.4x',['Bytes on last page of file',PImageDosHeader(FMFB)^.e_cblp]));
  FDOS.Add(Format('%s=0x%4.4x',['Pages in file',PImageDosHeader(FMFB)^.e_cp]));
  FDOS.Add(Format('%s=0x%4.4x',['Relocations',PImageDosHeader(FMFB)^.e_crlc]));
  FDOS.Add(Format('%s=0x%4.4x',['Size of header in paragraphs',PImageDosHeader(FMFB)^.e_cparhdr]));
  FDOS.Add(Format('%s=0x%4.4x',['Minimum extra paragraphs needed',PImageDosHeader(FMFB)^.e_minalloc]));
  FDOS.Add(Format('%s=0x%4.4x',['Maximum extra paragraphs needed',PImageDosHeader(FMFB)^.e_maxalloc]));
  FDOS.Add(Format('%s=0x%4.4x',['Initial (relative) SS value',PImageDosHeader(FMFB)^.e_ss]));
  FDOS.Add(Format('%s=0x%4.4x',['Initial SP value',PImageDosHeader(FMFB)^.e_sp]));
  FDOS.Add(Format('%s=0x%4.4x',['Checksum',PImageDosHeader(FMFB)^.e_csum]));
  FDOS.Add(Format('%s=0x%4.4x',['Initial IP value',PImageDosHeader(FMFB)^.e_ip]));
  FDOS.Add(Format('%s=0x%4.4x',['Initial (relative) CS value',PImageDosHeader(FMFB)^.e_cs]));
  FDOS.Add(Format('%s=0x%4.4x',['File address of relocation table',PImageDosHeader(FMFB)^.e_lfarlc]));
  FDOS.Add(Format('%s=0x%4.4x',['Overlay number',PImageDosHeader(FMFB)^.e_ovno]));
  FDOS.Add(Format('%s=0x%4.4x',['Reserved[0]',PImageDosHeader(FMFB)^.e_res[0]]));
  FDOS.Add(Format('%s=0x%4.4x',['Reserved[1]',PImageDosHeader(FMFB)^.e_res[1]]));
  FDOS.Add(Format('%s=0x%4.4x',['Reserved[2]',PImageDosHeader(FMFB)^.e_res[2]]));
  FDOS.Add(Format('%s=0x%4.4x',['Reserved[3]',PImageDosHeader(FMFB)^.e_res[3]]));
  FDOS.Add(Format('%s=0x%4.4x',['OEM identifier',PImageDosHeader(FMFB)^.e_oemid]));
  FDOS.Add(Format('%s=0x%4.4x',['OEM information',PImageDosHeader(FMFB)^.e_oeminfo]));
  FDOS.Add(Format('%s=0x%4.4x',['Reserved[0]',PImageDosHeader(FMFB)^.e_res2[0]]));
  FDOS.Add(Format('%s=0x%4.4x',['Reserved[1]',PImageDosHeader(FMFB)^.e_res2[1]]));
  FDOS.Add(Format('%s=0x%4.4x',['Reserved[2]',PImageDosHeader(FMFB)^.e_res2[2]]));
  FDOS.Add(Format('%s=0x%4.4x',['Reserved[3]',PImageDosHeader(FMFB)^.e_res2[3]]));
  FDOS.Add(Format('%s=0x%4.4x',['Reserved[4]',PImageDosHeader(FMFB)^.e_res2[4]]));
  FDOS.Add(Format('%s=0x%4.4x',['Reserved[5]',PImageDosHeader(FMFB)^.e_res2[5]]));
  FDOS.Add(Format('%s=0x%4.4x',['Reserved[6]',PImageDosHeader(FMFB)^.e_res2[6]]));
  FDOS.Add(Format('%s=0x%4.4x',['Reserved[7]',PImageDosHeader(FMFB)^.e_res2[7]]));
  FDOS.Add(Format('%s=0x%4.4x',['Reserved[8]',PImageDosHeader(FMFB)^.e_res2[8]]));
  FDOS.Add(Format('%s=0x%4.4x',['Reserved[9]',PImageDosHeader(FMFB)^.e_res2[9]]));
  FDOS.Add(Format('%s=0x%8.8x',['File address of new exe header',PImageDosHeader(FMFB)^._lfanew]));

  case FSig of
    LoWord(IMAGE_NT_SIGNATURE): begin
      FHDR.Add(Format('%s=0x%8.8x (%s)',['Signature',ImageNTHeaders.Signature,GetSignatureString(ImageNTHeaders.Signature)]));
      FHDR.Add(Format('%s=%s',['Machine',GetMachineString(ImageNTHeaders.FileHeader.Machine)]));
      FHDR.Add(Format('%s=%d',['Number of sections',ImageNTHeaders.FileHeader.NumberOfSections]));
      FHDR.Add(Format('%s=%s',['Timestamp',DatetimeToStr(UNIX32ToDatetime(ImageNTHeaders.FileHeader.TimeDateStamp))]));
      FHDR.Add(Format('%s=0x%8.8x',['Pointer to symbol table',ImageNTHeaders.FileHeader.PointerToSymbolTable]));
      FHDR.Add(Format('%s=%d',['Number of symbols',ImageNTHeaders.FileHeader.NumberOfSymbols]));
      FHDR.Add(Format('%s=%d',['Size of optional header',ImageNTHeaders.FileHeader.SizeOfOptionalHeader]));
      FHDR.Add(Format('%s=0x%4.4x',['Characteristics',ImageNTHeaders.FileHeader.Characteristics]));

      FOPT.Add(Format('%s=0x%4.4x (%s)',['Magic',OptionalHeader.Magic,GetMagicString(OptionalHeader.Magic)]));
      FOPT.Add(Format('%s=%d.%d',['Linker version',OptionalHeader.MajorLinkerVersion,OptionalHeader.MinorLinkerVersion]));
      FOPT.Add(Format('%s=%d',['Size of code',OptionalHeader.SizeOfCode]));
      FOPT.Add(Format('%s=%d',['Size of initialized data',OptionalHeader.SizeOfInitializedData]));
      FOPT.Add(Format('%s=%d',['Size of uninitialized',OptionalHeader.SizeOfUninitializedData]));
      FOPT.Add(Format('%s=0x%8.8x',['Address of entry point',OptionalHeader.AddressOfEntryPoint]));
      FOPT.Add(Format('%s=0x%8.8x',['Base of code',OptionalHeader.BaseOfCode]));
      if FIs64 then begin
        FOPT.Add(Format('%s=0x%16.16x',['Image base',OptionalHeader64.ImageBase]));
        FOPT.Add(Format('%s=%d',['Section alignment',OptionalHeader64.SectionAlignment]));
        FOPT.Add(Format('%s=%d',['File alignment',OptionalHeader64.FileAlignment]));
        FOPT.Add(Format('%s=%d.%d',['Operating system version',OptionalHeader64.MajorOperatingSystemVersion,OptionalHeader64.MinorOperatingSystemVersion]));
        FOPT.Add(Format('%s=%d.%d',['Image version',OptionalHeader64.MajorImageVersion,OptionalHeader64.MinorImageVersion]));
        FOPT.Add(Format('%s=%d.%d',['Subsystem version',OptionalHeader64.MajorSubsystemVersion,OptionalHeader64.MinorSubsystemVersion]));
        FOPT.Add(Format('%s=%d',['Win32 version value',OptionalHeader64.Win32VersionValue]));
        FOPT.Add(Format('%s=%d B',['Size of image',OptionalHeader64.SizeOfImage]));
        FOPT.Add(Format('%s=%d',['Size of headers',OptionalHeader64.SizeOfHeaders]));
        FOPT.Add(Format('%s=%d',['Checksum',OptionalHeader64.CheckSum]));
        FOPT.Add(Format('%s=%s',['Subsystem',GetSubsystemString(OptionalHeader64.Subsystem)]));
        FOPT.Add(Format('%s=0x%4.4x',['DLL characteristics',OptionalHeader64.DllCharacteristics]));
        FOPT.Add(Format('%s=%d',['Size of stack reserve',OptionalHeader64.SizeOfStackReserve]));
        FOPT.Add(Format('%s=%d',['Size of stack commit',OptionalHeader64.SizeOfStackCommit]));
        FOPT.Add(Format('%s=%d',['Size of heap reserve',OptionalHeader64.SizeOfHeapReserve]));
        FOPT.Add(Format('%s=%d',['Size of heap commit',OptionalHeader64.SizeOfHeapCommit]));
        FOPT.Add(Format('%s=0x%8.8x',['Loader flags',OptionalHeader64.LoaderFlags]));
        FOPT.Add(Format('%s=%d',['Number of RVA',OptionalHeader64.NumberOfRvaAndSizes]));
      end else begin
        FOPT.Add(Format('%s=0x%8.8x',['Base of data',OptionalHeader.BaseOfData]));
        FOPT.Add(Format('%s=0x%8.8x',['Image base',OptionalHeader.ImageBase]));
        FOPT.Add(Format('%s=%d',['Section alignment',OptionalHeader.SectionAlignment]));
        FOPT.Add(Format('%s=%d',['File alignment',OptionalHeader.FileAlignment]));
        FOPT.Add(Format('%s=%d.%d',['Operating system version',OptionalHeader.MajorOperatingSystemVersion,OptionalHeader.MinorOperatingSystemVersion]));
        FOPT.Add(Format('%s=%d.%d',['Image version',OptionalHeader.MajorImageVersion,OptionalHeader.MinorImageVersion]));
        FOPT.Add(Format('%s=%d.%d',['Subsystem version',OptionalHeader.MajorSubsystemVersion,OptionalHeader.MinorSubsystemVersion]));
        FOPT.Add(Format('%s=%d',['Win32 version value',OptionalHeader.Win32VersionValue]));
        FOPT.Add(Format('%s=%d B',['Size of image',OptionalHeader.SizeOfImage]));
        FOPT.Add(Format('%s=%d',['Size of headers',OptionalHeader.SizeOfHeaders]));
        FOPT.Add(Format('%s=%d',['Checksum',OptionalHeader.CheckSum]));
        FOPT.Add(Format('%s=%s',['Subsystem',GetSubsystemString(OptionalHeader.Subsystem)]));
        FOPT.Add(Format('%s=0x%4.4x',['DLL characteristics',OptionalHeader.DllCharacteristics]));
        FOPT.Add(Format('%s=%d',['Size of stack reserve',OptionalHeader.SizeOfStackReserve]));
        FOPT.Add(Format('%s=%d',['Size of stack commit',OptionalHeader.SizeOfStackCommit]));
        FOPT.Add(Format('%s=%d',['Size of heap reserve',OptionalHeader.SizeOfHeapReserve]));
        FOPT.Add(Format('%s=%d',['Size of heap commit',OptionalHeader.SizeOfHeapCommit]));
        FOPT.Add(Format('%s=0x%8.8x',['Loader flags',OptionalHeader.LoaderFlags]));
        FOPT.Add(Format('%s=%d',['Number of RVA',OptionalHeader.NumberOfRvaAndSizes]));
      end;
    end;
    IMAGE_OS2_SIGNATURE: begin
      FHDR.Add(Format('%s=0x%8.8x (%s)',['Signature',OS2Header.ne_magic,GetSignatureString(OS2Header.ne_magic)]));
      FHDR.Add(Format('%s=%d.%d',['Linker version',Byte(OS2Header.ne_ver),Byte(OS2Header.ne_rev)]));
      FHDR.Add(Format('%s=0x%4.4x',['Offset of Entry Table',OS2Header.ne_enttab]));
      FHDR.Add(Format('%s=%d',['Number of bytes in Entry Table',OS2Header.ne_cbenttab]));
      FHDR.Add(Format('%s=0x%8.8x',['Checksum of whole file',OS2Header.ne_crc]));
      FHDR.Add(Format('%s=0x%4.4x',['Flags',OS2Header.ne_flags]));
      FHDR.Add(Format('%s=0x%4.4x',['Automatic data segment number',OS2Header.ne_autodata]));
      FHDR.Add(Format('%s=0x%4.4x',['Initial heap allocation',OS2Header.ne_heap]));
      FHDR.Add(Format('%s=0x%4.4x',['Initial stack allocation',OS2Header.ne_stack]));
      FHDR.Add(Format('%s=0x%8.8x',['Initial CS:IP setting',OS2Header.ne_csip]));
      FHDR.Add(Format('%s=0x%8.8x',['Initial SS:SP setting',OS2Header.ne_sssp]));
      FHDR.Add(Format('%s=%d',['Count of file segments',OS2Header.ne_cseg]));
      FHDR.Add(Format('%s=%d',['Entries in Module Reference Table',OS2Header.ne_cmod]));
      FHDR.Add(Format('%s=%d',['Size of non-resident name table',OS2Header.ne_cbnrestab]));
      FHDR.Add(Format('%s=0x%4.4x',['Offset of Segment Table',OS2Header.ne_segtab]));
      FHDR.Add(Format('%s=0x%4.4x',['Offset of Resource Table',OS2Header.ne_rsrctab]));
      FHDR.Add(Format('%s=0x%4.4x',['Offset of resident name table',OS2Header.ne_restab]));
      FHDR.Add(Format('%s=0x%4.4x',['Offset of Module Reference Table',OS2Header.ne_modtab]));
      FHDR.Add(Format('%s=0x%4.4x',['Offset of Imported Names Table',OS2Header.ne_imptab]));
      FHDR.Add(Format('%s=0x%8.8x',['Offset of Non-resident Names Table',OS2Header.ne_nrestab]));
      FHDR.Add(Format('%s=%d',['Count of movable entries',OS2Header.ne_cmovent]));
      FHDR.Add(Format('%s=0x%4.4x',['Segment alignment shift count',OS2Header.ne_align]));
      FHDR.Add(Format('%s=%d',['Count of resource segments',OS2Header.ne_cres]));
      FHDR.Add(Format('%s=0x%2.2x',['Target Operating system',OS2Header.ne_exetyp]));
      FHDR.Add(Format('%s=0x%2.2x',['Other .EXE flags',OS2Header.ne_flagsothers]));
      FHDR.Add(Format('%s=0x%4.4x',['Offset to return thunks',OS2Header.ne_pretthunks]));
      FHDR.Add(Format('%s=0x%4.4x',['Offset to segment ref. bytes',OS2Header.ne_psegrefbytes]));
      FHDR.Add(Format('%s=0x%4.4x',['Minimum code swap area size',OS2Header.ne_swaparea]));
      FHDR.Add(Format('%s=%d.%d',['Expected Windows version number',Hi(OS2Header.ne_expver),Lo(OS2Header.ne_expver)]));
    end;
    IMAGE_VXD_SIGNATURE: begin
      FHDR.Add(Format('%s=0x%8.8x (%s)',['Signature',VxDHeader.e32_magic,GetSignatureString(VxDHeader.e32_magic)]));
      FHDR.Add(Format('%s=%d',['The byte ordering for the VXD',VxDHeader.e32_border]));
      FHDR.Add(Format('%s=%d',['The word ordering for the VXD',VxDHeader.e32_worder]));
      FHDR.Add(Format('%s=%d',['The EXE format level',VxDHeader.e32_level]));
      FHDR.Add(Format('%s=%d',['The CPU type',VxDHeader.e32_cpu]));
      FHDR.Add(Format('%s=%d',['The OS type',VxDHeader.e32_os]));
      FHDR.Add(Format('%s=%d',['Module version',VxDHeader.e32_ver]));
      FHDR.Add(Format('%s=0x%8.8x',['Module flags',VxDHeader.e32_mflags]));
      FHDR.Add(Format('%s=%d',['Module pages',VxDHeader.e32_mpages]));
      FHDR.Add(Format('%s=%d',['Number of objects for instruction pointer',VxDHeader.e32_startobj]));
      FHDR.Add(Format('%s=0x%8.8x',['Extended instruction pointer',VxDHeader.e32_eip]));
      FHDR.Add(Format('%s=%d',['Number of objects for stack pointer',VxDHeader.e32_stackobj]));
      FHDR.Add(Format('%s=0x%8.8x',['Extended stack pointer',VxDHeader.e32_esp]));
      FHDR.Add(Format('%s=%d',['VXD page size',VxDHeader.e32_pagesize]));
      FHDR.Add(Format('%s=0x%4.4x',['Last page size in VXD',VxDHeader.e32_lastpagesize]));
      FHDR.Add(Format('%s=%d',['Fixup section size',VxDHeader.e32_fixupsize]));
      FHDR.Add(Format('%s=0x%8.8x',['Fixup section checksum',VxDHeader.e32_fixupsum]));
      FHDR.Add(Format('%s=%d',['Loader section size',VxDHeader.e32_ldrsize]));
      FHDR.Add(Format('%s=0x%8.8x',['Loader section checksum',VxDHeader.e32_ldrsum]));
      FHDR.Add(Format('%s=0x%8.8x',['Object table offset',VxDHeader.e32_objtab]));
      FHDR.Add(Format('%s=%d',['Number of objects in module',VxDHeader.e32_objcnt]));
      FHDR.Add(Format('%s=0x%8.8x',['Object page map offset',VxDHeader.e32_objmap]));
      FHDR.Add(Format('%s=0x%8.8x',['Object iterated data map offset',VxDHeader.e32_itermap]));
      FHDR.Add(Format('%s=0x%8.8x',['Offset of Resource Table',VxDHeader.e32_rsrctab]));
      FHDR.Add(Format('%s=%d',['Number of resource entries',VxDHeader.e32_rsrccnt]));
      FHDR.Add(Format('%s=0x%8.8x',['Offset of resident name table',VxDHeader.e32_restab]));
      FHDR.Add(Format('%s=0x%8.8x',['Offset of Entry Table',VxDHeader.e32_enttab]));
      FHDR.Add(Format('%s=0x%8.8x',['Offset of Module Directive Table',VxDHeader.e32_dirtab]));
      FHDR.Add(Format('%s=%d',['Number of module directives',VxDHeader.e32_dircnt]));
      FHDR.Add(Format('%s=0x%8.8x',['Offset of Fixup Page Table',VxDHeader.e32_fpagetab]));
      FHDR.Add(Format('%s=0x%8.8x',['Offset of Fixup Record Table',VxDHeader.e32_frectab]));
      FHDR.Add(Format('%s=0x%8.8x',['Offset of Import Module Name Table',VxDHeader.e32_impmod]));
      FHDR.Add(Format('%s=%d',['Number of entries in Import Module Name Table',VxDHeader.e32_impmodcnt]));
      FHDR.Add(Format('%s=0x%8.8x',['Offset of Import Procedure Name Table',VxDHeader.e32_impproc]));
      FHDR.Add(Format('%s=0x%8.8x',['Offset of Per-Page Checksum Table',VxDHeader.e32_pagesum]));
      FHDR.Add(Format('%s=0x%8.8x',['Offset of Enumerated Data Pages',VxDHeader.e32_datapage]));
      FHDR.Add(Format('%s=%d',['Number of preload pages',VxDHeader.e32_preload]));
      FHDR.Add(Format('%s=0x%8.8x',['Offset of Non-resident Names Table',VxDHeader.e32_nrestab]));
      FHDR.Add(Format('%s=%d',['Size of Non-resident Name Table',VxDHeader.e32_cbnrestab]));
      FHDR.Add(Format('%s=0x%8.8x',['Non-resident Name Table Checksum',VxDHeader.e32_nressum]));
      FHDR.Add(Format('%s=%d',['Number of objects for automatic data object',VxDHeader.e32_autodata]));
      FHDR.Add(Format('%s=0x%8.8x',['Offset of the debugging information',VxDHeader.e32_debuginfo]));
      FHDR.Add(Format('%s=%d',['The length of the debugging info. in bytes',VxDHeader.e32_debuglen]));
      FHDR.Add(Format('%s=%d',['Number of instance pages in preload section of VXD file',VxDHeader.e32_instpreload]));
      FHDR.Add(Format('%s=%d',['Number of instance pages in demand load section of VXD file',VxDHeader.e32_instdemand]));
      FHDR.Add(Format('%s=%d',['Size of heap - for 16-bit apps',VxDHeader.e32_heapsize]));
      FHDR.Add(Format('%s=0x%8.8x',['Reserverd[0]',VxDHeader.e32_res3[0]]));
      FHDR.Add(Format('%s=0x%8.8x',['Reserverd[1]',VxDHeader.e32_res3[1]]));
      FHDR.Add(Format('%s=0x%8.8x',['Reserverd[2]',VxDHeader.e32_res3[2]]));
      FHDR.Add(Format('%s=0x%8.8x',['Reserverd[3]',VxDHeader.e32_res3[3]]));
      FHDR.Add(Format('%s=0x%8.8x',['Reserverd[4]',VxDHeader.e32_res3[4]]));
      FHDR.Add(Format('%s=0x%8.8x',['Reserverd[5]',VxDHeader.e32_res3[5]]));
      FHDR.Add(Format('%s=0x%8.8x',['Reserverd[6]',VxDHeader.e32_res3[6]]));
      FHDR.Add(Format('%s=0x%8.8x',['Reserverd[7]',VxDHeader.e32_res3[7]]));
      FHDR.Add(Format('%s=0x%8.8x',['Reserverd[8]',VxDHeader.e32_res3[8]]));
      FHDR.Add(Format('%s=0x%8.8x',['Reserverd[9]',VxDHeader.e32_res3[9]]));
      FHDR.Add(Format('%s=0x%8.8x',['Reserverd[10]',VxDHeader.e32_res3[10]]));
      FHDR.Add(Format('%s=0x%8.8x',['Reserverd[11]',VxDHeader.e32_res3[11]]));
      FHDR.Add(Format('%s=0x%8.8x',['Win res offset',VxDHeader.e32_winresoff]));
      FHDR.Add(Format('%s=%d',['Win res length',VxDHeader.e32_winreslen]));
      FHDR.Add(Format('%s=%d',['Device ID for VxD',VxDHeader.e32_devid]));
      FHDR.Add(Format('%s=%d.%d',['DDK version for VxD',Hi(VxDHeader.e32_ddkver),Lo(VxDHeader.e32_ddkver)]));
    end;
  end;
end;

procedure TPirate_PE.ReadInfo;
var
  i: Integer;
  s: string;
begin
  FSize:=GetFileSize(FFilename);

  ImageNTHeaders:=PImageNtHeaders(PChar(FMFB)+PImageDosHeader(FMFB)^._lfanew);
  OS2Header:=PImageOS2Header(PChar(FMFB)+PImageDosHeader(FMFB)^._lfanew);
  VxdHeader:=PImageVxdHeader(PChar(FMFB)+PImageDosHeader(FMFB)^._lfanew);
  OptionalHeader:=PImageOptionalHeader(PChar(FMFB)+PImageDosHeader(FMFB)^._lfanew+sizeof(TImageNTHeaders)-SizeOf(Word));
  OptionalHeader64:=PImageOptionalHeader64(PChar(FMFB)+PImageDosHeader(FMFB)^._lfanew+sizeof(TImageNTHeaders)-SizeOf(Word));
  FIs64:=ImageNtHeaders^.Magic=IMAGE_NT_OPTIONAL_HDR64_MAGIC;
  FSig:=LoWord(ImageNTHeaders.Signature);

  FHeadersAddress:=Cardinal(ImageNtHeaders);
  if FIs64 then
    FHeadersSize:=sizeof(TImageNTHeaders)-SizeOf(Word)+SizeOf(TImageOptionalHeader64)
  else
    FHeadersSize:=sizeof(TImageNTHeaders)-SizeOf(Word)+SizeOf(TImageOptionalHeader);

  if ValidMSEXEModule then begin           

    ReadHeaders;

    if not ValidReadableNTPEModule then
      Exit;

    try ReadCLRData except end;
    try CreateExportList except end;
    try if FIs64 then CreateImportList64 else CreateImportList except end;
    try CreateResList except end;
    try CreateFormList except end;
    try CreateDebugList except end;
    try if FIs64 then CreateExcList64 else CreateExcList except end;
    try if FIs64 then CreateLoadConfigList64 else CreateLoadConfigList except end;
    try if FIs64 then CreateTLSList64 else CreateTLSList except end;
    try CreateVerList except end;
    try CreateCertList except end;
    if not FIs64 then
      try CreateClassList except end;
    if (FLH>0) then begin
      try GetPackageInfo(FLH,FRP,FFlags,GetPackageInfoProc1) except FRP.Clear end;
      try GetPackageInfo(FLH,FCU,FFlags,GetPackageInfoProc2) except FCU.Clear; end;
      try FDesc:=GetPackageDescription(PChar(FFilename)) except FDesc:='' end;
    end;
  end;
end;

function TPirate_PE.RvaToVa;
var
  i: Integer;
  sh: PImageSectionHeader;
  d: Cardinal;
begin
  if Correct then begin
    for i:=0 to ImageNTHeaders.FileHeader.NumberOfSections-1 do begin
      sh:=PImageSectionHeader(FHeadersAddress+FHeadersSize+i*SizeOf(TImageSectionHeader));
      if ((rva>=sh.VirtualAddress) and (rva<sh.VirtualAddress+sh.Misc.VirtualSize)) then
        Break;
    end;
    d:=sh.VirtualAddress-sh.PointerToRawData;
  end else
    d:=0;  
  Result:=PChar(FMFB)+Rva-d;
end;

function TPirate_PE.RvaToVaEx(Rva: Cardinal): Pointer;
begin
  if FIs64 then begin
    if (Rva>FSize) and (Rva>OptionalHeader64.ImageBase) then
      Dec(Rva,OptionalHeader64.ImageBase);
  end else begin
    if (Rva>FSize) and (Rva>OptionalHeader.ImageBase) then
      Dec(Rva,OptionalHeader.ImageBase);
  end;
  Result:=RvaToVa(Rva);
end;

procedure TPirate_PE.SetFilename(const Value: string);
var
  ErrorMode: Word;
begin
  Close;
  FIPI:=False;
  FFilename:=Value;
  FMFB:=nil;

  FH:=CreateFile(PChar(FFilename),GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
  if (FH<>INVALID_HANDLE_VALUE) then begin
    FM:=CreateFileMapping(FH,0,PAGE_READONLY,0,0,nil);
    if (FM<>0) then begin
      FMFB:=MapViewOfFile(FM,FILE_MAP_READ,0,0,0);
    end;
  end;

  ErrorMode:=SetErrorMode(SEM_FailCriticalErrors or SEM_NoOpenFileErrorBox);
  try
    try FLH:=LoadLibraryEx(PChar(FFilename),0,DONT_RESOLVE_DLL_REFERENCES); except end;  
  finally
    SetErrorMode(ErrorMode);
  end;  

  if Assigned(FMFB) then
    ReadInfo;
end;

function TPirate_PE.ValidMSEXEModule: Boolean;
begin
  Result:=(PImageDosHeader(FMFB)^.e_magic=IMAGE_DOS_SIGNATURE);
end;

function TPirate_PE.ValidReadableNTPEModule: Boolean;
begin
  Result:=(not(IsBadReadPtr(ImageNTHeaders,SizeOf(TImageNTHeaders))) and
          (ImageNTHeaders^.Signature=IMAGE_NT_SIGNATURE));
end;

function TPirate_PE.SectionExists(ASectionName: string; var AHeader: Pointer): Boolean;
var
  i: Integer;
begin
  Result:=False;
  i:=-1;
  AHeader:=PImageSectionHeader(FHeadersAddress+FHeadersSize-SizeOf(TImageSectionHeader));
  while (not(Result) and (i<(ImageNTHeaders^.FileHeader.NumberOfSections-1))) do begin
    Inc(i);
    Inc(PImageSectionHeader(AHeader));
    Result:=(StrLIComp(PChar(@PImageSectionHeader(AHeader)^.Name),PChar(ASectionName),IMAGE_SIZEOF_SHORT_NAME)=0);
  end;
end;

{ TResourceRawStream }

constructor TResourceRawStream.Create(AItem: TResourceItem);
begin
  inherited Create;
  SetPointer(AItem.RawDataAddress,AItem.RawDataSize);
end;

function TResourceRawStream.Write(const Buffer; Count: Integer): Longint;
begin
end;

end.
