内嵌补丁

内嵌补丁

需求

有时候我们直接修改OEP代码是不行的,因为该区域有可能被运行时压缩或者被加密过,直接改会引发程序异常,

这个时候我们可以换个思路,将写好的补丁放入内存中空的区域,然后再解密之后,先JMP到我们配置的区域,完成了我们的代码后再JMP到OEP处运行程序

运行时压缩流程

1.很多个解压缩循环(解码OEP)

2.配置IAT

3.JMP到OEP

加密代码执行流程

1.解密(解密OEP代码)

2.校验解密之后的和

3.如果校验和正确,则JMP到OEP,不正确,则程序异常

开始内嵌补丁之旅

先来看看程序的样子:
在这里插入图片描述
在这里插入图片描述
下面开始

解密循环

首先,打开实例程序

在这里插入图片描述

会看到很多汇编指令都是经过加密的,这里用search for all references strings也没用,字符串都是经过加密的

这里我们只能先进入004010E9,如下图:

在这里插入图片描述

接着进入0040109B

在这里插入图片描述

这里我们会看到给ECX赋值了154,然后给EBX地址处的值进行XOR 44运算,接着ECX减少,EXB增加,再比较ECX和0,然后是个条件跳转

这里我们可以知道,是将EBX地址处的值解密处理,每次处理一个字节,范围是EBX的最初值+154-1

看一下EBX的最初值:

在这里插入图片描述

004010F5,

那么这个解密的区域就是004010F5~00401248

接着往下调式,进入CALL 4010BD:

在这里插入图片描述

可以看到又是两个解密循环

同上一样得到这2个解密区域分别为:

401007~401085

4010F5~401248

到这里我们发现第三次的解密区域和第一次的相同,说明程序给4010F5~401248进行了两次解密,第一次解密是XOR 44,第二次解密是XOR 11

校验求和

接着往下看,遇到CALL 401039

在这里插入图片描述

进入:

在这里插入图片描述

调式到401046:

在这里插入图片描述

观察寄存器的值,发现EBX又是4010F5了,这不就是刚才解密2次的那个区域的起始地址吗,

接着看,EDX值为0

从401039到40104F区域的意思就是将EBX所在地址的值以每次4个字节的方式与EDX相加,最终求得4010F5~401248区域所有值的总和,保存在EDX

思考一下上面这个过程:

4010F5~401248区域就是解密2次的区域,将里面所有值求和放入EDX,为的就是校验和,查看解密区域代码是否被改动过

继续调式,来看一下EDX的最终值:

在这里插入图片描述

EDX=31EB8DB0,先记下这个值

继续调试,遇到CALL 40108A,进入:

在这里插入图片描述

在这里插入图片描述

这里可以看到,又是一个解码循环,区域为:

40124A~401280

再接着就是CMP EDX,31EB8DB0,这个就是比较EDX的值是否为31EB8DB0,接着4个PUSH然后接一个CALL,很容易想到是调用弹窗,这里调用弹窗,那么肯定是为了显示校验和正确或错误的信息,从右边字符串ERROR也可以猜到,那么显然,这里就是校验和错误会进入的地方,接着调用了一个401274,我猜是程序退出的API,

如果校验和正确,那么会执行JMP 40121E,这个地址就是我们要找的OEP

进入OEP

进入OEP,如下图:

在这里插入图片描述

(这里有个小技巧,如果进入OEP是加密状态,可以使用OD的Analysis code功能)

可以看到这个程序的实际主要功能就是一个弹出对话框API DialogBoxParamA(),

API DialogBoxParamA()的第四个参数是用来指出Dialog Box Procedure的地址的,也就是说这个地址就是该程序弹出对话框的地址(对话框里有我们想要修改的字符串)

查看4010F5:

在这里插入图片描述

我们需要修改的字符串都在这里

通过上图我们可以得出

“You must unpack me!!!”的地址在0040110A

“You must patch this NGA!!!”的地址在00401123

小结

通过上述分析,这里总结一下该程序结构:

401000~401006:EP代码

401007~401085:第一次解码区域(假设叫A区)

40108A~4010F4:解码区域

4010F5~401248:解码2次的区域(B)

40124A~401280:第四次解码区域(C)

OEP:40121E,位于B区域

EP代码的作用就是调用解码区域的代码

制作内嵌补丁

找到放补丁的地方

想要制作内嵌补丁,那么先要找到设置补丁代码的地方

常用三种方法:

1.找文件节区空白处(因为PE头基本是没有可利用的区域了)

2.扩展最后一个节区

3.新增节区

来看看第一种方法:

找文件节区的空白区域,

在这里插入图片描述

从上图第一个节区头中的信息可以看到,第一节区在内存中的大小是280,在文件中的大小是400,我们知道每个节区最后部分会有一片NULL区域的,那么400变280,很明显,文件中第一节区还有120大小的空间是空白的,我们来看看,如下图:

在这里插入图片描述

第一节区文件偏移400,映射到内存的有280,正好到680,后面的全为空白区域,也就是说我们可以将补丁放置此处

用OD打开,转到此处:

在这里插入图片描述

证实以上推断,从401280处开始后面为空白区域

编写补丁代码

在这里插入图片描述

注意点:

这里编写补丁代码的时候要先解码到这个地方,也就是说要先调式到OEP处

改变原来的JMP OEP

在这里插入图片描述

如上图,机器码E9 9601是解过密的

这里为什么只看到E9 9601 呢?

因为根据上面一系列分析,这部分的解密区域是属于:

401007~401085:第一次解码区域(假设叫A区)

第一次解密区域(A区)到401085就结束了,401083到401085就3个字节,所以E9 9601是解密的后面并未加密解密

注意:这里的E9 9601是经过A区解密之后的,也就是经过XOR 7解密之后的代码

回到原文件中:

在这里插入图片描述

可以看到解密之前也就是加密状态下的该位置,机器码是EE 9106

那么再来看看我们的JMP 401280对应的机器码是什么:

在这里插入图片描述

可以看到为:E9 F801

将其还原成加密状态,XOR 7,就成了:

EE FF06

所以,在文件中将其改写并保存,如图:

在这里插入图片描述

知识点:

为什么这里不在OD中直接改了保存,而要在文件中修改?

因为在映射中保存的是解密后的机器码,并不是加密状态的机器码,如果这样直接保存,会导致加密区解密之后的错误,所以直接在文件中将其改为加密的原状态

打补丁成功

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值