尝试编写代码获取PE文件的信息。

首先使用 CreateFile打开一个PE文件并返回一个用于访问该对象的handle

HANDLE CreateFile(
LPCTSTR lpFileName, // pointer to name of the file
DWORD dwDesiredAccess, // access (read-write) mode
DWORD dwShareMode, // share mode
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes
DWORD dwCreationDistribution, // how to create
DWORD dwFlagsAndAttributes, // file attributes
HANDLE hTemplateFile // handle to file with attributes to copy
);

然后调用CreateFileMapping函数为该文件创建一个文件映射对象(file-mapping object),此时为文件创建了一个视图,而并未将该视图映射进进程的地址空间,也就是尚未装载进入内存之中的意思吧。

Creating a file-mapping object creates the potential for mapping a view of the file but does not map the view. The MapViewOfFile and MapViewOfFileEx functions map a view of a file into a process's address space.

HANDLE CreateFileMapping(
HANDLE hFile, // handle to file to map
LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // optional security attributes
DWORD flProtect, // protection for mapping object
DWORD dwMaximumSizeHigh, // high-order 32 bits of object size
DWORD dwMaximumSizeLow, // low-order 32 bits of object size
LPCTSTR lpName // name of file-mapping object
);

接着MapViewOfFile函数会将之前创建的视图对象映射进入当前调用父进程的内存地址空间中了,那也就是说此时该PE文件基址将不再会是默认的,与DLL文件被程序调用的载入方式一致。

LPVOID MapViewOfFile(
HANDLE hFileMappingObject, // file-mapping object to map into address space
DWORD dwDesiredAccess, // access mode
DWORD dwFileOffsetHigh, // high-order 32 bits of file offset
DWORD dwFileOffsetLow, // low-order 32 bits of file offset
DWORD dwNumberOfBytesToMap // number of bytes to map
);

MapViewOfFile返回值为LPVOID,为该映射视图对象在内存中的基址,指向PE文件中最开始的IMAGE_DOS_HEADER结构体,做完这些就可以开始对文件的结构进行分析了。

在写代码的时候要注意类型转换,不然运算结果可能出乎意料:)

大多数结构体中的地址成员为RVA,需要转化,我这里主要记录一下遇到的关于RVAToVA的问题。

  1. 转化RVA,可以使用ImageRvaToVa()函数,该函数在"Imagehlp.h"或"Dbghelp.h"中声明:
PVOID IMAGEAPI ImageRvaToVa(
\_In\_ PIMAGE_NT_HEADERS NtHeaders,
\_In\_ PVOID Base,
\_In\_ ULONG Rva,
\_In\_opt\_ OUT PIMAGE_SECTION_HEADER *LastRvaSection
);

在vs中碰到一个问题,编译时可能会出现引用错误之类的问题,这个在#include "imagehlp.h"下面添加#pragma comment(lib, "imagehlp.lib")即可;Dbghelp.h同理。

这里加入#pragma comment 解决问题的原因:出错的地方主要在于链接程序无法解析别引用的外部函数(此时已经编译完成),使用comment使linker根据指定的库名查找该库,从而可以识别调用的函数。

那为什么出现这种情况?谷歌一下,原因在于vs的链接器默认写入了我们常用的一些库,当是一些不常用的库则没有,这个时候链接器只找到声明,倒是没有函数的定义部分,也因此需要我们自己添加。

  1. 由于函数并不复杂,可以尝试自己手动实现一个ImageRvaToVa函数:
INT32 ImageRvaToVa(PIMAGE_NT_HEADERS pNtH, LPVOID ImageBase, DWORD Rva) {

	INT sectionTbNum = pNtH->FileHeader.NumberOfSections;		// 记录节区头的个数,便于遍历
PIMAGE_SECTION_HEADER pCurrentSection = (PIMAGE_SECTION_HEADER)((DWORD)pNtH + (pNtH->FileHeader).SizeOfOptionalHeader + 0x18); // 当前节区头VA
// printf("%x\n", pCurrentSection->VirtualAddress);
// printf("sectionTbNum : %x \npCurrentSection : %x", (DWORD)sectionTbNum, (DWORD)pCurrentSection);/////////////////// for (int i = 0; i < sectionTbNum; i++, pCurrentSection ++) {
// 判定待转化的RVA是否在当前的节区范围内
if (Rva > pCurrentSection->VirtualAddress && Rva <= pCurrentSection->VirtualAddress+pCurrentSection->SizeOfRawData) {
// return: RVA - CurrentSectionRVA + CurrentSectionRAW + ImageBase
return Rva - pCurrentSection->VirtualAddress + pCurrentSection->PointerToRawData + (DWORD)ImageBase;
}
}
return 0;
}

自己尝试写的原因在于刚开始尝试以RVA+ImageBase作为VA的时候一直出错,后面上网找写文章看看,后面又看了一下OD中该可执行文件的导入表的地址计算方式,发现时VA = RVA+ImageBase,然后又看见一个关于ImageRvaToVa函数的汇编代码,之后自己尝试调试之后根据其不复杂的逻辑可以写出代码。

根据这个情况,是不是说明通过函数将PE文件映射进入进程的地址空间的做法并没有如同通常的可执行文件一样根据VA来确定位置,而是带有基址的文件偏移作为地址。

当不使用该文件影响时,要完全关闭这个文件映射对象,需要调用CreateFileMappingCloseHandle函数,调用顺序随意。

初步了解PE分析的更多相关文章

  1. ASLR pe 分析

    ASLR 转:http://www.cnblogs.com/dliv3/p/6411814.html 3ks @author:dlive 微软从windows vista/windows server ...

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

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

  3. PE分析

    1 #include<windows.h> 2 #include<RichEdit.h> 3 #include "resource.h" 4 5 6 7 B ...

  4. 开源安全:PE分析

    https://github.com/JusticeRage/Manalyze.git https://github.com/JusticeRage/Manalyze https://www.free ...

  5. PE文件格式分析

    PE文件格式分析 PE 的意思是 Portable Executable(可移植的执行体).它是 Win32环境自身所带的执行文件格式.它的一些特性继承自Unix的Coff(common object ...

  6. Hybrid APP基础篇(二)->Native、Hybrid、React Native、Web App方案的分析比较

    说明 Native.Hybrid.React.Web App方案的分析比较 目录 前言 参考来源 前置技术要求 楔子 几种APP开发模式 概述 Native App Web App Hybrid Ap ...

  7. 转载:案例用Excel对会员客户交易数据进行RFM分析

    案例:用Excel对会员客户交易数据进行RFM分析                                背景: 一个会员服务的企业,有近1年约1200个会员客户的收银数据.由于公司想针对不同 ...

  8. yolov3源码分析keras(一)数据的处理

    一.前言 本次分析的源码为大佬复现的keras版本,上一波地址:https://github.com/qqwweee/keras-yolo3 初步打算重点分析两部分,第一部分为数据,即分析图像如何做等 ...

  9. 【逆向知识】PE ASLR

    1.知识点 微软从windows vista/windows server 2008(kernel version 6.0)开始采用ASLR技术,主要目的是为了防止缓冲区溢出 ASLR技术会使PE文件 ...

随机推荐

  1. oppo5.0以上系统怎么样不Root激活Xposed框架的经验

    在非常多单位的引流或者业务操作中,基本上都需要使用安卓的黑高科技术Xposed框架,前几天我们单位购来了一批新的oppo5.0以上系统,基本上都都是基于7.0以上版本,基本上都不能够获取root超级权 ...

  2. Accesss数据库的DBhelper类(带分页)

    首先配置web.config,使配置文件连接access数据库: <connectionStrings> <add name="DBConnection" con ...

  3. July 01st. 2018, Week 27th. Sunday

    Empty your cup so that it may be filled. 清空杯子,方能再次装满. From Bruce Lee. We can't learn anything new if ...

  4. CF592D Super M

    嘟嘟嘟 首先这题虽然不是很难,但是黄题是不是有点过分了--好歹算个蓝题啊. 手玩样例得知,这哥们儿瞬移到的城市\(A\)一定是这些被攻击的城市构成的树的一个叶子,然后他经过的最后一个城市\(B\)和\ ...

  5. iOS可视化动态绘制八种排序过程(Swift版)

    前面几篇博客都是关于排序的,在之前陆陆续续发布的博客中,我们先后介绍了冒泡排序.选择排序.插入排序.希尔排序.堆排序.归并排序以及快速排序.俗话说的好,做事儿要善始善终,本篇博客就算是对之前那几篇博客 ...

  6. 5个常常被大家忽略的Python小技巧

    下面我挑选出的这几个技巧常常会被人们忽略,但它们在日常编程中能真正的给我们带来不少帮助. 1. 字典推导(Dictionary comprehensions)和集合推导(Set comprehensi ...

  7. 统一修改表单参数(表单提交的空字符串统一转null)

    统一修改表单参数(表单提交的空字符串统一转null) 1.介绍: 我们业务中有时会遇到提交的表单中某个参数为空字符串,导致后台接受的为空字符串("")而不是我们理想中的null,会 ...

  8. 2. CMake 系列 - 编译多文件项目

    目录 1. 编译不使用第三方库的项目 1.1 项目目录结构 1.2 相关代码 1.3 编译 2. 编译使用第三方库的项目 2.1 项目目录结构 2.2 相关代码 2.3 编译 1. 编译不使用第三方库 ...

  9. 【Netty】(9)---Netty编解码器

    Netty编解码器 在了解Netty编解码之前,先了解Java的编解码: 编码(Encode)称为序列化, 它将对象序列化为字节数组,用于网络传输.数据持久化或者其它用途. 解码(Decode)称为反 ...

  10. BannerDemo【图片轮播图控件】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 这里简单记录下一个开源库youth5201314/banner的运用.具体用法请阅读<youth5201314/banner& ...