unit PEInfoFunctions;

{$MODE Delphi}

{
This unit will contain all functions used for PE-header inspection
}

{$warn 4056 off}

interface

uses
  {$ifdef windows}
  windows,
  {$endif}
  LCLIntf,SysUtils,classes, CEFuncProc,NewKernelHandler,filemapping, commonTypeDefs;


const
  IMAGE_DOS_SIGNATURE                     = $5A4D;      { MZ }
  IMAGE_OS2_SIGNATURE                     = $454E;      { NE }
  IMAGE_OS2_SIGNATURE_LE                  = $454C;      { LE }
  IMAGE_VXD_SIGNATURE                     = $454C;      { LE }
  IMAGE_NT_SIGNATURE                      = $00004550;  { PE00 }

const
  IMAGE_SIZEOF_FILE_HEADER                 = 20;

  IMAGE_FILE_RELOCS_STRIPPED               = $0001;  { Relocation info stripped from file. }
  IMAGE_FILE_EXECUTABLE_IMAGE              = $0002;  { File is executable  (i.e. no unresolved externel references). }
  IMAGE_FILE_LINE_NUMS_STRIPPED            = $0004;  { Line nunbers stripped from file. }
  IMAGE_FILE_LOCAL_SYMS_STRIPPED           = $0008;  { Local symbols stripped from file. }
  IMAGE_FILE_AGGRESIVE_WS_TRIM             = $0010;  { Agressively trim working set }
  IMAGE_FILE_BYTES_REVERSED_LO             = $0080;  { Bytes of machine word are reversed. }
  IMAGE_FILE_32BIT_MACHINE                 = $0100;  { 32 bit word machine. }
  IMAGE_FILE_DEBUG_STRIPPED                = $0200;  { Debugging info stripped from file in .DBG file }
  IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP       = $0400;  { If Image is on removable media, copy and run from the swap file. }
  IMAGE_FILE_NET_RUN_FROM_SWAP             = $0800;  { If Image is on Net, copy and run from the swap file. }
  IMAGE_FILE_SYSTEM                        = $1000;  { System File. }
  IMAGE_FILE_DLL                           = $2000;  { File is a DLL. }
  IMAGE_FILE_UP_SYSTEM_ONLY                = $4000;  { File should only be run on a UP machine }
  IMAGE_FILE_BYTES_REVERSED_HI             = $8000;  { Bytes of machine word are reversed. }

  IMAGE_FILE_MACHINE_UNKNOWN               = 0;
  IMAGE_FILE_MACHINE_I386                  = $14c;   { Intel 386. }
  IMAGE_FILE_MACHINE_R3000                 = $162;   { MIPS little-endian, 0x160 big-endian }
  IMAGE_FILE_MACHINE_R4000                 = $166;   { MIPS little-endian }
  IMAGE_FILE_MACHINE_R10000                = $168;   { MIPS little-endian }
  IMAGE_FILE_MACHINE_ALPHA                 = $184;   { Alpha_AXP }
  IMAGE_FILE_MACHINE_POWERPC               = $1F0;   { IBM PowerPC Little-Endian }

  IMAGE_SIZEOF_SECTION_HEADER              = 40;
   {$EXTERNALSYM IMAGE_SIZEOF_SECTION_HEADER}


   IMAGE_SCN_TYPE_NO_PAD                    = $00000008;  { Reserved. }
   IMAGE_SCN_CNT_CODE                       = $00000020;  { Section contains code. }
   IMAGE_SCN_CNT_INITIALIZED_DATA           = $00000040;  { Section contains initialized data. }
   IMAGE_SCN_CNT_UNINITIALIZED_DATA         = $00000080;  { Section contains uninitialized data. }

   IMAGE_SCN_LNK_OTHER                      = $00000100;  { Reserved. }
   IMAGE_SCN_LNK_INFO                       = $00000200;  { Section contains comments or some other type of information. }
   IMAGE_SCN_LNK_REMOVE                     = $00000800;  { Section contents will not become part of image. }
   IMAGE_SCN_LNK_COMDAT                     = $00001000;  { Section contents comdat. }
   IMAGE_SCN_MEM_FARDATA                    = $00008000;
   IMAGE_SCN_MEM_PURGEABLE                  = $00020000;
   IMAGE_SCN_MEM_16BIT                      = $00020000;
   IMAGE_SCN_MEM_LOCKED                     = $00040000;
   IMAGE_SCN_MEM_PRELOAD                    = $00080000;

   IMAGE_SCN_ALIGN_1BYTES                   = $00100000;
   IMAGE_SCN_ALIGN_2BYTES                   = $00200000;
   IMAGE_SCN_ALIGN_4BYTES                   = $00300000;
   IMAGE_SCN_ALIGN_8BYTES                   = $00400000;
   IMAGE_SCN_ALIGN_16BYTES                  = $00500000;  { Default alignment if no others are specified. }
   IMAGE_SCN_ALIGN_32BYTES                  = $00600000;
   IMAGE_SCN_ALIGN_64BYTES                  = $00700000;

   IMAGE_SCN_LNK_NRELOC_OVFL                = $01000000;  { Section contains extended relocations. }
   IMAGE_SCN_MEM_DISCARDABLE                = $02000000;  { Section can be discarded. }
   IMAGE_SCN_MEM_NOT_CACHED                 = $04000000;  { Section is not cachable. }
   IMAGE_SCN_MEM_NOT_PAGED                  = $08000000;  { Section is not pageable. }
   IMAGE_SCN_MEM_SHARED                     = $10000000;  { Section is shareable. }
   IMAGE_SCN_MEM_EXECUTE                    = $20000000;  { Section is executable. }
   IMAGE_SCN_MEM_READ                       = $40000000;  { Section is readable. }
   IMAGE_SCN_MEM_WRITE                      = DWORD($80000000);  { Section is writeable. }



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


type PUINT64=^UINT64;
type TUINT64Array=array[0..0] of UINT64;
type PUINT64Array=^TDwordArray;

type TImportEntry=packed record
  xxx: word;
  name: pchar;
end;
type PInportEntry=^TImportEntry;


type TImageImportDirectory=record
  characteristicsOrFirstThunk: dword;  //0 for terminating null import descriptor || RVA to original unbound IAT (PIMAGE_THUNK_DATA)
  TimeDateStamp: dword;
  ForwarderChain: dword; //-1 if none
  Name: dword;
  FirstThunk: dword;
end;
type PImageImportDirectory=^TImageImportDirectory;

PImageExportDirectory = ^TImageExportDirectory;
_IMAGE_EXPORT_DIRECTORY = packed record
    Characteristics: DWord;      //0-3
    TimeDateStamp: DWord;        //4-7
    MajorVersion: Word;          //8-9
    MinorVersion: Word;          //a-b
    Name: DWord;                 //c-f
    Base: DWord;                 //10-13
    NumberOfFunctions: DWord;    //14-17
    NumberOfNames: DWord;        //18-1b
    AddressOfFunctions: DWORD;   //1c-1f
    AddressOfNames: DWORD;       //20-23
    AddressOfNameOrdinals: DWORD;//24-27
end;
TImageExportDirectory = _IMAGE_EXPORT_DIRECTORY;
IMAGE_EXPORT_DIRECTORY = _IMAGE_EXPORT_DIRECTORY;

PImageNtHeaders = ^TImageNtHeaders;
_IMAGE_NT_HEADERS = packed record
  Signature: DWORD;
  FileHeader: TImageFileHeader;
  OptionalHeader: TImageOptionalHeader;
end;
TImageNtHeaders = _IMAGE_NT_HEADERS;
IMAGE_NT_HEADERS = _IMAGE_NT_HEADERS;


type TIMAGE_BASE_RELOCATION=record
  virtualaddress: dword;
  SizeOfBlock: dword;
  rel: TWordArray;
end;
type PIMAGE_BASE_RELOCATION=^TIMAGE_BASE_RELOCATION;


TISHMisc = packed record
  case Integer of
    0: (PhysicalAddress: DWORD);
    1: (VirtualSize: DWORD);
end;

PImageSectionHeader = ^TImageSectionHeader;
_IMAGE_SECTION_HEADER = packed record
  Name: packed array[0..IMAGE_SIZEOF_SHORT_NAME-1] of Byte;
  Misc: TISHMisc;
  VirtualAddress: DWORD;
  SizeOfRawData: DWORD;
  PointerToRawData: DWORD;
  PointerToRelocations: DWORD;
  PointerToLinenumbers: DWORD;
  NumberOfRelocations: Word;
  NumberOfLinenumbers: Word;
  Characteristics: DWORD;
end;
TImageSectionHeader = _IMAGE_SECTION_HEADER;
IMAGE_SECTION_HEADER = _IMAGE_SECTION_HEADER;

PImageDosHeader = ^TImageDosHeader;
_IMAGE_DOS_HEADER = packed record      { DOS .EXE header                  }
    e_magic: Word;                     { Magic number                     }
    e_cblp: Word;                      { Bytes on last page of file       }
    e_cp: Word;                        { Pages in file                    }
    e_crlc: Word;                      { Relocations                      }
    e_cparhdr: Word;                   { Size of header in paragraphs     }
    e_minalloc: Word;                  { Minimum extra paragraphs needed  }
    e_maxalloc: Word;                  { Maximum extra paragraphs needed  }
    e_ss: Word;                        { Initial (relative) SS value      }
    e_sp: Word;                        { Initial SP value                 }
    e_csum: Word;                      { Checksum                         }
    e_ip: Word;                        { Initial IP value                 }
    e_cs: Word;                        { Initial (relative) CS value      }
    e_lfarlc: Word;                    { File address of relocation table }
    e_ovno: Word;                      { Overlay number                   }
    e_res: array [0..3] of Word;       { Reserved words                   }
    e_oemid: Word;                     { OEM identifier (for e_oeminfo)   }
    e_oeminfo: Word;                   { OEM information; e_oemid specific}
    e_res2: array [0..9] of Word;      { Reserved words                   }
    _lfanew: LongInt;                  { File address of new exe header   }
end;
TImageDosHeader = _IMAGE_DOS_HEADER;
IMAGE_DOS_HEADER = _IMAGE_DOS_HEADER;


(*
typedef struct IMAGE_COR20_HEADER
{
    // Header versioning
    DWORD                   cb;
    WORD                    MajorRuntimeVersion;
    WORD                    MinorRuntimeVersion;

    // Symbol table and startup information
    IMAGE_DATA_DIRECTORY    MetaData;
    DWORD                   Flags;

    // If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is not set, EntryPointToken represents a managed entrypoint.
    // If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is set, EntryPointRVA represents an RVA to a native entrypoint.
    union {
        DWORD               EntryPointToken;
        DWORD               EntryPointRVA;
    } DUMMYUNIONNAME;

    // Binding information
    IMAGE_DATA_DIRECTORY    Resources;
    IMAGE_DATA_DIRECTORY    StrongNameSignature;

    // Regular fixup and binding information
    IMAGE_DATA_DIRECTORY    CodeManagerTable;
    IMAGE_DATA_DIRECTORY    VTableFixups;
    IMAGE_DATA_DIRECTORY    ExportAddressTableJumps;

    // Precompiled image info (internal use only - set to zero)
    IMAGE_DATA_DIRECTORY    ManagedNativeHeader;

} IMAGE_COR20_HEADER, *PIMAGE_COR20_HEADER;

*)
TImageCLRRuntimeDirectory=record
  cb: DWORD;
  MajorRuntimeVersion: WORD;
  MinorRuntimeVersion: WORD;
  MetaData: IMAGE_DATA_DIRECTORY;
  Flags: DWORD;
  EntryPointTokenOrRVA: DWORD;
  Resources: IMAGE_DATA_DIRECTORY;
  StrongNameSignature: IMAGE_DATA_DIRECTORY;
  CodeManagerTable: IMAGE_DATA_DIRECTORY;
  VTableFixups: IMAGE_DATA_DIRECTORY;
  ExportAddressTableJumps: IMAGE_DATA_DIRECTORY;
  ManagedNativeHeader: IMAGE_DATA_DIRECTORY;
end;

PImageCLRRuntimeDirectory=^TImageCLRRuntimeDirectory;


type
  TRunTimeEntry=packed record
    start: dword;
    stop: dword;
    unwind: dword;
  end;
  PRuntimeEntry=^TRunTimeEntry;

  TRunTimeList=array [0..10000] of TRunTimeEntry;
  PRuntimeList=^TRuntimeList;

  TExceptionList=class
  private
    fmodulebase: ptruint;
    exceptionAddress: ptruint;
    size: integer;


    list: PRuntimeList;
    function getEntry(index: integer): TRunTimeEntry;
    function getCount: integer;
  public
    function getRunTimeEntry(address: ptruint): PRuntimeEntry;
    constructor create(modulebase: ptruint; ela: ptruint; els: integer);
    destructor destroy; override;
    property ModuleBase: ptruint read fModuleBase;
    property Count: integer read getCount;
    property Entry[index: integer]: TRunTimeEntry read getEntry; default;


  end;



function peinfo_getImageNtHeaders(headerbase: pointer; maxsize: dword):PImageNtHeaders;
function peinfo_getExportList(filename: string; dllList: Tstrings): boolean; overload;
function peinfo_getExportList(modulebase: ptruint; dllList: Tstrings): boolean; overload;
function peinfo_is64bitfile(filename: string; var is64bit: boolean): boolean;
function peinfo_isdotnetfile(filename: string; var isdotnet: boolean): boolean;
function peinfo_getimagesizefromfile(filename: string; var size: dword): boolean;

function peinfo_getExceptionList(modulebase: ptruint): TExceptionList;
     {$endif}


implementation

{$ifdef windows}
uses ProcessHandlerUnit;


function peinfo_getImageDosHeader(headerbase: pointer):PImageDosHeader;
{
basicly returns the headerbase, or returns nil if it isn't a valid MZ header
}
begin
  if PImageDosHeader(headerbase)^.e_magic<>IMAGE_DOS_SIGNATURE then
    result:=nil
  else
    result:=headerbase;
end;

function peinfo_getImageNtHeaders(headerbase: pointer; maxsize: dword):PImageNtHeaders;
{
Returns the base of the NT Headers
Returns nil if nto a valid exe/pe
}
var DH: PImageDosHeader;
    NTH: PImageNtHeaders;
begin
  result:=nil;
  DH:=peinfo_getImageDosHeader(headerbase);
  if dh=nil then exit;

  if DH^._lfanew>maxsize then exit; //out of range
  
  NTH:=PImageNtHeaders(ptrUint(headerbase)+DH^._lfanew);
  if NTH^.Signature<>IMAGE_NT_SIGNATURE then exit;

  result:=NTH;
end;

function peinfo_getOptionalHeaders(headerbase: pointer; maxsize: dword): pointer;
{
Returns a pointer to the optional header.
Can return that of both 64-bit and 32-bit
}
var NTH: PImageNtHeaders;
begin
  result:=nil;
  NTH:=peinfo_getImageNtHeaders(headerbase,maxsize);
  if NTH=nil then exit;

  result:=@NTH^.OptionalHeader;
end;

function peinfo_getImageSectionHeader(headerbase: pointer; maxsize: dword): PImageSectionHeader;
var NTH: PImageNtHeaders;
    ISH: PImageSectionHeader;
begin
  result:=nil;
  NTH:=peinfo_getImageNtHeaders(headerbase,maxsize);
  if NTH=nil then exit;

  ISH:=PImageSectionHeader(ptrUint(@NTH^.OptionalHeader)+NTH^.FileHeader.SizeOfOptionalHeader);

  if (ptrUint(ISH)-ptrUint(headerbase))>maxsize then exit; //overflow
  result:=ISH;
end;

function peinfo_VirtualAddressToFileAddress(header: pointer; maxsize: dword; VirtualAddress: dword): pointer;
{
Go through the sections to find out where this virtual address belongs and return the offset starting from the header, offset 0
}
var i: integer;
    ImageNTHeader: PImageNtHeaders;
    ImageSectionHeader: PImageSectionHeader;
begin
  result:=nil;
  ImageNTHeader:=peinfo_getImageNtHeaders(header,maxsize);
  if ImageNTHeader=nil then exit;

  //het the pointer to the first imagesection header
  ImageSectionHeader:=peinfo_getImageSectionHeader(header,maxsize);
  for i:=0 to ImageNTHeader^.FileHeader.NumberOfSections-1 do
  begin
    if (VirtualAddress>=ImageSectionHeader.VirtualAddress) and (VirtualAddress<(ImageSectionHeader.VirtualAddress+ImageSectionHeader.SizeOfRawData)) then
    begin
      //found it
      if ImageSectionHeader.PointerToRawData+(VirtualAddress-ImageSectionHeader.VirtualAddress)>maxsize then exit; //too big

      //set the found address
      result:=pointer(ptrUint(header)+ImageSectionHeader.PointerToRawData+(VirtualAddress-ImageSectionHeader.VirtualAddress));
      exit;
    end;
    inc(ImageSectionHeader); //next one
  end;
end;

resourcestring
  strInvalidFile='Invalid file';
  rsPEIFNoExports = 'No exports';


function TExceptionList.getRunTimeEntry(address: ptruint): PRunTimeEntry;
var
  i, count: integer;
begin
  //todo: use a sorted scan
  result:=nil;
  count:=size div 12;

  address:=address-ModuleBase;

  for i:=0 to count-1 do
  begin
    if InRangeQ(address, list^[i].start, list^[i].stop-1) then
      exit(@list^[i]);
  end;
end;


function TExceptionList.getEntry(index: integer): TRunTimeEntry;
begin
  if index<count then
    result:=list[index]
  else
    raise exception.create('Invalid index');
end;

function TExceptionList.getCount: integer;
begin
  result:=size div 12;
end;

constructor TExceptionList.create(modulebase: ptruint; ela: ptruint; els: integer);
var br: ptruint;
begin
  fmodulebase:=modulebase;
  exceptionAddress:=ela;
  size:=els;

  getmem(list,size);

  readprocessmemory(processhandle, pointer(modulebase+exceptionAddress), list, size,br);

  size:=br;
end;

destructor TExceptionList.destroy;
begin
  freemem(list);
  inherited destroy;
end;

function peinfo_getExceptionList(modulebase: ptruint): TExceptionList;
var
  ar: ptruint;
  header: pointer;
  ImageNtHeader: PImageNtHeaders;
  OptionalHeader: PImageOptionalHeader;
  OptionalHeader64: PImageOptionalHeader64 absolute OptionalHeader;
  is64bit: boolean;
begin
  result:=nil;
  getmem(header, 8192);
  try
    if readProcessMemory(processhandle, pointer(modulebase),header, 8192, ar)=false then exit;
    ImageNtHeader:=peinfo_getImageNtHeaders(header, 8192);
    if ImageNTHeader=nil then exit;
    is64bit:=ImageNTHeader^.FileHeader.Machine=$8664;

    if is64bit=false then exit;


    OptionalHeader:=peinfo_getOptionalHeaders(header, 8192);
    if OptionalHeader=nil then exit;

    if OptionalHeader64^.DataDirectory[3].VirtualAddress<>0 then
      result:=TExceptionList.Create(modulebase, OptionalHeader64^.DataDirectory[3].VirtualAddress, OptionalHeader64^.DataDirectory[3].Size);

  finally
    freemem(header);
  end;
end;

function peinfo_getExportList(modulebase: ptruint; dllList: Tstrings): boolean;
var
    header: pointer;
    ImageNtHeader: PImageNtHeaders;
    OptionalHeader: PImageOptionalHeader;
    OptionalHeader64: PImageOptionalHeader64 absolute OptionalHeader;
    ImageExportDirectory: PImageExportDirectory;
    is64bit: boolean;

    addresslist: PDwordArray;
    exportlist: PDwordArray;
    functionname: pchar;
    i: integer;
    ar:ptruint;

    imagesize: dword;
begin
  result:=false;

  getmem(header, 4096);
  try
    if readProcessMemory(processhandle, pointer(modulebase),header, 4096, ar)=false then raise exception.create('Invalid memory address');

    ImageNtHeader:=peinfo_getImageNtHeaders(header, 4096);
    if ImageNTHeader=nil then raise exception.create(strInvalidFile);
    is64bit:=ImageNTHeader^.FileHeader.Machine=$8664;

    OptionalHeader:=peinfo_getOptionalHeaders(header, 4096);
    if OptionalHeader=nil then raise exception.create(strInvalidFile);

    imagesize:=OptionalHeader.SizeOfImage;
    freemem(header);
    getmem(header,imagesize);
    ar:=0;
    if readProcessMemory(processhandle, pointer(modulebase),header, imagesize, ar)=false then
    begin
      imagesize:=ar;
      if imagesize=0 then raise exception.create('Invalid header');
    end;

    ImageNtHeader:=peinfo_getImageNtHeaders(header, imagesize);
    OptionalHeader:=peinfo_getOptionalHeaders(header, imagesize);



    if ImageNTHeader=nil then raise exception.Create(strInvalidFile);
    if OptionalHeader=nil then raise exception.Create(strInvalidFile);

    if is64bit then
      ImageExportDirectory:=PImageExportDirectory(ptruint(header)+OptionalHeader64^.DataDirectory[0].VirtualAddress)
    else
      ImageExportDirectory:=PImageExportDirectory(ptruint(header)+OptionalHeader^.DataDirectory[0].VirtualAddress);


    if (ptruint(ImageExportDirectory)<=ptruint(header)) or (ptruint(ImageExportDirectory)>=(ptruint(header)+imagesize)) then
      raise exception.create(rsPEIFNoExports);

    exportlist:=PDWordArray(ptruint(header)+dword(ImageExportDirectory^.AddressOfNames));
    addresslist:=PDWordArray(ptruint(header)+dword(ImageExportDirectory^.AddressOfFunctions));

    if (ptruint(exportlist)<=ptruint(header)) or (ptruint(exportlist)>=(ptruint(header)+imagesize)) then
      raise exception.create(rsPEIFNoExports);

    if (ptruint(addresslist)<=ptruint(header)) or (ptruint(addresslist)>=(ptruint(header)+imagesize)) then
      raise exception.create(rsPEIFNoExports);


    for i:=0 to ImageExportDirectory.NumberOfNames-1 do
    begin
      functionname:=pchar(ptruint(header)+exportlist[i]);

      if functionname<>nil then
        dllList.AddObject(functionname, pointer(ptruint(modulebase+addresslist[i])));
    end;
    result:=true;
  finally
    if header<>nil then
      freemem(header);
  end;
end;


function peinfo_getExportList(filename: string; dllList: Tstrings): boolean;
var fmap: TFileMapping;
    header: pointer;
    ImageNtHeader: PImageNtHeaders;
    OptionalHeader: PImageOptionalHeader;
    OptionalHeader64: PImageOptionalHeader64 absolute OptionalHeader;
    ImageExportDirectory: PImageExportDirectory;
    is64bit: boolean;

    addresslist: PDwordArray;
    exportlist: PDwordArray;
    functionname: pchar;
    i: integer;

    ordinaloffset: integer;

   // a: dword;
begin
  //open the file
  //parse the header
  //get rva 0
  //write rva0 to list
  result:=false;

  fmap:=TFileMapping.create(filename);
  if fmap<>nil then
  begin
    try
      header:=fmap.fileContent;

      ImageNtHeader:=peinfo_getImageNtHeaders(header,fmap.filesize);


      if ImageNTHeader=nil then raise exception.Create(strInvalidFile);
      if ImageNTHeader^.FileHeader.Machine=$8664 then
        is64bit:=true
      else
        is64bit:=false;

      OptionalHeader:=peinfo_getOptionalHeaders(header,fmap.filesize);
      if OptionalHeader=nil then raise exception.Create(strInvalidFile);

      if is64bit then
        ImageExportDirectory:=peinfo_VirtualAddressToFileAddress(header, fmap.filesize, OptionalHeader64^.DataDirectory[0].VirtualAddress)
      else
        ImageExportDirectory:=peinfo_VirtualAddressToFileAddress(header, fmap.filesize, OptionalHeader^.DataDirectory[0].VirtualAddress);

      if ImageExportDirectory=nil then raise exception.Create(rsPEIFNoExports);

      exportlist:=peinfo_VirtualAddressToFileAddress(header,fmap.filesize, dword(ImageExportDirectory.AddressOfNames));
      addresslist:=peinfo_VirtualAddressToFileAddress(header,fmap.filesize, dword(ImageExportDirectory.AddressOfFunctions));

      if exportlist=nil then raise exception.Create(rsPEIFNoExports);

      if ImageExportDirectory.NumberOfFunctions>ImageExportDirectory.NumberOfNames then
      begin
        ordinaloffset:=ImageExportDirectory.NumberOfFunctions-ImageExportDirectory.NumberOfNames;
        for i:=0 to ordinaloffset-1 do
          dllList.AddObject('Ordinal'+inttostr(ImageExportDirectory.Base+i), pointer(ptruint(addresslist[i])));
      end
      else
        ordinaloffset:=0;

      for i:=0 to ImageExportDirectory.NumberOfNames-1 do
      begin
        functionname:=peinfo_VirtualAddressToFileAddress(header,fmap.filesize, exportlist[i]);

        if functionname<>nil then
          dllList.AddObject(functionname, pointer(ptruint(addresslist[ordinaloffset+i])));
      end;
      result:=true;

    finally
      fmap.free;
    end;

  end;
end;

function peinfo_getimagesizefromfile(filename: string; var size: dword): boolean;
var
  fmap: TFileMapping;
  header: pointer;
  ImageNtHeader: PImageNtHeaders;
  OptionalHeader: PImageOptionalHeader;
  OptionalHeader64: PImageOptionalHeader64 absolute OptionalHeader;
begin
  result:=false;

  try
    fmap:=TFileMapping.create(filename);
    if fmap<>nil then
    begin
      try
        header:=fmap.fileContent;
        ImageNtHeader:=peinfo_getImageNtHeaders(header,fmap.filesize);
        OptionalHeader:=peinfo_getOptionalHeaders(header,fmap.filesize);
        if ImageNTHeader=nil then raise exception.Create(strInvalidFile);
        if ImageNTHeader^.FileHeader.Machine=$8664 then
          size:=OptionalHeader64.SizeOfImage
        else
          size:=OptionalHeader.SizeOfImage;

        result:=true; //success
      finally
        fmap.free;
      end;

    end;
  except

  end;
end;

function peinfo_isdotnetfile(filename: string; var isdotnet: boolean): boolean;
var fmap: TFileMapping;
    header: pointer;
    OptionalHeader: PImageOptionalHeader;
    OptionalHeader64: PImageOptionalHeader64 absolute OptionalHeader;
    is64bit: boolean;
    ImageNtHeader: PImageNtHeaders;
    netdata: dword;
begin
  result:=false;

  try
    fmap:=TFileMapping.create(filename);
    if fmap<>nil then
    begin
      try
        header:=fmap.fileContent;
        ImageNtHeader:=peinfo_getImageNtHeaders(header,fmap.filesize);
        if ImageNTHeader=nil then raise exception.Create(strInvalidFile);
        if ImageNTHeader^.FileHeader.Machine=$8664 then
          is64bit:=true
        else
          is64bit:=false;

        OptionalHeader:=peinfo_getOptionalHeaders(header,fmap.filesize);
        if OptionalHeader<>nil then
        begin
          if is64bit then
            netdata:=OptionalHeader64.DataDirectory[14].Size
          else
            netdata:=OptionalHeader.DataDirectory[14].Size;

          isdotnet:=netdata<>0;
          result:=true;
        end;
      finally
        fmap.free;
      end;

    end;
  except

  end;
end;

function peinfo_is64bitfile(filename: string; var is64bit: boolean): boolean;
var fmap: TFileMapping;
    header: pointer;
    ImageNtHeader: PImageNtHeaders;
begin
  //open the file
  //parse the header
  //fill in is64bit and return true.
  //On exception, false

  result:=false;

  try

    fmap:=TFileMapping.create(filename);
    if fmap<>nil then
    begin
      try
        header:=fmap.fileContent;
        ImageNtHeader:=peinfo_getImageNtHeaders(header,fmap.filesize);
        if ImageNTHeader=nil then raise exception.Create(strInvalidFile);
        if ImageNTHeader^.FileHeader.Machine=$8664 then
          is64bit:=true
        else
          is64bit:=false;

        result:=true; //success

      finally
        fmap.free;
      end;

    end;
  except

  end;
end;

{$endif}


end.


