取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文件格式的理解,也希望可以对看雪论坛有所贡献.因为了解 ...
随机推荐
- M端页面-绝对定位布局
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name ...
- Transition 所支持的css属性
transition-property是用来指定当元素其中一个属性改变时执行transition效果: 所支持的属性类型如下: color: 通过红.绿.蓝和透明度组件变换(每个数值处理)如:back ...
- xstream对象xml互转
1.引入jar包 xpp3_min-1.1.4c.jarxstream-1.4.8.jar 2.建立java bean package com.jdw.bean; import java.util.A ...
- Net Core WebApi单元测试
单元测试 本篇将结合这个系列的例子的基础上演示在Asp.Net Core里如何使用XUnit结合Moq进行单元测试,同时对整个项目进行集成测试. 第一部分.XUnit 修改 Project.json ...
- 使用Java管理Azure(1):基础配置
Azure针对Java开发人员提供了非常丰富的开发库,开发工具,和相关插件,让你通过Java对Azure进行服务管理和开发,本文第一步先介绍如何快速的配置Java开发工具,主要针对目前比较流行的Ecl ...
- Android 自定义PopupWindow动画效果
public class RollActivity extends Activity { private View view; private Button btn; private PopupWin ...
- VC++自绘界面
// MySkinDlg.cpp : implementation file // #include "stdafx.h" #include "MySkin.h" ...
- Java泛型介绍!!!
Java总结篇系列:Java泛型 转自:http://www.cnblogs.com/lwbqqyumidi/p/3837629.html 一. 泛型概念的提出(为什么需要泛型)? 首先,我们看下下 ...
- IIS给网站地址配置成HTTPS的
2.增加网站绑定 3.如果https的URL访问不了,可能是443端口被占用 然后netstat -anono
- uva10820 send a table (nlogn求1-n欧拉函数值模版
//重点就是求1-n的欧拉函数啦,重点是nlogn求法的版 //大概过程类似于筛选法求素数 #include<cstdio> #include<iostream> #inclu ...