取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文件格式的理解,也希望可以对看雪论坛有所贡献.因为了解 ...
随机推荐
- sqlite数据库常用语句
这个文件型数据库小巧好用,可以替代ACCESS,以下是常用的语句 获取数据库时间(设计表字段时的当前时间默认值) sqlite datetime('now', 'localtime') ...
- 一个纯CSS DIV天气动画图标【转扒的】
<p> </p> <style><!-- /* SUNNY */ .sunny { -webkit-animation: sunny 15s linear i ...
- Window10安装TestLink,以及登录mysql数据库的错误处理
步骤一: 需要安装apache和mysql,但是我们这里仅仅是使用testlink,不关注其他,所以使用Vertrigoserv进行傻瓜式安装,安装完后,下载testlink解压,将解压后的文件放入D ...
- WIN_2003_SP2.iso VMware 不能进行网络访问的处理
1.打开IE发现不能上网的问题 ping命令 发现确实是网络不通: 2.关闭虚拟机设置网络适配器 3.ping命令验证是否设置成功 4.打开IE访问百度
- MongoDB C driver API continues
开篇前 <1,mongoc_init() func> mongoc_init() Synopsis void mongoc_init (void); Description This fu ...
- [置顶] ASP.Net中服务器控件的生命周期
(1)初始化:在此阶段中,主要完成两项工作:一.初始化在传入Web请求生命周期内所需的设置;二.跟踪视图状态.首先,页面框架通过默认方式引发Init事件,并调用OnInit()方法,控件开发人员可以重 ...
- docker学习笔记(1)
(1)Docker介绍 关于Docker的介绍,我就不列举出来了.到百度.谷歌搜索.非常多介绍文章.以下我给出官网的介绍:https://www.docker.com/whatisdocker/ (2 ...
- 济南最新公交线路一览(BRT)
济南最新公交线路一览(BRT) 济南BRT1路 高速公交线路 黄岗路东5:30-21:30 全福立交桥西5:30-21:30 票价1元,刷卡9折,月票有效 高速公交公司 去程:黄岗路东(BRT) - ...
- Android 获取 root权限
在进行android 开发的时候,经常用真机进行调试,有时候需要把手机中的sqlite数据复制出来.这时候就需要获取手机的root权限.通过 adb shell 命令可以获取权限. 1. 运行cmd ...
- ubuntu下nvm,node以及npm的安装与使用
一:安装nvm 首先下载nvm,这里我们需要使用git,如果没有安装git,可以使用 sudo apt-get install git 来安装 git clone https://github.com ...