unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls;
type
//导入表元素结构
TImageImportDiscriptor = packed record
OriginalFirstThunk: DWORD;
DataTimpStamp: DWORD;
ForwardChain: DWORD;
DLLName: DWORD;
FirstThunk: DWORD;
end;
PImageImportDiscriptor = ^TImageImportDiscriptor;
//导出表元素结构
PImageExportDirectory = ^TImageExportDirectory;
TImageExportDirectory = packed record
Characteristics: DWORD;
TimeDateStamp: DWORD;
MajorVersion: WORD;
MinorVersion: WORD;
Name: DWORD;
Base: DWORD;
NumberOfFunctions: DWORD;
NumberOfNames: DWORD;
AddressOfFunctions: DWORD;
AddressOfNames: DWORD;
AddressOfNameOrdinals: DWORD;
end;
//函数名结构
TImportByName = packed record
proHint: Word;
proName: array [0..1] of char;
end;
PImportByName = ^TImportByName;
TForm1 = class(TForm)
OpenDialog1: TOpenDialog;
Button1: TButton;
TreeView1: TTreeView;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
procedure GetList(filename:string);
{导入列表}
procedure GetImportList(pBaseAddress:Pointer;ntHeader:PImageNtHeaders);
{导出列表}
procedure GetExportList(pBaseAddress:Pointer;ntHeader:PImageNtHeaders);
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TForm1 }
procedure TForm1.GetList(filename: string);
var
fileHandle:THandle;
fileMap:THandle;
pBaseAddress:Pointer;
dosHeader: PImageDosHeader;
ntHeader: PImageNtHeaders;
begin
TreeView1.Items.Clear;
try
//打开文件
fileHandle := CreateFile(PChar(filename),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
if fileHandle = INVALID_HANDLE_VALUE then
begin
ShowMessage('文件打开失败!');
Exit;
end;
//创建内存映射
fileMap := CreateFileMapping(fileHandle,nil,PAGE_READONLY,0,0,nil);
if fileMap = 0 then
begin
ShowMessage('创建内存映射失败!');
Exit;
end;
//映射到当前进程,pBaseAddress是基址
pBaseAddress := MapViewOfFile(fileMap,FILE_MAP_READ,0,0,0);
if pBaseAddress = nil then
begin
ShowMessage('获取地址失败!');
Exit;
end;
//获取Dos信息头部结构数据
dosHeader := pImageDosHeader(LongInt(pBaseAddress));
//判断Dos标识
if dosHeader.e_magic <> IMAGE_DOS_SIGNATURE then
begin
ShowMessage('不可识别的文件格式!');
Exit;
end;
//获取NT信息头部结构数据,IsBadReadPtr判断指针是否可读,ntHeader.Signature是NT标识
ntHeader := pImageNtHeaders(LongInt(pBaseAddress)+dosHeader._lfanew);
if (IsBadReadPtr(ntHeader,SizeOf(TImageNtHeaders))) or
(ntHeader.Signature <> IMAGE_NT_SIGNATURE) then
begin
ShowMessage('不是有效地Win32程序!');
Exit;
end;
GetImportList(pBaseAddress,ntHeader);
GetExportList(pBaseAddress,ntHeader);
finally
UnmapViewOfFile(pBaseAddress);
CloseHandle(fileMap);
CloseHandle(fileHandle);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then
begin
Label1.Caption := '以下是'+OpenDialog1.FileName+'的导入及导出表';
GetList(OpenDialog1.FileName);
end;
end;
procedure TForm1.GetExportList(pBaseAddress: Pointer; ntHeader: PImageNtHeaders);
var
imageEntry: PImageExportDirectory;
sectionHeader: PImageSectionHeader;
importbyname: PImportByName;
proEntry:PDWORD;
proTemp:PWORD;
rva,frva: DWORD;
dllname: string;
i,j:integer;
node:TTreeNode;
s:string;
pname:PChar;
begin
rva := ntHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if rva = 0 then Exit;
//定位到第一个节的地址
sectionHeader := PImageSectionHeader(LongInt(ntHeader)+SizeOf(TImageNtHeaders));
//ntHeader^.FileHeader.NumberOfSections为节的数量,此处循环,找到引入表的节
for i := 0 to ntHeader^.FileHeader.NumberOfSections - 1 do
begin
//IMAGE_DIRECTORY_ENTRY_IMPORT,引入表,检查rva是否落在节内
if ( rva >= LongInt(sectionHeader.VirtualAddress)) and (rva
begin
Break;
end;
//没找到,那么增加SizeOf(TImageSectionHeader)字节数,指向下一个节
Inc(sectionHeader);
end;
node := TreeView1.Items.Add(nil,'导出函数表');
frva := sectionHeader.VirtualAddress - sectionHeader.PointerToRawData;
//导出表入口
imageEntry := PImageExportDirectory(LongInt(pBaseAddress)+rva-frva);
proEntry := PDWord(LongInt(pBaseAddress)+imageEntry.AddressOfFunctions-frva);
pname := PChar(LongInt(pBaseAddress)+imageEntry.Name-frva);
for i := 0 to imageEntry.NumberOfFunctions - 1 do
begin
if proEntry^ = 0 then Continue;
proTemp := PWORD(LongInt(pBaseAddress)+LongInt(imageEntry.AddressOfNameOrdinals)-frva);
for j := 0 to imageEntry.NumberOfNames - 1 do
begin
if proTemp^ = i then
begin
s := '';
while True do
begin
if pname^=#0 then Break;
Inc(pname);
end;
while True do
begin
if (pname-1)^=#0 then
begin
s:=Format('%s', [pname]);
Break;
end;
Inc(pname);
end;
end;
Inc(proTemp);
end;
TreeView1.Items.AddChild(node,s);
Inc(proEntry);
end;
end;
procedure TForm1.GetImportList(pBaseAddress: Pointer; ntHeader: PImageNtHeaders);
var
imageEntry: PImageImportDiscriptor;
sectionHeader: PImageSectionHeader;
importbyname: PImportByName;
proEntry:PDWORD;
rva,frva: DWORD;
dllname: string;
i:integer;
node:TTreeNode;
begin
rva := ntHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
if rva = 0 then Exit;
//定位到第一个节的地址
sectionHeader := PImageSectionHeader(LongInt(ntHeader)+SizeOf(TImageNtHeaders));
//ntHeader^.FileHeader.NumberOfSections为节的数量,此处循环,找到引入表的节
for i := 0 to ntHeader^.FileHeader.NumberOfSections - 1 do
begin
//IMAGE_DIRECTORY_ENTRY_IMPORT,引入表,检查rva是否落在节内
if ( rva >= LongInt(sectionHeader.VirtualAddress)) and (rva
begin
Break;
end;
//没找到,那么增加SizeOf(TImageSectionHeader)字节数,指向下一个节
Inc(sectionHeader);
end;
frva := sectionHeader.VirtualAddress - sectionHeader.PointerToRawData;
TreeView1.Items.Add(nil,'导入函数表');
//引入表入口
imageEntry := PImageImportDiscriptor(LongInt(pBaseAddress)+rva-frva);
//加载的DLL的名称,这里是RVA地址,需要转换成文件偏移地址,因为我们不是通过PE加载器加载,而是映射到内存
while imageEntry.DLLName <> 0 do
begin
dllname := PChar(LongInt(pBaseAddress)+imageEntry.DLLName-frva);
node := TreeView1.Items.AddChild(TreeView1.Items[0],dllname);
if imageEntry.OriginalFirstThunk <> 0 then
proEntry := PDWord(LongInt(pBaseAddress)+imageEntry.OriginalFirstThunk-frva)
else
proEntry := PDWord(LongInt(pBaseAddress)+imageEntry.FirstThunk-frva);
while proEntry^ <> 0 do
begin
if (proEntry^ and $80000000) <> 0 then
TreeView1.Items.AddChild(node,Format('函数编号:%-15d',[proEntry^ and $7FFFFFFF]))
else
begin
importbyname := PImportByName(LongInt(pBaseAddress)+proEntry^-frva);
TreeView1.Items.AddChild(node,Format('函数名称:%-15s',[importbyname.proName]));
end;
Inc(proEntry);
end;
//继续读取
Inc(imageEntry);
end;
end;
end.