2004. április 27., kedd

Get the list of function that an executable file imports


Problem/Question/Abstract:

How to get the list of functions that an executable file imports as well as other information like the dlls from which the program imports these functions.

Answer:

The following program shows how you can get the list of functions imported by the executable file. It consists of two units the first one is the 'structures' unit which is required by the program unit

Here is the code

Structures File

unit structures;

interface
uses Windows, sysutils;
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 }

  IMAGE_SIZEOF_SHORT_NAME = 8;
  IMAGE_SIZEOF_SECTION_HEADER = 40;
  IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
  IMAGE_RESOURCE_NAME_IS_STRING = $80000000;
  IMAGE_RESOURCE_DATA_IS_DIRECTORY = $80000000;
  IMAGE_OFFSET_STRIP_HIGH = $7FFFFFFF;
  DIRECTORY_ENTRY_EXPORT = 0; // Export Directory
  IMAGE_DIRECTORY_ENTRY_IMPORT = 1; // Import Directory
  IMAGE_DIRECTORY_ENTRY_RESOURCE = 2; // Resource Directory
  IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3; // Exception Directory
  IMAGE_DIRECTORY_ENTRY_SECURITY = 4; // Security Directory
  IMAGE_DIRECTORY_ENTRY_BASERELOC = 5; // Base Relocation Table
  IMAGE_DIRECTORY_ENTRY_DEBUG = 6; // Debug Directory
  IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7; // Description String
  IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8; // Machine Value (MIPS GP)
  IMAGE_DIRECTORY_ENTRY_TLS = 9; // TLS Directory
  IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10; // Load Configuration Directory
  IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11; // Bound Import Directory in headers
  IMAGE_DIRECTORY_ENTRY_IAT = 12;

type
  plist_entry = ^LIST_ENTRY;
  LIST_ENTRY = record
    Flink: pLIST_ENTRY;
    Blink: pLIST_ENTRY;
  end;

type
  IMAGE_EXPORT_DIRECTORY = packed record
    Characteristics: DWORD;
    TimeDateStamp: DWORD;
    MajorVersion: WORD;
    MinorVersion: WORD;
    Name: DWORD;
    Base: DWORD;
    NumberOfFunctions: DWORD;
    NumberOfNames: DWORD;
    pAddressOfFunctions: PDWORD;
    pAddressOfNames: PDWORD;
    pAddressOfNameOrdinals: PWORD;
  end;
  PIMAGE_EXPORT_DIRECTORY = ^IMAGE_EXPORT_DIRECTORY;

type
  FPO_DATA = packed record
    ulOffStart: DWORD; // offset 1st byte of function code
    cbProcSize: DWORD; // # bytes in function
    cdwLocals: DWORD; // # bytes in locals/4
    cdwParams: WORD; // # bytes in params/4
    cbProlog: WORD; // # bytes in prolog
    cbRegs: WORD; // # regs saved
    fHasSEH: WORD; // TRUE if SEH in func
    fUseBP: WORD; // TRUE if EBP has been allocated
    reserved: WORD; // reserved for future use
    cbFrame: WORD; // frame type
  end;
  PFPO_DATA = ^FPO_DATA;

type
  IMAGE_FUNCTION_ENTRY = packed record
    StartingAddress: dword;
    EndingAddress: dword;
    EndOfPrologue: dword;
  end;
  PIMAGE_FUNCTION_ENTRY = ^IMAGE_FUNCTION_ENTRY;

type
  PIMAGE_DOS_HEADER = ^IMAGE_DOS_HEADER;
  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: packed 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: packed array[0..9] of WORD; { Reserved words }
    e_lfanew: Longint; { File address of new exe header }
  end;

  PIMAGE_FILE_HEADER = ^IMAGE_FILE_HEADER;
  IMAGE_FILE_HEADER = packed record
    Machine: WORD;
    NumberOfSections: WORD;
    TimeDateStamp: DWORD;
    PointerToSymbolTable: DWORD;
    NumberOfSymbols: DWORD;
    SizeOfOptionalHeader: WORD;
    Characteristics: WORD;
  end;

  PIMAGE_DATA_DIRECTORY = ^IMAGE_DATA_DIRECTORY;
  IMAGE_DATA_DIRECTORY = packed record
    VirtualAddress: DWORD;
    Size: DWORD;
  end;

  PIMAGE_OPTIONAL_HEADER = ^IMAGE_OPTIONAL_HEADER;
  IMAGE_OPTIONAL_HEADER = 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: DWORD;
    SectionAlignment: DWORD;
    FileAlignment: DWORD;
    MajorOperatingSystemVersion: WORD;
    MinorOperatingSystemVersion: WORD;
    MajorImageVersion: WORD;
    MinorImageVersion: WORD;
    MajorSubsystemVersion: WORD;
    MinorSubsystemVersion: WORD;
    Reserved1: DWORD;
    SizeOfImage: DWORD;
    SizeOfHeaders: DWORD;
    CheckSum: DWORD;
    Subsystem: WORD;
    DllCharacteristics: WORD;
    SizeOfStackReserve: DWORD;
    SizeOfStackCommit: DWORD;
    SizeOfHeapReserve: DWORD;
    SizeOfHeapCommit: DWORD;
    LoaderFlags: DWORD;
    NumberOfRvaAndSizes: DWORD;
    DataDirectory: packed array[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1] of
      IMAGE_DATA_DIRECTORY;
  end;

  PIMAGE_SECTION_HEADER = ^IMAGE_SECTION_HEADER;
  IMAGE_SECTION_HEADER = packed record
    Name: packed array[0..IMAGE_SIZEOF_SHORT_NAME - 1] of Char;
    PhysicalAddress: DWORD; // or VirtualSize (union);
    VirtualAddress: DWORD;
    SizeOfRawData: DWORD;
    PointerToRawData: DWORD;
    PointerToRelocations: DWORD;
    PointerToLinenumbers: DWORD;
    NumberOfRelocations: WORD;
    NumberOfLinenumbers: WORD;
    Characteristics: DWORD;
  end;

  PIMAGE_NT_HEADERS = ^IMAGE_NT_HEADERS;
  IMAGE_NT_HEADERS = packed record
    Signature: DWORD;
    FileHeader: IMAGE_FILE_HEADER;
    OptionalHeader: IMAGE_OPTIONAL_HEADER;
  end;

  PIMAGE_RESOURCE_DIRECTORY = ^IMAGE_RESOURCE_DIRECTORY;
  IMAGE_RESOURCE_DIRECTORY = packed record
    Characteristics: DWORD;
    TimeDateStamp: DWORD;
    MajorVersion: WORD;
    MinorVersion: WORD;
    NumberOfNamedEntries: WORD;
    NumberOfIdEntries: WORD;
  end;

  PIMAGE_RESOURCE_DIRECTORY_ENTRY = ^IMAGE_RESOURCE_DIRECTORY_ENTRY;
  IMAGE_RESOURCE_DIRECTORY_ENTRY = packed record
    Name: DWORD; // Or ID: Word (Union)
    OffsetToData: DWORD;
  end;

  PIMAGE_RESOURCE_DATA_ENTRY = ^IMAGE_RESOURCE_DATA_ENTRY;
  IMAGE_RESOURCE_DATA_ENTRY = packed record
    OffsetToData: DWORD;
    Size: DWORD;
    CodePage: DWORD;
    Reserved: DWORD;
  end;

  PIMAGE_RESOURCE_DIR_STRING_U = ^IMAGE_RESOURCE_DIR_STRING_U;
  IMAGE_RESOURCE_DIR_STRING_U = packed record
    Length: WORD;
    NameString: array[0..0] of WCHAR;
  end;

type
  LOADED_IMAGE = record
    ModuleName: pchar;
    hFile: thandle;
    MappedAddress: pchar;
    FileHeader: PIMAGE_NT_HEADERS;
    LastRvaSection: PIMAGE_SECTION_HEADER;
    NumberOfSections: integer;
    Sections: PIMAGE_SECTION_HEADER;
    Characteristics: integer;
    fSystemImage: boolean;
    fDOSImage: boolean;
    Links: LIST_ENTRY;
    SizeOfImage: integer;
  end;
  PLOADED_IMAGE = ^LOADED_IMAGE;

type
  IMAGE_LOAD_CONFIG_DIRECTORY = packed record
    Characteristics: DWORD;
    TimeDateStamp: DWORD;
    MajorVersion: WORD;
    MinorVersion: WORD;
    GlobalFlagsClear: DWORD;
    GlobalFlagsSet: DWORD;
    CriticalSectionDefaultTimeout: DWORD;
    DeCommitFreeBlockThreshold: DWORD;
    DeCommitTotalFreeThreshold: DWORD;
    LockPrefixTable: Pointer;
    MaximumAllocationSize: DWORD;
    VirtualMemoryThreshold: DWORD;
    ProcessHeapFlags: DWORD;
    ProcessAffinityMask: DWORD;
    Reserved: array[0..2] of DWORD;
  end;
  PIMAGE_LOAD_CONFIG_DIRECTORY = ^IMAGE_LOAD_CONFIG_DIRECTORY;

type
  IMAGE_IMPORT_BY_NAME = packed record
    Hint: WORD;
    Name: DWORD;
  end;
  PIMAGE_IMPORT_BY_NAME = ^IMAGE_IMPORT_BY_NAME;

type
  IMAGE_THUNK_DATA = packed record
    ForwarderString: PBYTE;
    Func: PDWORD;
    Ordinal: DWORD;
    AddressOfData: PIMAGE_IMPORT_BY_NAME;
  end;
  PIMAGE_THUNK_DATA = ^IMAGE_THUNK_DATA;

type
  IMAGE_IMPORT_DESCRIPTOR = packed record
    Characteristics: DWORD;
    TimeDateStamp: DWORD;
    ForwarderChain: DWORD;
    Name: DWORD;
    FirstThunk: DWORD;
  end;
  PIMAGE_IMPORT_DESCRIPTOR = ^IMAGE_IMPORT_DESCRIPTOR;

implementation

end.

Code File

unit p1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, structures;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    procedure ProcessFile;
  end;

var
  Form1: TForm1;
  h1, hmap: integer;
  bptr: pointer;
  gptr: pbyte;
  ntsign: plongword;
  doshd: PIMAGE_DOS_HEADER;
  pehd: PIMAGE_FILE_HEADER;
  peoptn: PIMAGE_OPTIONAL_HEADER;
  sectionheads: array of PIMAGE_SECTION_HEADER;
  offsetmem: longword;
  idataphysicaladress: pbyte;
  idata: PIMAGE_IMPORT_DESCRIPTOR;
  modulename, functionname: pchar;
  dptr: plongword;
  ord: word;
  pexpdir: PIMAGE_EXPORT_DIRECTORY;
  pexpnames: pdword;
  expfname: pchar;
implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
  processfile;
end;

procedure TForm1.ProcessFile;
var
  i, j: integer;
begin
  if opendialog1.Execute = false then
    exit
  else
    h1 := fileopen(opendialog1.FileName, fmShareDenyNone or fmOpenRead);
  hmap := CreateFileMapping(h1, nil, PAGE_READONLY, 0, 0, nil);
  doshd := PIMAGE_DOS_HEADER(mapviewoffile(hmap, FILE_MAP_READ, 0, 0, 0));
  bptr := doshd;
  memo1.lines.add('DOS Header');
  memo1.Lines.Add(' -e_magic=' + inttostr(doshd.e_magic));
  memo1.Lines.Add(' -e_cblp=' + inttostr(doshd.e_cblp));
  memo1.Lines.Add(' -e_cp=' + inttostr(doshd.e_cp));
  memo1.Lines.Add(' -e_crlc=' + inttostr(doshd.e_crlc));
  memo1.Lines.Add(' -e_cparhdr=' + inttostr(doshd.e_cparhdr));
  memo1.Lines.Add(' -e_minalloc=' + inttostr(doshd.e_minalloc));
  memo1.Lines.Add(' -e_maxalloc=' + inttostr(doshd.e_maxalloc));
  memo1.Lines.Add(' -e_ss=' + inttostr(doshd.e_ss));
  memo1.Lines.Add(' -e_sp=' + inttostr(doshd.e_sp));
  memo1.Lines.Add(' -e_csum=' + inttostr(doshd.e_csum));
  memo1.Lines.Add(' -e_ip=' + inttostr(doshd.e_ip));
  memo1.Lines.Add(' -e_cs=' + inttostr(doshd.e_cs));
  memo1.Lines.Add(' -e_lfarlc=' + inttostr(doshd.e_lfarlc));
  memo1.Lines.Add(' -e_ovno=' + inttostr(doshd.e_ovno));
  memo1.Lines.Add(' -e_oemid=' + inttostr(doshd.e_oemid));
  memo1.Lines.Add(' -e_oeminfo=' + inttostr(doshd.e_oeminfo));
  memo1.Lines.Add(' -e_lfanew=' + inttostr(doshd.e_lfanew));
  gptr := bptr;
  inc(gptr, doshd.e_lfanew);
  ntsign := plongword(gptr);
  if (ntsign^ = IMAGE_NT_SIGNATURE) then
  begin
    memo1.Lines.Add('NT Signature<' + inttostr(IMAGE_NT_SIGNATURE) + '>=' +
      inttostr(ntsign^));
    memo1.Lines.Add('Windows Executable');
    memo1.lines.add('------------------------------------------');
    gptr := bptr;
    inc(gptr, doshd.e_lfanew + 4);
    pehd := PIMAGE_FILE_HEADER(gptr);
    memo1.lines.add('PE Header');
    memo1.Lines.Add(' -Machine=' + inttostr(pehd.Machine));
    memo1.Lines.Add(' -Number of Sections=' + inttostr(pehd.NumberOfSections));
    memo1.Lines.Add(' -TimeDateStamp=' + IntToStr(pehd.TimeDateStamp));
    memo1.Lines.Add(' -PointerToSymbolTable=' + IntToStr(pehd.PointerToSymbolTable));
    memo1.Lines.Add(' -Number of Symbols=' + IntToStr(pehd.NumberOfSymbols));
    memo1.Lines.Add(' -SizeOfOptionalHeader=' + IntToStr(pehd.SizeOfOptionalHeader));
    memo1.Lines.Add(' -Characteristics=' + IntToStr(pehd.Characteristics));
    memo1.lines.add('------------------------------------------');
    gptr := pbyte(pehd);
    inc(gptr, sizeof(IMAGE_FILE_HEADER));
    peoptn := PIMAGE_OPTIONAL_HEADER(gptr);
    memo1.lines.add('PE Optional Header');
    memo1.Lines.Add(' -Magic=' + inttostr(peoptn.Magic));
    memo1.Lines.Add(' -MajorLinkerVersion=' + inttostr(peoptn.MajorLinkerVersion));
    memo1.Lines.Add(' -MinorLinkerVersion=' + inttostr(peoptn.MinorLinkerVersion));
    memo1.Lines.Add(' -SizeOfCode=' + inttostr(peoptn.SizeOfCode));
    memo1.Lines.Add(' -SizeOfInitializedData=' +
      inttostr(peoptn.SizeOfInitializedData));
    memo1.Lines.Add(' -SizeOfUninitializedData=' +
      inttostr(peoptn.SizeOfUninitializedData));
    memo1.Lines.Add(' -AddressOfEntryPoint=' + inttostr(peoptn.AddressOfEntryPoint));
    memo1.Lines.Add(' -BaseOfCode=' + inttostr(peoptn.BaseOfCode));
    memo1.Lines.Add(' -BaseOfData=' + inttostr(peoptn.BaseOfData));
    memo1.Lines.Add(' -ImageBase=' + inttostr(peoptn.ImageBase));
    memo1.Lines.Add(' -SectionAlignment=' + inttostr(peoptn.SectionAlignment));
    memo1.Lines.Add(' -FileAlignment=' + inttostr(peoptn.FileAlignment));
    memo1.Lines.Add(' -MajorOperatingSystemVersion=' +
      inttostr(peoptn.MajorOperatingSystemVersion));
    memo1.Lines.Add(' -MinorOperatingSystemVersion=' +
      inttostr(peoptn.MinorOperatingSystemVersion));
    memo1.Lines.Add(' -MajorImageVersion=' + inttostr(peoptn.MajorImageVersion));
    memo1.Lines.Add(' -MinorImageVersion=' + inttostr(peoptn.MinorImageVersion));
    memo1.Lines.Add(' -MajorSubsystemVersion=' +
      inttostr(peoptn.MajorSubsystemVersion));
    memo1.Lines.Add(' -MinorSubsystemVersion =' +
      inttostr(peoptn.MinorSubsystemVersion));
    memo1.Lines.Add(' -Reserved1 =' + inttostr(peoptn.Reserved1));
    memo1.Lines.Add(' -SizeOfImage =' + inttostr(peoptn.SizeOfImage));
    memo1.Lines.Add(' -SizeOfHeaders =' + inttostr(peoptn.SizeOfHeaders));
    memo1.Lines.Add(' -CheckSum =' + inttostr(peoptn.CheckSum));
    memo1.Lines.Add(' -SubSystem =' + inttostr(peoptn.Subsystem));
    memo1.Lines.Add(' -DllCharacteristics =' + inttostr(peoptn.DllCharacteristics));
    memo1.Lines.Add(' -SizeOfStackReserve =' + inttostr(peoptn.SizeOfStackReserve));
    memo1.Lines.Add(' -SizeOfStackCommit =' + inttostr(peoptn.SizeOfStackCommit));
    memo1.Lines.Add(' -SizeOfHeapReserve =' + inttostr(peoptn.SizeOfHeapReserve));
    memo1.Lines.Add(' -SizeOfHeapCommit =' + inttostr(peoptn.SizeOfHeapCommit));
    memo1.Lines.Add(' -LoaderFlags =' + inttostr(peoptn.LoaderFlags));
    memo1.Lines.Add(' -NumberOfRvaAndSizes =' + inttostr(peoptn.NumberOfRvaAndSizes));
    memo1.lines.add('------------------------------------------');
    setlength(sectionheads, pehd.NumberOfSections);
    for i := 0 to pehd.NumberOfSections - 1 do
    begin
      gptr := pbyte(peoptn);
      inc(gptr, sizeof(IMAGE_OPTIONAL_HEADER) + i * sizeof(IMAGE_SECTION_HEADER));
      sectionheads[i] := PIMAGE_SECTION_HEADER(gptr);
    end;
    if peoptn.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = 0 then
    begin
      memo1.lines.add('No Export Table Present');
      memo1.lines.add('------------------------------------------');
    end
    else
    begin
      memo1.lines.add('Export Table Present');
      for i := pehd.NumberOfSections - 1 downto 0 do
      begin
        if peoptn.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress >=
          sectionheads[i].VirtualAddress then
        begin
          offsetmem := sectionheads[i].PointerToRawData -
            sectionheads[i].VirtualAddress;
          break;
        end;
      end;
      gptr := bptr;
      inc(gptr, offsetmem +
        peoptn.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
      pexpdir := PIMAGE_EXPORT_DIRECTORY(gptr);
      pexpnames := pdword(longint(bptr) +
        integer(PIMAGE_EXPORT_DIRECTORY(gptr).pAddressOfNames));
      for i := 0 to pexpdir.NumberOfNames - 1 do
      begin
        expfname := pchar(integer(bptr) + integer(pexpnames^));
        memo1.lines.add(' -' + expfname);
        inc(pexpnames);
      end;
      memo1.lines.add('------------------------------------------');
    end;
    if peoptn.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = 0 then
      memo1.lines.add('No Import Table Present')
    else
    begin
      memo1.lines.add('Import Table Present');
      for i := pehd.NumberOfSections - 1 downto 0 do
      begin
        if peoptn.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress >=
          sectionheads[i].VirtualAddress then
        begin
          offsetmem := sectionheads[i].PointerToRawData -
            sectionheads[i].VirtualAddress;
          break;
        end;
      end;
      gptr := bptr;
      inc(gptr, offsetmem +
        peoptn.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
      idataphysicaladress := gptr;
      i := 0;
      j := 0;
      while true do
      begin
        gptr := idataphysicaladress;
        inc(gptr, i * sizeof(IMAGE_IMPORT_DESCRIPTOR));
        idata := PIMAGE_IMPORT_DESCRIPTOR(gptr);
        if idata.Name = 0 then
          break;
        gptr := bptr;
        inc(gptr, offsetmem + idata.Name);
        modulename := pchar(gptr);
        memo1.Lines.Add('Module Name:' + modulename);
        while true do
        begin
          if (idata.FirstThunk + j * 4) = 0 then
            break;
          gptr := bptr;
          inc(gptr, offsetmem + idata.FirstThunk + j * 4);
          dptr := plongword(gptr);
          gptr := bptr;
          inc(gptr, offsetmem + dptr^);
          if isbadcodeptr(gptr) then
            break;
          ord := pword(gptr)^;
          inc(gptr, 2);
          functionname := pchar(gptr);
          if isbadcodeptr(functionname) then
            break;
          if functionname = nil then
            break;
          memo1.Lines.Add('  -Ord:' + inttohex(ord, 3) + ' Function Name:' +
            functionname);
          inc(j);
        end;
        inc(i);
      end;
    end;
  end;
  UnmapViewOfFile(bptr);
  closehandle(hmap);
  fileclose(h1);
end;

end.

Nincsenek megjegyzések:

Megjegyzés küldése