PE文件笔记九 实战之HOOK程序添加弹窗续
在前面的PE文件笔记八 实战之HOOK程序添加弹窗中能够使用OD达到在运行态时添加弹窗的功能,接下来则要对先前的反汇编的硬编码稍作修改然后插入到PE文件中,最后再修改入口点即可;具体流程在上个笔记已经说明了,这里不再赘述
PE实战之给程序添加弹窗续
最终效果图
先看一下最终的效果图
反汇编和硬编码的对应关系
因为后面要将反汇编代码转换为硬编码,于是这里就要研究一下两者的对应关系
先贴上先前得到的反汇编代码
复制代码 隐藏代码00401130 > 6A 00 push 0x0 |
push对应硬编码
压入的第一个和第四个参数是一个立即数0,于是它对应的硬编码固定为6A 00
复制代码 隐藏代码00401130 > 6A 00 push 0x0 |
前面的6A是固定的,表示压入一个立即数,
后面的字节码表示压入的立即数,该立即数 的范围是0~0x7F即0~127
当立即数大于0x7F后硬编码和其含义就都改变了
复制代码 隐藏代码6A 7F push 0x7F |
于是得到了push 立即数 对应的硬编码为6A 立即数
压入的第二个和第三个参数是内存地址0x00401152中存储的数据和0x00401148中存储的数据
复制代码 隐藏代码00401132 68 52114000 push MessageB.00401152 |
观察硬编码和压入的地址的关系
前面的68是固定的,表示push 一个内存地址
后面的则是要push的内存地址的小端存储,倒过来看就是压入的内存地址了
举个例子,如果push 的内存地址为0x12345678
则其对应的硬编码为 68 78 56 34 12
复制代码 隐藏代码 |
于是得到了push 内存地址 对应的硬编码为 68 内存地址的小端存储
call对应硬编码
接下来就是调用MessageBoxA了,其形式为:call MessageBoxA对应的内存地址
复制代码 隐藏代码0040113E E8 A7F69477 call user32.MessageBoxA |
分析call 内存地址 和 硬编码的关系
前面的E8是固定的,表示直接调用一个内存地址
后面的则是偏移,该偏移为小端存储,此时值为:0x7794F6A7
不难发现这个偏移 = call的内存地址 - 当前的内存地址 - 当前指令的总长度
即 0x7794F6A7 = 0x77D507EA - 0x0040113E - 5
再举个例子,如果当前要跳转的内存地址为0x12345678
则其对应的 偏移 = 0x12345678 - 0040113E - 5 = 11F44535
复制代码 隐藏代码 |
于是得到了call 内存地址 对应的硬编码为 E8 偏移的小端存储,其中偏移 = 要调用的内存地址 - 当前的内存地址 - 当前指令的总长度
jmp对应硬编码
复制代码 隐藏代码 |
前面的E9是固定的,表示跳转到一个内存地址
后面的也是偏移,该偏移为小端存储,此时值为:0xFFC40188
偏移 = jmp的内存地址 - 当前的内存地址 - 当前指令总长度
即 0xFFC40188 = 0x000412D0 - 0x00401143 - 5
于是得到了jmp 内存地址 对应的硬编码为 E9 偏移的小端存储,其中偏移 = 要跳转的内存地址 - 当前的内存地址 - 当前指令总长度
寻找空白区
知道了硬编码如何构造以后,就要在PE文件中找一块空白区,向里面写入要执行的硬编码
有了先前PE文件笔记二 PE文件的两种状态的知识,可以知道由于文件对齐,在块表和块之间是存在空隙(空白区)的,于是可以向这块区域写入硬编码
这次用来演示的软件是前面经常出场的EverEdit.exe,直接找到其对应的空白区:
构造硬编码
找到空白区的地址为0x2B0,注意此时的地址为文件中的状态
在内存中其对应的地址为ImageBase+0x2B0 = 0x00400000+0x2B0 = 0x004002B0
PS:如果选取的空白区为块中的空白区,则需要进行FOA到VA的转换,相关内容在PE文件笔记七 RVA与FOA转换已说明,这里不再赘述
于是从这里开始构造硬编码
根据前面反汇编一行一行来构造硬编码
复制代码 隐藏代码00401130 > 6A 00 push 0x0 |
push 参数
1.push 0 直接用6A 00填充,无需修改
2.push 内存地址,该内存地址存储第二个参数”tips”,因为内存地址尚未填充,先用00代替,为 68 00 00 00 00
3.push 内存地址,该内存地址存储第三个参数”lyl610abc”,同样先用00代替,为 68 00 00 00 00
4.push 0 直接用6A 00填充,无需修改
于是得到的硬编码为:6A 00 68 00 00 00 00 68 00 00 00 00 6A 00,将其写入文件中:
复制代码 隐藏代码 |
call MessageBoxA
call 内存地址,要call的内存地址为MessageBoxA对应的地址,在本机中为0x77D507EA
此时的内存地址为ImageBase+0x2BE= 0x004002BE
于是可以算出 偏移 = 要跳转的地址 - 内存地址 - 当前指令总长度 = 0x77D507EA - 0x004002BE -5 = 0x77950527
于是得到的硬编码为 E8 27 05 95 77,将其写入文件中:
复制代码 隐藏代码 |
jmp 程序入口点
所谓的程序入口点就是 扩展PE头中的AddressOfEntryPoint + ImageBase得到的内存地址
在先前的PE文件笔记五 PE文件头之扩展PE头中其实已经看过了,这里再用PE工具:Detect It Easy查看一下:
可以得到AddressOfEntryPoint 为0x16AF12,加上ImageBase得到0x56AF12
于是要跳转的地址就是0x56AF12,对应汇编为 jmp 0x56AF12
此时的内存地址为ImageBase+0x2C3 = 0x004002C3
偏移 = 要跳转的地址 - 此时的内存地址 - 当前指令的总长度 = 0x56AF12 - 0x004002C3 - 5 = 0x0016AC4A
于是得到对应的硬编码为 E9 4A AC 16 00,将其写入文件中:
复制代码 隐藏代码 |
填充字符串ASCII码
参数 | 含义 | 字符串 | ASCII | 文件中起始地址 | 内存中起始地址 |
---|---|---|---|---|---|
第三个参数 | 窗口内容 | lyl610abc | 6C796C36313061626300 | 2C8 | 004002C8 |
第二个参数 | 窗口标题 | tips | 7469707300 | 2D2 | 004002D2 |
填充完如下:
修正参数
填充完字符串就可以修正参数了
第二个参数 为 push 0x004002D2,对应”tips”,对应硬编码为68 D2 02 40 00
复制代码 隐藏代码 |
第三个参数为 push 0x004002C8,对应”lyl610abc”,对应硬编码为68 C8 02 40 00
复制代码 隐藏代码 |
修正完的结果为:
所有的硬编码
复制代码 隐藏代码 |
修改程序入口点
构造完硬编码后,只要将程序入口点改为硬编码的首地址:0x2B0即可
找到原本的程序入口点
修改程序入口点
保存程序并测试运行
最后便是将程序保存,然后打开
保存
我这里另存为了EverEdit2.exe
测试运行
可以看到能够成功地为程序添加弹窗,完毕(~ ̄▽ ̄)~
说明
测试的系统务必为32位的XP系统,在高版本的系统有DEP和ASLR等保护机制,使用以上方法修改后无法运行
上面的MessageBoxA的地址是用OD获取的,具体方法见上一篇笔记,如果想要复现为程序添加弹窗,则要修改对应的MessageBoxA的地址
附件
附上本笔记中要修改的EverEdit文件:点我下载