取PE文件的引入表和导出表
直接上代码(这里列出C++和Delphi的代码),Delphi代码中包含导入及导出文件和函数列表,PE结构可参阅资料,很多很详细,需要注意的是,本例中是映射到内存,不是通过PE装载器装入的,所以对于节的RVA地址需要转换成为文件偏移地址。
Delphi代码
- 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.
C++代码
- #include<string>
- #include<windows.h>
- void GetImportDllList(void)
- {
- IMAGE_IMPORT_DESCRIPTOR* importEntry = 0;
- IMAGE_SECTION_HEADER* sectionHeader = 0;
- char* filename = "c://test.exe";
- //打开文件
- HANDLE hfile = CreateFileA(filename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
- if (hfile == INVALID_HANDLE_VALUE)
- {
- printf("%s","文件打开失败!");
- return;
- }
- //创建内存映射
- HANDLE hmap = CreateFileMapping(hfile,NULL,PAGE_READONLY,0,0,NULL);
- if (hmap == 0)
- {
- printf("%s","创建内存映射失败!");
- return;
- }
- //映射到当前进程,pBaseAddress是基址
- HANDLE pBaseAddress = MapViewOfFile(hmap,FILE_MAP_READ,0,0,0);
- if (!pBaseAddress)
- {
- printf("%s","获取地址失败!");
- return;
- }
- //获取Dos信息头部结构数据
- IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)pBaseAddress;
- //判断Dos标识
- if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
- {
- printf("%s","不可识别的文件格式!");
- return;
- }
- //获取NT信息头部结构数据,IsBadReadPtr判断指针是否可读,ntHeader->Signature是NT标识
- IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)((DWORD)pBaseAddress+dosHeader->e_lfanew);
- if (ntHeader->Signature != IMAGE_NT_SIGNATURE)
- {
- printf("%s","不是有效地Win32程序!");
- return;
- }
- //定位到第一个节的地址
- sectionHeader = (IMAGE_SECTION_HEADER*)((DWORD)ntHeader+sizeof(IMAGE_NT_HEADERS));
- //ntHeader->FileHeader.NumberOfSections为节的数量,此处循环,找到引入表的节
- for (int i=0;i<ntHeader->FileHeader.NumberOfSections;i++)
- {
- //IMAGE_DIRECTORY_ENTRY_IMPORT,引入表
- if (sectionHeader->VirtualAddress == ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
- {
- break;
- }
- //没找到,那么增加SizeOf(IMAGE_SECTION_HEADER)字节数,指向下一个节
- sectionHeader++;
- }
- //引入表入口
- importEntry = (IMAGE_IMPORT_DESCRIPTOR*)((DWORD)pBaseAddress+sectionHeader->PointerToRawData);
- printf("下面是%s的引入文件/n",filename);
- //加载的DLL的名称,这里是RVA地址,需要转换成文件偏移地址,因为我们不是通过PE加载器加载,而是映射到内存
- while (importEntry->Name != 0)
- {
- DWORD offset = (DWORD)pBaseAddress+importEntry->Name-(sectionHeader->VirtualAddress - sectionHeader->PointerToRawData);
- char* s = (char*)offset;
- printf("%s/n",s);
- //继续读取
- importEntry++;
- }
- UnmapViewOfFile(pBaseAddress);
- CloseHandle(hmap);
- CloseHandle(hfile);
- }
- int main()
- {
- GetImportDllList();
- return 0;
- }


http://blog.csdn.net/bdmh/article/details/6100745
取PE文件的引入表和导出表的更多相关文章
- 【学习】Windows PE文件学习(一:导出表)
今天做了一个读取PE文件导出表的小程序,用来学习. 参考了<Windows PE权威指南>一书. 首先, PE文件的全称是Portable Executable,可移植的可执行的文件,常见 ...
- PE文件 01 导入表
0x01 导入表结构 数据目录表中的第二个成员标记了导入表的RVA和Size大小,由此可以定位到导入表: typedef struct _IMAGE_DATA_DIRECTORY { DWORD ...
- 小甲鱼PE详解之输入表(导出表)详解(PE详解09)
小甲鱼PE详解之输出表(导出表)详解(PE详解09) 当PE 文件被执行的时候,Windows 加载器将文件装入内存并将导入表(Export Table) 登记的动态链接库(一般是DLL 格式)文件一 ...
- PE文件 02 导出表
0x01 导出表结构 导出表是由数据目录表中的第一个成员DataDirectory[0]指出的: typedef struct _IMAGE_DATA_DIRECTORY { DWORD Virt ...
- 深入学习PE文件(转)
PE文件是Win32的原生文件格式.每一个Win32可执行文件都遵循PE文件格式.对PE文件格式的了解可以加深你对Win32系统的深入理解. 一. 基本结构. 上图便是PE文件的基本结构.(注意:DO ...
- 深入剖析PE文件
不赖猴的笔记,转载请注明出处. 深入剖析PE文件 PE文件是Win32的原生文件格式.每一个Win32可执行文件都遵循PE文件格式.对PE文件格式的了解可以加深你对Win32系统的深入理解. 一. ...
- 解析PE文件
最近在自学解析PE文件,根据小辣椒(CFF Explorer)以及各论坛上大佬的帖子,做了个黑屏打印PE文件的,历时7天完成,在此想跟有相关需要的同学们分享下思路,有不足之处也希望大家不吝赐教,指点出 ...
- 破解软件感悟-PE文件格式之Import Table(引入表)(四)
先来看一个可执行文件的实例:本例程打开一PE文件,将所有引入dll和对应的函数名读入一编辑控件,同时显示 IMAGE_IMPORT_DESCRIPTOR 结构各域值. C:\QQDownload\bl ...
- 【PE结构】由浅入深PE基础学习-菜鸟手动查询导出表、相对虚拟地址(RVA)与文件偏移地址转换(FOA)
0 前言 此篇文章想写如何通过工具手查导出表.PE文件代码编程过程中的原理.文笔不是很好,内容也是查阅了很多的资料后整合出来的.希望借此加深对PE文件格式的理解,也希望可以对看雪论坛有所贡献.因为了解 ...
随机推荐
- jQuery工具函数下
测试操作 1.判断是否为数组对象 $(function () { //判断是否为数组对象 var arr = [1,2,3,4]; alert($.isArray(arr));//true }); 2 ...
- Composer的使用
安装 curl -sS https://getcomposer.org/installer | php 你可以使用--install-dir选项将Composer安装到指定的目录,例如: curl - ...
- Python之路第九天,高级(1)-网络编程
SOCKET编程 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. so ...
- Android: ScrollView监听滑动到顶端和底端
在项目中需要监听ScrollView滑动到顶端和底端的时候以实现自己的ScrollView,那么怎样去监听呢?今天查看了一下ScrollView的源码,找到了一种方法.先看一下源码中的overScro ...
- CodeForces 203C Photographer
简单贪心.注意内存够大,能满足所有顾客的特殊情况. #include <iostream> #include <cstring> #include <algorithm& ...
- vs2005的MFC程序在64位机上不能运行
出现上述错误大多因为该机上没有安装vs2005程序,vs2005要运行需要一些必要的文件,没有添加到你发布的可执行文件目录下,所以程序不能运行. 解决方法: 安装目录\Microsoft Visual ...
- 【Xamarin挖墙脚系列:Xamarin正式发布了IOS的模拟器在Windows下】
xamarin 的发展越来越迅速.如果还感觉这玩意儿是个鸡肋,辣么请跟的上时代吧 . (额,对微软产品有严重偏见的请绕行..............其实你可以看看.net 基金会现有的开源项目再说不开 ...
- 如何让ios app支持32位和64位?
将ios app转换为兼容32位和64位步骤: 1. 安装 Xcode 5. 2. 打开你的项目.Xcode会提示你更新你的项目,其中的警告和错误信息对于转换到64位相当重要. 3. 将你的项目 ...
- 【HDU 5572 An Easy Physics Problem】计算几何基础
2015上海区域赛现场赛第5题. 题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5572 题意:在平面上,已知圆(O, R),点B.A(均在圆外),向量 ...
- Python with ASP
Python with ASP Python with ASP