20.“内嵌补丁”练习

1. 内嵌补丁(Inline Patch)

“内嵌补丁”是“内嵌代码补丁”(InlineCodePatch)的简称,难以直接修改指定代码时,插人并运行被称为“洞穴代码”(Code Cave)的补丁代码后,对程序打补丁。

用处:常用于对象程序经过运行时压缩(或加密处理)而难以直接修改的情况
如图:
Pasted image 20250920163630.png

这是典型的运行时压缩代码(或者加密代码)。EP代码先把加密的OEP代码解密,然后跳转到OEP代码处。

但是如果 要打补丁的代码存在于被加密的OEP区域 则是很难打补丁的(即使知道代码位置), 因为解码过程中很可能解出完全不同的结果

解决办法:右图

  • 先解密OEP代码、然后修改JMP指令,运行洞穴代码
  • 在洞穴代码中执行补丁代码后(因为OEP已经被解密了,所以可以这样修改),再跳转到OEP处。

即每次运行时都会运行另外的补丁代码对进程内存的代码打补丁,这种方法就被称为 内嵌代码补丁 或者 内嵌补丁

1.1. 代码补丁与内嵌补丁的异同

对象 代码补丁 内嵌补丁
对象 文件 文件 & 内存
次数 1次 文件中 1 次,内存中每次运行时
方法 直接 (直接对指定位置打补丁) 间接 (提前设置漏洞代码,在内存中对指定区域解密时打补丁)

1.2. 练习

unpackme-1.aC.exe

unpackme-1.aC_patched.exe

此程序会先检测它是否含有病毒代码再运行,打开后会要求你更改显示的字符串
Pasted image 20250920171554.png

1.3. 调试:查看代码流

Pasted image 20250920172351.png
401007之后就是加密代码

先找字符串
Pasted image 20250920172858.png
可以发现都是加密的
先进入第一个函数内部看看
Pasted image 20250920173036.png
这里就是一个循环解密的代码

004010A3  |> /8033 44       /xor     byte ptr ds:[ebx],0x44

使用上面的命令对特定区域(4010F5--401248)解密。跟踪进入地址4010b0处的call命令调用函数(4010bd)可以看到另外两个解密循环

Pasted image 20250920174010.png
地址4010C8处的XOR命令用来解密401007~401085区域,然后再使用4010DB地址处的XOR 命令对4010F5~401248区域解密。该区域与图中解密区域一致,由此可知该区域经过双重加密处理

4010BD函数调用完毕后遇到4010B6地址处的CALL401039命令

跟踪进人被调用的函数(401039),看到图中代码。
Pasted image 20250920174712.png

401039函数中需要注意的是位于401046地址处的校验和计算循环。首先使用401041地址处的MOV EDX,0命令,将0代入(初始化)EDX。然后使用401046地址处的ADD命令,从特定地址区域(4010F5~401248)以4个字节为单位依次读入值,进行加法运算后,将累加结果存储到EDX 寄存器。

循环结束时,EDX寄存器中存储着某个特定值,这就是校验和值。由前面的讲解可知,该校验和计算区域是一个双重加密区域。可以推测出,我们要修改的字符串就存在于此。

Tip

EDX寄存器为4个字节大小,像这样向其中不断加上4个字节的值,就会发生溢出(overflow)问题。一般的校验和计算中常常忽略该溢出问题,使用最后一个保存在EDX的值。

位于地址401062~401068处的CMP/JE命令用来将计算得到的校验和(存储在EDX寄存器的)值与31EB8DB0比较,若相同(表示代码未被改动过),则由401083地址处的JMP指令跳转到OEP (40120.)处;若不同,则输出错误信息“CrC of this file has been modified!!!”,终止程序。

这种校验和计算方法常常用来验证特定区域的代码/数据是否被改动过。只要指定区域中的一个字节发生改变,校验和值就会改变。所以更改了指定区域中的代码/数据时,一定要修改校验和比较相关部分。

图中显示的是OEP代码,用来运行对话框。执行位于40123E地址处的 CALL user32.DialogBoxParamAO 命令后,即弹出对话框。下面是DialogBoxParamAOAPI的定义。
Pasted image 20250920180305.png
Pasted image 20250920180314.png

INT_PTR WINAPI DialogBoxParam(
    __in_opt HINSTANCE hInstance,
    __in     LPCTSTR lpTemplateName,
    __in_opt HWND    hWndParent,
    __in_opt DLGPROC lpDialogFunc,
    __in     LPARAM  dwInitParam
);