• 取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
  • 相关阅读:
    HTTPs与HTTP的区别&HTTPs如何建立连接
    HTTP协议常见状态码和字段
    服务器负载均衡
    ARP协议工作原理
    C++智能指针
    C++类型转换
    Rust 只出现一次的数字 两种解法
    Rust 存在重复元素 两种解法
    Rust 旋转数组
    Rust 动态规划 买卖股票的最佳时机 II
  • 原文地址:https://www.cnblogs.com/key-ok/p/3428908.html
Copyright © 2020-2023  润新知