NO.1~NO.3在第一课——脱壳基础就已经实践完了,所以这个笔记从NO.4开始。这个笔记是在调试器使用教程的基础上讲解,所以一定要保证自己已经了解OD的基本操作才推荐看这个笔记,但绝对会比论坛的大牛们讲解的详细。
NO.4 破解实战
由于我是用户大牛在讲解的帖子上没有附上实验程序的下载链接,所以只能挑附上下载链接的进行详细记录,没有附上下载链接的只能讲解流程,详细请看我是用户的帖子。
第一战:超级U盘锁
https://www.52pojie.cn/thread-197281-1-1.html
ASPack壳+两处自校验+跳转爆破/赋值爆破
第二战:豪杰屏幕录像机 v2.0
http://www.52pojie.cn/thread-197598-1-1.html
修改DLL
第三战:LukoolRecorder2.7.5cn
https://www.52pojie.cn/thread-197957-1-1.html
明码比较+跳转爆破/赋值爆破
第四战:PilotEdit5.9
https://www.52pojie.cn/thread-198203-1-1.html
跳转爆破
第五战:文件夹加密精灵V5.3
https://www.52pojie.cn/thread-198365-1-1.html
重启验证+跳转爆破+算法分析(MD5+程序加密算法)
第六战:(帖子被删除了)
第七战:XX注册税务师考试锦囊(完)
https://www.52pojie.cn/thread-199459-1-1.html
MPRESS壳+CRC相互校验+浮点错误+爆破+去除NAG
先运行一下程序,单独打开ESIExamPlatform.exe
(主程序)是运行不了的,需要打开ESPlatform.exe
再让它自行启动ESIExamPlatform.exe
。查壳,两个都有MPRESS壳。
先解决两个程序的脱壳问题。这是个压缩壳,用ESP定律秒脱。脱完名字要改为原程序的名字。脱完壳后两个程序都显示CRC校验失败。
载入ESIExamPlatform.exe
搜索字符串把它跳过。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 00419DA1 . /7C 1C jl short ESIExamP.00419DBF;nop掉 00419DA3 . |68 206D4A00 push ESIExamP.004A6D20 ; 495 00419DA8 . |50 push eax 00419DA9 . |E8 B4A40500 call ESIExamP.00474262 00419DAE . |83C4 08 add esp,0x8 00419DB1 . |85C0 test eax,eax 00419DB3 . |74 0A je short ESIExamP.00419DBF;nop掉 00419DB5 . |2B4424 14 sub eax,dword ptr ss:[esp+0x14] 00419DB9 . |D1F8 sar eax,1 00419DBB . |3BC6 cmp eax,esi 00419DBD . |75 62 jnz short ESIExamP.00419E21;改为jmp 00419DBF > \6A 00 push 0x0 00419DC1 . 6A 00 push 0x0 00419DC3 . 68 286D4A00 push ESIExamP.004A6D28 ; 《考试锦囊》CRC校验失败,请杀毒后重新下载本系统! 00419DC8 . E8 02FB0300 call ESIExamP.004598CF
|
载入ESPlatform.exe
搜索字符串把它跳过。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 004015DF /74 22 je short ESPlatfo.00401603;nop掉 004015E1 |8B4424 20 mov eax,dword ptr ss:[esp+0x20] ; kernel32.7C839AD8 004015E5 |8378 F4 00 cmp dword ptr ds:[eax-0xC],0x0 004015E9 |7C 18 jl short ESPlatfo.00401603;nop掉 004015EB |51 push ecx 004015EC |50 push eax 004015ED |E8 727F0200 call ESPlatfo.00429564 004015F2 |83C4 08 add esp,0x8 004015F5 |85C0 test eax,eax 004015F7 |74 0A je short ESPlatfo.00401603;nop掉 004015F9 |2B4424 20 sub eax,dword ptr ss:[esp+0x20] ; kernel32.7C839AD8 004015FD |D1F8 sar eax,1 004015FF |3BC6 cmp eax,esi 00401601 |75 3E jnz short ESPlatfo.00401641;改为jmp 00401603 \6A 00 push 0x0 00401605 6A 00 push 0x0 00401607 68 00934400 push ESPlatfo.00449300 ; 《考试锦囊》CRC校验失败,请杀毒后重新下载本系统! 0040160C |. E8 2FCD0000 call ESPlatfo.0040E340
|
此时单独运行ESIExamPlatform.exe
会出现异常。
再次载入OD,找到4757CA
,在4757C5
下断,进入函数。
1 2
| 004757C5 |. E8 D8F4FFFF call ESIExamP.00474CA2 004757CA |. 83C4 14 add esp,0x14
|
1 2 3 4 5 6 7
| 00474C56 |. FF15 44B34900 call dword ptr ds:[<&kernel32.#IsSystemResum>; [IsDebuggerPresent 00474C5C |. 6A 00 push 0x0 ; /pTopLevelFilter = NULL 00474C5E |. 8BD8 mov ebx,eax ; | 00474C60 |. FF15 48B14900 call dword ptr ds:[<&kernel32.#SetVolumeMoun>; \SetUnhandledExceptionFilter 00474C66 |. 8D85 28FDFFFF lea eax,[local.182] 00474C6C |. 50 push eax ; /pExceptionInfo = 00124C88 00474C6D |. FF15 44B14900 call dword ptr ds:[<&kernel32.#UnregisterWai>; \UnhandledExceptionFilter
|
程序运行到UnhandledExceptionFilter
处出错。因为这个函数前面没有跳转指令,所以要返回到父函数寻找跳转指令绕过这个子函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 004757AD |. /74 07 je short ESIExamP.004757B6;绕过循环跳转就必须jmp,但同时异常也会被执行 004757AF |. |8B5D 0C mov ebx,[arg.2] 004757B2 |. |3BDF cmp ebx,edi 004757B4 |. |77 1E ja short ESIExamP.004757D4;这个跳转实现虽然绕过异常,但一直在循环,直到不循环时也是要执行异常 004757B6 |> \E8 BB2D0000 call ESIExamP.00478576 004757BB |. 6A 16 push 0x16 004757BD |. 5E pop esi ; ESIExamP.0047BEE6 004757BE |. 8930 mov dword ptr ds:[eax],esi 004757C0 |> 57 push edi;这个跳过来的是个jmp指令,没办法不执行,改nop也不行 004757C1 |. 57 push edi 004757C2 |. 57 push edi 004757C3 |. 57 push edi 004757C4 |. 57 push edi 004757C5 |. E8 D8F4FFFF call ESIExamP.00474CA2;异常函数
|
所以这两个跳转无论如何都不能够使这个异常不实现,继续找父函数。在堆栈窗口找到返回地址跟随。
1
| 00124F84 |0041B9E7 返回到 ESIExamP.0041B9E7 来自 ESIExamP.0047579E
|
发现可以利用0041B9D4
的跳转指令绕过异常函数。
1 2 3 4 5 6 7
| 0041B9D4 |. /74 14 je short ESIExamP.0041B9EA;改为jmp 0041B9D6 |. |68 84744A00 push ESIExamP.004A7484 ; s 0041B9DB |. |6A 01 push 0x1 0041B9DD |. |68 FFFFFF00 push 0xFFFFFF 0041B9E2 |. |E8 B79D0500 call ESIExamP.0047579E;异常函数 0041B9E7 |. |83C4 0C add esp,0xC 0041B9EA |> \8D8C24 900000>lea ecx,dword ptr ss:[esp+0x90]
|
发现单独运行它又弹出一连串的“CRC校验失败,请重新下载本软件”的对话框。搜索字符串,在函数开头下断运行,发现0043DB14
能绕过弹窗,0043DB94
不能,因为je指令会绕过jnz指令。所以要在0043DB14
改为jmp。
1 2 3 4 5 6 7 8 9 10 11
| 0043DB14 |. /0F84 C0000000 je ESIExamP.0043DBDA;改为jmp ... 0043DB89 |. /74 0B je short ESIExamP.0043DB96 0043DB8B |. |2B4424 14 sub eax,dword ptr ss:[esp+0x14] 0043DB8F |. |D1F8 sar eax,1 0043DB91 |. |83F8 FF cmp eax,-0x1 0043DB94 |. |75 1A jnz short ESIExamP.0043DBB0 0043DB96 |> \6A 00 push 0x0 0043DB98 |. 6A 00 push 0x0 0043DB9A |. 68 F4EF4A00 push ESIExamP.004AEFF4 ; 程序CRC校验失败,请重新下载本软件! 0043DB9F |. E8 2BBD0100 call ESIExamP.004598CF
|
但这样改就会跳转到“程序不完整”。
1 2 3 4 5 6 7 8
| 0043DBDA |> \8B4E 20 mov ecx,dword ptr ds:[esi+0x20] 0043DBDD |. 6A 65 push 0x65 ; /TimerID = 65 (101.) 0043DBDF |. 51 push ecx ; |hWnd = 494F6396 0043DBE0 |. FF15 D8B54900 call dword ptr ds:[<&user32.#435>] ; \KillTimer 0043DBE6 |. 6A 00 push 0x0 0043DBE8 |. 6A 00 push 0x0 0043DBEA |. 68 1CF04A00 push ESIExamP.004AF01C ; 程序不完整,请重新下载! 0043DBEF |. E8 DBBC0100 call ESIExamP.004598CF
|
重新修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| 0043DB77 |. /7C 1D jl short ESIExamP.0043DB96;nop掉 0043DB79 |. |68 206D4A00 push ESIExamP.004A6D20 ; 495 0043DB7E |. |50 push eax 0043DB7F |. |E8 DE660300 call ESIExamP.00474262 0043DB84 |. |83C4 08 add esp,0x8 0043DB87 |. |85C0 test eax,eax 0043DB89 |. |74 0B je short ESIExamP.0043DB96;nop掉 0043DB8B |. |2B4424 14 sub eax,dword ptr ss:[esp+0x14] 0043DB8F |. |D1F8 sar eax,1 0043DB91 |. |83F8 FF cmp eax,-0x1 0043DB94 |. |75 1A jnz short ESIExamP.0043DBB0;修改为jmp 0043DB96 |> \6A 00 push 0x0 0043DB98 |. 6A 00 push 0x0 0043DB9A |. 68 F4EF4A00 push ESIExamP.004AEFF4 ; 程序CRC校验失败,请重新下载本软件! 0043DB9F |. E8 2BBD0100 call ESIExamP.004598CF 0043DBA4 |. 8B16 mov edx,dword ptr ds:[esi] ; ESIExamP.004AF6BC 0043DBA6 |. 8B82 5C010000 mov eax,dword ptr ds:[edx+0x15C] 0043DBAC |. 8BCE mov ecx,esi 0043DBAE |. FFD0 call eax 0043DBB0 |> C68424 880000>mov byte ptr ss:[esp+0x88],0x2 0043DBB8 |. 8B4424 14 mov eax,dword ptr ss:[esp+0x14] 0043DBBC |. 83C0 F0 add eax,-0x10 0043DBBF |. 8D48 0C lea ecx,dword ptr ds:[eax+0xC] 0043DBC2 |. 83CA FF or edx,-0x1 0043DBC5 |. f0:0fc111 lock xadd dword ptr ds:[ecx],edx 0043DBC9 |. 4A dec edx 0043DBCA |. 85D2 test edx,edx 0043DBCC |. 7F 3D jg short ESIExamP.0043DC0B;修不修改终将会绕过“程序不完整”弹窗 0043DBCE |. 8B08 mov ecx,dword ptr ds:[eax] ; ESIExamP.004C8790 0043DBD0 |. 8B11 mov edx,dword ptr ds:[ecx] 0043DBD2 |. 50 push eax 0043DBD3 |. 8B42 04 mov eax,dword ptr ds:[edx+0x4] 0043DBD6 |. FFD0 call eax 0043DBD8 |. EB 31 jmp short ESIExamP.0043DC0B 0043DBDA |> 8B4E 20 mov ecx,dword ptr ds:[esi+0x20] 0043DBDD |. 6A 65 push 0x65 ; /TimerID = 65 (101.) 0043DBDF |. 51 push ecx ; |hWnd = 00B1AF3C 0043DBE0 |. FF15 D8B54900 call dword ptr ds:[<&user32.#435>] ; \KillTimer 0043DBE6 |. 6A 00 push 0x0 0043DBE8 |. 6A 00 push 0x0 0043DBEA |. 68 1CF04A00 push ESIExamP.004AF01C ; 程序不完整,请重新下载! 0043DBEF |. E8 DBBC0100 call ESIExamP.004598CF
|
运行ESPlatform.exe
可以正常启动ESIExamPlatform.exe
出现主程序,单独启动ESIExamPlatform.exe
也可出现主程序。至此,CRC校验全被清除。
在主程序点击一下功能看程序是否能正常工作。发现在点击“答题记录”或“统计曲线”或“习题集”时出现错误提示框,然后直接退出程序。
这是因为代码调用了浮点数,而程序在启动时因为缺省没有调用初始化浮点数的函数。程序启动阶段___tmainCRTStartup
函数中调用了__cinit
函数,在这个函数的第一个判断是校验浮点运算初始化函数指针所处的section是否为可写,如果可写的话就跳过浮点运算初始化函数,因此缺省情况下会直接显示出错信息并退出,如果该区段不可写,代码会调用浮点运算初始化函数,缺省的指向出错函数的指针会被替换成正常处理函数,因此可以正常运算。
又因为它会退出程序,Ctrl+G搜索ExitProcess
下断,按下“统计曲线”->确定,程序停在断点处。在堆栈窗口返回到父函数。不断堆栈回溯再跟进来到这,看到下面有个WriteFile
函数,说明.MPRESS1
区段可写。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| 0047BC3C |> \68 10200100 push 0x12010 0047BC41 |. 68 60174A00 push ESIExamP.004A1760 ; Microsoft Visual C++ Runtime Library 0047BC46 |. 57 push edi 0047BC47 |. E8 A4EF0000 call ESIExamP.0048ABF0 ; 错误函数 0047BC4C |. 83C4 0C add esp,0xC 0047BC4F |. EB 32 jmp short ESIExamP.0047BC83 0047BC51 |> 6A F4 push -0xC ; /DevType = STD_ERROR_HANDLE 0047BC53 |. FF15 80B14900 call dword ptr ds:[<&kernel32.#GetStringTypeExA_433>] ; \GetStdHandle 0047BC59 |. 8BD8 mov ebx,eax 0047BC5B |. 3BDE cmp ebx,esi 0047BC5D |. 74 24 je short ESIExamP.0047BC83 0047BC5F |. 83FB FF cmp ebx,-0x1 0047BC62 |. 74 1F je short ESIExamP.0047BC83 0047BC64 |. 6A 00 push 0x0 0047BC66 |. 8D45 F8 lea eax,[local.2] 0047BC69 |. 50 push eax 0047BC6A |. 8D34FD 246B4C>lea esi,dword ptr ds:[edi*8+0x4C6B24] ; R6002\r\n- floating point support not loaded\r\n 0047BC71 |. FF36 push dword ptr ds:[esi] 0047BC73 |. E8 982A0000 call ESIExamP.0047E710 0047BC78 |. 59 pop ecx ; |ESIExamP.004754A8 0047BC79 |. 50 push eax ; |nBytesToWrite = 0x0 0047BC7A |. FF36 push dword ptr ds:[esi] ; |Buffer = NULL 0047BC7C |. 53 push ebx ; |hFile = 00124EFC 0047BC7D |. FF15 4CB34900 call dword ptr ds:[<&kernel32.#WritePrivateProfileString>; \WriteFile 0047BC83 |> 5F pop edi ; ESIExamP.004754A8 0047BC84 |. 5E pop esi ; ESIExamP.004754A8 0047BC85 |. 5B pop ebx ; ESIExamP.004754A8 0047BC86 |. C9 leave 0047BC87 \. C3 retn
|
将.MPRESS1
区段改为不可写显然不现实,因为程序不止这一处是写入的,那就只能强制初始化。载入IDA查看__cinit
函数,发现它有__IsNonwritableInCurrentImage
函数,用来判断地址是否可写,不能写则调用__fpmath
(call off_4A11A8)进行初始化。
回到OD修改475561
和475570
地址的jz
指令改为nop
。
1 2
| 00475561 /74 19 je short ESIExamP.0047557C;nop掉 00475570 /74 0A je short ESIExamP.0047557C;nop掉
|
习题集、统计曲线等等都可以正常打开了。
接着爆破。最终目的是能bp试卷,所以找到两处购买试题的地方,可知标志位保存在ebx+0x15C
中。
1 2 3 4 5 6 7 8 9 10
| 0043032E > \83BB 5C010000>cmp dword ptr ds:[ebx+0x15C],0x0 00430335 . 0F85 A5000000 jnz ESIExamP.004303E0 0043033B . 8D8B CC050000 lea ecx,dword ptr ds:[ebx+0x5CC] 00430341 . 51 push ecx 00430342 . 8D95 B0F8FFFF lea edx,dword ptr ss:[ebp-0x750] 00430348 . 68 78CB4A00 push ESIExamP.004ACB78 ; <a href= 0043034D . 52 push edx ; ntdll.KiFastSystemCallRet 0043034E . E8 3D56FDFF call ESIExamP.00405990 00430353 . 83C4 0C add esp,0xC 00430356 . 68 28CB4A00 push ESIExamP.004ACB28 ; ><font color=red>未购买该试题 点击购买</font></a>
|
1 2 3 4 5 6 7 8 9 10
| 00430B14 . 83BB 5C010000>cmp dword ptr ds:[ebx+0x15C],0x0 00430B1B . 0F85 9C000000 jnz ESIExamP.00430BBD 00430B21 . 8D8B CC050000 lea ecx,dword ptr ds:[ebx+0x5CC] 00430B27 . 51 push ecx 00430B28 . 8D95 90F8FFFF lea edx,dword ptr ss:[ebp-0x770] 00430B2E . 68 C4CC4A00 push ESIExamP.004ACCC4 ; <a href= 00430B33 . 52 push edx ; ntdll.KiFastSystemCallRet 00430B34 . E8 574EFDFF call ESIExamP.00405990 00430B39 . 83C4 0C add esp,0xC 00430B3C . 68 28CB4A00 push ESIExamP.004ACB28 ; ><font color=red>未购买该试题 点击购买</font></a>
|
修改方法有两种:
- 查找参考->地址常量,找到所有
cmp dword ptr ds:[ecx+0x15C],0x0
,修改其下面的跳转指令;
- 查找参考->地址常量,找到所有给[ebx+0x15C]赋值的地方,修改其赋值。
选择哪一个比较好视工作量而定,肯定是哪个修改量少修改哪个。
我觉得在这程序里第一种方法工作量比较小。修改完后已经没有“购买试题”的字样了,但NAG窗口还在。搜索字符串先将这里修改了,试题我都bp了,怎么能说我没注册呢!
1 2 3 4 5 6 7 8 9
| 0043E6A2 /74 66 je short ESIExamP.0043E70A ; nop掉 0043E6A4 . |68 8CF04A00 push ESIExamP.004AF08C ; 您已获得本套系统正版授权,谢谢您的支持! 0043E6A9 . |68 24040000 push 0x424 0043E6AE . |8BCD mov ecx,ebp 0043E6B0 . |E8 A2270100 call ESIExamP.00450E57 0043E6B5 . |8BC8 mov ecx,eax 0043E6B7 . |E8 DB280100 call ESIExamP.00450F97 0043E6BC . |68 B8F04A00 push ESIExamP.004AF0B8 ; 系统已经注册 0043E6C1 . |6A 01 push 0x1
|
接着去掉NAG窗口。在命令窗口下断bp CreateDialogIndirectParamW
(CreateDialogIndirectParam是用于从内存中的对话框模板上创建一个无模式对话框的函数)。第一次F9运行至断点处,第二次F9出现主程序,第三次F9出现NAG。所以要在第二次F9到第三次F9之间找到绕过NAG窗口的指令。
在第二次F9后,一路F8,运行到这一句时弹出NAG窗口。(这里前面有个可以绕过call
指令的跳转指令,但是不能将它改为jmp
,因为你会发现这个call
指令被运行了两次,第一次是主程序,第二次才是NAG)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 00452936 /74 1E je short ESIExamP.00452956 00452938 . |6A 04 push 0x4 0045293A . |5F pop edi 0045293B . |8BCE mov ecx,esi 0045293D . |E8 C9E5FFFF call ESIExamP.00450F0B 00452942 . |A9 00010000 test eax,0x100 00452947 . |74 03 je short ESIExamP.0045294C 00452949 . |6A 05 push 0x5 0045294B . |5F pop edi 0045294C > |57 push edi 0045294D . |8BCE mov ecx,esi 0045294F . |E8 B8270000 call ESIExamP.0045510C ; 第一次主程序,第二次NAG窗口 00452954 . |33FF xor edi,edi 00452956 > \397E 20 cmp dword ptr ds:[esi+0x20],edi
|
在堆栈窗口找到这句反汇编窗口跟随。(主程序与NAG“返回到”的地址不同)
1
| 00124ED0 0043835E 返回到 ESIExamP.0043835E 来自 ESIExamP.00452827
|
将jnz
修改为jmp
指令绕过NAG窗口。
1 2 3 4 5 6 7 8 9 10 11 12
| 00438341 . /75 2A jnz short ESIExamP.0043836D;jmp 00438343 . |8D8D E4F9FFFF lea ecx,dword ptr ss:[ebp-0x61C] 00438349 . |51 push ecx 0043834A . |E8 4122FEFF call ESIExamP.0041A590 0043834F . |8D8D E4F9FFFF lea ecx,dword ptr ss:[ebp-0x61C] 00438355 . |C645 FC 27 mov byte ptr ss:[ebp-0x4],0x27 00438359 . |E8 C9A40100 call ESIExamP.00452827 ; NAG 0043835E . |8D95 E4F9FFFF lea edx,dword ptr ss:[ebp-0x61C] 00438364 . |52 push edx 00438365 . |885D FC mov byte ptr ss:[ebp-0x4],bl 00438368 . |E8 2323FEFF call ESIExamP.0041A690 0043836D > \8D4D E8 lea ecx,dword ptr ss:[ebp-0x18]
|
第八战:A-PDF Split(已下载)
https://www.52pojie.cn/thread-199834-1-1.html
ASProtect1.23 RC1+14处自校验+跳转爆破
发现不会手脱,那就用脱壳工具中的ASProtect Unpacker 汉化版脱壳。是用Delphi写的程序。
载入OD,下bp MessageBoxA
和bp MessageBoxW
断点,运行,点击试用卡在了kernel32模块的某个地方。F8走出来,回到用户代码处。
1 2 3
| 0040B285 E8 8692FFFF call PdfSplit.00404510 0040B28A |. 5F pop edi ; PdfSplit.0040B28A 0040B28B |. 5E pop esi ; PdfSplit.0040B28A
|
发现应该是40B285
地址的call指令产生的错误,直接把它NOP掉。保存,运行发现程序直接退出了。程序退出调用的是PostQuitMessage
函数,下这个断点。点击“Try”,程序停在断点处。堆栈查看返回函数。
1 2 3 4 5
| 0012FD88 0048BDBC /CALL 到 PostQuitMessage 来自 PdfSplit.0048BDB7 0012FD8C 00000000 \ExitCode = 0x0 0012FD90 00576B5B 返回到 PdfSplit.00576B5B 来自 PdfSplit.0048BDAC 0012FD94 0012FDEC 指向下一个 SEH 记录的指针 0012FD98 0057705E SE处理程序
|
1 2 3 4
| 0048BDB3 |. /74 07 je short PdfSplit.0048BDBC;要跳 0048BDB5 |. |6A 00 push 0x0 ; /ExitCode = 0x0 0048BDB7 |. |E8 18BDF7FF call <jmp.&user32.PostQuitMessage> ; \PostQuitMessage 0048BDBC \> \C3 retn
|
je
修改为jmp
。保存。运行程序发现点击“Try”能进入主程序了,也没有错误框。但点击“Browse”又弹出错误框。
点击关闭还关闭不了了。
…好难,脱壳好像引发别的错误了…
第九战:XXPDF转WORD助手
https://www.52pojie.cn/thread-200655-1-1.html
tElock壳+自校验+爆破
第十战:LanHelper算法分析与注册机的编写
https://www.52pojie.cn/thread-200798-1-1.html
算法分析
拿去查壳,没有壳,是Delphi写的程序。载入OD搜索字符串“注册码”没有找到。没关系,谁让它是Delphi写的呢?把它载入Delphi Decompiler,点击“Procedures”(过程),找到有关注册字样的单元名。注册的窗体有两个文本框和三个按钮,找到最符合的注册窗体。
猜测Button1Click
是“确定”按钮,因为“取消”就会返回到父窗口,相当于关闭嘛,没有按钮可以理解。为了验证我们的猜想,双击Button1Click
进去找到第一条汇编指令,地址为004DCB40
。
回到OD,Ctrl + G输入地址,下断运行。输入名称、注册码后点击确定,OD成功停在断点处,说明找对了。
F8往下运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 004DCB6D . E8 5616FAFF call LanHelpe.0047E1C8 004DCB72 . 8B45 B8 mov eax,dword ptr ss:[ebp-0x48] 004DCB75 . 8D55 BC lea edx,dword ptr ss:[ebp-0x44] 004DCB78 . E8 47CCF2FF call LanHelpe.004097C4 ; 获取用户名 004DCB7D . 837D BC 00 cmp dword ptr ss:[ebp-0x44],0x0 ; 判断用户名是否为空 004DCB81 . 74 22 je short LanHelpe.004DCBA5 004DCB83 . 8D55 B0 lea edx,dword ptr ss:[ebp-0x50] 004DCB86 . 8B45 FC mov eax,dword ptr ss:[ebp-0x4] 004DCB89 . 8B80 04030000 mov eax,dword ptr ds:[eax+0x304] 004DCB8F . E8 3416FAFF call LanHelpe.0047E1C8 004DCB94 . 8B45 B0 mov eax,dword ptr ss:[ebp-0x50] 004DCB97 . 8D55 B4 lea edx,dword ptr ss:[ebp-0x4C] 004DCB9A . E8 25CCF2FF call LanHelpe.004097C4 ; 获取假码 004DCB9F . 837D B4 00 cmp dword ptr ss:[ebp-0x4C],0x0 ; 判断假码是否为空 004DCBA3 . 75 44 jnz short LanHelpe.004DCBE9 004DCBA5 > 8D4D F0 lea ecx,dword ptr ss:[ebp-0x10]
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 004DCBE9 > \8D55 A8 lea edx,dword ptr ss:[ebp-0x58] 004DCBEC . 8B45 FC mov eax,dword ptr ss:[ebp-0x4] 004DCBEF . 8B80 04030000 mov eax,dword ptr ds:[eax+0x304] 004DCBF5 . E8 CE15FAFF call LanHelpe.0047E1C8 004DCBFA . 8B45 A8 mov eax,dword ptr ss:[ebp-0x58] 004DCBFD . 50 push eax 004DCBFE . 8D55 A4 lea edx,dword ptr ss:[ebp-0x5C] 004DCC01 . 8B45 FC mov eax,dword ptr ss:[ebp-0x4] 004DCC04 . 8B80 00030000 mov eax,dword ptr ds:[eax+0x300] 004DCC0A . E8 B915FAFF call LanHelpe.0047E1C8 004DCC0F . 8B45 A4 mov eax,dword ptr ss:[ebp-0x5C] 004DCC12 . 5A pop edx ; 0012F338 004DCC13 . E8 9C270000 call LanHelpe.004DF3B4 ; 用户名和假码放到寄存器,这个是关键call 004DCC18 84C0 test al,al ; 比较al的值 004DCC1A 0F84 F4030000 je LanHelpe.004DD014 ; 关键跳
|
运行到关键跳处修改Z标志位,F9运行,发现成功注册,但程序是重启验证类型的。
那我们将关键跳nop掉作为2.exe,修改al的值作为3.exe试试。
意料之中,2.exe每次都需要注册,根本就行不通。3.exe竟然说注册码有误,我们不是跳过了吗?载入OD发现al确实是变成1,但是je跳转还是实现了。好吧既然这样就进入关键call一探究竟。
输入用户名v5le0n9,假码l30n9ry0n。进入关键call。
将这循环跑了6次之后,可以知道真码前6位固定为LH4A8N。循环结束后,比较dl的值,如果dl为0则跳转到eax清零处。
重新载入,将假码的前6位设置为LH4A8N
再分析。去到比较dl的值处,现在已经不为0了。继续往下走,看到一些红色指令。
fild和fstp都是x86指令,fild是将整数转化为长双精FP80压栈(压到st0),
fstp是将弹栈指令,将st0弹出。ebp始终指向栈顶,ebp是在堆栈中寻址用的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 004DF49C . 84D2 test dl,dl 004DF49E . 0F84 F8030000 je LanHelpe.004DF89C 004DF4A4 . 33C0 xor eax,eax 004DF4A6 . 8945 E0 mov dword ptr ss:[ebp-0x20],eax 004DF4A9 . 8945 E4 mov dword ptr ss:[ebp-0x1C],eax 004DF4AC . 8B45 F8 mov eax,dword ptr ss:[ebp-0x8] ; eax是假码 004DF4AF . 8A58 06 mov bl,byte ptr ds:[eax+0x6] ; 将第7位赋值给bl 004DF4B2 . 33C0 xor eax,eax ; eax清零 004DF4B4 . 8AC3 mov al,bl ; bl再赋值给al 004DF4B6 . 8945 A0 mov dword ptr ss:[ebp-0x60],eax ; 将假码第7位压入[ebp-0x60] 004DF4B9 . DB45 A0 fild dword ptr ss:[ebp-0x60] ; 将第7位放入st0中 004DF4BC . 83C4 F4 add esp,-0xC ; 更新栈顶指针 004DF4BF . DB3C24 fstp tbyte ptr ss:[esp] ; pop栈顶数据 004DF4C2 . 9B wait 004DF4C3 . 68 FE3F0000 push 0x3FFE 004DF4C8 . 68 BD529691 push 0x919652BD 004DF4CD . 68 3411363C push 0x3C361134 004DF4D2 . E8 9D1AF5FF call LanHelpe.00430F74 ; 将上面3个参数入栈调用F74
|
后面也有很多调用F74的,所以进去F74分析一下。
…又要进去BF4分析一下,我真看不懂啊救命
NO.5 .NET系列教程
Blue的实战软件全都过期了,所以我找了别的教程自力更生。
.Net零基础破解教程
NO.6 去软件弹窗系列教程
第一课:弹窗暗桩
运行一下程序,弹出网页。程序无壳,查找一下字符串,定位关键代码处。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| 00401004 /. 55 push ebp 00401005 |. 8BEC mov ebp,esp 00401007 |. 6A 00 push 0x0 00401009 |. 68 106B4600 push 第一课.00466B10 ; 恭喜你:暗桩没有触发 0040100E |. 6A FF push -0x1 00401010 |. 6A 08 push 0x8 00401012 |. 68 04000116 push 0x16010004 00401017 |. 68 01000152 push 0x52010001 0040101C |. E8 A0000000 call 第一课.004010C1 00401021 |. 83C4 18 add esp,0x18 00401024 |. E8 04000000 call 第一课.0040102D;暗桩关键call,nop即可 00401029 |. 8BE5 mov esp,ebp 0040102B |. 5D pop ebp ; kernel32.7C817077 0040102C \. C3 retn 0040102D /$ 55 push ebp 0040102E |. 8BEC mov ebp,esp 00401030 |. 68 04000080 push 0x80000004 00401035 |. 6A 00 push 0x0 00401037 |. 68 256B4600 push 第一课.00466B25 ; www.52pojie.cn 0040103C |. 68 01000000 push 0x1 00401041 |. B8 01000000 mov eax,0x1 00401046 |. BB 10584400 mov ebx,第一课.00445810 0040104B |. E8 77000000 call 第一课.004010C7 00401050 |. 83C4 10 add esp,0x10 00401053 |. 6A 00 push 0x0 00401055 |. 68 346B4600 push 第一课.00466B34 ; 失败了!暗桩已经触发
|
第二课:再探弹窗暗桩
这次是两个弹网页。依旧无壳,载入OD,发现查找字符串无果。查找所有模块间的调用,找到弹网页的函数ShellExecuteA
,下断。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 00445DD0 /$ 68 F8114800 push 第二课.004811F8 ; /Microsoft Internet Explorer 00445DD5 |. 6A 00 push 0x0 ; |Class = 0x0 00445DD7 |. 6A 00 push 0x0 ; |hAfterWnd = NULL 00445DD9 |. 6A 00 push 0x0 ; |hParent = NULL 00445DDB |. FF15 40654600 call dword ptr ds:[<&USER32.FindWindowEx>; \FindWindowExA 00445DE1 |. 8B4C24 04 mov ecx,dword ptr ss:[esp+0x4] 00445DE5 |. 6A 01 push 0x1 ; /IsShown = 0x1 00445DE7 |. 6A 00 push 0x0 ; |DefDir = NULL 00445DE9 |. 6A 00 push 0x0 ; |Parameters = NULL 00445DEB |. 51 push ecx ; |FileName = "" 00445DEC |. 68 F0114800 push 第二课.004811F0 ; |open 00445DF1 |. 50 push eax ; |hWnd = 001631B8 00445DF2 |. FF15 84634600 call dword ptr ds:[<&SHELL32.ShellExecut>; \ShellExecuteA 00445DF8 \. C2 0400 retn 0x4
|
执行到返回,程序弹出一个网页。再经过这里一次,程序弹出第二个网页。
1 2 3 4 5 6
| 00445CD5 . E8 3A150100 call 第二课.00457214 00445CDA 8B4424 00 mov eax,dword ptr ss:[esp] 00445CDE 8D4C24 04 lea ecx,dword ptr ss:[esp+0x4] 00445CE2 50 push eax 00445CE3 E8 E8000000 call 第二课.00445DD0 ; 暗桩 00445CE8 . 8D4C24 00 lea ecx,dword ptr ss:[esp]
|
所以只要将2-5行代码都nop掉,两个弹窗都没有了。但运行程序还是说暗桩已经触发。那有没有好一点的办法让它说没有触发呢?
在数据窗口Ctrl+B搜索ASCII码“ www.52pojie.cn ”,下内存访问断点。运行单步
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 004010C4 /$ 55 push ebp 004010C5 |. 8BEC mov ebp,esp 004010C7 |. 81EC 04000000 sub esp,0x4 004010CD |. 68 010100A0 push 0xA0000101 004010D2 |. 6A 00 push 0x0 004010D4 |. 68 F87B4600 push 第二课.00467BF8 004010D9 |. 68 01000000 push 0x1 004010DE |. BB 10144000 mov ebx,第二课.00401410 004010E3 |. E8 B4010000 call 第二课.0040129C 004010E8 |. 83C4 10 add esp,0x10 004010EB |. 8945 FC mov [local.1],eax 004010EE |. 68 04000080 push 0x80000004 004010F3 |. 6A 00 push 0x0 004010F5 |. 8B45 FC mov eax,[local.1] 004010F8 |. 85C0 test eax,eax 004010FA |. 75 05 jnz short 第二课.00401101 004010FC |. B8 0E7C4600 mov eax,第二课.00467C0E ; ā 00401101 |> 50 push eax 00401102 |. 68 01000000 push 0x1 00401107 |. B8 01000000 mov eax,0x1 0040110C |. BB B05C4400 mov ebx,第二课.00445CB0 00401111 |. E8 8C010000 call 第二课.004012A2 ; 第一次弹窗
|
继续单步,004010C4
就是第一次弹窗的位置,所以将这两个call指令nop掉即可。
1 2 3 4 5
| 004010A9 |. 83C4 04 add esp,0x4 004010AC |> E8 13000000 call 第二课.004010C4 ; 第一次弹窗 004010B1 |. E8 C3000000 call 第二课.00401179 004010B6 |. E8 C5000000 call 第二课.00401180 ; 第二次弹窗 004010BB |. E8 75010000 call 第二课.00401235
|
这次它说暗桩没有触发。