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<LongInt(sectionHeader.VirtualAddress+sectionHeader.Misc.VirtualSize)) then 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<LongInt(sectionHeader.VirtualAddress+sectionHeader.Misc.VirtualSize)) then 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.