取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文件格式的理解,也希望可以对看雪论坛有所贡献.因为了解 ...
随机推荐
- UVA 10943 How do you add?
设函数 f(k)(n); 则: f(1)(n)=1; f(2)(n)=f(1)(0)+f(1)(1)+f(1)(2)+...+f(1)(n); f(3)(n)=f(2)(0)+f(2)(1)+f(2) ...
- web前端开发工程师
web前端开发工程师 百科名片 Web前端开发工程师是一个很新的职业,在国内乃至国际上真正开始受到重视的时间不超过5年.Web前端开发是从网页制作演变而来的,名称上有很明显的时代特征.在互联网的演化进 ...
- 【思考题】CSDN第四届在线编程大赛2014初赛:带通配符的数
题目要求: 输入参数:参数A,含有任意个数的?的数值字符串,如:12?4,?代表一位任意数 参数B,不含?的数值字符串,长度与参数A一致 输出结果:参数A比参数 ...
- 杭电 HDU 4608 I-number
http://acm.hdu.edu.cn/showproblem.php?pid=4608 听说这个题是比赛的签到题......无语..... 问题:给你一个数x,求比它大的数y. y的要求: 1. ...
- SQLServer中临时表与表变量的区别分析【转】
在实际使用的时候,我们如何灵活的在存储过程中运用它们,虽然它们实现的功能基本上是一样的,可如何在一个存储过程中有时候去使用临时表而不使用表变量,有时候去使用表变量而不使用临时表呢? 临时表 临时表与永 ...
- ExtJs3学习资料分享
最近在学习EXTJS3,在网上找了一些pdf的书.不过网上分享的有些书都是Ext2.0的.Ext3的比较少.有些书也不全.很多是样章.最近找到一本分享的书<ExtJS源码分析与开发实例宝典> ...
- 什么是OAuth
什么是OAuth 如今很多网站的功能都强调彼此间的交互,因此我们需要一种简单,标准的解决方案来安全的完成应用的授权,于是,OAuth应运而生,看看官网对其的定义: An open protocol t ...
- bootstrap之Swipe
Swipe 我定义为滑动,但它字面的意思又不是,事件的形式类似于小时候拿着一块石头片,朝水面飞过去,假设你手法能够那么就是swipe走的路线,假设你手法不行,接触水面的时候就没再飞起来那就会被人嘲笑的 ...
- Android简单登录系统
很长时间没有写博客了,最近一直在写android for gis方面的项目.不过这篇博客就不写gis方面的了,今天刚刚做的一个简单的android登录系统.数据库是android自带的sqlite,s ...
- (五)认识Android中的Service
一.使用Service 1.右击java文件夹,选择新建Service,然后重写其中的onStartCommand函数,只要执行了startService函数,onStartCommand便会被执行 ...