PE基础2

怎么找到Nt头?

(PIMAGE_NT_HEADER)(DOS.e_lfanew + (DWORD)m_pBuff)

怎么找到第一个区段表?

区段头位置 = pNt + 4 + 文件头的大小 + 扩展头大小 IMAGE_FIRST_SECTION()

区段表中的VirtualAddress字段保存的是什么?PointToRawData呢?

VirtualAdddress : 区段在内存的相对虚拟地址

RVA PointToRawData: 区段在文件中偏移Offset

记录OEP的字段在哪里?

扩展头.AddressOfEntryPoint (OEP)

怎么判断一个PE文件是32位的还是64位的?

扩展头.magic x86(10B) , x64(20B)

文件头.machine x86(014c) , x64(8664)

文件头.SizeOfOptionalheader x84(E0), x64(F0)

exe的默认加载基址是多少?DLL的默认加载基址?

exe: 0x00400000

dll: 0x10000000

文件对齐粒度一般是多少? 内存对齐粒度一般?

文件对齐值:0x200

内存对齐值:0x1000 (4kb)

RVA怎么转换成FOA ?

FOA = RVA - 区段在内存中的相对虚拟地址 + 区段在文件中偏移

导出表

导出回顾 dll导出函数的几种方式

声明导出: _declspec(dllexport)

def文件导出

dll函数调用

隐式链接 :

包含头文件,载入lib库

显示连接 :

LoadLibray,GetProcAddress

导出表作用

导出是PE为其它程序提供API的一种函数实例导出行为

windows下存在导出表的可执行文件,可以提供其它第三方程序使用

导出表支持符号导出,序号导出,这两种方式可以共存

导出表位于数据目录表中第0选项(默认我们以数组下标0开始数)

导出表结构

typedef struct _IMAGE_EXPORT_DIRECTORY { 
   DWORD  Characteristics;        // (1) 保留,恒为0x00000000    
   DWORD  TimeDateStamp;          // (2) 时间戳  
   WORD   MajorVersion;            // (3) 主版本号,一般不赋值  
   WORD   MinorVersion;            // (4) 子版本号,一般不赋值  
   DWORD  Name;                    // (5) 模块名称*  
   DWORD  Base;                    // (6) 索引基数*  
   DWORD  NumberOfFunctions;       // (7) 导出地址表中成员个数*  
   DWORD  NumberOfNames;          // (8) 导出名称表中成员个数*  
   DWORD  AddressOfFunctions;      // (9) 导出地址表(EAT)*  
   DWORD  AddressOfNames;          // (10) 导出名称表(ENT)*  
   DWORD  AddressOfNameOrdinals;   // (11) 指向导出序号数组*
}IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY;

手工解析导出表

需要注意的是导出表的地址都是RVA 导出表中有三张表分别是 EAT,ENT,EOT。

EAT: 导出地址表 ENT: 导出名称表(与EOT一一对应)

EOT:导出序号表

代码解析导出表

void PE::ShowExportTable() {
PIMAGE_EXPORT_DIRECTORY p = GetExportDirectory(); //输出导出表信息
char * dllName = (char*)(RVAToFoa(p->Name) + (DWORD)m_pbuff);
printf("dll名 %s\n", dllName);
printf("导出函数地址表个数 %2d\n", p->NumberOfFunctions);
printf("导出函数名称表个数 %2d\n", p->NumberOfFunctions);
//遍历导出函数 //导出序号表
WORD *EOT = (WORD*)(RVAToFoa(p->AddressOfNameOrdinals) + (DWORD)m_pbuff);
//导出名称表
DWORD *pENT = (DWORD*)(RVAToFoa(p->AddressOfNames) + (DWORD)m_pbuff);
//导出序号表
DWORD *pEAT = (DWORD*)(RVAToFoa(p->AddressOfFunctions) + (DWORD)m_pbuff);
//遍历地址表所有函数
for (int i = ; i < p->NumberOfFunctions; i++)
{
printf("序号%d ", i + p->Base);
int j = ;
//遍历所有序号表,找到有名字的函数
for (; j < p->NumberOfNames; j++)
{
if (i == EOT[j])
{
// 导出名称表[ 序号表[j] ]
int RvaName = pENT[EOT[j]];
char *szName = (char*)(RVAToFoa(RvaName) + (DWORD)m_pbuff);
printf("函数名 %s ", szName);
break;
}
}
//没有找到函数名
if (j > p->NumberOfNames)
{
printf("函数名 NULL ");
}
//打印导出函数地址
printf("%08X\n", *(DWORD*)(RVAToFoa(pEAT[i]) + (DWORD)m_pbuff));
}
}

导入表

导入表作用

导入表是PE文件从其它第三方程序中导入API,以供本程序调用的机制(与导出表对应)

在exe运行起来的时候, 加载器会遍历导入表, 将导入表中所有dll 都加载到进程中,被加载的DLL的DllMain就会 被调用

通过导入表可以知道程序使用了哪些函数

当然有写程序可以没有导入表,自己实现动态加载功能 导入表结构,

这个导入表是一个数组,以全为零结尾

typedef struct _IMAGE_IMPORT_DESCRIPTOR {  
   union {  
       DWORD Characteristics;  
       DWORD OriginalFirstThunk;//(1) 指向导入名称表(INT)的RAV*  
  };  
   DWORD   TimeDateStamp;  // (2) 时间标识  
   DWORD   ForwarderChain; // (3) 转发链,如果不转发则此值为0
   DWORD   Name;       // (4) 指向导入映像文件的名字*  
   DWORD   FirstThunk; // (5) 指向导入地址表(IAT)的RAV*
} IMAGE_IMPORT_DESCRIPTOR;

导入表解析

导入表中重要的字段 : OriginalFirstThunk(INT)

导入表中重要的字段 : FirstThunk(IAT)

导入表中重要的字段 :Name

其中IAT 与 INT都指向 IMAGE_THUNK_DATA32

typedef struct _IMAGE_THUNK_DATA32 {  
   union {      
       PBYTE  ForwarderString;                // (1) 转发字符串的RAV      
       PDWORD Function;                        // (2) 被导入函数的地址    
       DWORD Ordinal;                          // (3) 被导入函数的序号    
       PIMAGE_IMPORT_BY_NAME  AddressOfData;   // (4) 指向输入名称表
  } u1;
  } IMAGE_THUNK_DATA32;

IAT与INT区别在于,在文件中他们都指向一个函数名字或序号,在内存中IAT会被填充到正确的函数地址

IMAGE_THUNK_DATA32中值的最高位为1,表示序号导入,

Ordinal IMAGE_THUNK_DATA32中值的最高位为0,表示函数名导入,

AddressOfData字段有效 PIMAGE_IMPORT_BY_NAME 指向导入函数序号与函数名

typedef struct _IMAGE_IMPORT_BY_NAME {    
   WORD    Hint;           // (1) 需导入的函数序号  
   BYTE    Name[1];        // (2) 需导入的函数名称
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

void PE::ShowImportInfo()
{
//获取导入表
PIMAGE_IMPORT_DESCRIPTOR pImport = GetImportDirectory(); //遍历所有导入表,最后一项以0结尾
while (pImport->Name)
{
//显示导入模块的名字
char * szDllName =(char*)( RvaToFoa(pImport->Name)+ (DWORD)m_pBuff);
printf("%s\n", szDllName);

//显示导入函数的名称
//遍历导入地址表IAT(导入名称表INT)
//IAT
PIMAGE_THUNK_DATA pIat =
(PIMAGE_THUNK_DATA)(RvaToFoa(pImport->FirstThunk) + (DWORD)m_pBuff);

//INT
PIMAGE_THUNK_DATA pInt =
(PIMAGE_THUNK_DATA)(RvaToFoa(pImport->OriginalFirstThunk) + (DWORD)m_pBuff);

//IAT表个数不确定,最后一项以全为0结尾
while (pIat->u1.Ordinal)
{
//判断是否名称导出还是序号导出
//通过最高位是否为1 ,如果为1,那么序号导出
//如果为0,名称导出
if (pIat->u1.Ordinal & 0x80000000)
{
//最高位为1,序号导入
//打印一下序号
printf(" 序号%2d\n", pIat->u1.Ordinal & 0xFFFF);

}
else {
//最高位位0,名称导入
//显示序号,和名称
PIMAGE_IMPORT_BY_NAME pName =
(PIMAGE_IMPORT_BY_NAME)(RvaToFoa(pIat->u1.AddressOfData) + (DWORD)m_pBuff);

printf(" 序号%2d", pName->Hint);
printf(" %s\n", pName->Name);
}
pIat++;
}
pImport++;
} }

PE基础2的更多相关文章

  1. 【PE结构】由浅入深PE基础学习-菜鸟手动查询导出表、相对虚拟地址(RVA)与文件偏移地址转换(FOA)

    0 前言 此篇文章想写如何通过工具手查导出表.PE文件代码编程过程中的原理.文笔不是很好,内容也是查阅了很多的资料后整合出来的.希望借此加深对PE文件格式的理解,也希望可以对看雪论坛有所贡献.因为了解 ...

  2. PE基础1

    PE文件概述 文件格式 .png ..mp4..gif..dll等等,这些文件都具有不同格式 不能随意修改这些文件,否则将无法打开 PE文件(可执行文件) 学习PE文件目标 掌握PE文件就掌握wino ...

  3. PE文件解析 基础篇

    PE文件解析 基础篇 来源 https://bbs.pediy.com/thread-247114.htm 前言 之前学习了PE格式,为了更好的理解,决定写一个类似LoadPE的小工具. 编译器是VS ...

  4. [系统安全] 十六.PE文件逆向基础知识(PE解析、PE编辑工具和PE修改)

    [系统安全] 十六.PE文件逆向基础知识(PE解析.PE编辑工具和PE修改) 文章来源:https://masterxsec.github.io/2017/05/02/PE%E6%96%87%E4%B ...

  5. 基础篇-初步认识PE格式

    1 PE(Portable Executable)格式,是Win32环境可移植可执行文件(如exe.dll.vxd.sys和vdm等)的标准文件格式.PE格式衍生于早期建立在VAX(R)VMS(R)上 ...

  6. Windows PE入门基础知识:Windows PE的作用、命名规则、启动方式、启动原理

    Windows PE的全名是WindowsPreinstallationEnvironment(WinPE)直接从字面上翻译就 是"Windows预安装环境".微软的本意是:Win ...

  7. 【调试基础】Part 5 PE格式

    PE概念.区块分类

  8. PE文件基础

    ① PE (Portable Executable):微软参考COFF(Common Object File Format)规范,在Windows NT系统上制定的一种标准, 用于exe可执行文件.o ...

  9. .NET面试题系列[2] - .NET框架基础知识(2)

    3 程序集 面试出现频率:虽然很重要但不怎么出现,可能会考你定义,以及程序集包括什么,然后自然的话题就跑到反射上去了. 重要程度:8/10,很重要 需要理解的程度:知道程序集包括IL和元数据.知道元数 ...

随机推荐

  1. Flutter实战视频-移动电商-52.购物车_数据模型建立和Provide修改

    52.购物车_数据模型建立和Provide修改 根据json数据生成模型类 {,"price":830.0,"images":"http://imag ...

  2. 【废弃中】JavaScript 式与运算符

    创建: 2017/09/25 更新: 2019/01/14 修改标题 [JavaScript 式与运算符] ->  [JavaScript 式与主要Object的方法] 更新: 2019/02/ ...

  3. 2019ICPC西安邀请赛 - B. Product - 数论

    打印的时候麻烦把:https://blog.csdn.net/skywalkert/article/details/50500009这个打印下来. 求\(\prod\limits_{i=1}^{n} ...

  4. T^TOJ - 2360 - Home_W的超级数学题 - 莫比乌斯反演 - 质因数分解

    求单个莫比乌斯函数忘记算n本身的质数,WA了一发. http://www.fjutacm.com/Problem.jsp?pid=2360 首先,显然随着n增大,与m互质的数不会变少.可以二分来求k, ...

  5. Math对象产生随机数一个小应用

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  6. lightoj 1125【背包·从n个选m个】

    题意: 给你 n 个背包,然后给你两个数,D,M,问你从n个里面挑M个出来,有多少种方法能够整除D: 思路: 试想我先不挑M个出来的话,仅仅是构造一个D的倍数,其实就是构造一个数的话, 其实就是个递推 ...

  7. 【源码系列】Eureka源码分析

    对于服务注册中心.服务提供者.服务消费者这个三个主要元素来说,服务提供者和服务消费者(即Eureka客户端)在整个运行机制中是大部分通信行为的主动发起者(服务注册.续约.下线等),而注册中心主要是处理 ...

  8. A - Bi-shoe and Phi-shoe

    每一个数字的欧拉函数要大于或等于该数字.求,最小的欧拉函数的下标和的大小. 答案要用longlong存 #include <iostream> #include <algorithm ...

  9. aws cli command line interface的安装与使用

    安装 在centos中安装aws cli,安装依赖python,先装好python,然后按下述命令执行 yum install wget wget https://bootstrap.pypa.io/ ...

  10. 测试 | 代码覆盖测试工具 | Eclemma

    安装: 打开eclipse,点击Help菜单下的Install New Software 在弹出的对话框中,点击Add 输入Name,如EclEmma 输入Location: http://updat ...