取PE文件的引入表和导出表

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.
View Code

 

你可能感兴趣的:(文件)