在前面的PE文件笔记八 实战之HOOK程序添加弹窗中能够使用OD达到在运行态时添加弹窗的功能,接下来则要对先前的反汇编的硬编码稍作修改然后插入到PE文件中,最后再修改入口点即可;具体流程在上个笔记已经说明了,这里不再赘述

PE实战之给程序添加弹窗续

最终效果图

先看一下最终的效果图

弹窗


反汇编和硬编码的对应关系

因为后面要将反汇编代码转换为硬编码,于是这里就要研究一下两者的对应关系

先贴上先前得到的反汇编代码

 复制代码 隐藏代码00401130 >    6A 00         push 0x0
00401132 68 52114000 push MessageB.00401152
00401137 68 48114000 push MessageB.00401148
0040113C 6A 00 push 0x0
0040113E E8 A7F69477 call user32.MessageBoxA
00401143 - E9 8801C4FF jmp 000412D0
00401148 6c db 6c
........

push对应硬编码

压入的第一个和第四个参数是一个立即数0,于是它对应的硬编码固定为6A 00

 复制代码 隐藏代码00401130 >    6A 00         push 0x0
0040113C 6A 00 push 0x0

前面的6A是固定的,表示压入一个立即数,

后面的字节码表示压入的立即数,该立即数 的范围是0~0x7F即0~127

当立即数大于0x7F后硬编码和其含义就都改变了

 复制代码 隐藏代码6A 7F         push 0x7F
68 80000000 push 0x80

于是得到了push 立即数 对应的硬编码为6A 立即数


压入的第二个和第三个参数是内存地址0x00401152中存储的数据和0x00401148中存储的数据

 复制代码 隐藏代码00401132      68 52114000   push MessageB.00401152
00401137 68 48114000 push MessageB.00401148

观察硬编码和压入的地址的关系

前面的68是固定的,表示push 一个内存地址

后面的则是要push的内存地址的小端存储,倒过来看就是压入的内存地址了

举个例子,如果push 的内存地址为0x12345678

则其对应的硬编码为 68 78 56 34 12

 复制代码 隐藏代码
68 78563412 push 0x12345678

于是得到了push 内存地址 对应的硬编码为 68 内存地址的小端存储


call对应硬编码

接下来就是调用MessageBoxA了,其形式为:call MessageBoxA对应的内存地址

 复制代码 隐藏代码0040113E      E8 A7F69477   call user32.MessageBoxA
上面为OD的反汇编引擎为方便我们观看,而显示的内容,下面才是实际的反汇编代码
0040113E E8 A7F69477 call 77D507EA

分析call 内存地址 和 硬编码的关系

前面的E8是固定的,表示直接调用一个内存地址

后面的则是偏移,该偏移为小端存储,此时值为:0x7794F6A7

不难发现这个偏移 = call的内存地址 - 当前的内存地址 - 当前指令的总长度

即 0x7794F6A7 = 0x77D507EA - 0x0040113E - 5

再举个例子,如果当前要跳转的内存地址为0x12345678

则其对应的 偏移 = 0x12345678 - 0040113E - 5 = 11F44535

 复制代码 隐藏代码
0040113E E8 3545F411 call 12345678

于是得到了call 内存地址 对应的硬编码为 E8 偏移的小端存储,其中偏移 = 要调用的内存地址 - 当前的内存地址 - 当前指令的总长度


jmp对应硬编码

 复制代码 隐藏代码
00401143 - E9 8801C4FF jmp 000412D0

前面的E9是固定的,表示跳转到一个内存地址

后面的也是偏移,该偏移为小端存储,此时值为:0xFFC40188

偏移 = jmp的内存地址 - 当前的内存地址 - 当前指令总长度

即 0xFFC40188 = 0x000412D0 - 0x00401143 - 5

于是得到了jmp 内存地址 对应的硬编码为 E9 偏移的小端存储,其中偏移 = 要跳转的内存地址 - 当前的内存地址 - 当前指令总长度

寻找空白区

知道了硬编码如何构造以后,就要在PE文件中找一块空白区,向里面写入要执行的硬编码

有了先前PE文件笔记二 PE文件的两种状态的知识,可以知道由于文件对齐,在块表和块之间是存在空隙(空白区)的,于是可以向这块区域写入硬编码

这次用来演示的软件是前面经常出场的EverEdit.exe,直接找到其对应的空白区:

image-20210403135440893


构造硬编码

找到空白区的地址为0x2B0,注意此时的地址为文件中的状态

在内存中其对应的地址为ImageBase+0x2B0 = 0x00400000+0x2B0 = 0x004002B0

PS:如果选取的空白区为块中的空白区,则需要进行FOA到VA的转换,相关内容在PE文件笔记七 RVA与FOA转换已说明,这里不再赘述

image-20210403141604370


于是从这里开始构造硬编码

根据前面反汇编一行一行来构造硬编码

 复制代码 隐藏代码00401130 >    6A 00         push 0x0
00401132 68 52114000 push MessageB.00401152
00401137 68 48114000 push MessageB.00401148
0040113C 6A 00 push 0x0
0040113E E8 A7F69477 call user32.MessageBoxA
00401143 - E9 8801C4FF jmp 000412D0
00401148 6c db 6c

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,将其写入文件中:

 复制代码 隐藏代码
6A00680000000068000000006A00

image-20210403142658934


call MessageBoxA

call 内存地址,要call的内存地址为MessageBoxA对应的地址,在本机中为0x77D507EA

此时的内存地址为ImageBase+0x2BE= 0x004002BE

于是可以算出 偏移 = 要跳转的地址 - 内存地址 - 当前指令总长度 = 0x77D507EA - 0x004002BE -5 = 0x77950527

于是得到的硬编码为 E8 27 05 95 77,将其写入文件中:

 复制代码 隐藏代码
E827059577

image-20210403143107638


jmp 程序入口点

所谓的程序入口点就是 扩展PE头中的AddressOfEntryPoint + ImageBase得到的内存地址

在先前的PE文件笔记五 PE文件头之扩展PE头中其实已经看过了,这里再用PE工具:Detect It Easy查看一下:

image-20210403143747806


可以得到AddressOfEntryPoint 为0x16AF12,加上ImageBase得到0x56AF12

于是要跳转的地址就是0x56AF12,对应汇编为 jmp 0x56AF12

此时的内存地址为ImageBase+0x2C3 = 0x004002C3

偏移 = 要跳转的地址 - 此时的内存地址 - 当前指令的总长度 = 0x56AF12 - 0x004002C3 - 5 = 0x0016AC4A

于是得到对应的硬编码为 E9 4A AC 16 00,将其写入文件中:

 复制代码 隐藏代码
E94AAC1600

image-20210403144457310


填充字符串ASCII码

参数 含义 字符串 ASCII 文件中起始地址 内存中起始地址
第三个参数 窗口内容 lyl610abc 6C796C36313061626300 2C8 004002C8
第二个参数 窗口标题 tips 7469707300 2D2 004002D2

填充完如下:

image-20210403150527290


修正参数

填充完字符串就可以修正参数了

第二个参数 为 push 0x004002D2,对应”tips”,对应硬编码为68 D2 02 40 00

 复制代码 隐藏代码
68D2024000

第三个参数为 push 0x004002C8,对应”lyl610abc”,对应硬编码为68 C8 02 40 00

 复制代码 隐藏代码
68C8024000

修正完的结果为:

image-20210403150921982


所有的硬编码

 复制代码 隐藏代码
6A0068D202400068C80240006A00E827059577E94AAC16006C796C363130616263007469707300

修改程序入口点

构造完硬编码后,只要将程序入口点改为硬编码的首地址:0x2B0即可

找到原本的程序入口点

image-20210403151245859


修改程序入口点

image-20210403151407916


保存程序并测试运行

最后便是将程序保存,然后打开

保存

我这里另存为了EverEdit2.exe

image-20210403151545013


测试运行

弹窗

可以看到能够成功地为程序添加弹窗,完毕(~ ̄▽ ̄)~

说明

测试的系统务必为32位的XP系统,在高版本的系统有DEP和ASLR保护机制,使用以上方法修改后无法运行

上面的MessageBoxA的地址是用OD获取的,具体方法见上一篇笔记,如果想要复现为程序添加弹窗,则要修改对应的MessageBoxA的地址

附件

附上本笔记中要修改的EverEdit文件:点我下载