Eazy Inline Code Patch
常用于对象程序经过了加密处理或者加了压缩壳等而难以直接修改的情况
就是在程序已经解压缩或者解密后会有一个JMP跳转到OEP,我们修改这个JMP指令,将其目标地址设置为我们的"内嵌补丁的代码处"
接下来用一个示例来演示一下:
链接:https://pan.baidu.com/s/1ngpcVnEiTZ9ib3uKGUbCng
提取码:0syj
复制这段内容后打开百度网盘手机App,操作更方便哦--来自百度网盘超级会员V1的分享
运行一下,发现就是通过消息框显示字符串并退出
用OD打开程序,发现程序是被加密过的,那么直接搜索并修改字符串的方法是不对的
F7跟进函数
继续跟进
这里ebx的初值为0x004010F5,然后这个循环会进行0x154(ecx)次,0x0F5+0x154 = 0x249那么这个循环的意思就是将0x004010F5地址到0x00401248的区域的数据都和0x44进行异或。
跳过循环之后,跟进函数0x004010BD
又发现和之前的相同的操作,这里是将0x401007-0x401085区域的数据和0x7进行异或
继续单步向下
这里将0x004010F5到0x00401248处的数据都和0x11进行异或一下
继续单步,会回到0x004010B6处,然后调用函数0x00401039
跟进函数0x00401039
发现这段代码将0x004010F5-0x00401248以4个字节为单位依次读取值,然后add后储存到edx中,最后和0x31EB8DB0进行比较(校验和是比较常见判断指令是否被修改过的一种方法),如果相等,则跳转到0x00401083,否则便不跳转
然后继续单步,最后在地址0x00401083处发现了这个jmp到OEP的指令
然后会调用一个API函数
函数原型:
int DialogBoxParam
{
HINSTANCE hInstance,
LPCTSTR IpTemplateName,
HWND hWndParent,
DLGPROC IPDialogFunc,
LPARAM dwlnitParam
};
hlnstance:标识一个模块的实例,该模块的可执行文件含有对话框模板。
IpTemplateName:标识对话框模板。此参数可以指向一个以NULL结尾的字符串的指针,该字符串指定对话框模扳名,或是指定对话框模板的资源标识符的一个整型值。如果此参数指定了一个资源标识符,则它的高位字一定为零,且低位字一定含有标识符。一定用MAKEINTRESOURCE宏指令创建此值。
hWndParent:指定拥有对话框的窗口。
IpDialogFunc:指向对话框过程的指针。有关更详细的关于对话框过程的信息,请参见DialogProc。
dwInitParam:指定传递到对话框过程中的 WM_INITDIALOG 消息 IParam 参数的值。
返回值:如果函数调用成功则返回值为在对函数EndDialog的调用中的nResult参数,该EndDialog函数用于中止对话框。如果函数调用失败,则返回值为-1。若想获得错误信息,请调用GetLastError函数。
查看从OEP开始的汇编指令,发现在0x0040122C地址处的指令, push 0x004010F5是DialogBoxParam这个函数的第四个参数,说明DlgProc的地址为0x004010F5
DialogProc是一个窗口过程函数。该函数为一个应用程序定义可与DialogBox函数一起使用的回调函数。它处理发送到一个模态的或无模式对话框的消息。DLGPROC类型定义了一个指向此回调函数的指针。DialogProc函数是应用程序定义函数名的一个占位符。
这里就可以看到我们想要修改的字符串所在的地址了
0x0040110A和0x00401123地址处储存的字符串
现在我们的大脑中有了具体的流程,可以画一下大致的流程图
现在有一个问题,如果我们想要加入我们的补丁代码,那么我们应该如何加呢。
有三个方法可以设置:一:设置到文件的段的空白区域,二:扩展最后节区后设置,三:添加新节区后设置
一般代码少的话,直接使用第一种即可
现在我们来查找程序的哪些地方是空白的
查看stud_pe
发现第一个节区是从文件偏移的400开始的,大小为400,换算成RVA是(0x00401000-0x00401400,实际上,通过查看image_optional_header的sectionalignment可以得到节区的对齐值为0x1000,所以实际上第一个节区占的范围是0x00401000-0x00402000),然而VAsize的值为0x280,所以有指令的区域就只到0x00401280,换算成文件偏移就是680,我们可以通过winhex等16进制工具查看一下文件偏移680开始是否是空的
如果是,我们就可以往这段文件映射的内存中补入我们的补丁代码
将程序运行到OEP之后可以查看0x00401280处开始的全部是空的,我们可以在这个地方设置我们的补丁代码
在此之前,先了解几个指令
MOVSB、MOVSW 和 MOVSD 指令将数据从 ESI 指向的内存位置复制到 EDI 指向的内存位置。(根据方向标志位的值)这两个寄存器自动地增加或减少:
cld 设置方向标志位DF为0, 每次复制完, esi, edi自动增加, 指向下一个地址.
std 设置方向标志位DF为1, 每次复制完, esi, edi自动减少, 指向下一个地址.
至于esi, edi, 增加或减少多少个字节, 是根据 movsb/movsw/movsd最后面哪个字母决定.
movsb 以字节形式复制, 每次复制一个字节大小, esi/edi自动增加或减少1个字节
movsw 以字形式复制,每次复制一个字(2个字节)大小, esi/edi自动增加或减少2个字节
movsd 以双字形式复制, 每次复制2个字(4个字节)带下, esi/edi自动增加或减少4个字节
这几条命令一般都是配合 rep (repeat) 指令来使用, 表示重复复制
rep movs byte ptr es:[edi], byte ptr ds:[esi] 简写为: rep movsb
rep movs word ptr es:[edi], word ptr ds:[esi] 简写为: rep movsw
rep movs dword ptr es:[edi], dword ptr ds:[esi] 简写为: rep movsd
至于复制多少次, 是由ecx决定的.
先设置好指令,然后将我们的目的字符串直接在下方内存窗口中粘贴上去
这样之后,我们设置好了我们的补丁代码,接下来我们将原先那个jmp到OEP的指令跳转到我们的补丁代码的起始地址0x401280
将这个jmp设置为jmp到0x401280地址处即可
然而这样还不行
细心的话还会记得0x401083这个区域是被xor 7过的
我们也将E9 F8 01 00 00 和7进行异或
得到 EE FF 06 00 00
先将我们已经修改了的保存出去,然后使用16进制工具修改VA为0x401083处(文件偏移就为0x483)的指令
修改后再保存出去
运行程序,成功啦!就是这种破解好的成就感很爽
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)