我是靠谱客的博主 年轻羽毛,最近开发中收集的这篇文章主要介绍手工解析PE(文件注入),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

说明

准备工作  编译生成A.exe

一、使用OD 找到messagebox的函数地址

二、使用PE 找到程序入口点

三、找出一个节,看看空闲空间够不够存放我们自己的代码

四、将汇编语言转化为二进制   嵌入到文件中

 五、修改程序入口OEP

六、一些其他事项


说明

本次实验的内容就是先找出A.exe的messagebox()函数地址,把调用messagebox()的代码嵌入到 A.exe的文件当中 ,使得A.exe在启动的时候可以先调用messagebox() 再调用fun() 这样做的目的是可以手工调用原程序的函数

思路就是将调用messagebox()的代码写入A.exe的空闲区,然后将程序入口修改为我们嵌入的代码,执行完嵌入的代码后 让程序再跳回原来的入口点

准备工作  编译生成A.exe

#include <stdio.h>
#include <Windows.h>
void fun()
{
	printf("hello n");
}

int main()
{
	fun();
	return 0;
}

一、使用OD 找到messagebox的函数地址

在MessageBoxA处下个断点,找到内存中messagebox函数地址为 774D0A50

二、使用PE 找到程序入口点

找到A程序入口地址为0x00001380

三、找出一个节,看看空闲空间够不够存放我们自己的代码

根据PE结构,可以看出 第一节从文件的400处开始,大小为31D6,到400+3200处结束,空闲空间为 3200-31D6= 2A  ,够放我们的代码,所以最终我们会把自己的代码写到文件的 400+31D6=35D6 后面

35D6 后面3600前面 都可以写, 那我们就写到35D0的下一行 35E0处

四、将汇编语言转化为二进制   嵌入到文件中

因为我们要修改文件,添加我们自己的代码,所以添加的内容是关键。这里不能直接将call 774D0A50 和 jmp 00001380 写进去,因为文件中全是16进制的数字,所以我们也只能写16进制的数字进去,这样就需要将汇编语言转化为二进制数字

就是将  call 774D0A50和 jmp 00001380 转化为二进制

call对应的硬编码为E8

jmp对应的硬编码为E9

另外,需要计算E8和E9后面跟的跳转地址X。

比如下面这段代码:

int main()
{
内存地址  文件编码             汇编指令
00601050 55                   push        ebp  
00601051 8B EC                mov         ebp,esp  
	fun();
00601053 E8 AD FF FF FF       call        fun (601005h)  
	return 0;
00601058 33 C0                xor         eax,eax  
}

从上面汇编代码可以看出 如果 我们想调用fun()函数,需要跳到 601005h这个地址,对应的文件编码并不是 E8 601005, 而是 E8 ADFFFFFF ,那么文件编码地址ADFFFFFF和内存地址601005有什么关系呢

可以根据下面这个公式计算得出  【内存函数地址 = 文件指令地址 + 偏移地址(文件编码地址) 】

公式:文件编码地址  =  内存中的函数地址 -  当前指令的下条指令地址

                                  =  内存中的函数地址 -  (当前指令地址 + 5)   

         

        即  偏移地址 = 内存地址   - (调用处地址 + 5)

        其实就是计算调用处地址距离内存函数地址有多远

    说明

        E8和E9后面跟的其实不是内存的函数地址,而是当前指令的偏移地址,我们需要根据内存地址和当前指令地址(E8的地址) 计算出偏移地址 ,嵌入到文件中的代码为  E8 偏移地址

     

    计算过程:

        例如上面那段汇编代码

                内存中的函数地址 = 601005

                当前指令地址  = 601053

                偏移地址  =  内存中的函数地址 -  (当前指令地址 + 5)

                                =   601005 - ( 601053 + 5 ) 

                                =   FFFFFFAD

         所以 文件编码是 E8 AD FF FF FF

因为要调用messagebox() 还需要传4个参数 PUSH 0 (6A 00),所以我们要嵌入的代码就是

6A 00 6A 00 6A 00 6A 00 E8 XX XX XX XX E9 XX XX XX XX

 由上图可以看出

        E8 当前指令地址为35E8        但是在内存中 当前指令地址为  imagebase   +    节偏移    + ( 35E8 -   文件节起始地址)

        E9 当前指令地址为35ED       但是在内存中 当前指令地址为  imagebase   +    节偏移    + ( 35ED -   文件节起始地址) 

然后计算后面的偏移地址 XX XX XX XX 

       E8 偏移地址 = 内存中的函数地址 -  (当前指令地址 + 5)

                            = 774D0A50 -  (( imagebase   +    节偏移    + ( 35E8 -   文件节起始地址) ) + 5 )

                            = 774D0A50 - (4041E8 + 5)

                            = 770CC863

       E9 偏移地址 = 内存中的函数地址 -  (当前指令地址 + 5)

                            =  00400000 + 13A0 -  (当前指令地址 + 5)

                           =  00401380 - (4041ED + 5)

                           =  FFFFD18E

注意:以上【当前指令地址】这个变量 应该是对应的内存中的地址,35E8 是文件中的指令偏移,真正在内存中的指令地址应该是 

                         imagebase   +    vir节偏移    + ( 文件节指令偏移   -   文件节起始地址)

                          00400000        00001000                 35E8                         400 

综上所述 我们嵌入的代码为

6A 00 6A 00 6A 00 6A 00 E8 63 C8 0C 77 E9 8E D1 FF FF

 五、修改程序入口OEP

        35E0距离节开始位置 (35E0-400)

        真正在内存中的程序入口为   节在内存偏移+入口偏移节

                                                  =  节在内存偏移 + ( 入口 - 节开始位置)

                                                  =         1000        + ( 35E0 - 400)

                                                  = 41E0

       所以将 原来的程序入口 1380 改为 41E0

       因为入口点是相对于imagebase的偏移量,所以这里入口点的值应该改为入口点距离imagebase有多远的偏移量,而不是入口点的内存地址 4041E0

        

        

 用PE软件解析以下,发现已经改过来了

六、一些其他事项

在我们修改完文件之后,重新运行发现无法运行,使用OD查看,发现每次修改完文件,OD中的内存地址都会改变,为了使内存地址固定,我们需要关闭ASLR 或者 在项目中关闭动态基址

https://www.52pojie.cn/thread-1099755-1-1.html

改了以后如果还不好使 试试这个方法

关闭程序的动态基地址功能_别人家的好孩子的博客-CSDN博客

最后

以上就是年轻羽毛为你收集整理的手工解析PE(文件注入)的全部内容,希望文章能够帮你解决手工解析PE(文件注入)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(47)

评论列表共有 0 条评论

立即
投稿
返回
顶部