取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文件格式的理解,也希望可以对看雪论坛有所贡献.因为了解 ...
随机推荐
- Oops信息及栈回溯
1. Oops信息来源及格式Oops这个单词含义为“惊讶”,当内核出错时(比如访问非法地址)打印出来的信息被称为Oops信息.Oops信息包含以下几部分内容:(1)一段文本描述信息. 比如类 ...
- js禁止中文输入 最简洁的【禁止输入中文】
方法一:禁止中文输入法 <input type="text" > 方法二:禁止黏贴,禁止拖拽,禁止中文输入法! 这种方法是最强的禁止 中文输入 <input t ...
- python运维开发(八)----面向对象(下)
内容目录: 面向对象三大特性之多态性 面向对象中的成员:字段.方法.属性 类的成员修饰符 类的特殊成员 特殊成员方法 面向对象其他 异常处理 设计模式之单例模式 面向对象的多态性 多态性:即指多种形态 ...
- Net Core WebApi单元测试
单元测试 本篇将结合这个系列的例子的基础上演示在Asp.Net Core里如何使用XUnit结合Moq进行单元测试,同时对整个项目进行集成测试. 第一部分.XUnit 修改 Project.json ...
- 解决CentOS(RedHat)中sendmail和sm-client启动慢故障(转)
Starting sendmail: Starting sm-client: 刚才发了修改主机名那篇文章后,我意外发现重新启动CentOS的时候系统会卡在sendmail和sm-client那里将近3 ...
- C语言的本质(25)——C标准库之内存管理
程序中需要动态分配一块内存时怎么办呢?我们可以定义一个缓冲区数组,但是这种方法不够灵活,C89要求定义的数组是固定长度的,而程序往往在运行时才知道要动态分配多大的内存,例如: void foo(cha ...
- 新 Azure SQL 数据库服务等级的性能
4 月 24 日,我们发布了 SQL Database 基本级(预览版)和标准级(预览版)新服务等级的预览版以及新的业务连续性功能.在本博客文章中,我们将深入探究 SQL Database 中新等级的 ...
- linux之SQL语句简明教程---CREATE VIEW
视观表 (View) 可以被当作是虚拟表格.它跟表格的不同是,表格中有实际储存资料,而视观表是建立在表格之上的一个架构,它本身并不实际储存资料. 建立一个视观表的语法如下: CREATE VIEW & ...
- OpenCms创建站点过程图解——献给OpenCms的刚開始学习的人们
非常多人都听说了OpenCms,知道了它的强大,索性的下载安装了,最终见到了久违OpenCms,看到了它简洁的界面,欣喜过后却不免一脸茫然,这个东西怎么用,我怎么用它来建站,从哪開始,无从下手,找资料 ...
- win7下安装Ubuntukylin-14.04双系统
工具准备: 下载ISO系统镜像,UltraISO,EasyBCD,分区助手,8G 优盘 U盘启动制作流程: 1,打开分区助手,从硬盘中分出空闲空间(60G)作为Ubuntu工作空间,文件系统设为Ext ...