大悟还俗

邮箱 key_ok@qq.com 我的收集 http://pan.baidu.com/share/home?uk=1177427271
posts - 236, comments - 8, trackbacks - 0, articles - 0
  新随笔 :: 联系 :: 订阅 订阅 :: 管理

公告

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

Posted on 2013-11-18 10:36 大悟还俗 阅读(...) 评论(...) 编辑 收藏
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