text:
unit PE.Common;

interface

{$MINENUMSIZE 4}

{ Base types }

type
  Int8 = ShortInt;
  Int16 = SmallInt;
  Int32 = Integer;
  IntPtr = NativeInt;
  UInt8 = Byte;
  UInt16 = Word;
  UInt32 = Cardinal;

  Dword = UInt32;
  PDword = ^Dword;

  TVA = UInt64;
  TRVA = UInt64;

  PInt8 = ^Int8;
  PInt16 = ^Int16;
  PInt32 = ^Int32;
  PInt64 = ^Int64;

  PUInt8 = ^UInt8;
  PUInt16 = ^UInt16;
  PUInt32 = ^UInt32;
  PUInt64 = ^UInt64;

  TFileOffset = type UInt64;

  TParserFlag = (
    PF_EXPORT,
    PF_IMPORT,
    PF_IMPORT_DELAYED,
    PF_RELOCS,
    PF_TLS,
    PF_RESOURCES
    );

  TParserFlags = set of TParserFlag;

  TPEImageKind = (
    PEIMAGE_KIND_DISK,
    PEIMAGE_KIND_MEMORY
    );

  TPEImageObject = TObject; // Meant to cast TObject -> TPEImage

  TParserOption = (
    // If section vsize is 0 try to use rsize instead.
    PO_SECTION_VSIZE_FALLBACK,

    // Rename non-alphanumeric section names.
    PO_SECTION_AUTORENAME_NON_ALPHANUMERIC,

    // If data directory is invalid directory RVA and Size nulled.
    PO_NULL_INVALID_DIRECTORY
    );

  TParserOptions = set of TParserOption;

const
  MAX_PATH_WIN = 260;

  SUSPICIOUS_MIN_LIMIT_EXPORTS = $10000;
  DEFAULT_SECTOR_SIZE          = 512;
  DEFAULT_PAGE_SIZE            = 4096;

  ALL_PARSER_FLAGS = [PF_EXPORT, PF_IMPORT, PF_IMPORT_DELAYED, PF_RELOCS,
    PF_TLS, PF_RESOURCES];

  DEFAULT_PARSER_FLAGS = ALL_PARSER_FLAGS;
  DEFAULT_OPTIONS      = [
    PO_SECTION_VSIZE_FALLBACK,

  // This is disabled by default because now it can reject good names, like
  // .text, .data. In future this option must be either removed or reworked.
  // PO_SECTION_AUTORENAME_NON_ALPHANUMERIC,

  PO_NULL_INVALID_DIRECTORY
    ];

  // Data directories.
  DDIR_EXPORT           = 0;
  DDIR_IMPORT           = 1;
  DDIR_RESOURCE         = 2;
  DDIR_EXCEPTION        = 3;
  DDIR_CERTIFICATE      = 4;
  DDIR_RELOCATION       = 5;
  DDIR_DEBUG            = 6;
  DDIR_ARCHITECTURE     = 7;
  DDIR_GLOBALPTR        = 8;
  DDIR_TLS              = 9;
  DDIR_LOADCONFIG       = 10;
  DDIR_BOUNDIMPORT      = 11;
  DDIR_IAT              = 12;
  DDIR_DELAYIMPORT      = 13;
  DDIR_CLRRUNTIMEHEADER = 14;

  DDIR_LAST = 14;

type
  TParserResult = (PR_OK, PR_ERROR, PR_SUSPICIOUS);

  { Overlay }

type
  TOverlay = packed record
    Offset: TFileOffset;
    Size: UInt64;
  end;

  POverlay = ^TOverlay;

{$SCOPEDENUMS ON}
  TEndianness = (Little, Big);
{$SCOPEDENUMS OFF}

const
  SCategoryLoadFromFile = 'LoadFromFile';
  SCategoryDOSHeader    = 'DOS Header';
  SCategorySections     = 'Sections';
  SCategoryDataDirecory = 'Data Directories';
  SCategoryResources    = 'Resources';
  SCategoryImports      = 'Imports';
  SCategoryTLS          = 'TLS';
  SCategoryRelocs       = 'Relocs';

implementation

end.


text:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <ProjectGuid>{563BBFE2-4D67-4021-A116-332D0BF71BC7}</ProjectGuid>
        <ProjectVersion>16.0</ProjectVersion>
        <FrameworkType>None</FrameworkType>
        <MainSource>AllUnits.dpr</MainSource>
        <Base>True</Base>
        <Config Condition="'$(Config)'==''">Debug</Config>
        <Platform Condition="'$(Platform)'==''">Win32</Platform>
        <TargetedPlatforms>1</TargetedPlatforms>
        <AppType>Console</AppType>
    </PropertyGroup>
    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
        <Base>true</Base>
    </PropertyGroup>
    <PropertyGroup Condition="('$(Platform)'=='OSX32' and '$(Base)'=='true') or '$(Base_OSX32)'!=''">
        <Base_OSX32>true</Base_OSX32>
        <CfgParent>Base</CfgParent>
        <Base>true</Base>
    </PropertyGroup>
    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
        <Base_Win32>true</Base_Win32>
        <CfgParent>Base</CfgParent>
        <Base>true</Base>
    </PropertyGroup>
    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
        <Base_Win64>true</Base_Win64>
        <CfgParent>Base</CfgParent>
        <Base>true</Base>
    </PropertyGroup>
    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
        <Cfg_1>true</Cfg_1>
        <CfgParent>Base</CfgParent>
        <Base>true</Base>
    </PropertyGroup>
    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
        <Cfg_1_Win32>true</Cfg_1_Win32>
        <CfgParent>Cfg_1</CfgParent>
        <Cfg_1>true</Cfg_1>
        <Base>true</Base>
    </PropertyGroup>
    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
        <Cfg_2>true</Cfg_2>
        <CfgParent>Base</CfgParent>
        <Base>true</Base>
    </PropertyGroup>
    <PropertyGroup Condition="'$(Base)'!=''">
        <SanitizedProjectName>AllUnits</SanitizedProjectName>
        <DCC_UnitSearchPath>vdlib;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
        <VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
        <VerInfo_Locale>1033</VerInfo_Locale>
        <Manifest_File>None</Manifest_File>
        <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
        <DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
        <DCC_ExeOutput>bin</DCC_ExeOutput>
        <DCC_E>false</DCC_E>
        <DCC_N>false</DCC_N>
        <DCC_S>false</DCC_S>
        <DCC_F>false</DCC_F>
        <DCC_K>false</DCC_K>
    </PropertyGroup>
    <PropertyGroup Condition="'$(Base_OSX32)'!=''">
        <DCC_UsePackage>bindcompfmx;DBXSqliteDriver;fmx;rtl;dbrtl;DbxClientDriver;IndySystem;bindcomp;inetdb;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;xmlrtl;DbxCommonDriver;IndyProtocols;dbxcds;DBXMySQLDriver;bindengine;soaprtl;bindcompdbx;DBXOracleDriver;CustomIPTransport;dsnap;IndyIPServer;DBXInformixDriver;fmxase;IndyCore;IndyIPCommon;DBXFirebirdDriver;inet;fmxobj;inetdbxpress;DBXSybaseASADriver;fmxdae;dbexpress;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage)</DCC_UsePackage>
    </PropertyGroup>
    <PropertyGroup Condition="'$(Base_Win32)'!=''">
        <VerInfo_Locale>1033</VerInfo_Locale>
        <DCC_UsePackage>bindcompfmx;DBXSqliteDriver;vcldbx;fmx;rtl;dbrtl;DbxClientDriver;IndySystem;TeeDB;bindcomp;inetdb;vclib;inetdbbde;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DBXOdbcDriver;DataSnapServer;Tee;FrameViewerXE3;DataSnapProviderClient;xmlrtl;svnui;ibxpress;DbxCommonDriver;DBXSybaseASEDriver;vclimg;IndyProtocols;dbxcds;DBXMySQLDriver;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vclactnband;bindengine;vcldb;soaprtl;bindcompdbx;vcldsnap;bindcompvcl;FMXTee;TeeUI;vclie;vcltouch;DBXDb2Driver;websnap;DBXOracleDriver;CustomIPTransport;vclribbon;VclSmp;dsnap;IndyIPServer;DBXInformixDriver;Intraweb;fmxase;vcl;IndyCore;DataSnapConnectors;IndyIPCommon;CloudService;DBXMSSQLDriver;dsnapcon;DBXFirebirdDriver;FmxTeeUI;inet;fmxobj;vclx;inetdbxpress;webdsnap;svn;DBXSybaseASADriver;fmxdae;bdertl;dbexpress;adortl;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage)</DCC_UsePackage>
        <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
    </PropertyGroup>
    <PropertyGroup Condition="'$(Base_Win64)'!=''">
        <DCC_UsePackage>bindcompfmx;DBXSqliteDriver;fmx;rtl;dbrtl;DbxClientDriver;IndySystem;bindcomp;inetdb;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DBXOdbcDriver;DataSnapServer;DataSnapProviderClient;xmlrtl;DbxCommonDriver;DBXSybaseASEDriver;vclimg;IndyProtocols;dbxcds;DBXMySQLDriver;vclactnband;bindengine;vcldb;soaprtl;bindcompdbx;vcldsnap;bindcompvcl;vclie;vcltouch;DBXDb2Driver;websnap;DBXOracleDriver;CustomIPTransport;VclSmp;dsnap;IndyIPServer;DBXInformixDriver;fmxase;vcl;IndyCore;IndyIPCommon;DBXMSSQLDriver;dsnapcon;DBXFirebirdDriver;inet;fmxobj;vclx;inetdbxpress;webdsnap;DBXSybaseASADriver;fmxdae;dbexpress;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage)</DCC_UsePackage>
    </PropertyGroup>
    <PropertyGroup Condition="'$(Cfg_1)'!=''">
        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
        <DCC_DebugDCUs>true</DCC_DebugDCUs>
        <DCC_Optimize>false</DCC_Optimize>
        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
        <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
        <DCC_RemoteDebug>true</DCC_RemoteDebug>
    </PropertyGroup>
    <PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
        <DCC_RemoteDebug>false</DCC_RemoteDebug>
    </PropertyGroup>
    <PropertyGroup Condition="'$(Cfg_2)'!=''">
        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
        <DCC_DebugInformation>0</DCC_DebugInformation>
    </PropertyGroup>
    <ItemGroup>
        <DelphiCompile Include="$(MainSource)">
            <MainSource>MainSource</MainSource>
        </DelphiCompile>
        <DCCReference Include="PE.Build.Common.pas"/>
        <DCCReference Include="PE.Build.Export.pas"/>
        <DCCReference Include="PE.Build.Import.pas"/>
        <DCCReference Include="PE.Build.pas"/>
        <DCCReference Include="PE.Build.Relocs.pas"/>
        <DCCReference Include="PE.Build.Resource.pas"/>
        <DCCReference Include="PE.COFF.pas"/>
        <DCCReference Include="PE.COFF.Types.pas"/>
        <DCCReference Include="PE.Common.pas"/>
        <DCCReference Include="PE.DataDirectories.pas"/>
        <DCCReference Include="PE.ExportSym.pas"/>
        <DCCReference Include="PE.FileHeaderToStr.pas"/>
        <DCCReference Include="PE.Headers.pas"/>
        <DCCReference Include="PE.Image.Defaults.pas"/>
        <DCCReference Include="PE.Image.pas"/>
        <DCCReference Include="PE.Image.Saving.pas"/>
        <DCCReference Include="PE.Image.x86.pas"/>
        <DCCReference Include="PE.Imports.pas"/>
        <DCCReference Include="PE.MemoryStream.pas"/>
        <DCCReference Include="PE.Msg.pas"/>
        <DCCReference Include="PE.Parser.Export.pas"/>
        <DCCReference Include="PE.Parser.Headers.pas"/>
        <DCCReference Include="PE.Parser.Import.pas"/>
        <DCCReference Include="PE.Parser.PData.pas"/>
        <DCCReference Include="PE.Parser.Relocs.pas"/>
        <DCCReference Include="PE.Parser.Resources.pas"/>
        <DCCReference Include="PE.Parser.TLS.pas"/>
        <DCCReference Include="PE.Resources.Extract.pas"/>
        <DCCReference Include="PE.Resources.pas"/>
        <DCCReference Include="PE.Resources.Windows.pas"/>
        <DCCReference Include="PE.RTTI.pas"/>
        <DCCReference Include="PE.Section.pas"/>
        <DCCReference Include="PE.Sections.pas"/>
        <DCCReference Include="PE.TLS.pas"/>
        <DCCReference Include="PE.Types.Directories.pas"/>
        <DCCReference Include="PE.Types.DOSHeader.pas"/>
        <DCCReference Include="PE.Types.Export.pas"/>
        <DCCReference Include="PE.Types.FileHeader.pas"/>
        <DCCReference Include="PE.Types.Imports.pas"/>
        <DCCReference Include="PE.Types.NTHeaders.pas"/>
        <DCCReference Include="PE.Types.OptionalHeader.pas"/>
        <DCCReference Include="PE.Types.pas"/>
        <DCCReference Include="PE.Types.Relocations.pas"/>
        <DCCReference Include="PE.Types.Resources.pas"/>
        <DCCReference Include="PE.Types.Sections.pas"/>
        <DCCReference Include="PE.Types.TLS.pas"/>
        <DCCReference Include="PE.Utils.pas"/>
        <DCCReference Include="PE.ExecutableLoader.pas"/>
        <DCCReference Include="PE.ParserCallbacks.pas"/>
        <DCCReference Include="PE.Types.ImportsDelayed.pas"/>
        <DCCReference Include="PE.Parser.ImportDelayed.pas"/>
        <DCCReference Include="NullStream.pas"/>
        <DCCReference Include="PE.Imports.Func.pas"/>
        <DCCReference Include="PE.Imports.Lib.pas"/>
        <BuildConfiguration Include="Release">
            <Key>Cfg_2</Key>
            <CfgParent>Base</CfgParent>
        </BuildConfiguration>
        <BuildConfiguration Include="Base">
            <Key>Base</Key>
        </BuildConfiguration>
        <BuildConfiguration Include="Debug">
            <Key>Cfg_1</Key>
            <CfgParent>Base</CfgParent>
        </BuildConfiguration>
    </ItemGroup>
    <ProjectExtensions>
        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
        <Borland.ProjectType/>
        <BorlandProject>
            <Delphi.Personality>
                <VersionInfo>
                    <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
                    <VersionInfo Name="AutoIncBuild">False</VersionInfo>
                    <VersionInfo Name="MajorVer">1</VersionInfo>
                    <VersionInfo Name="MinorVer">0</VersionInfo>
                    <VersionInfo Name="Release">0</VersionInfo>
                    <VersionInfo Name="Build">0</VersionInfo>
                    <VersionInfo Name="Debug">False</VersionInfo>
                    <VersionInfo Name="PreRelease">False</VersionInfo>
                    <VersionInfo Name="Special">False</VersionInfo>
                    <VersionInfo Name="Private">False</VersionInfo>
                    <VersionInfo Name="DLL">False</VersionInfo>
                    <VersionInfo Name="Locale">1033</VersionInfo>
                    <VersionInfo Name="CodePage">1252</VersionInfo>
                </VersionInfo>
                <VersionInfoKeys>
                    <VersionInfoKeys Name="CompanyName"/>
                    <VersionInfoKeys Name="FileDescription"/>
                    <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
                    <VersionInfoKeys Name="InternalName"/>
                    <VersionInfoKeys Name="LegalCopyright"/>
                    <VersionInfoKeys Name="LegalTrademarks"/>
                    <VersionInfoKeys Name="OriginalFilename"/>
                    <VersionInfoKeys Name="ProductName"/>
                    <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
                    <VersionInfoKeys Name="Comments"/>
                    <VersionInfoKeys Name="CFBundleName"/>
                    <VersionInfoKeys Name="CFBundleDisplayName"/>
                    <VersionInfoKeys Name="CFBundleIdentifier"/>
                    <VersionInfoKeys Name="CFBundleVersion"/>
                    <VersionInfoKeys Name="CFBundlePackageType"/>
                    <VersionInfoKeys Name="CFBundleSignature"/>
                    <VersionInfoKeys Name="CFBundleAllowMixedLocalizations"/>
                    <VersionInfoKeys Name="CFBundleExecutable"/>
                </VersionInfoKeys>
                <Source>
                    <Source Name="MainSource">AllUnits.dpr</Source>
                </Source>
                <Excluded_Packages>
                    <Excluded_Packages Name="$(BDSBIN)\dcloffice2k170.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
                    <Excluded_Packages Name="$(BDSBIN)\dclofficexp170.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
                </Excluded_Packages>
            </Delphi.Personality>
            <Deployment>
                <DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
                    <Platform Name="OSX32">
                        <Overwrite>true</Overwrite>
                    </Platform>
                    <Platform Name="iOSSimulator">
                        <Overwrite>true</Overwrite>
                    </Platform>
                </DeployFile>
                <DeployFile LocalName="bin\AllUnits.exe" Configuration="Debug" Class="ProjectOutput">
                    <Platform Name="Win32">
                        <RemoteName>AllUnits.exe</RemoteName>
                        <Overwrite>true</Overwrite>
                    </Platform>
                </DeployFile>
                <DeployClass Required="true" Name="DependencyPackage">
                    <Platform Name="iOSDevice">
                        <Operation>1</Operation>
                        <Extensions>.dylib</Extensions>
                    </Platform>
                    <Platform Name="Win32">
                        <Operation>0</Operation>
                        <Extensions>.bpl</Extensions>
                    </Platform>
                    <Platform Name="OSX32">
                        <Operation>1</Operation>
                        <Extensions>.dylib</Extensions>
                    </Platform>
                    <Platform Name="iOSSimulator">
                        <Operation>1</Operation>
                        <Extensions>.dylib</Extensions>
                    </Platform>
                </DeployClass>
                <DeployClass Name="DependencyModule">
                    <Platform Name="OSX32">
                        <Operation>1</Operation>
                        <Extensions>.dylib</Extensions>
                    </Platform>
                    <Platform Name="Win32">
                        <Operation>0</Operation>
                        <Extensions>.dll;.bpl</Extensions>
                    </Platform>
                </DeployClass>
                <DeployClass Name="iPad_Launch2048">
                    <Platform Name="iOSDevice">
                        <Operation>1</Operation>
                    </Platform>
                    <Platform Name="iOSSimulator">
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="ProjectOSXInfoPList"/>
                <DeployClass Name="ProjectiOSDeviceDebug">
                    <Platform Name="iOSDevice">
                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="Android_SplashImage470">
                    <Platform Name="Android">
                        <RemoteDir>res\drawable-normal</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="AndroidLibnativeX86File">
                    <Platform Name="Android">
                        <RemoteDir>library\lib\x86</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="ProjectiOSResource">
                    <Platform Name="iOSDevice">
                        <Operation>1</Operation>
                    </Platform>
                    <Platform Name="iOSSimulator">
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="ProjectOSXEntitlements"/>
                <DeployClass Name="AndroidGDBServer">
                    <Platform Name="Android">
                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="iPhone_Launch640">
                    <Platform Name="iOSDevice">
                        <Operation>1</Operation>
                    </Platform>
                    <Platform Name="iOSSimulator">
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="Android_SplashImage960">
                    <Platform Name="Android">
                        <RemoteDir>res\drawable-xlarge</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="Android_LauncherIcon96">
                    <Platform Name="Android">
                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="iPhone_Launch320">
                    <Platform Name="iOSDevice">
                        <Operation>1</Operation>
                    </Platform>
                    <Platform Name="iOSSimulator">
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="Android_LauncherIcon144">
                    <Platform Name="Android">
                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="AndroidLibnativeMipsFile">
                    <Platform Name="Android">
                        <RemoteDir>library\lib\mips</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="AndroidSplashImageDef">
                    <Platform Name="Android">
                        <RemoteDir>res\drawable</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="DebugSymbols">
                    <Platform Name="OSX32">
                        <Operation>1</Operation>
                    </Platform>
                    <Platform Name="iOSSimulator">
                        <Operation>1</Operation>
                    </Platform>
                    <Platform Name="Win32">
                        <Operation>0</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="DependencyFramework">
                    <Platform Name="OSX32">
                        <Operation>1</Operation>
                        <Extensions>.framework</Extensions>
                    </Platform>
                    <Platform Name="Win32">
                        <Operation>0</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="Android_SplashImage426">
                    <Platform Name="Android">
                        <RemoteDir>res\drawable-small</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="ProjectiOSEntitlements"/>
                <DeployClass Name="AdditionalDebugSymbols">
                    <Platform Name="OSX32">
                        <Operation>1</Operation>
                    </Platform>
                    <Platform Name="Win32">
                        <RemoteDir>Contents\MacOS</RemoteDir>
                        <Operation>0</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="AndroidClassesDexFile">
                    <Platform Name="Android">
                        <RemoteDir>classes</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="ProjectiOSInfoPList"/>
                <DeployClass Name="iPad_Launch1024">
                    <Platform Name="iOSDevice">
                        <Operation>1</Operation>
                    </Platform>
                    <Platform Name="iOSSimulator">
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="Android_DefaultAppIcon">
                    <Platform Name="Android">
                        <RemoteDir>res\drawable</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="ProjectOSXResource">
                    <Platform Name="OSX32">
                        <RemoteDir>Contents\Resources</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="ProjectiOSDeviceResourceRules"/>
                <DeployClass Name="iPad_Launch768">
                    <Platform Name="iOSDevice">
                        <Operation>1</Operation>
                    </Platform>
                    <Platform Name="iOSSimulator">
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Required="true" Name="ProjectOutput">
                    <Platform Name="iOSDevice">
                        <Operation>1</Operation>
                    </Platform>
                    <Platform Name="Android">
                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                    <Platform Name="Win32">
                        <Operation>0</Operation>
                    </Platform>
                    <Platform Name="OSX32">
                        <Operation>1</Operation>
                    </Platform>
                    <Platform Name="iOSSimulator">
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="AndroidLibnativeArmeabiFile">
                    <Platform Name="Android">
                        <RemoteDir>library\lib\armeabi</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="Android_SplashImage640">
                    <Platform Name="Android">
                        <RemoteDir>res\drawable-large</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="File">
                    <Platform Name="iOSDevice">
                        <Operation>0</Operation>
                    </Platform>
                    <Platform Name="Android">
                        <Operation>0</Operation>
                    </Platform>
                    <Platform Name="Win32">
                        <Operation>0</Operation>
                    </Platform>
                    <Platform Name="OSX32">
                        <Operation>0</Operation>
                    </Platform>
                    <Platform Name="iOSSimulator">
                        <Operation>0</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="iPhone_Launch640x1136">
                    <Platform Name="iOSDevice">
                        <Operation>1</Operation>
                    </Platform>
                    <Platform Name="iOSSimulator">
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="Android_LauncherIcon36">
                    <Platform Name="Android">
                        <RemoteDir>res\drawable-ldpi</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="AndroidSplashStyles">
                    <Platform Name="Android">
                        <RemoteDir>res\values</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="iPad_Launch1536">
                    <Platform Name="iOSDevice">
                        <Operation>1</Operation>
                    </Platform>
                    <Platform Name="iOSSimulator">
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="Android_LauncherIcon48">
                    <Platform Name="Android">
                        <RemoteDir>res\drawable-mdpi</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="Android_LauncherIcon72">
                    <Platform Name="Android">
                        <RemoteDir>res\drawable-hdpi</RemoteDir>
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <DeployClass Name="ProjectAndroidManifest">
                    <Platform Name="Android">
                        <Operation>1</Operation>
                    </Platform>
                </DeployClass>
                <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
                <ProjectRoot Platform="iOSDevice" Name="$(PROJECTNAME).app"/>
                <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
                <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME)"/>
                <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
                <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
            </Deployment>
            <Platforms>
                <Platform value="OSX32">False</Platform>
                <Platform value="Win32">True</Platform>
                <Platform value="Win64">False</Platform>
            </Platforms>
        </BorlandProject>
        <ProjectFileVersion>12</ProjectFileVersion>
    </ProjectExtensions>
    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
    <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
</Project>

repo_name: vdisasm/pe-image-for-delphi

repo_language: Pascal

mime_type: text/plain


text:
const
// 4.2.1. Type Indicators
// x64 Processors
// The following relocation type indicators are defined for x64 and compatible processors.
  IMAGE_REL_AMD64_ABSOLUTE	= $0000;  //  The relocation is ignored.
  IMAGE_REL_AMD64_ADDR64	  = $0001;  // 	The 64-bit VA of the relocation target.
  IMAGE_REL_AMD64_ADDR32	  = $0002;  // 	The 32-bit VA of the relocation target.
  IMAGE_REL_AMD64_ADDR32NB  = $0003;  // 	The 32-bit address without an image base (RVA).
  IMAGE_REL_AMD64_REL32	    = $0004;  // 	The 32-bit relative address from the byte following the relocation.
  IMAGE_REL_AMD64_REL32_1	  = $0005;  // 	The 32-bit address relative to byte distance 1 from the relocation.
  IMAGE_REL_AMD64_REL32_2	  = $0006;  // 	The 32-bit address relative to byte distance 2 from the relocation.
  IMAGE_REL_AMD64_REL32_3	  = $0007;  // 	The 32-bit address relative to byte distance 3 from the relocation.
  IMAGE_REL_AMD64_REL32_4	  = $0008;  // 	The 32-bit address relative to byte distance 4 from the relocation.
  IMAGE_REL_AMD64_REL32_5	  = $0009;  // 	The 32-bit address relative to byte distance 5 from the relocation.
  IMAGE_REL_AMD64_SECTION	  = $000A;  // 	The 16-bit section index of the section that contains the target.
                                      //  This is used to support debugging information.
  IMAGE_REL_AMD64_SECREL	  = $000B;  // 	The 32-bit offset of the target from the beginning of its section.
                                      //  This is used to support debugging information and static thread local storage.
  IMAGE_REL_AMD64_SECREL7	  = $000C;  // 	A 7-bit unsigned offset from the base of the section that contains the target.
  IMAGE_REL_AMD64_TOKEN	    = $000D;  // 	CLR tokens.
  IMAGE_REL_AMD64_SREL32  	= $000E;  // 	A 32-bit signed span-dependent value emitted into the object.
  IMAGE_REL_AMD64_PAIR	    = $000F;  // 	A pair that must immediately follow every span-dependent value.
  IMAGE_REL_AMD64_SSPAN32	  = $0010;  // 	A 32-bit signed span-dependent value that is applied at link time.

// ARM Processors
// The following relocation type indicators are defined for ARM processors.
  IMAGE_REL_ARM_ABSOLUTE	  = $0000;  // 	The relocation is ignored.
  IMAGE_REL_ARM_ADDR32	    = $0001;  // 	The 32-bit VA of the target.
  IMAGE_REL_ARM_ADDR32NB	  = $0002;  // 	The 32-bit RVA of the target.
  IMAGE_REL_ARM_BRANCH24	  = $0003;  // 	The most significant 24 bits of the signed 26-bit relative displacement of the target.  Applied to a B or BL instruction in ARM mode.
  IMAGE_REL_ARM_BRANCH11	  = $0004;  // 	The most significant 22 bits of the signed 23-bit relative displacement of the target.  Applied to a contiguous 16-bit B+BL pair in Thumb mode prior to ARMv7.
  IMAGE_REL_ARM_TOKEN	      = $0005;  // 	CLR tokens.
  IMAGE_REL_ARM_BLX24	      = $0008;  // 	The most significant 24 or 25 bits of the signed 26-bit relative displacement of the target.  Applied to an unconditional BL instruction in ARM mode.  The BL is transformed to a BLX during relocation if the target is in Thumb mode.
  IMAGE_REL_ARM_BLX11	      = $0009;  // 	The most significant 21 or 22 bits of the signed 23-bit relative displacement of the target.  Applied to a contiguous 16-bit B+BL pair in Thumb mode prior to ARMv7.  The BL is transformed to a BLX during relocation if the target is in ARM mode.
  IMAGE_REL_ARM_SECTION	    = $000E;  // 	The 16-bit section index of the section that contains the target. This is used to support debugging information.
  IMAGE_REL_ARM_SECREL	    = $000F;  // 	The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage.
  IMAGE_REL_ARM_MOV32A	    = $0010;  // 	The 32-bit VA of the target.  Applied to a contiguous MOVW+MOVT pair in ARM mode.  The 32-bit VA is added to the existing value that is encoded in the immediate fields of the pair.
  IMAGE_REL_ARM_MOV32T	    = $0011;  // 	The 32-bit VA of the target.  Applied to a contiguous MOVW+MOVT pair in Thumb mode.  The 32-bit VA is added to the existing value that is encoded in the immediate fields of the pair.
  IMAGE_REL_ARM_BRANCH20T	  = $0012;  // 	The most significant 20 bits of the signed 21-bit relative displacement of the target.  Applied to a 32-bit conditional B instruction in Thumb mode.
  IMAGE_REL_ARM_BRANCH24T	  = $0014;  // 	The most significant 24 bits of the signed 25-bit relative displacement of the target.  Applied to a 32-bit unconditional B or BL instruction in Thumb mode.
  IMAGE_REL_ARM_BLX23T	    = $0015;  // 	The most significant 23 or 24 bits of the signed 25-bit relative displacement of the target.  Applied to a 32-bit BL instruction in Thumb mode.  The BL is transformed to a BLX during relocation if the target is in ARM mode.

  // Hitachi SuperH Processors
  // The following relocation type indicators are defined for SH3 and SH4 processors.
  // SH5-specific relocations are noted as SHM (SH Media).
  IMAGE_REL_SH3_ABSOLUTE	      = $0000;  // 	The relocation is ignored.
  IMAGE_REL_SH3_DIRECT16	      = $0001;  // 	A reference to the 16-bit location that contains the VA of the target symbol.
  IMAGE_REL_SH3_DIRECT32	      = $0002;  // 	The 32-bit VA of the target symbol.
  IMAGE_REL_SH3_DIRECT8	        = $0003;  // 	A reference to the 8-bit location that contains the VA of the target symbol.
  IMAGE_REL_SH3_DIRECT8_WORD	  = $0004;  // 	A reference to the 8-bit instruction that contains the effective 16-bit VA of the target symbol.
  IMAGE_REL_SH3_DIRECT8_LONG	  = $0005;  // 	A reference to the 8-bit instruction that contains the effective 32-bit VA of the target symbol.
  IMAGE_REL_SH3_DIRECT4	        = $0006;  // 	A reference to the 8-bit location whose low 4 bits contain the VA of the target symbol.
  IMAGE_REL_SH3_DIRECT4_WORD	  = $0007;  // 	A reference to the 8-bit instruction whose low 4 bits contain the effective 16-bit VA of the target symbol.
  IMAGE_REL_SH3_DIRECT4_LONG	  = $0008;  // 	A reference to the 8-bit instruction whose low 4 bits contain the effective 32-bit VA of the target symbol.
  IMAGE_REL_SH3_PCREL8_WORD	    = $0009;  // 	A reference to the 8-bit instruction that contains the effective 16-bit relative offset of the target symbol.
  IMAGE_REL_SH3_PCREL8_LONG	    = $000A;  // 	A reference to the 8-bit instruction that contains the effective 32-bit relative offset of the target symbol.
  IMAGE_REL_SH3_PCREL12_WORD	  = $000B;  // 	A reference to the 16-bit instruction whose low 12 bits contain the effective 16-bit relative offset of the target symbol.
  IMAGE_REL_SH3_STARTOF_SECTION	= $000C;  // 	A reference to a 32-bit location that is the VA of the section that contains the target symbol.
  IMAGE_REL_SH3_SIZEOF_SECTION	= $000D;  // 	A reference to the 32-bit location that is the size of the section that contains the target symbol.
  IMAGE_REL_SH3_SECTION	        = $000E;  // 	The 16-bit section index of the section that contains the target. This is used to support debugging information.
  IMAGE_REL_SH3_SECREL	        = $000F;  // 	The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage.
  IMAGE_REL_SH3_DIRECT32_NB	    = $0010;  // 	The 32-bit RVA of the target symbol.
  IMAGE_REL_SH3_GPREL4_LONG	    = $0011;  // 	GP relative.
  IMAGE_REL_SH3_TOKEN	          = $0012;  // 	CLR token.
  IMAGE_REL_SHM_PCRELPT	        = $0013;  // 	The offset from the current instruction in longwords. If the NOMODE bit is not set, insert the inverse of the low bit at bit 32 to select PTA or PTB.
  IMAGE_REL_SHM_REFLO	          = $0014;  // 	The low 16 bits of the 32-bit address.
  IMAGE_REL_SHM_REFHALF	        = $0015;  // 	The high 16 bits of the 32-bit address.
  IMAGE_REL_SHM_RELLO 	        = $0016;  // 	The low 16 bits of the relative address.
  IMAGE_REL_SHM_RELHALF	        = $0017;  // 	The high 16 bits of the relative address.
  IMAGE_REL_SHM_PAIR  	        = $0018;  // 	The relocation is valid only when it immediately follows a REFHALF, RELHALF, or RELLO relocation. The SymbolTableIndex field of the relocation contains a displacement and not an index into the symbol table.
  IMAGE_REL_SHM_NOMODE	        = $8000;  // 	The relocation ignores section mode.

  // IBM PowerPC Processors
  // The following relocation type indicators are defined for PowerPC processors.
  IMAGE_REL_PPC_ABSOLUTE	= $0000;  // 	The relocation is ignored.
  IMAGE_REL_PPC_ADDR64	  = $0001;  // 	The 64-bit VA of the target.
  IMAGE_REL_PPC_ADDR32	  = $0002;  // 	The 32-bit VA of the target.
  IMAGE_REL_PPC_ADDR24	  = $0003;  // 	The low 24 bits of the VA of the target. This is valid only when the target symbol is absolute and can be sign-extended to its original value.
  IMAGE_REL_PPC_ADDR16	  = $0004;  // 	The low 16 bits of the target’s VA.
  IMAGE_REL_PPC_ADDR14	  = $0005;  // 	The low 14 bits of the target’s VA. This is valid only when the target symbol is absolute and can be sign-extended to its original value.
  IMAGE_REL_PPC_REL24	    = $0006;  // 	A 24-bit PC-relative offset to the symbol’s location.
  IMAGE_REL_PPC_REL14	    = $0007;  // 	A 14-bit PC-relative offset to the symbol’s location.
  IMAGE_REL_PPC_ADDR32NB	= $000A;  // 	The 32-bit RVA of the target.
  IMAGE_REL_PPC_SECREL	  = $000B;  // 	The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage.
  IMAGE_REL_PPC_SECTION	  = $000C;  // 	The 16-bit section index of the section that contains the target. This is used to support debugging information.
  IMAGE_REL_PPC_SECREL16	= $000F;  // 	The 16-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage.
  IMAGE_REL_PPC_REFHI	    = $0010;  // 	The high 16 bits of the target’s 32-bit VA. This is used for the first instruction in a two-instruction sequence that loads a full address. This relocation must be immediately followed by a PAIR relocation whose SymbolTableIndex contains a signed 16-bit displacement that is added to the upper 16 bits that was taken from the location that is being relocated.
  IMAGE_REL_PPC_REFLO	    = $0011;  // 	The low 16 bits of the target’s VA.
  IMAGE_REL_PPC_PAIR	    = $0012;  // 	A relocation that is valid only when it immediately follows a REFHI or SECRELHI relocation. Its SymbolTableIndex contains a displacement and not an index into the symbol table.
  IMAGE_REL_PPC_SECRELLO	= $0013;  // 	The low 16 bits of the 32-bit offset of the target from the beginning of its section.
  IMAGE_REL_PPC_GPREL	    = $0015;  // 	The 16-bit signed displacement of the target relative to the GP register.
  IMAGE_REL_PPC_TOKEN	    = $0016;  // 	The CLR token.

  // Intel 386 Processors
  // The following relocation type indicators are defined for Intel 386 and compatible processors.
  IMAGE_REL_I386_ABSOLUTE	= $0000;  // 	The relocation is ignored.
  IMAGE_REL_I386_DIR16	  = $0001;  // 	Not supported.
  IMAGE_REL_I386_REL16	  = $0002;  // 	Not supported.
  IMAGE_REL_I386_DIR32	  = $0006;  // 	The target’s 32-bit VA.
  IMAGE_REL_I386_DIR32NB	= $0007;  // 	The target’s 32-bit RVA.
  IMAGE_REL_I386_SEG12	  = $0009;  // 	Not supported.
  IMAGE_REL_I386_SECTION	= $000A;  // 	The 16-bit section index of the section that contains the target. This is used to support debugging information.
  IMAGE_REL_I386_SECREL	  = $000B;  // 	The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage.
  IMAGE_REL_I386_TOKEN	  = $000C;  // 	The CLR token.
  IMAGE_REL_I386_SECREL7	= $000D;  // 	A 7-bit offset from the base of the section that contains the target.
  IMAGE_REL_I386_REL32	  = $0014;  // 	The 32-bit relative displacement of the target. This supports the x86 relative branch and call instructions.

  // Intel Itanium Processor Family (IPF)
  // The following relocation type indicators are defined for the Intel Itanium processor family and compatible processors.
  // Note that relocations on instructions use the bundle’s offset and slot number for the relocation offset.
  IMAGE_REL_IA64_ABSOLUTE	  = $0000;  // 	The relocation is ignored.
  IMAGE_REL_IA64_IMM14	    = $0001;  // 	The instruction relocation can be followed by an ADDEND relocation whose value is added to the target address before it is inserted into the specified slot in the IMM14 bundle. The relocation target must be absolute or the image must be fixed.
  IMAGE_REL_IA64_IMM22	    = $0002;  // 	The instruction relocation can be followed by an ADDEND relocation whose value is added to the target address before it is inserted into the specified slot in the IMM22 bundle. The relocation target must be absolute or the image must be fixed.
  IMAGE_REL_IA64_IMM64	    = $0003;  // 	The slot number of this relocation must be one (1). The relocation can be followed by an ADDEND relocation whose value is added to the target address before it is stored in all three slots of the IMM64 bundle.
  IMAGE_REL_IA64_DIR32	    = $0004;  // 	The target’s 32-bit VA. This is supported only for /LARGEADDRESSAWARE:NO images.
  IMAGE_REL_IA64_DIR64	    = $0005;  // 	The target’s 64-bit VA.
  IMAGE_REL_IA64_PCREL21B	  = $0006;  // 	The instruction is fixed up with the 25-bit relative displacement of the 16-bit aligned target. The low 4 bits of the displacement are zero and are not stored.
  IMAGE_REL_IA64_PCREL21M	  = $0007;  // 	The instruction is fixed up with the 25-bit relative displacement of the 16-bit aligned target. The low 4 bits of the displacement, which are zero, are not stored.
  IMAGE_REL_IA64_PCREL21F	  = $0008;  // 	The LSBs of this relocation’s offset must contain the slot number whereas the rest is the bundle address. The bundle is fixed up with the 25-bit relative displacement of the 16-bit aligned target. The low 4 bits of the displacement are zero and are not stored.
  IMAGE_REL_IA64_GPREL22	  = $0009;  // 	The instruction relocation can be followed by an ADDEND relocation whose value is added to the target address and then a 22-bit GP-relative offset that is calculated and applied to the GPREL22 bundle.
  IMAGE_REL_IA64_LTOFF22	  = $000A;  // 	The instruction is fixed up with the 22-bit GP-relative offset to the target symbol’s literal table entry. The linker creates this literal table entry based on this relocation and the ADDEND relocation that might follow.
  IMAGE_REL_IA64_SECTION	  = $000B;  // 	The 16-bit section index of the section contains the target. This is used to support debugging information.
  IMAGE_REL_IA64_SECREL22	  = $000C;  // 	The instruction is fixed up with the 22-bit offset of the target from the beginning of its section. This relocation can be followed immediately by an ADDEND relocation, whose Value field contains the 32-bit unsigned offset of the target from the beginning of the section.
  IMAGE_REL_IA64_SECREL64I	= $000D;  // 	The slot number for this relocation must be one (1). The instruction is fixed up with the 64-bit offset of the target from the beginning of its section. This relocation can be followed immediately by an ADDEND relocation whose Value field contains the 32-bit unsigned offset of the target from the beginning of the section.
  IMAGE_REL_IA64_SECREL32	  = $000E;  // 	The address of data to be fixed up with the 32-bit offset of the target from the beginning of its section.
  IMAGE_REL_IA64_DIR32NB	  = $0010;  // 	The target’s 32-bit RVA.
  IMAGE_REL_IA64_SREL14	    = $0011;  // 	This is applied to a signed 14-bit immediate that contains the difference between two relocatable targets. This is a declarative field for the linker that indicates that the compiler has already emitted this value.
  IMAGE_REL_IA64_SREL22	    = $0012;  // 	This is applied to a signed 22-bit immediate that contains the difference between two relocatable targets. This is a declarative field for the linker that indicates that the compiler has already emitted this value.
  IMAGE_REL_IA64_SREL32	    = $0013;  // 	This is applied to a signed 32-bit immediate that contains the difference between two relocatable values. This is a declarative field for the linker that indicates that the compiler has already emitted this value.
  IMAGE_REL_IA64_UREL32	    = $0014;  // 	This is applied to an unsigned 32-bit immediate that contains the difference between two relocatable values. This is a declarative field for the linker that indicates that the compiler has already emitted this value.
  IMAGE_REL_IA64_PCREL60x	  = $0015;  // 	A 60-bit PC-relative fixup that always stays as a BRL instruction of an MLX bundle.
  IMAGE_REL_IA64_PCREL60B	  = $0016;  // 	A 60-bit PC-relative fixup. If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MBB bundle with NOP.B in slot 1 and a 25-bit BR instruction (with the 4 lowest bits all zero and dropped) in slot 2.
  IMAGE_REL_IA64_PCREL60F	  = $0017;  // 	A 60-bit PC-relative fixup. If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MFB bundle with NOP.F in slot 1 and a 25-bit (4 lowest bits all zero and dropped) BR instruction in slot 2.
  IMAGE_REL_IA64_PCREL60I	  = $0018;  // 	A 60-bit PC-relative fixup. If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MIB bundle with NOP.I in slot 1 and a 25-bit (4 lowest bits all zero and dropped) BR instruction in slot 2.
  IMAGE_REL_IA64_PCREL60M	  = $0019;  // 	A 60-bit PC-relative fixup. If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MMB bundle with NOP.M in slot 1 and a 25-bit (4 lowest bits all zero and dropped) BR instruction in slot 2.
  IMAGE_REL_IA64_IMMGPREL64	= $001a;  // 	A 64-bit GP-relative fixup.
  IMAGE_REL_IA64_TOKEN	    = $001b;  // 	A CLR token.
  IMAGE_REL_IA64_GPREL32  	= $001c;  // 	A 32-bit GP-relative fixup.
  IMAGE_REL_IA64_ADDEND	    = $001F;  // 	The relocation is valid only when it immediately follows one of the following relocations: IMM14, IMM22, IMM64, GPREL22, LTOFF22, LTOFF64, SECREL22, SECREL64I, or SECREL32. Its value contains the addend to apply to instructions within a bundle, not for data.

  // MIPS Processors
  // The following relocation type indicators are defined for MIPS processors.
  IMAGE_REL_MIPS_ABSOLUTE	  = $0000;  // 	The relocation is ignored.
  IMAGE_REL_MIPS_REFHALF	  = $0001;  // 	The high 16 bits of the target’s 32-bit VA.
  IMAGE_REL_MIPS_REFWORD	  = $0002;  // 	The target’s 32-bit VA.
  IMAGE_REL_MIPS_JMPADDR	  = $0003;  // 	The low 26 bits of the target’s VA. This supports the MIPS J and JAL instructions.
  IMAGE_REL_MIPS_REFHI	    = $0004;  // 	The high 16 bits of the target’s 32-bit VA. This is used for the first instruction in a two-instruction sequence that loads a full address. This relocation must be immediately followed by a PAIR relocation whose SymbolTableIndex contains a signed 16-bit displacement that is added to the upper 16 bits that are taken from the location that is being relocated.
  IMAGE_REL_MIPS_REFLO	    = $0005;  // 	The low 16 bits of the target’s VA.
  IMAGE_REL_MIPS_GPREL	    = $0006;  // 	A 16-bit signed displacement of the target relative to the GP register.
  IMAGE_REL_MIPS_LITERAL	  = $0007;  // 	The same as IMAGE_REL_MIPS_GPREL.
  IMAGE_REL_MIPS_SECTION	  = $000A;  // 	The 16-bit section index of the section contains the target. This is used to support debugging information.
  IMAGE_REL_MIPS_SECREL	    = $000B;  // 	The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage.
  IMAGE_REL_MIPS_SECRELLO	  = $000C;  // 	The low 16 bits of the 32-bit offset of the target from the beginning of its section.
  IMAGE_REL_MIPS_SECRELHI	  = $000D;  // 	The high 16 bits of the 32-bit offset of the target from the beginning of its section. An IMAGE_REL_MIPS_PAIR relocation must immediately follow this one. The SymbolTableIndex of the PAIR relocation contains a signed 16-bit displacement that is added to the upper 16 bits that are taken from the location that is being relocated.
  IMAGE_REL_MIPS_JMPADDR16	= $0010;  // 	The low 26 bits of the target’s VA. This supports the MIPS16 JAL instruction.
  IMAGE_REL_MIPS_REFWORDNB	= $0022;  // 	The target’s 32-bit RVA.
  IMAGE_REL_MIPS_PAIR	      = $0025;  // 	The relocation is valid only when it immediately follows a REFHI or SECRELHI relocation. Its SymbolTableIndex contains a displacement and not an index into the symbol table.

  // Mitsubishi M32R
  // The following relocation type indicators are defined for the Mitsubishi M32R processors.
  IMAGE_REL_M32R_ABSOLUTE	= $0000;  // 	The relocation is ignored.
  IMAGE_REL_M32R_ADDR32	  = $0001;  // 	The target’s 32-bit VA.
  IMAGE_REL_M32R_ADDR32NB	= $0002;  // 	The target’s 32-bit RVA.
  IMAGE_REL_M32R_ADDR24	  = $0003;  // 	The target’s 24-bit VA.
  IMAGE_REL_M32R_GPREL16	= $0004;  // 	The target’s 16-bit offset from the GP register.
  IMAGE_REL_M32R_PCREL24	= $0005;  // 	The target’s 24-bit offset from the program counter (PC), shifted left by 2 bits and sign-extended
  IMAGE_REL_M32R_PCREL16	= $0006;  // 	The target’s 16-bit offset from the PC, shifted left by 2 bits and sign-extended
  IMAGE_REL_M32R_PCREL8 	= $0007;  // 	The target’s 8-bit offset from the PC, shifted left by 2 bits and sign-extended
  IMAGE_REL_M32R_REFHALF	= $0008;  // 	The 16 MSBs of the target VA.
  IMAGE_REL_M32R_REFHI	  = $0009;  // 	The 16 MSBs of the target VA, adjusted for LSB sign extension. This is used for the first instruction in a two-instruction sequence that loads a full 32-bit address. This relocation must be immediately followed by a PAIR relocation whose SymbolTableIndex contains a signed 16-bit displacement that is added to the upper 16 bits that are taken from the location that is being relocated.
  IMAGE_REL_M32R_REFLO	  = $000A;  // 	The 16 LSBs of the target VA.
  IMAGE_REL_M32R_PAIR	    = $000B;  // 	The relocation must follow the REFHI relocation. Its SymbolTableIndex contains a displacement and not an index into the symbol table.
  IMAGE_REL_M32R_SECTION	= $000C;  // 	The 16-bit section index of the section that contains the target. This is used to support debugging information.
  IMAGE_REL_M32R_SECREL	  = $000D;  // 	The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage.
  IMAGE_REL_M32R_TOKEN	  = $000E;  // 	The CLR token.

// 5.6.2. Base Relocation Types
  IMAGE_REL_BASED_ABSOLUTE	      = 0;  //  The base relocation is skipped. This type can be used to pad a block.
  IMAGE_REL_BASED_HIGH	          = 1;  //	The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the high value of a 32-bit word.
  IMAGE_REL_BASED_LOW	            = 2;  //	The base relocation adds the low 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the low half of a 32-bit word.
  IMAGE_REL_BASED_HIGHLOW	        = 3;  //	The base relocation applies all 32 bits of the difference to the 32-bit field at offset.
  IMAGE_REL_BASED_HIGHADJ	        = 4;  //	The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the high value of a 32-bit word. The low 16 bits of the 32-bit value are stored in the 16-bit word that follows this base relocation. This means that this base relocation occupies two slots.
  IMAGE_REL_BASED_MIPS_JMPADDR    = 5;  //  For MIPS machine types, the base relocation applies to a MIPS jump instruction.
  IMAGE_REL_BASED_ARM_MOV32A	    = 5;  //  For ARM machine types, the base relocation applies the difference to the 32-bit value encoded in the immediate fields of a contiguous MOVW+MOVT pair in ARM mode at offset.
                                //  6;  //	Reserved, must be zero.
  IMAGE_REL_BASED_ARM_MOV32T      =	7;  //	The base relocation applies the difference to the 32-bit value encoded in the immediate fields of a contiguous MOVW+MOVT pair in Thumb mode at offset.
  IMAGE_REL_BASED_MIPS_JMPADDR16  =	9;  //	The base relocation applies to a MIPS16 jump instruction.
  IMAGE_REL_BASED_DIR64	          = 10; //	The base relocation applies the difference to the 64-bit field at offset.


text:
unit PE.Types.OptionalHeader;

interface

uses
  PE.Types.Directories;

// 2.4.1. Optional Header Standard Fields (Image Only)
// 2.4.2. Optional Header Windows-Specific Fields (Image Only)
type
//  PImageOptionalHeader = ^TImageOptionalHeader;
//  TImageOptionalHeader = packed record
//     // Standard fields.
//     Magic                    : uint16;   //  0x10b: PE32
//                                          //  0x20b: PE32+
//     MajorLinkerVersion       : uint8;
//     MinorLinkerVersion       : uint8;
//     SizeOfCode               : uint32;
//     SizeOfInitializedData    : uint32;
//     SizeOfUninitializedData  : uint32;
//     AddressOfEntryPoint      : uint32;
//     BaseOfCode               : uint32;
//
//     BaseOfData               : uint32;   // PE32 only
//
//     // NT additional fields.
//     ImageBase                    : uint3264;
//     SectionAlignment             : uint32;
//     FileAlignment                : uint32;
//     MajorOperatingSystemVersion  : uint16;
//     MinorOperatingSystemVersion  : uint16;
//     MajorImageVersion            : uint16;
//     MinorImageVersion            : uint16;
//     MajorSubsystemVersion        : uint16;
//     MinorSubsystemVersion        : uint16;
//     Win32VersionValue            : uint32;
//     SizeOfImage                  : uint32;
//     SizeOfHeaders                : uint32;
//     CheckSum                     : uint32;
//     Subsystem                    : uint16;
//     DllCharacteristics           : uint16;
//     SizeOfStackReserve           : uint3264;
//     SizeOfStackCommit            : uint3264;
//     SizeOfHeapReserve            : uint3264;
//     SizeOfHeapCommit             : uint3264;
//     LoaderFlags                  : uint32;
//     NumberOfRvaAndSizes          : uint32;
//
////   DataDirectory: array [0 .. IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1] of TImageDataDirectory;
//     DataDirectories              : TImageDataDirectories;
// end;

  TImageOptionalHeader32 = packed record

     // Standard fields.
     Magic                    : uint16;   //  0x10b: PE32
                                          //  0x20b: PE32+
     MajorLinkerVersion       : uint8;
     MinorLinkerVersion       : uint8;
     SizeOfCode               : uint32;
     SizeOfInitializedData    : uint32;
     SizeOfUninitializedData  : uint32;
     AddressOfEntryPoint      : uint32;
     BaseOfCode               : uint32;

     BaseOfData               : uint32;   // PE32 only

     // NT additional fields.
     ImageBase                    : uint32;

     SectionAlignment             : uint32;
     FileAlignment                : uint32;
     MajorOperatingSystemVersion  : uint16;
     MinorOperatingSystemVersion  : uint16;
     MajorImageVersion            : uint16;
     MinorImageVersion            : uint16;
     MajorSubsystemVersion        : uint16;
     MinorSubsystemVersion        : uint16;
     Win32VersionValue            : uint32;
     SizeOfImage                  : uint32;
     SizeOfHeaders                : uint32;
     CheckSum                     : uint32;
     Subsystem                    : uint16;
     DllCharacteristics           : uint16;

     SizeOfStackReserve           : uint32;
     SizeOfStackCommit            : uint32;
     SizeOfHeapReserve            : uint32;
     SizeOfHeapCommit             : uint32;

     LoaderFlags                  : uint32;
     NumberOfRvaAndSizes          : uint32;

     //   DataDirectory: array [0 .. IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1] of TImageDataDirectory;
     DataDirectories              : TImageDataDirectories;
  end;
  PImageOptionalHeader32 = ^TImageOptionalHeader32;

  TImageOptionalHeader64 = packed record

     // Standard fields.
     Magic                    : uint16;   //  0x10b: PE32
                                          //  0x20b: PE32+
     MajorLinkerVersion       : uint8;
     MinorLinkerVersion       : uint8;
     SizeOfCode               : uint32;
     SizeOfInitializedData    : uint32;
     SizeOfUninitializedData  : uint32;
     AddressOfEntryPoint      : uint32;
     BaseOfCode               : uint32;

     // NT additional fields.
     ImageBase                    : uint64;

     SectionAlignment             : uint32;
     FileAlignment                : uint32;
     MajorOperatingSystemVersion  : uint16;
     MinorOperatingSystemVersion  : uint16;
     MajorImageVersion            : uint16;
     MinorImageVersion            : uint16;
     MajorSubsystemVersion        : uint16;
     MinorSubsystemVersion        : uint16;
     Win32VersionValue            : uint32;
     SizeOfImage                  : uint32;
     SizeOfHeaders                : uint32;
     CheckSum                     : uint32;
     Subsystem                    : uint16;
     DllCharacteristics           : uint16;

     SizeOfStackReserve           : uint64;
     SizeOfStackCommit            : uint64;
     SizeOfHeapReserve            : uint64;
     SizeOfHeapCommit             : uint64;

     LoaderFlags                  : uint32;
     NumberOfRvaAndSizes          : uint32;

     //   DataDirectory: array [0 .. IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1] of TImageDataDirectory;
     DataDirectories              : TImageDataDirectories;
  end;
  PImageOptionalHeader64 = ^TImageOptionalHeader64;

  TImageOptionalHeader = packed record
     case integer of
       32: (pe32: TImageOptionalHeader32);
       64: (pe64: TImageOptionalHeader64);
     end;

  implementation

  end.


text:
unit PE.Build;

interface

uses
  System.Classes,
  PE.Common,
  PE.Section;

{
  * Rebuild directory data.
  *
  * If TryToOverwritesection is True, it will try to put new section at
  * old section space (if new section is smaller).
  *
  * If new section is bigger than old it will be forced to create new section.
  *
  * Result is new section if it was created or nil if old section was replaced.
}
function ReBuildDirData(PE: TObject; DDIR_ID: integer; Overwrite: boolean): TPESection;

implementation

uses
  PE.Image,
  PE.Types.Directories,
  PE.Build.Common,

  PE.Build.Export,
  PE.Build.Import,
  PE.Build.Resource,
  PE.Build.Relocs;

const
  RebuilderTable: array [0 .. DDIR_LAST] of TDirectoryBuilderClass =
    (
    PE.Build.Export.TExportBuilder, // export
    PE.Build.Import.TImportBuilder, // import
    PE.Build.Resource.TRsrcBuilder, // resources
    nil,                            // exception
    nil,                            // certificate
    PE.Build.Relocs.TRelocBuilder,  // relocations
    nil,                            // debug
    nil,                            // architecture
    nil,                            // global ptr
    nil,                            // tls
    nil,                            // load config
    nil,                            // bound import
    nil,                            // iat
    nil,                            // delay import
    nil                             // clr runtime header
    );

function ReBuildDirData(PE: TObject; DDIR_ID: integer; Overwrite: boolean): TPESection;
var
  stream: TMemoryStream;
  builder: TDirectoryBuilder;
  img: TPEImage;
  sec: TPESection;
  dir: TImageDataDirectory;
  prognoseRVA, destRVA: TRVA;
  destMem: Pointer;
  destSize: uint32;
begin
  Result := nil;

  if (DDIR_ID < 0) or (DDIR_ID > High(RebuilderTable)) then
    exit; // no builder found

  if RebuilderTable[DDIR_ID] = nil then
    exit; // no builder found

  img := PE as TPEImage;

  builder := RebuilderTable[DDIR_ID].Create(img);
  stream := TMemoryStream.Create;
  try

    // Prognose dest RVA.
    if img.DataDirectories.Get(DDIR_ID, @dir) then
      prognoseRVA := dir.VirtualAddress
    else
      prognoseRVA := 0;

    // Build to get size.
    builder.Build(prognoseRVA, stream);

    sec := nil;
    destRVA := 0;  // compiler friendly
    destSize := 0; // compiler friendly

    // Try to get old section space.
    if Overwrite then
      if img.DataDirectories.Get(DDIR_ID, @dir) then
        if dir.Size >= stream.Size then
          if img.RVAToSec(dir.VirtualAddress, @sec) then
          begin
            // If directory occupies whole section.
            if (sec.RVA = dir.VirtualAddress) and (sec.RawSize = dir.Size) then
            begin
              // Leave section as it is.
            end;
            // Set dest rva/size (reuse this section).
            destRVA := dir.VirtualAddress;
            destSize := dir.Size;
          end;

    // If stream is empty, no need to rebuild anything.
    if stream.Size <> 0 then
    begin

      // If we still have no section, create new with default name and flags.
      // User can change it later.
      if sec = nil then
      begin
        sec := img.Sections.AddNew(builder.GetDefaultSectionName,
          stream.Size, builder.GetDefaultSectionFlags, nil);
        destRVA := sec.RVA;
        destSize := stream.Size;
        // Make old data directory region unused.
        if img.DataDirectories.Get(DDIR_ID, @dir) then
          img.RegionRemove(dir.VirtualAddress, dir.Size);
      end;

      // Rebuild data to have valid RVAs (if prognose is wrong)
      if builder.NeedRebuildingIfRVAChanged then
        if prognoseRVA <> destRVA then
        begin
          stream.Clear;
          builder.Build(destRVA, stream);
        end;

      // Get address where data of built directory should reside.
      destMem := img.RVAToMem(destRVA);

      // Move built data to section.
      Move(stream.Memory^, destMem^, stream.Size);
    end
    else
    begin
      // If stream size = 0
      destRVA := 0;
      destSize := 0;
    end;

    // Update directory pointer.
    img.DataDirectories.Put(DDIR_ID, destRVA, destSize);

    // For imports also update IAT table.
    if DDIR_ID = DDIR_IMPORT then
    begin
      img.DataDirectories.Put(DDIR_IAT,
        TImportBuilder(builder).BuiltIatRVA,
        TImportBuilder(builder).BuiltIatSize);
    end;

    Result := sec;

  finally
    builder.Free;
    stream.Free;
  end;
end;

end.


text:
unit PE.Resources.Windows.Strings;

interface

uses
  System.Classes,
  System.SysUtils;

type
  TStringBundleID = uint32;

  TResourceStringBundle = class
  public
    id: TStringBundleID;
    Strings: TStringList;

    function GetStringId(stringNumber: cardinal): cardinal;

    constructor Create(id: TStringBundleID);
    destructor Destroy; override;

    procedure LoadFromStream(Stream: TStream);
  end;

function BundleToStringId(bundleID: TStringBundleID): cardinal; inline;

// Parse string bundle.
function ParseStringResource(const Stream: TStream; bundleID: TStringBundleID): TResourceStringBundle;

implementation

{
  see
  https://msdn.microsoft.com/en-us/library/windows/desktop/aa381050
  http://blogs.msdn.com/b/oldnewthing/archive/2004/01/30/65013.aspx
}

// Bundle id to first string id in block of 16 strings.
function BundleToStringId(bundleID: TStringBundleID): cardinal;
begin
  if bundleID < 1 then
    raise Exception.Create('Wrong bundle id.');
  result := (bundleID - 1) * 16;
end;

{ TResourceStringBundle }

constructor TResourceStringBundle.Create(id: TStringBundleID);
begin
  self.id := id;
  self.Strings := TStringList.Create;
  self.Strings.Capacity := 16;
end;

destructor TResourceStringBundle.Destroy;
begin
  Strings.Free;
  inherited;
end;

function TResourceStringBundle.GetStringId(stringNumber: cardinal): cardinal;
begin
  result := BundleToStringId(id) + stringNumber;
end;

procedure TResourceStringBundle.LoadFromStream(Stream: TStream);
var
  dwLen: uint16;
  allocLen: integer;
  bytes: TBytes;
  str: string;
begin
  self.Strings.Clear;

  while Stream.Position < Stream.Size do
  begin
    if Stream.Read(dwLen, 2) <> 2 then
      raise Exception.Create('Failed to read string length.');

    if dwLen = 0 then
    begin
      continue;
    end;

    dwLen := dwLen * 2; // 2 bytes per char

    if length(bytes) < dwLen then
    begin
      allocLen := ((dwLen + 128) div 128) * 128;
      setlength(bytes, allocLen);
    end;

    if Stream.Read(bytes, dwLen) <> dwLen then
      raise Exception.Create('String read error.');

    str := TEncoding.Unicode.GetString(bytes, 0, dwLen);

    Strings.Add(str);
  end;
end;

function ParseStringResource(const Stream: TStream; bundleID: TStringBundleID): TResourceStringBundle;
begin
  result := TResourceStringBundle.Create(bundleID);
  try
    result.LoadFromStream(Stream);
  except
    result.Free;
    result := nil;
  end;
end;

end.


text:
unit PE.Types.ImportsDelayed;

interface

// 4.8. Delay-Load Import Tables (Image Only)
// 4.8.1. The Delay-Load Directory Table
type
  TDelayLoadDirectoryTable = packed record
  private
    function GetUsesVA: boolean; inline;
    function GetUsesRVA: boolean; inline;
    function GetEmpty: boolean; inline;
  public

    // Must be zero.
    Attributes: UInt32;

    // The RVA of the name of the DLL to be loaded. The name resides in the
    // read-only data section of the image.
    Name: UInt32;

    // The RVA of the module handle (in the data section of the image) of the
    // DLL to be delay-loaded. It is used for storage by the routine that is
    // supplied to manage delay-loading.
    ModuleHandle: UInt32;

    // The RVA of the delay-load import address table. For more information,
    // see section “Delay Import Address Table (IAT).”
    DelayImportAddressTable: UInt32;

    // The RVA of the delay-load name table, which contains the names of the
    // imports that might need to be loaded. This matches the layout of the
    // import name table. For more information, see section “Hint/Name Table.”
    DelayImportNameTable: UInt32;

    // The RVA of the bound delay-load address table, if it exists.
    BoundDelayImportTable: UInt32;

    // The RVA of the unload delay-load address table, if it exists. This is an
    // exact copy of the delay import address table. If the caller unloads
    // the DLL, this table should be copied back over the delay import address
    // table so that subsequent calls to the DLL continue to use the thunking
    // mechanism correctly.
    UnloadDelayImportTable: UInt32;

    // The timestamp of the DLL to which this image has been bound.
    TimeStamp: UInt32;

    // Check if addresses are VA/RVA (by attibute).
    property UsesVA: boolean read GetUsesVA;
    property UsesRVA: boolean read GetUsesRVA;

    property Empty: boolean read GetEmpty;
  end;

implementation

const
  FLAG_RVA = 1;

  { TDelayLoadDirectoryTable }

function TDelayLoadDirectoryTable.GetUsesVA: boolean;
begin
  Result := (Attributes and FLAG_RVA) = 0;
end;

function TDelayLoadDirectoryTable.GetUsesRVA: boolean;
begin
  Result := (Attributes and FLAG_RVA) <> 0;
end;

function TDelayLoadDirectoryTable.GetEmpty: boolean;
begin
  Result := Name = 0;
end;

end.


text:
{
  RT_VERSION resource
  http://msdn.microsoft.com/en-us/library/aa381058.aspx
}
unit PE.Resources.VersionInfo;

interface

uses
  System.Classes,
  System.SysUtils,
  System.Generics.Collections,

  PE.Common,
  PE.Utils;

{$i 'VerRsrc.inc'}

type
  TBlock = class;
  TBlockList = TObjectList<TBlock>;
  TBlockClass = class of TBlock;

  TRootBlock = class
  public
    Name: string;
    Parent: TRootBlock;
    Children: TBlockList;
    constructor Create(Parent: TRootBlock);
    destructor Destroy; override;
  end;

  TBlock = class(TRootBlock)
  private
    Size: integer;
    Offset: TFileOffset;
    ValueOffset: TFileOffset;
    ValueSize: integer;
    function GetBlockEndOffset: TFileOffset; inline;
  end;

  TBlockVersionInfo = class(TBlock)
  public
    FixedInfo: VS_FIXEDFILEINFO;
  end;

  TBlockStringInfo = class(TBlock)
  end;

  TBlockStringInfoNode = class(TBlockStringInfo)
  public
    Lang: word;
    Charset: word;
  end;

  TBlockStringInfoItems = TList<TPair<string, string>>;

  TBlockStringInfoPair = class(TBlock)
  public
    Value: string;
    property Key: string read Name;
  end;

  TBlockVarInfo = class(TBlock);

  TBlockVarTranslationInfo = class(TBlock)
  public
    langID: word;
    charsetID: word;
  end;

  TPrintFunc = reference to procedure(const Text: string);

  TPEVersionInfo = class
  private
    procedure ProcessBlocks(Stream: TStream; Blocks: TBlockList);
    procedure PrintTreeEx(n: TRootBlock; PrintFn: TPrintFunc; Indent: integer);
  public
    Root: TRootBlock;

    constructor Create;
    destructor Destroy; override;

    procedure LoadFromStream(Stream: TStream);
    procedure PrintTree(PrintFn: TPrintFunc; Indent: integer = 0);
  end;

implementation

type
  TVersionInfoBlockHeader = packed record
    Length: uint16;      // block length w/o padding
    ValueLength: uint16; // value length (optional)
    &Type: uint16;       // Value type (0: binary; 1: text)

    // Here goes value name (UTF-16, 0-terminated)
  end;

  { TPEVersionInfo }

procedure ReadStringInfoItems(Stream: TStream; EndOffset: TFileOffset);
var
  blockHdr: TVersionInfoBlockHeader;
  Key, Value: string;
  Offset: TFileOffset;
begin
  Offset := Stream.Position;
  while (Offset < EndOffset) and StreamSeek(Stream, Offset) do
  begin
    if not StreamRead(Stream, blockHdr, SizeOf(blockHdr)) then
      break;
    StreamReadStringW(Stream, Key);
    StreamSeekAlign(Stream, 4);

    if blockHdr.ValueLength <> 0 then
      StreamReadStringW(Stream, Value)
    else
      Value := '';

    Offset := AlignUp(Offset + blockHdr.Length, 4);
  end;
end;

function CreateBlockByName(const BlockName: string; Parent: TRootBlock): TBlock;
begin
  if Parent.ClassType = TBlockVarInfo then
  begin
    if BlockName = 'Translation' then
      Exit(TBlockVarTranslationInfo.Create(Parent));
  end;

  if BlockName = 'VS_VERSION_INFO' then
    Exit(TBlockVersionInfo.Create(Parent))
  else if BlockName = 'StringFileInfo' then
    Exit(TBlockStringInfo.Create(Parent))
  else if BlockName = 'VarFileInfo' then
    Exit(TBlockVarInfo.Create(Parent))
  else
    Exit(TBlock.Create(Parent));
end;

procedure ReadLevelOfBlocks(Stream: TStream; Offset, EndOffset: TFileOffset;
  var List: TBlockList;
  Parent: TRootBlock;
  BlockClass: TBlockClass = nil);
var
  blockHdr: TVersionInfoBlockHeader;
  BlockName: string;
  block: TBlock;
begin
  List.Clear;

  while (Offset < EndOffset) and StreamSeek(Stream, Offset) do
  begin
    if not StreamRead(Stream, blockHdr, SizeOf(blockHdr)) then
      break;

    if not StreamReadStringW(Stream, BlockName) then
      break;

    StreamSeekAlign(Stream, 4); // align 4

    if BlockClass = nil then
      block := CreateBlockByName(BlockName, Parent)
    else
      block := BlockClass.Create(Parent);

    block.Size := blockHdr.Length;
    block.Offset := Offset;
    block.ValueOffset := Stream.Position;
    block.ValueSize := blockHdr.ValueLength;
    block.Name := BlockName;

    List.Add(block);

    // Next block.
    Offset := AlignUp(Offset + blockHdr.Length, 4);
  end;
end;

constructor TPEVersionInfo.Create;
begin
  inherited;
  self.Root := TRootBlock.Create(nil);
end;

destructor TPEVersionInfo.Destroy;
begin
  self.Root.Free;
  inherited;
end;

procedure TPEVersionInfo.LoadFromStream;
begin
  self.Root.Children.Clear;
  ReadLevelOfBlocks(Stream, 0, Stream.Size, self.Root.Children, self.Root);
  ProcessBlocks(Stream, self.Root.Children);
end;

procedure TPEVersionInfo.PrintTree(PrintFn: TPrintFunc; Indent: integer);
begin
  PrintTreeEx(self.Root, PrintFn, Indent);
end;

procedure TPEVersionInfo.PrintTreeEx(n: TRootBlock; PrintFn: TPrintFunc;
  Indent: integer);
var
  sIndent: string;
  c: TRootBlock;
begin
  sIndent := string.Create(' ', Indent);

  if n.ClassType = TRootBlock then
    PrintFn(sIndent + 'Root')
  else if n.ClassType = TBlockVersionInfo then
    PrintFn(sIndent + 'VersionInfo')
  else if n.ClassType = TBlockStringInfo then
    PrintFn(sIndent + 'StringInfo')
  else if n.ClassType = TBlockStringInfoNode then
  begin
    PrintFn(Format('%sStringInfoNode (lang: %4.4x; charset: %4.4x)', [
      sIndent, TBlockStringInfoNode(n).Lang, TBlockStringInfoNode(n).Charset]));
  end
  else if n.ClassType = TBlockStringInfoPair then
  begin
    PrintFn(Format('%s"%s" = "%s"', [sIndent, TBlockStringInfoPair(n).Key, TBlockStringInfoPair(n).Value]));
  end
  else if n.ClassType = TBlockVarInfo then
    PrintFn(sIndent + 'VarInfo')
  else if n.ClassType = TBlockVarTranslationInfo then
    PrintFn(Format('%sTranslation, landID=%x, charsetID=%x', [
      sIndent, TBlockVarTranslationInfo(n).langID, TBlockVarTranslationInfo(n).charsetID]))
  else
    PrintFn(Format('%s%s(%s)', [sIndent, n.Name, n.ClassName]));

  for c in n.Children do
    PrintTreeEx(c, PrintFn, Indent + 2);
end;

procedure TPEVersionInfo.ProcessBlocks(Stream: TStream; Blocks: TBlockList);
var
  n: TBlock;
begin
  for n in Blocks do
  begin
    if n.ClassType = TBlockVersionInfo then
    begin
      // value
      if n.ValueSize < SizeOf(VS_FIXEDFILEINFO) then
        raise Exception.Create('Version Info resource: size for VS_FIXEDFILEINFO is too low.');
      if not StreamSeek(Stream, n.ValueOffset) then
        raise Exception.Create('Failed to seek offset of VS_FIXEDFILEINFO.');
      if not StreamRead(Stream, TBlockVersionInfo(n).FixedInfo, SizeOf(VS_FIXEDFILEINFO)) then
        raise Exception.Create('Failed to read VS_FIXEDFILEINFO.');

      // sub-nodes
      ReadLevelOfBlocks(Stream, AlignUp(Stream.Position, 4), n.GetBlockEndOffset, n.Children, n);
      ProcessBlocks(Stream, n.Children);
    end
    else if n.ClassType = TBlockStringInfo then
    begin
      ReadLevelOfBlocks(Stream, AlignUp(n.ValueOffset, 4), n.GetBlockEndOffset, n.Children, n, TBlockStringInfoNode);
      ProcessBlocks(Stream, n.Children);
    end
    else if n.ClassType = TBlockStringInfoNode then
    begin
      // lang
      TBlockStringInfoNode(n).Lang := StrToInt('$' + copy(n.Name, 1, 4));
      // charset
      TBlockStringInfoNode(n).Charset := StrToInt('$' + copy(n.Name, 5, 4));
      // sub-nodes
      ReadLevelOfBlocks(Stream, AlignUp(n.ValueOffset, 4), n.GetBlockEndOffset, n.Children, n, TBlockStringInfoPair);
      ProcessBlocks(Stream, n.Children);
    end
    else if n.ClassType = TBlockStringInfoPair then
    begin
      if n.ValueSize <> 0 then
      begin
        Stream.Position := n.ValueOffset;
        StreamReadStringW(Stream, TBlockStringInfoPair(n).Value);
      end;
    end
    else if n.ClassType = TBlockVarInfo then
    begin
      ReadLevelOfBlocks(Stream, AlignUp(n.ValueOffset, 4), n.GetBlockEndOffset, n.Children, n);
      ProcessBlocks(Stream, n.Children);
    end
    else if n.ClassType = TBlockVarTranslationInfo then
    begin
      if n.ValueSize >= 4 then
      begin
        Stream.Position := n.ValueOffset;
        StreamRead(Stream, TBlockVarTranslationInfo(n).langID, 2);
        StreamRead(Stream, TBlockVarTranslationInfo(n).charsetID, 2);
      end;
    end
    else
      ProcessBlocks(Stream, n.Children);
  end;
end;

{ TRootBlock }

constructor TRootBlock.Create(Parent: TRootBlock);
begin
  inherited Create;
  self.Parent := Parent;
  self.Children := TBlockList.Create;
end;

destructor TRootBlock.Destroy;
begin
  self.Children.Free;
  inherited;
end;

{ TBlock }

function TBlock.GetBlockEndOffset: TFileOffset;
begin
  result := self.Offset + self.Size;
end;

end.


text:
unit PE.Parser.Relocs;

interface

uses
  PE.Common,
  PE.Types,
  PE.Types.Directories,
  PE.Types.Relocations;

type
  TPERelocParser = class(TPEParser)
  public
    function Parse: TParserResult; override;
  end;

implementation

uses
  PE.Image;

{ TRelocParser }

function TPERelocParser.Parse: TParserResult;
var
  dir: TImageDataDirectory;
  block: TBaseRelocationBlock;
  blCnt, iBlock: Integer;
  entry: TBaseRelocationEntry;
  r_ofs, r_type: dword;
  r_rva: dword;
  Ofs: dword;
  reloc: TReloc;
  PE: TPEImage;
var
  tmpRVA: TRVA;
begin
  PE := TPEImage(FPE);
  PE.Relocs.Clear;

  if not PE.DataDirectories.Get(DDIR_RELOCATION, @dir) then
    exit(PR_OK);

  if dir.IsEmpty then
    exit(PR_OK);

  if not PE.SeekRVA(dir.VirtualAddress) then
  begin
    PE.Msg.Write(SCategoryRelocs, 'Bad directory RVA (0x%x)', [dir.VirtualAddress]);
    exit(PR_ERROR);
  end;

  Ofs := 0;

  while (Ofs < dir.Size) do
  begin
    tmpRVA := PE.PositionRVA;

    if (not PE.ReadEx(@block, SizeOf(block))) then
      break;

    if Assigned(PE.ParseCallbacks) then
      PE.ParseCallbacks.ParsedRelocationBlockHeader(tmpRVA, block);

    if block.IsEmpty then
      break;

    inc(Ofs, SizeOf(block));

    if block.BlockSize < SizeOf(TBaseRelocationBlock) then
    begin
      PE.Msg.Write(SCategoryRelocs, 'Bad size of block (%d).', [block.BlockSize]);
      continue;
    end;

    blCnt := block.Count;

    for iBlock := 0 to blCnt - 1 do
    begin
      if (Ofs + SizeOf(entry)) > dir.Size then
      begin
        PE.Msg.Write(SCategoryRelocs, 'Relocation is out of table. PageRVA:0x%x #:%d', [block.PageRVA, iBlock]);
        PE.Msg.Write(SCategoryRelocs, 'Skipping next relocs.');
        exit(PR_OK);
      end;

      if not PE.ReadEx(@entry, SizeOf(entry)) then
        exit(PR_ERROR);

      inc(Ofs, SizeOf(entry));
      r_type := entry.GetType;
      r_ofs := entry.GetOffset;
      r_rva := r_ofs + block.PageRVA;
      if r_type <> IMAGE_REL_BASED_ABSOLUTE then
      begin
        reloc.RVA := r_rva;
        reloc.&Type := r_type;
        PE.Relocs.Put(reloc);
      end;
    end;
  end;

  exit(PR_OK);
end;

end.


text:
unit PE.Parser.Export;

interface

uses
  PE.Common,
  PE.Types,
  PE.Types.Directories,
  PE.Types.Export;

type
  TPEExportParser = class(TPEParser)
  public
    function Parse: TParserResult; override;
  end;

implementation

uses
  PE.Image,
  PE.ExportSym;

{ TPEExportParser }

function TPEExportParser.Parse: TParserResult;
var
  PE: TPEImage;
  ExpIDD: TImageDataDirectory;
  ExpDir: TImageExportDirectory;
  i, base: uint32;
  ordnl: uint16;
  RVAs: array of uint32;
  NamePointerRVAs: array of uint32;
  OrdinalTableRVAs: array of uint16;
  Exp: array of TPEExportSym;
  Item: TPEExportSym;
begin
  PE := TPEImage(FPE);

  // Clear exports.
  PE.ExportSyms.Clear;

  // Get export dir.
  if not PE.DataDirectories.Get(DDIR_EXPORT, @ExpIDD) then
    exit(PR_OK);

  // No exports is ok.
  if ExpIDD.IsEmpty then
    exit(PR_OK);

  // If can't find Export dir, failure.
  if not PE.SeekRVA(ExpIDD.VirtualAddress) then
    exit(PR_ERROR);

  // If can't read whole table, failure.
  if not PE.ReadEx(@ExpDir, Sizeof(ExpDir)) then
  begin
    PE.Msg.Write('Export Parser: not enough space to read dir. header.');
    exit(PR_ERROR);
  end;

  // If no addresses, ok.
  if ExpDir.AddressTableEntries = 0 then
  begin
    PE.Msg.Write('Export Parser: directory present, but there are no functions.');
    exit(PR_OK);
  end;

  if ExpDir.ExportFlags <> 0 then
  begin
    PE.Msg.Write('Export Parser: reserved directory flags <> 0');
    exit(PR_ERROR);
  end;

  // Read lib exported name.
  if (ExpDir.NameRVA <> 0) then
  begin
    if not PE.SeekRVA(ExpDir.NameRVA) then
    begin
      PE.Msg.Write('Export Parser: Wrong RVA of dll exported name = 0x%x', [ExpDir.NameRVA]);
      exit(PR_ERROR);
    end;
    PE.ExportedName := PE.ReadAnsiString;
  end;

  base := ExpDir.OrdinalBase;

  // Check if there's too many exports.
  if (ExpDir.AddressTableEntries >= SUSPICIOUS_MIN_LIMIT_EXPORTS) or
    (ExpDir.NumberOfNamePointers >= SUSPICIOUS_MIN_LIMIT_EXPORTS) then
  begin
    exit(PR_SUSPICIOUS);
  end;

  SetLength(Exp, ExpDir.AddressTableEntries);
  SetLength(RVAs, ExpDir.AddressTableEntries);

  // load RVAs of exported data
  if not(PE.SeekRVA(ExpDir.ExportAddressTableRVA) and
    PE.ReadEx(@RVAs[0], 4 * ExpDir.AddressTableEntries)) then
    exit(PR_ERROR);

  if ExpDir.NumberOfNamePointers <> 0 then
  begin
    // name/ordinal only
    SetLength(NamePointerRVAs, ExpDir.NumberOfNamePointers);
    SetLength(OrdinalTableRVAs, ExpDir.NumberOfNamePointers);

    // load RVAs of name pointers
    if not((PE.SeekRVA(ExpDir.NamePointerRVA)) and
      PE.ReadEx(@NamePointerRVAs[0], 4 * ExpDir.NumberOfNamePointers)) then
      exit(PR_ERROR);

    // load ordinals according to names
    if not((PE.SeekRVA(ExpDir.OrdinalTableRVA)) and
      PE.ReadEx(@OrdinalTableRVAs[0], 2 * ExpDir.NumberOfNamePointers)) then
      exit(PR_ERROR);
  end;

  if ExpDir.AddressTableEntries <> 0 then
  begin
    for i := 0 to ExpDir.AddressTableEntries - 1 do
    begin
      Item := TPEExportSym.Create;
      Item.Ordinal := i + base;
      Item.RVA := RVAs[i];

      Exp[i] := Item;

      // if rva in export section, it's forwarder
      Exp[i].Forwarder := ExpIDD.Contain(RVAs[i]);
    end;
  end;

  // read names
  if ExpDir.NumberOfNamePointers <> 0 then
  begin
    for i := 0 to ExpDir.NumberOfNamePointers - 1 do
    begin
      if (NamePointerRVAs[i] <> 0) then
      begin
        ordnl := OrdinalTableRVAs[i];

        // Check if ordinal is correct.
        if ordnl >= length(Exp) then
          continue;

        if not Exp[ordnl].IsValid then
          continue;

        // Read export name.
        if not PE.SeekRVA(NamePointerRVAs[i]) then
          exit(PR_ERROR);

        Exp[ordnl].Name := PE.ReadAnsiString;

        // Read forwarder, if it is.
        if Exp[ordnl].Forwarder then
        begin
          // if it is forwarder, rva will point inside of export dir.
          if not PE.SeekRVA(Exp[ordnl].RVA) then
            exit(PR_ERROR);
          Exp[ordnl].ForwarderName := PE.ReadAnsiString;
          Exp[ordnl].RVA := 0; // no real address
        end;

      end;
    end;
  end;

  // finally array to list
  for i := low(Exp) to high(Exp) do
    if Exp[i].IsValid then
      PE.ExportSyms.Add(Exp[i])
    else
      Exp[i].Free;

  exit(PR_OK);
end;

end.


text:
unit PE.Types.Export;

interface

uses
  PE.Common;

type
  TImageExportDirectory = packed record
    ExportFlags:           uint32;     //  Reserved, must be 0.
    TimeDateStamp:         uint32;     //  The time and date that the export data was created.
    MajorVersion:          uint16;     //  The major version number.
                                       //  The major and minor version numbers can be set by the user.
    MinorVersion:          uint16;     //  The minor version number.
    NameRVA:               uint32;     //  The address of the ASCII string that contains the name of the DLL.
                                       //  This address is relative to the image base.
    OrdinalBase:           uint32;     //  The starting ordinal number for exports in this image.
                                       //  This field specifies the starting ordinal number for the export address table.
                                       //  It is usually set to 1.
    AddressTableEntries:   uint32;     //  NumberOfFunctions; The number of entries in the export address table.
    NumberOfNamePointers:  uint32;     //  The number of entries in the name pointer table.
                                       //  This is also the number of entries in the ordinal table.
    ExportAddressTableRVA: uint32;     //  The address of the export address table, relative to the image base.
    NamePointerRVA:        uint32;     //  The address of the export name pointer table, relative to the image base.
                                       //  The table size is given by the Number of Name Pointers field.
    OrdinalTableRVA:       uint32;     //  The address of the ordinal table, relative to the image base.
  end;

  PImageExportDirectory = ^TImageExportDirectory;

implementation

end.


text:
unit PE.Types.NTHeaders;

interface

uses
  PE.Types.FileHeader,
  PE.Types.OptionalHeader;

type
{
  TImageNTHeaders32 = packed record
    Signature: uint32;
    FileHeader: TImageFileHeader;
    OptionalHeader: TImageOptionalHeader32;
  end;

  PImageNTHeaders32 = ^TImageNTHeaders32;

  TImageNTHeaders64 = packed record
    Signature: uint32;
    FileHeader: TImageFileHeader;
    OptionalHeader: TImageOptionalHeader64;
  end;

  PImageNTHeaders64 = ^TImageNTHeaders64;
}

  TNTSignature = record
  public
    function IsPE00: boolean; inline;
  public
    case integer of
      0:
        (chars: array [0 .. 3] of AnsiChar);
  end;

  TImageNTHeaders = packed record
    Signature: TNTSignature;
    FileHeader: TImageFileHeader;
    OptionalHeader: TImageOptionalHeader;
  end;

  PImageNTHeaders = ^TImageNTHeaders;

const
  PE00_SIGNATURE: TNTSignature = (chars: 'PE'#0#0);

implementation

{ TNTSignature }

function TNTSignature.IsPE00: boolean;
begin
  result := self.chars = PE00_SIGNATURE.chars;
end;

end.


text:
unit PE.Parser.ImportDelayed;

interface

uses
  System.Generics.Collections,
  System.SysUtils,

  PE.Common,
  PE.Imports,
  PE.Types,
  PE.Types.Directories,
  PE.Types.FileHeader, // expand TPEImage.Is32bit
  PE.Types.Imports,
  PE.Types.ImportsDelayed,
  PE.Utils;

type
  TPEImportDelayedParser = class(TPEParser)
  public
    function Parse: TParserResult; override;
  end;

implementation

uses
  PE.Image,
  PE.Imports.Func,
  PE.Imports.Lib;

// Testing mode: check if read fields are correct.
function ParseTable(
  const PE: TPEImage;
  const Table: TDelayLoadDirectoryTable;
  Testing: boolean
  ): boolean;
var
  DllName: string;
  FnName: string;
  Fn: TPEImportFunctionDelayed;
  HintNameRva: TRVA;
  Ilt: TImportLookupTable;
  iFunc: uint32;
var
  iLen: integer;
  Ordinal: UInt16;
  Hint: UInt16 absolute Ordinal;
  Iat: TRVA;
  SubValue: uint32;
  Lib: TPEImportLibrary;
begin
  if Table.UsesVA then
    SubValue := PE.ImageBase
  else
    SubValue := 0;

  if Testing then
  begin
    if (Table.Name = 0) or (Table.Name < SubValue) then
    begin
      PE.Msg.Write('Delayed Import: Name address incorrect.');
      exit(false);
    end;

    if (Table.DelayImportNameTable = 0) or (Table.DelayImportNameTable < SubValue) then
    begin
      PE.Msg.Write('Delayed Import: Name table address incorrect.');
      exit(false);
    end;

    if (Table.DelayImportAddressTable = 0) or (Table.DelayImportAddressTable < SubValue) then
    begin
      PE.Msg.Write('Delayed Import: Address table incorrect.');
      exit(false);
    end;
  end;

  if not PE.SeekRVA(Table.Name - SubValue) then
    exit(false);

  if not PE.ReadAnsiStringLen(MAX_PATH_WIN, iLen, DllName) then
    exit(false);

  if not Testing then
  begin
    Lib := TPEImportLibrary.Create(DllName, False, True);
    PE.ImportsDelayed.Add(Lib);
  end
  else
  begin
    Lib := nil; // compiler friendly
  end;

  iFunc := 0;
  Iat := Table.DelayImportAddressTable - SubValue;

  while PE.SeekRVA(Table.DelayImportNameTable - SubValue + iFunc * PE.ImageWordSize) do
  begin
    HintNameRva := PE.ReadWord();
    if HintNameRva = 0 then
      break;

    Ilt.Create(HintNameRva, PE.Is32bit);

    Ordinal := 0;
    FnName := '';

    if Ilt.IsImportByOrdinal then
    begin
      // Import by ordinal only. No hint/name.
      Ordinal := Ilt.OrdinalNumber;
    end
    else
    begin
      // Import by name. Get hint/name
      if not PE.SeekRVA(HintNameRva - SubValue) then
      begin
        PE.Msg.Write('Delayed Import: incorrect Hint/Name RVA encountered.');
        exit(false);
      end;

      Hint := PE.ReadWord(2);
      FnName := PE.ReadANSIString;
    end;

    if not Testing then
    begin
      Fn := TPEImportFunctionDelayed.Create(FnName, Ordinal);
      Lib.Functions.Add(Fn);
    end;

    inc(Iat, PE.ImageWordSize);
    inc(iFunc);
  end;

  exit(true);
end;

function TPEImportDelayedParser.Parse: TParserResult;
var
  PE: TPEImage;
  ddir: TImageDataDirectory;
  ofs: uint32;
  Table: TDelayLoadDirectoryTable;
  Tables: TList<TDelayLoadDirectoryTable>;
  TablesUseRVA: boolean;
begin
  PE := TPEImage(FPE);

  result := PR_ERROR;

  // If no imports, it's ok.
  if not PE.DataDirectories.Get(DDIR_DELAYIMPORT, @ddir) then
    exit(PR_OK);
  if ddir.IsEmpty then
    exit(PR_OK);

  // Seek import dir.
  if not PE.SeekRVA(ddir.VirtualAddress) then
    exit;

  Tables := TList<TDelayLoadDirectoryTable>.Create;
  try

    // Delay-load dir. tables.
    ofs := 0;
    TablesUseRVA := true; // default, compiler-friendly
    while true do
    begin
      if ofs > ddir.Size then
        exit(PR_ERROR);

      if not PE.ReadEx(Table, SizeOf(Table)) then
        break;

      if Table.Empty then
        break;

      // Attribute:
      // 0: addresses are VA (old VC6 binaries)
      // 1: addresses are RVA

      if (ofs = 0) then
      begin
        TablesUseRVA := Table.UsesRVA; // initialize once
      end
      else if TablesUseRVA <> Table.UsesRVA then
      begin
        // Normally all tables must use either VA or RVA. No mix allowed.
        // If mix found it must be not real table.
        // For example, some Delphi versions used such optimization.
        break;
      end;

      Tables.Add(Table);
      inc(ofs, SizeOf(Table));
    end;

    // Parse tables.
    for Table in Tables do
      // First test if fields are correct
      if ParseTable(PE, Table, true) then
        // Then do real reading.
        ParseTable(PE, Table, false);

    exit(PR_OK);
  finally
    Tables.Free;
  end;
end;

end.


text:
{
  *
  * Class for X86, X86-64 specifics.
  *
}
unit PE.Image.x86;

interface

uses
  System.Generics.Collections,
  System.SysUtils,
  PE.Common,
  PE.Image,
  PE.Section;

type
  // Buf points to data which should be matched.
  // Set MatchedSize to size of matched sequence. If nothing matched don't set it.
  // VA is address to be matched.
  // Size is size left in scanned region you can check starting from VA.
  TPatternMatchFunc = reference to procedure(VA: TVA; Size: integer; Buf: PByte; var MatchedSize: integer);

  TPEImageX86 = class(TPEImage)
  protected
    // Find relative jump or call in section, e.g e8,x,x,x,x or e9,x,x,x,x.
    // List must be created before passing it to the function.
    // Found VAs will be appended to list.
    function FindRelativeJumpInternal(
      const Sec: TPESection;
      ByteOpcode: Byte;
      TargetVA: TVA;
      const List: TList<TVA>): boolean;
  public
    function FindRelativeJump(
      const Sec: TPESection;
      TargetVA: TVA;
      const List: TList<TVA>): boolean;

    function FindRelativeCall(
      const Sec: TPESection;
      TargetVA: TVA;
      const List: TList<TVA>): boolean;

    // Fill Count bytes at VA with nops (0x90).
    // Result is number of nops written.
    function Nop(VA: TVA; Count: integer = 1): UInt32;

    // Nop range.
    // BeginVA: inclusive
    // EndVA: exclusive
    function NopRange(BeginVA, EndVA: TVA): UInt32; inline;

    // Nop Call or Jump.
    function NopCallOrJump(VA: TVA): boolean;

    // Write call or jump, like:
    // E8/E9 xx xx xx xx
    // IsCall: True - call, False - jump.
    function WriteRelCallOrJump(SrcVA, DstVA: TVA; IsCall: boolean): boolean;

    // Perform custom pattern matching scan for Sec section.
    // All found addresses are stored in List (if it is not nil, otherwise
    // user must handle it manually).
    // PatternMatchFunc function used to match pattern.
    // VA0, Size define range (optional). Whole section is scanned by default.
    function ScanRange(
      const Sec: TPESection;
      PatternMatchFunc: TPatternMatchFunc;
      const List: TList<TVA> = nil;
      VA: TVA = 0;
      Size: integer = 0
      ): boolean;
  end;

implementation

const
  OPCODE_NOP      = $90;
  OPCODE_CALL_REL = $E8;
  OPCODE_JUMP_REL = $E9;

  { TPEImageX86 }

function TPEImageX86.FindRelativeCall(
  const Sec: TPESection;
  TargetVA: TVA;
  const List: TList<TVA>): boolean;
begin
  Result := FindRelativeJumpInternal(Sec, OPCODE_CALL_REL, TargetVA, List);
end;

function TPEImageX86.FindRelativeJump(
  const Sec: TPESection;
  TargetVA: TVA;
  const List: TList<TVA>): boolean;
begin
  Result := FindRelativeJumpInternal(Sec, OPCODE_JUMP_REL, TargetVA, List);
end;

function TPEImageX86.FindRelativeJumpInternal(
  const Sec: TPESection;
  ByteOpcode: Byte;
  TargetVA: TVA;
  const List: TList<TVA>): boolean;
var
  curVa, VA0, VA1, tstVa: TVA;
  delta: int32;
  opc: Byte;
begin
  Result := False;

  VA0 := RVAToVA(Sec.RVA);
  VA1 := RVAToVA(Sec.GetEndRVA - SizeOf(ByteOpcode) - SizeOf(delta));

  if not SeekVA(VA0) then
    exit(False);

  while self.PositionVA <= VA1 do
  begin
    curVa := self.PositionVA;

    // get opcode
    if Read(@opc, SizeOf(ByteOpcode)) <> SizeOf(ByteOpcode) then
      exit;
    if opc = ByteOpcode then
    // on found probably jmp/call
    begin
      delta := int32(ReadUInt32);
      tstVa := curVa + SizeOf(ByteOpcode) + SizeOf(delta) + delta;
      if tstVa = TargetVA then
      begin // hit
        List.Add(curVa);
        Result := True; // at least 1 result is ok
      end
      else
      begin
        if not SeekVA(curVa + SizeOf(ByteOpcode)) then
          exit;
      end;
    end;
  end;
end;

function TPEImageX86.Nop(VA: TVA; Count: integer): UInt32;
begin
  Result := Sections.FillMemory(VAToRVA(VA), Count, OPCODE_NOP);
end;

function TPEImageX86.NopRange(BeginVA, EndVA: TVA): UInt32;
begin
  if EndVA > BeginVA then
    Result := Nop(BeginVA, EndVA - BeginVA)
  else
    Result := 0;
end;

function TPEImageX86.ScanRange(
  const Sec: TPESection;
  PatternMatchFunc: TPatternMatchFunc;
  const List: TList<TVA>;
  VA: TVA;
  Size: integer): boolean;
var
  Buf: PByte;
  MatchedSize: integer;
begin
  // Define range.
  if VA = 0 then
    VA := RVAToVA(Sec.RVA);
  if Size = 0 then
    Size := Sec.VirtualSize;

  // Start scan at VA0.
  Buf := self.VAToMem(VA);
  if Buf = nil then
    exit(False); // such address not found

  while Size > 0 do
  begin
    MatchedSize := 0;
    PatternMatchFunc(VA, Size, Buf, MatchedSize);
    if MatchedSize <> 0 then
    begin
      if Assigned(List) then
        List.Add(VA);
    end
    else
      MatchedSize := 1;

    inc(Buf, MatchedSize);
    inc(VA, MatchedSize);
    dec(Size, MatchedSize);
  end;

  exit(True);
end;

function TPEImageX86.NopCallOrJump(VA: TVA): boolean;
begin
  Result := Sections.FillMemoryEx(VAToRVA(VA), 5, True, OPCODE_NOP) = 5;
end;

function TPEImageX86.WriteRelCallOrJump(SrcVA, DstVA: TVA; IsCall: boolean): boolean;
type
  TJump = packed record
    Opcode: Byte;
    delta: integer;
  end;
var
  jmp: TJump;

begin
  if IsCall then
    jmp.Opcode := OPCODE_CALL_REL
  else
    jmp.Opcode := OPCODE_JUMP_REL;
  jmp.delta := DstVA - (SrcVA + SizeOf(TJump));
  self.PositionVA := SrcVA;
  Result := self.WriteEx(@jmp, SizeOf(TJump));
end;

end.