因为这是我做的第一个PatchMe,所以哪里不对还请大佬们指出来。
0x0 初探
首先,程序有一个rules.txt,内容如下:
只看得懂一部分,大致是说,给Exit菜单添加代码,单击的时候弹出一个信息框,内容是"Do you fickbirne really want to quit?",如果点[是]就退出,否则不退出。
打开CM看一下,发现程序有两个菜单,第一个是[About],点击以后弹出一个信息框,如下图所示:
第二个则是[Exit],点击以后啥提示也没有。
直接给user32!MessageBoxTimeoutW下断点,然后点击[About],可以断下来(我选中的部分就是这个函数的参数)。
一直F8单步,可以返回到程序领空,浏览一下附近的代码就可以发现函数头了(0x0043CC14处),往下走还可以发现程序有一个参数(因为使用了retn 4指令来返回)。
一直F8单步,来到retn 4(0x0043CD69处),可以发现这个函数的返回地址。
然后来到这里
发现代码很奇怪,我猜测是代码和数据混在了一起,不过看这个机器码可以发现0x0043E277(0x0043E276 + 1)处的应该是代码了。
这段好像也没什么有用的呢,再返回,来到0x0042F42E处
看一下这段代码,很容易就能猜测到,这段代码应该就是获取对应组件的事件地址然后调用的吧。
给0x0042F420处下断点,然后点击[About],断下后查看ebx寄存器的值。
这个正好是这个[About]菜单的名字。
于是就可以写一段代码来拦截这个函数,在中途判断,如果是[Exit]菜单,就修改调用的函数地址。其中dword ptr ds:[ebx + 0x80]就是对应的事件函数地址。
不过有这个思路了,但是却不知道如果点击了[Exit]菜单,在ebx寄存器所指向的地址中看到的字符串,因此没办法判断,于是就需要获取一下,获取的方法如下:
1.给0x00435039处下断点,然后点击[Exit]菜单,此时可以断下。
2.断下后,再给0x0042F416处下断点,然后F9运行,运行到这里后,直接查看ebx寄存器所指向的地址。
这样就拿到了两个字符串了,其中:
dword ptr ds:[ebx + 0x08]是"Exit1"
dword ptr ds:[ebx + 0x24]是"&Exit"
这样只要在适当的位置拦截即可。
拦截的方法很简单,就是修改这个函数,判断是否是这两个字符串,如果不是则返回,是的话则修改函数的事件地址。
在修改的时候,为了保证通用性,首先我们查看程序的输入表是否有kernel32.dll(一般都有),再查看是否有导入ExitProcess这个API,如果没有的话就需要我们添加他。
很幸运,程序中有导入这个函数,那么就简单多了,从导入表的信息可以得知ImageBase + 0x00041164处就存放着kernel32!ExitProcess的地址了。
同理,再去用这个方法寻找user32.dll中的信息框的API。
0x1 修改
现在信息都已经收集完毕,可以开始修改了。
我有使用FFIcoustmtk来修改这个文件,百度可以找到,只要搜索"FFI通用脱壳工具"就可以找到下载了。
首先去掉程序的重定位表,以免修改的时候遇到各种奇葩问题。
然后添加一个区段,大小设置成0x1000
然后修改区段属性为0xE00000E0
记下新区段的虚拟地址,然后OD载入,来到ImageBase + VA处(VA是新区段的虚拟地址。我这里是ImageBase + VA = 0x00400000 + 0x0004E000)
然后在新区段中加入如下代码:
0044E000 60 pushad
0044E001 90 nop
0044E002 FF73 08 push dword ptr [ebx+0x8]
0044E005 68 87E04400 push 0044E087 ; ASCII "Exit1"
0044E00A E8 28000000 call 0044E037
0044E00F 85C0 test eax, eax
0044E011 74 1B je short 0044E02E
0044E013 FF73 24 push dword ptr [ebx+0x24]
0044E016 68 8DE04400 push 0044E08D ; ASCII "&Exit"
0044E01B E8 17000000 call 0044E037
0044E020 85C0 test eax, eax
0044E022 74 0A je short 0044E02E
0044E024 C783 80000000 9>mov dword ptr [ebx+0x80], 0044E093 ; 新函数的地址
0044E02E 90 nop
0044E02F 61 popad
0044E030 68 E4E04400 push 0044E0E4 ; UNICODE "荦刍"
0044E035 C3 retn
0044E036 90 nop
0044E037 FF7424 04 push dword ptr [esp+0x4] ; 字符串比较
0044E03B E8 33000000 call 0044E073
0044E040 50 push eax
0044E041 FF7424 08 push dword ptr [esp+0x8]
0044E045 E8 29000000 call 0044E073
0044E04A 8BD0 mov edx, eax
0044E04C 58 pop eax
0044E04D 3BC2 cmp eax, edx
0044E04F 75 1D jnz short 0044E06E
0044E051 33C9 xor ecx, ecx
0044E053 8B7424 04 mov esi, dword ptr [esp+0x4]
0044E057 8B7C24 08 mov edi, dword ptr [esp+0x8]
0044E05B 8A1431 mov dl, byte ptr [ecx+esi]
0044E05E 3A1439 cmp dl, byte ptr [ecx+edi]
0044E061 75 0B jnz short 0044E06E
0044E063 41 inc ecx
0044E064 3BC8 cmp ecx, eax
0044E066 ^ 75 F3 jnz short 0044E05B
0044E068 33C0 xor eax, eax
0044E06A 40 inc eax
0044E06B C2 0800 retn 0x8
0044E06E 33C0 xor eax, eax
0044E070 C2 0800 retn 0x8
0044E073 33C9 xor ecx, ecx ; 取字符串长度
0044E075 8B4424 04 mov eax, dword ptr [esp+0x4]
0044E079 803C08 00 cmp byte ptr [eax+ecx], 0x0
0044E07D 74 03 je short 0044E082
0044E07F 41 inc ecx
0044E080 ^ EB F7 jmp short 0044E079
0044E082 8BC1 mov eax, ecx
0044E084 C2 0400 retn 0x4
0044E087 45 inc ebp
0044E088 78 69 js short 0044E0F3
0044E08A 74 31 je short 0044E0BD
0044E08C 0026 add byte ptr [esi], ah
0044E08E 45 inc ebp
0044E08F 78 69 js short 0044E0FA
0044E091 74 00 je short 0044E093
0044E093 6A 24 push 0x24 ; MB_YESNO | MB_ICONQUESTION
0044E095 68 DCE04400 push 0044E0DC ; ASCII "_KaQqi"
0044E09A 68 B6E04400 push 0044E0B6 ; ASCII "Do you fickbirne really want to quit?"
0044E09F 6A 00 push 0x0
0044E0A1 FF15 A4114400 call dword ptr [<&user32.MessageBoxA>] ; user32.MessageBoxA
0044E0A7 83F8 06 cmp eax, 0x6
0044E0AA 75 09 jnz short 0044E0B5
0044E0AC 6A 00 push 0x0
0044E0AE 2E:FF15 6411440>call dword ptr cs:[<&kernel32.ExitProcess>] ; kernel32.ExitProcess
0044E0B5 C3 retn
0044E0B6 44 inc esp ; 提示信息和标题
0044E0B7 6f outs dx, dword ptr [esi]
0044E0B8 2079 6F and byte ptr [ecx+0x6F], bh
0044E0BB 75 20 jnz short 0044E0DD
0044E0BD 66:6963 6B 6269 imul sp, word ptr [ebx+0x6B], 0x6962
0044E0C3 72 6E jb short 0044E133
0044E0C5 65:2072 65 and byte ptr gs:[edx+0x65], dh
0044E0C9 61 popad
0044E0CA 6c ins byte ptr [edi], dx
0044E0CB 6c ins byte ptr [edi], dx
0044E0CC 79 20 jns short 0044E0EE
0044E0CE 77 61 ja short 0044E131
0044E0D0 6e outs dx, byte ptr [esi]
0044E0D1 74 20 je short 0044E0F3
0044E0D3 74 6F je short 0044E144
0044E0D5 2071 75 and byte ptr [ecx+0x75], dh
0044E0D8 69743F 00 5F4B6>imul esi, dword ptr [edi+edi], 0x51614B5F
0044E0E0 71 69 jno short 0044E14B
0044E0E2 0000 add byte ptr [eax], al
0044E0E4 66:83BB 8200000>cmp word ptr [ebx+0x82], 0x0 ; 转移
0044E0EC - E9 2D13FEFF jmp 0042F41E
0044E0F1 90 nop
0044E0F2 0000 add byte ptr [eax], al
对应的十六进制代码如下(可以直接拷贝到OD中):
60 90 FF 73 08 68 87 E0 44 00 E8 28 00 00 00 85 C0 74 1B FF 73 24 68 8D E0 44 00 E8 17 00 00 00
85 C0 74 0A C7 83 80 00 00 00 93 E0 44 00 90 61 68 E4 E0 44 00 C3 90 FF 74 24 04 E8 33 00 00 00
50 FF 74 24 08 E8 29 00 00 00 8B D0 58 3B C2 75 1D 33 C9 8B 74 24 04 8B 7C 24 08 8A 14 31 3A 14
39 75 0B 41 3B C8 75 F3 33 C0 40 C2 08 00 33 C0 C2 08 00 33 C9 8B 44 24 04 80 3C 08 00 74 03 41
EB F7 8B C1 C2 04 00 45 78 69 74 31 00 26 45 78 69 74 00 6A 24 68 DC E0 44 00 68 B6 E0 44 00 6A
00 FF 15 A4 11 44 00 83 F8 06 75 09 6A 00 2E FF 15 64 11 44 00 C3 44 6F 20 79 6F 75 20 66 69 63
6B 62 69 72 6E 65 20 72 65 61 6C 6C 79 20 77 61 6E 74 20 74 6F 20 71 75 69 74 3F 00 5F 4B 61 51
71 69 00 00 66 83 BB 82 00 00 00 00 E9 2D 13 FE FF 90 00 00
然后保存即可。
保存后再用OD打开保存的文件,来到0x0042F216处,将代码修改成如下的代码(目的是转移到我们设置的函数中):
0042F416 68 00E04400 push 0044E000
0042F41B C3 retn
0042F41C 90 nop
0042F41D 90 nop
对应的十六进制代码如下:
68 00 E0 44 00 C3 90 90
最后保存即可。
0x2 结尾
都修改好以后,看看效果吧。
还是在OD中运行,不过这次要删掉设置的断点,然后F9运行即可。
首先是程序截图:
点击[About]菜单的图片:
点击[Exit]菜单的图片:
退出成功的图片:
全文完。