内存Dump出PE
Posted 不会写代码的丝丽
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内存Dump出PE相关的知识,希望对你有一定的参考价值。
前言
我们常常会对内存数据导出从而得到运行时相关数据或者原始程序二进制,比如JAVA
堆转储分析内存泄漏,android
从内存导出脱壳后dex
或者so
。本文记录作者在学习在Windows下dump出原始二进制文件。
PE
PE
全称为Portable Executable
是Windows下二进制文件格式。微软PE官方解释
大致结构如下所示
你可以大致理解为主要有两个部分组成一个是头部
另一个是节区数据
.当然头部
和节区
存在8字节的空白区域
您可以看以下更详细图片
其中我们详细看看节区格式:
下图每一个小空格标识一个字节
其中我们介绍若干介绍会在Dump
使用的字段:
VirtualSize
:标识这个节区别加载到内存后的有效数据大小
VirtualAddress
:加载的内存地址,注意这个地址是一个相对基础模块的地址偏移值。
SizeOfRawData
:这个节区存储在文件中大小
PointerToRawData
存储节区数据在文件中的位置的偏移
简单理解就是,拷贝文件偏移地址PointerToRawData
的数据到内存位置为VirtualAddress
.拷贝的大小为SizeOfRawData
.
举个例子:
下图一个程序文件某个节区信息(蓝色高亮区域)
Name
:.text
VirtualSize
:0x36
VirtualAddress
:0x1F8
SizeOfRawData
: 0x38
PointerToRawData
: 0x1F8
我们看看位于PointerToRawData
(0x1F8
)位置,大小为SizeOfRawData
(0x38
)的截图(注意我们看看到):
随后我们将这个程序加入内存中的截图:
这个程序模块基础地址为:0x400000h (头文件有描述)
程序一共两个节区 (头文件有描述)
因此我们这个节区在内存的地址为0x400000h+0x1F8h = 0x4001F8h
我们将这个程序载入内存中 跳转到0x4001F8h
并高亮0x36
个数据(文件中是0x38)
开始dump
有上述知识后我们开始从内存dump一个程序,要求dump这个程序可以直接运行。
我们首先用winhex打开一个程序的主模块
首先无脑拷贝1A0
+8字节
+28*2=0x56h
内存到另一个空白二进制文件中.其中1A0
是头部的大小,8字节
是空白区域,0x56
是两个节区大小综合.
因为这个模块的基础地址为00400000
,所以我们拷贝0x00400000h
到0x4001F7h
即可(注意需要减一,因为文件偏移是从0开始的)
因为这个程序有两个节区,所以我们要分析两个节区信息拷贝回另一个文件。(下图高亮区域标识节区大小头部信息可自行查表)
我们这里举例其中一个节区区域拷贝.
下图高亮区域便是一个节区
VirtualSize
:0x36
VirtualAddress
:0x1F8
SizeOfRawData
: 0x38
PointerToRawData
: 0x1F8
根据上面的信息我们从 0x400000h+0x1F8h=0x4001F8h
拷贝38字节
(SizeOfRawData
)到文件偏移为 0x1F8
(PointerToRawData
)地方.
另一个节区不在演示直接看粘贴结果
我们将上面拷贝的文件的后可以直接运行。
所有的内存dump 都可运行?
答案是否定的
因为你dump的节区数据可能被更改,所以你应该在程序OEP
处进行dump。
举个例子:
#include <iostream>
#include<Windows.h>
long *p = nullptr;
int main()
if (p==nullptr)
p = new long;
int i = 0;
while (true)
Sleep(100);
*p = ++i;
如果你在while(true)
进行dump那么会触发内存非法访问的异常。因为p数据会放在未初始化区域,但是你dump后可能导致把初始化new long也给带出了。
以上是关于内存Dump出PE的主要内容,如果未能解决你的问题,请参考以下文章