Title: Get The list of function that an executable file imports.
Question: 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(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.