吾爱破解学习指导教程

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修改475561475570地址的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 ; &nbsp;&nbsp;&nbsp;<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>

修改方法有两种:

  1. 查找参考->地址常量,找到所有cmp dword ptr ds:[ecx+0x15C],0x0,修改其下面的跳转指令;
  2. 查找参考->地址常量,找到所有给[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 MessageBoxAbp 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

这次它说暗桩没有触发。