吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5355|回复: 8
收起左侧

[原创] 160 个 CrackMe 之 099 -- RingZ3r0 的解码脱壳、兼容修复及注册分析

  [复制链接]
solly 发表于 2019-12-1 02:08
本帖最后由 solly 于 2019-12-2 01:24 编辑

160 个 CrackMe 之 099 -- RingZ3r0 在 Windows 10 下不能直接运行,需要修复一个堆栈平衡的问题,并且其代码关键部分和字符串资源是编码了的,在运行时会异或解码,同时,其是一个 KeyFile 方式的 Crackme。


我们先看看文件信息:
00.png
显示代码有回写保护,并没有壳。“Scan /t”如下图所示:
01.png
显示编译环境是 VC8。节的情况如下:
02.png
在 Windows 10 下用 OD 加载,可以正常加载,表示其应该可以在最新的 Windows 下运行,如下图所示:
11.png

最前面一段代码首先取得 CrackMe 的命令行数据,然后判断命令行最后一个字符是否“\t”字符,不是则加上一个“\t"字符,接着直接用这个命令行字符串重新创建进程,然后退出了。也算是一种反调试手段吧,如下图所示:
12.png

具体代码如下所示:
[Asm] 纯文本查看 复制代码
00401000 > $  E8 3A090000           call    <jmp.&KERNEL32.GetCommandLineA>              ; [GetCommandLineA
00401005   .  50                    push    eax                                          ;  eax===> 命令行
00401006   .  8BF8                  mov     edi, eax
00401008   .  32C0                  xor     al, al                                       ;  '\0'
0040100A   .  B9 FFFFFFFF           mov     ecx, -1
0040100F   .  F2:AE                 repne   scas byte ptr es:[edi]                       ;  edi ===> 命令行
00401011   .  F7D9                  neg     ecx
00401013   .  49                    dec     ecx                                          ;  命令行长度 = ecx
00401014   .  5E                    pop     esi
00401015   .  BF 10204000           mov     edi, 00402010                                ;  ASCII """E:\Downloads\crack\099_RingZ3r0\Krypton.EXE"""
0040101A   .  F3:A4                 rep     movs byte ptr es:[edi], byte ptr [esi]
0040101C   .  4F                    dec     edi
0040101D   .  4F                    dec     edi
0040101E   .  803F 09               cmp     byte ptr [edi], 9                            ;  最后一个字符是否为"\t"
00401021   .  74 31                 je      short 00401054                               ;  将 je 改成 jmp 指令,跳过退出
00401023   .  47                    inc     edi
00401024   .  C607 09               mov     byte ptr [edi], 9                            ;  添加一个'\t'符
00401027   .  47                    inc     edi
00401028   .  C607 00               mov     byte ptr [edi], 0                            ;  添加'\0'
0040102B   .  68 00204000           push    00402000                                     ; /pProcessInfo = Krypton.00402000
00401030   .  68 14214000           push    00402114                                     ; |pStartupInfo = Krypton.00402114
00401035   .  6A 00                 push    0                                            ; |CurrentDir = NULL
00401037   .  6A 00                 push    0                                            ; |pEnvironment = NULL
00401039   .  6A 08                 push    8                                            ; |CreationFlags = DETACHED_PROCESS
0040103B   .  6A 01                 push    1                                            ; |InheritHandles = TRUE
0040103D   .  6A 00                 push    0                                            ; |pThreadSecurity = NULL
0040103F   .  6A 00                 push    0                                            ; |pProcessSecurity = NULL
00401041   .  68 10204000           push    00402010                                     ; |CommandLine = """E:\Downloads\crack\099_RingZ3r0\Krypton.EXE"""
00401046   .  6A 00                 push    0                                            ; |ModuleFileName = NULL
00401048   .  E8 C8080000           call    <jmp.&KERNEL32.CreateProcessA>               ; \CreateProcessA
0040104D   .  6A FF                 push    -1                                           ; /ExitCode = FFFFFFFF
0040104F   .  E8 C7080000           call    <jmp.&KERNEL32.ExitProcess>                  ; \ExitProcess
00401054   >  E9 45070000           jmp     0040179E


我们首先要破除这个限制,如下图所示:
13.png

我们需要直接跳转到下面的代码,而不去创建新的进程。修改如下:
14.png
直接将 je 指令改成 jmp 指令就可以了。这样就直接来到了下图所示位置:
20.png
可以看到,后面一段代码看起来很混乱,那是因为代码加密的了。直接按 F8 跳过这段加密了的代码,来到如下位置:
21.png
这里的代码又正常了,继续 F8 执行,来到下面代码处:
22.png

这一段代码是 CrackMe 程序在我们的注册表中留一个”到此一游“的标记,内容为("Yado says: Hi gui! ;"),没什么特别的用处。
继续 F8 往下走,来到了代码解码处,如下图所示:
23.png

具体解码代码如下:
[Asm] 纯文本查看 复制代码
004017F8   .  B8 59104000           mov     eax, 00401059
004017FD   .  BA 9D174000           mov     edx, 0040179D
00401802   >  4A                    dec     edx
00401803   .  3BC2                  cmp     eax, edx
00401805   .  74 05                 je      short 0040180C
00401807   .  8032 11               xor     byte ptr [edx], 11                           ;  代码解码
0040180A   .^ EB F6                 jmp     short 00401802
0040180C   >  8032 11               xor     byte ptr [edx], 11                           ;  解码最后一个字节


执行完上面的解码程序后,我们前面看到的混乱代码恢复正常,如下图所示,红色代码就是刚才解码后的代码了:
24.png
但有可能显示上有问题,没有显示完整代码,需要 OD 重新分析代码,我们按一次 "CTRL+A",就可以重新分析代码,如下图所示,重新分析后就正常了:
25.png
这样就显示为正常代码了。这段代码的结束位置如下所示:
26.png
我们继续执行 CrackMe,按几次 F8,来到下面代码处,如下图所示:
27.png
这里也是一段修改自身代码的程序:是从内存数据段复制8个字节的代码,主要是用来反“SoftICE”的调试的,其实就是一个 Int 68 功能,这个功能与 Windows NT 系列内核不兼容,会导致程序退出。
具体代码如下所示:
[Asm] 纯文本查看 复制代码
0040182F   .  B8 4D234000           mov     eax, 0040234D  
00401834   .  BA 69234000           mov     edx, 00402369
00401839   .  8B00                  mov     eax, dword ptr [eax]
0040183B   .  8B0A                  mov     ecx, dword ptr [edx]
0040183D   .  66:8948 06            mov     word ptr [eax+6], cx                         ;  修改指令码
00401841   .  83C2 02               add     edx, 2
00401844   .  8B0A                  mov     ecx, dword ptr [edx]
00401846   .  66:8908               mov     word ptr [eax], cx                           ;  修改指令码
00401849   .  83C2 02               add     edx, 2
0040184C   .  8B0A                  mov     ecx, dword ptr [edx]
0040184E   .  66:8948 02            mov     word ptr [eax+2], cx                         ;  修改指令码
00401852   .  83C2 02               add     edx, 2
00401855   .  8B0A                  mov     ecx, dword ptr [edx]
00401857   .  66:8948 04            mov     word ptr [eax+4], cx                         ;  修改指令码

按F8 执行这段代码,其修改后的代码如下图所示:
28.png
红色部分8个字节被修改了,这个 Int 68 就是检测 SoftICE 有没有在运行的,用于反调试。
其功能是将以下代码:
[Asm] 纯文本查看 复制代码
0040185D   .  8BF8                  mov     edi, eax                                     ;  Sofice 检测
0040185F   .  8B00                  mov     eax, dword ptr [eax]                         ;  设置新IP跳过Int68
00401861   ?  8BF0                  mov     esi, eax
00401863   .  8B00                  mov     eax, dword ptr [eax]

修改成以下代码了:
[Asm] 纯文本查看 复制代码
0040185D   .  CD 68                 int     68                                           ;  Sofice 检测
0040185F   .  66:3D 86F3            cmp     ax, 0F386                                    ;  设置新IP跳过Int68
00401863   .  74 09                 je      short 0040186E

如上面的图示所示,当执行到 Int 68 指令,重新设置新的 IP 值跳过这条指令即可,如下图所示:
29.png
跳过这条指令就不会引起异常退出了。重新 F8 执行程序:
30.png
来到 "jmp ebx"这里,代码解码就完成了,在这条跳转指令前,还执行了这样一条指令 “mov  byte ptr [40234B], 63”,这是很重要的一个数据写入(后面会讲到):
[Asm] 纯文本查看 复制代码
0040185B   .  B4 43                 mov     ah, 43
0040185D   .  CD 68                 int     68                                           ;  Sofice 检测
0040185F   .  66:3D 86F3            cmp     ax, 0F386                                    ;  设置新IP跳过Int68
00401863   .  74 09                 je      short 0040186E
00401865   .  C605 4B234000 63      mov     byte ptr [40234B], 63                        ;  无调试,写入一个 0x63 到 0x0040234B,这个字节是后面注册算法的密钥
0040186C   .  FFE3                  jmp     ebx
0040186E   >  C605 4B234000 17      mov     byte ptr [40234B], 17                        ;  有调试
00401875   .  FFE3                  jmp     ebx


这里写入的 0x63 在后面会用到。
再次 F8 执行跳转,来到下图所示位置:
31.png
这里是将原来我们跳过混乱代码那一条 JMP 0040179E 改成 nop 指令,原有指令如下所示:
[Asm] 纯文本查看 复制代码
; 跳过未解密代码
00401054   > \E9 45070000           jmp     0040179E

;


来个图片更清楚,修改前状态:
32.png
按 F8 执行程序,代码修改后的效果如下(这样改了还有一个好处,本来解码后要脱掉解码代码的话,要把这个jmp去掉,否则还会去解码,没想到 CrackMe 自己去掉了):
33.png
再按 F8 执行 JMP 指令,来到如下位置:
34.png
这里是我们前面解码后的代码,先静态分析一下这段代码,如上图所示,这里是创建一个基于 Dialog 的程序,其 DlgProc = 0x00401083
我们来到 0x00401083 看看 DlgProc() 的代码,如上图所示,后面部分即是 DlgProc 代码,处理了三条消息:WM_DESTROY,WM_COMMAND,WM_INITDIALOG
我们主要关注其 WM_COMMAND 消息的处理代码,如下图所示:
35.png
处理了三个 ControlID 分别为 0x65,0x66,0x67 的控件事件。通过三个 je 指令的跟随,可以看出指令功能如下图中的注释所示:
36.png
我们在处理第一条指令的位置下一个断点,用来断下 WM_COMMAND 消息的处理。
先看看注册验证代码,如下图所示:
37.png
其第一条指令就是取出我前面提醒过的位于0x0040234B一个字节数据:0x63,后接着的是一大段xor解码程序,这个只有进行动态跟踪来确定其完成的功能了。
下面我们先将程序进行脱壳化处理,就是以后不用再自解码代码了,操作如下图所示:
38.png
右键菜单”复制到可执行文件“,弹出如下提示:
39.png
选择”复制全部“,又会弹出另一个提示:
40.png
选择”“,到保存文件界面,如下图所示,再一次右键菜单:
41.png
选择”保存文件“,弹出一个保存文件对话框:
42.png
输入一个新的文件名,点”保存“即可。
下面,我们先执行 CrackMe,准备动态跟踪算法:
43.png
先下一个断点,便于再次调试。我们直接按 ”F9“ 运行程序。不料再次出现异常,如下图所示:
44.png
点”确定“,如下图所示,IP = 0x00000030 了,肯定没有办法执行下去了:
45.png

由于刚才执行的是创建对话框的程序代码,看来是 DlgProc() 中的代码有问题。因为基于对话框程序,首先执行的就是 DlgProc()。

重新加载我们刚才保存的已经脱掉解码的程序,如下图所示:
50.png
JE 指令已变了 JMP 指令了,但是数据区在0x0040234B处那个重要的数据 0x63 却没有保存出来,所以我们还得先把这个初始化数据恢复,如下图所示:
54.png

在上图中OD数据区,将 0x00 手动修改成 0x63 即可。如上图所示,我们跟随那条前面修改的 JMP 指令,来到一段nop 指令处,其中前5条nop指令,是由一条 jmp 指令修改来的。

如下图所示,我们再次来到 DlgProc() 代码处,并下一个断点,动态跟踪看看前面出的是什么错误:
55.png
然后,直接按 F9,看看会有什么情况,程序没有出错,来到了上面下的断点处,如下图所示:
56.png
我们按 F8 一条一条执行指令,来到下图所示位置:
57.png
可以看到,消息码为 0x00000030,这是一条 WM_SETFONT 消息,CrackMe 并不会处理,会退出 DlgProc() 由 Windows 来处理该消息。还是一步一步 F8,来到 DlgProc() 最后一条指令,还是没有出错,如下图所示:
58_1.png
再一次按”F8“,来到了 User32.dll 的代码空间,如下图所示:
59.png
如上图所示,DlgProc() 在返回时,只弹出了 0x0C 字节的堆栈数据(返回时执行的是 retn 0x0C),还有一个 0x00000000 留在了堆栈中,导致了堆栈不平衡了。
这个 User32 的过程代码如下所示:
[Asm] 纯文本查看 复制代码
768046A0    55                      push    ebp
768046A1    8BEC                    mov     ebp, esp
768046A3    56                      push    esi
768046A4    57                      push    edi
768046A5    53                      push    ebx
768046A6    68 CDABBADC             push    DCBAABCD                                 ; 堆栈平衡标志
768046AB    56                      push    esi                                      ; 这个重复压入,占坑的
768046AC    FF75 18                 push    dword ptr [ebp+18]                       ; 参数4
768046AF    FF75 14                 push    dword ptr [ebp+14]                       ; 参数3
768046B2    FF75 10                 push    dword ptr [ebp+10]                       ; 参数2
768046B5    FF75 0C                 push    dword ptr [ebp+C]                        ; 参数1
768046B8    64:800D CA0F0000 01     or      byte ptr fs:[FCA], 1
768046C0    8B4D 08                 mov     ecx, dword ptr [ebp+8]
768046C3    FF15 C44F8676           call    dword ptr [76864FC4]                     ; USER32.76804780
768046C9    FFD1                    call    ecx                                      ; 调用 DlgProc()
768046CB    64:8025 CA0F0000 FE     and     byte ptr fs:[FCA], 0FE
768046D3    817C24 04 CDABBADC      cmp     dword ptr [esp+4], DCBAABCD              ; 检查平衡标志
768046DB    74 11                   je      short 768046EE
768046DD    813C24 CDABBADC         cmp     dword ptr [esp], DCBAABCD                ; 检查平衡标志
768046E4    75 05                   jnz     short 768046EB
768046E6    83EC 04                 sub     esp, 4                                   ; 平衡堆栈(相当于重新 PUSH ESI)
768046E9    EB 03                   jmp     short 768046EE
768046EB    83C4 10                 add     esp, 10                                  ; 平衡堆栈(如果应用的 DlgProc() 没有pop掉4个参数的数据,则由 User32 自己来pop掉4个参数)
768046EE    83C4 08                 add     esp, 8                                   ; 平衡堆栈(pop掉ESI和“平衡标志”)
768046F1    5B                      pop     ebx
768046F2    5F                      pop     edi
768046F3    5E                      pop     esi
768046F4    5D                      pop     ebp
768046F5    C2 1400                 retn    14


按 F8 执行,来到下图所示位置:
60.png
可以看到,由于找不到”平衡标志“,Windows 将再次弹出 0x18 字节的堆栈数据,ESP 将变成 0x0019FA34,然后再执行4个pop指令,ESP 变为 0x0019FA44,可以看到这个位置保存的是 0x00000030,如果这时还执行 ret 0x14 指令,就会出现我们先前看到的错误提示了,IP = 0x00000030 的错误。
如下图所示,我们先看看该过程的前面,将”平衡标志“压入堆栈后,还插入了一个ESI,这个对应于当 [esp] == 平衡标志 时,执行 sub esp, 4 时平衡用的。
然后,压入4个参数,这个是传递给 DlgProc() 的,共 0x10 字节,所以当 DlgProc() 只弹出 0x0C 字节时,会导致 User32 找不到平衡标志,从而弹出更多的堆栈数据,导致出错了。
61.png

我们先手动修复这个错误,如下图所示:
62.png
将 IP 重新指定为 0x768046D3(这个地址每个机器可能不一样),并将 ESP 的值加4,变成 0x0019FA20,再次 F8 单步运行,这次堆栈没有异常了,找到平衡标志了:
63.png
如上图所示,堆栈位置正常了。因为函数没有改动 ebx 的值,在执行 pop ebx 前,ebx == [esp],就表示应该没有问题了。


这样,我们就可以根据前面找到的原因对 CrackMe 进行修的复了,如下图所示,将返回指令 ret 0C 改成 ret 10 即可
64.png

根据 DlgProc() 内的消息处理分支以及 WM_COMMAND 消息内的处理分支,一共有 6 个 ret 0C 需要改成 ret 10


改好后,我们按前面保存文件的方法,将这些改动保存到 CrackMe 程序中,如下图所示,重新保到一个新的文件中:
65.png


保存后,我们先试试能否正常运行,取消前面在 DlgProc() 中下的断点,直接按 F9 运行,这次没有报错了,主界面出现了,如下图所示:
66.png

提示需要按”Register“按钮进行注册验证。


下面再看看 WM_COMMAND 消息的处理代码,如下图所示:
70.png
跟随跳转到 WM_COMMAND 的处理代码,如下图所示:
71.png
其有三个分支,对应界面上的三个按钮的事件处理,如下图所示,加了注释:
72.png

下面我们看看 CrackMe 的 Info,点击 "Info" 按钮,如下图所示:
80.png
没有反应,没有弹出显示 Info 的消息框
我们跟随 ControlID = 0x66 的控件消息,可以看到,在 MessageBoxA() 的参数中,第一个参数应该是 hWnd 类型的参数,但 CrackMe 压入的是 hModule 参数,这个在 Windows 9x 下没有问题,但 Windows 10 下无效,导致无法显示消息框。
81.png
具体代码如下:
[Asm] 纯文本查看 复制代码
004010D6   > \6A 00                 push    0                                        ; /Style = MB_OK|MB_APPLMODAL
004010D8   .  68 A5224000           push    004022A5                                 ; |Title = "How to ... "
004010DD   .  68 78214000           push    00402178                                 ; |Text = "Nothing more simple ...",CR,LF,"Press Register and read ...",CR,LF,"In the box there must be Registered ... ;)",CR,LF,"Disasm arent Allowed (.. there is a little trick ...)",CR,LF,"Debugger like Sice allowed",CR,LF,CR,LF,CR,LF,"Send yo"...
004010E2   .  FF35 87244000         push    dword ptr [402487]                       ; |hOwner = 00400000
004010E8   .  E8 7C080000           call    <jmp.&USER32.MessageBoxA>                ; \MessageBoxA


我们跟随这个 call MessageBoxA(),来到下图所示位置:
82.png
OD的提示区,显示有两个地方调用了 MessageBoxA() 函数,我们在提示区按右键,跳转到调用处,如下图所示:
83.png
84.png
将 push hModule 改成压入 DlgProc() 函数自己的 hWnd 参数,如上图所示,改成 push dword ptr [ebp+8] 即可
修改后代码如下所示:
[Asm] 纯文本查看 复制代码
004010D6   > \6A 00                 push    0
004010D8   .  68 A5224000           push    004022A5                                 ;  ASCII "How to ... "
004010DD   .  68 78214000           push    00402178                                 ;  ASCII "Nothing more simple ...",CR,LF,"Press Register and read ...",CR,LF,"In the box there must be Registered ... ;)",CR,LF,"Disasm arent Allowed (.. there is a little trick ...)",CR,LF,"Debugger like Sice allowed",CR,LF,CR,LF,CR,LF,"Send your"...
004010E2      FF75 08               push    dword ptr [ebp+8]
004010E5      90                    nop
004010E6      90                    nop
004010E7      90                    nop
004010E8   .  E8 7C080000           call    <jmp.&USER32.MessageBoxA>                ; \MessageBoxA


同样,另一处也进行同样的修改,如下图所示:
85.png


然后我们再一次把这些变动保存到文件中,如下图所示:
86.png


保存完后,我们先将那个 0x63 没有保存的问题处理一下,用 UltraEditor 等二进制工具打开文件,直接修改即可,如下图所示:
51.png
如上图所示的位置,直接将原有的 0x00 修改成我们需要的 0x63 即可,修改后保存文件。


现在我们重新在 OD 中载入我们改好的程序,继续进行测试,返回界面,点”Info“按钮,这次正常弹出消息框了:
87.png


下面,我们开始注册算法跟踪了,可以看到数据区中 0x0040234B 处已变成了 0x63,函数返回指令也已是 ret 10 了:
90.png
如上图所示,我们在”Register“分支跳转指令上下一个断点,进行动态跟踪。直接在界面点击”Register“,断下后,按"F8"来到下图所示位置:
91.png
这里就是处理注册的代码,第1条指令(0x004010F4处的指令)就是取出我们前面讲到的 0x63,按 F8 执行到如下位置:
92.png
可以看到,这段代码是将0x63作为异或解密参数生成一个字符串”ya.do“,继续向下看代码:
93.png
可以看到,这段代码是打开一个名叫”ya.do“的文件,判断大小,如果大小为21字节则读入其内容后,关闭文件。
我们先不要执行,先用工具生成一个21字节的文件,并保存为 "ya.do",如下图所示,用 ultraEditor 生成并保存:
94.png
文件内容先随便输入。按 F8 执行程序,如下图所示:
95.png
正常读入文件内容,上图OD数据区显示了文件内容。按 F8 继续执行,如下图所示,又是指令修改:
96.png
修改后面的跳转指令,跳转到注册算法代码。如下图所示:
97.png
指令已修改好了,将跳转到注册算法代码处。
98.png

这里,先把刚才改动的跳转代码又改回去了。


接下来,就是真正的算法代码了,如下图所示:
100.png

具体代码如下,这一小段代码处理文件内容的第1个字节 FILE[0]:
[Asm] 纯文本查看 复制代码
00401414   .  B8 78234000           mov     eax, 00402378
00401419   .  BB CE234000           mov     ebx, 004023CE                            ;  ASCII 04,"!:'6"
0040141E   .  B9 4C234000           mov     ecx, 0040234C                            ;  ecx-1 == 0x0040234B
00401423   .  8A49 FF               mov     cl, byte ptr [ecx-1]                     ;  cl = 0x63, 未调试标志,ecx-1 = 0x0040234B
00401426   .  80E9 10               sub     cl, 10                                   ;  cl = 0x53
00401429   .  8A2B                  mov     ch, byte ptr [ebx]                       ;  ch = 0x04, 常量数组:xor_Base[0]
0040142B   .  32E9                  xor     ch, cl                                   ;  ch = 0x53 ^ xor_Base[0] = 0x53 ^ 0x04 = 0x57
0040142D   .  8A30                  mov     dh, byte ptr [eax]                       ;  dh = FILE[0],文件内容
0040142F   .  80C1 0D               add     cl, 0D                                   ;  cl = 0x53 + 0x0D = 0x60
00401432   .  32F1                  xor     dh, cl                                   ;  FILE[0] xor 0x60
00401434   .  3AEE                  cmp     ch, dh                                   ;  FILE[0] ^ 0x60 == ch = 0x57 = 0x53 ^ xor_Base[0]
00401436   .  0F85 5B030000         jnz     00401797                                 ;  FILE[0] = 0x60^0x57=0x60^0x53^xor_Base[0] = 0x37

可以看出,这里再一次读取了字节数据 0x63,作为 xor 操作的一个参数(只是在使用前先减去了 0x10 变成了 0x53)。
这里将文件的第1个字节与内存中一个常量字节数组进行 xor 处理,然后对处理结果进行检查。如果 FILE[0] 不等于 0x37 就会退出算法,所以文件第1个字节 FILE[0] = 0x37。
由于注册文件不对,我们直接跳过jnz指令,改变IP来到后一条指令,接下来继续看后面字节的处理:

101.png
具体代码如下:
[Asm] 纯文本查看 复制代码
0040143C   .  8A15 B1224000         mov     dl, byte ptr [4022B1]                    ;  dl = 加密的字符
00401442   .  32D6                  xor     dl, dh                                   ;  解码
00401444   .  8815 E8224000         mov     byte ptr [4022E8], dl                    ;  保存解码字符
0040144A   .  83C0 01               add     eax, 1                                   ;  FILE++
0040144D   .  83C3 01               add     ebx, 1                                   ;  xor_Base++
00401450   .  80E9 0D               sub     cl, 0D                                   ;  cl = 0x60 - 0x0D = 0x53,恢复原值
00401453   .  8A2B                  mov     ch, byte ptr [ebx]                       ;  ch = xor_Base[1]
00401455   .  32E9                  xor     ch, cl                                   ;  ch = xor_Base[1] ^ 0x53
00401457   .  8A30                  mov     dh, byte ptr [eax]                       ;  dh = FILE[1]
00401459   .  80C1 0D               add     cl, 0D                                   ;  cl = 0x53 + 0x0D = 0x60,重新赋值 0x60
0040145C   .  32F1                  xor     dh, cl                                   ;  FILE[1] ^ 0x60
0040145E   .  3AEE                  cmp     ch, dh                                   ;  FILE[1] ^ 0x60 == ch = xor_Base[1] ^ 0x53
00401460   .  0F85 31030000         jnz     00401797                                 ;  FILE[1]=0x60^0x53^xor_Base[1]=0x33^0x21=0x12
00401466   .  8A15 B2224000         mov     dl, byte ptr [4022B2]                    ;  由上面两个数据可以看出:
0040146C   .  32D6                  xor     dl, dh                                   ;  转换关系为:FILE[ i ]= xor_Base[ i ] ^ 0x33
0040146E   .  8815 E9224000         mov     byte ptr [4022E9], dl


可以看到,处理方式与 FILE[0]字节一样,得到一个规律:FILE[ i ] = xor_Base[ i ] ^ 0x33。


常量字节数组如下:
[Asm] 纯文本查看 复制代码
004023CE  04 21 3A 27 36 0A 32 37 3C 13 3B 3C 27 3E 32 3A 
004023DE  3F 7D 30 3C 3E 1A 02 4D 07 0C 


后面的就不用看了,应该都是这样计算的,直接 F9 退出算法过程,由于我们的注册文件不对,所以会弹出注册错误:
102.png
不能注册!!!下面我们重新生成新的注册文件,写一段如下代码,计算文件内容:
[C++] 纯文本查看 复制代码
#include <iostream>

int genSN();

int main(int argc, char** argv) {
        genSN();
        return 0;
}

int genSN() {
        char xor_Base[] = {0x04, 0x21, 0x3A, 0x27, 0x36, 0x0A, 0x32, 0x37, 0x3C, 
        0x13, 0x3B, 0x3C, 0x27, 0x3E, 0x32, 0x3A, 0x3F, 0x7D, 0x30, 0x3C, 0x3E};

        printf("Key file content for RingZ3r0 crackme:\n");
        for(int i=0; i<21; i++) {
                printf("%02X ", xor_Base[ i ] ^ 0x33);
        }
        printf("\n");
}

以上代码在 Dev-C++中调试通过,运行后输出如下:
[Shell] 纯文本查看 复制代码
Key file content for RingZ3r0 crackme:
37 12 09 14 05 39 01 04 0F 20 08 0F 14 0D 01 09 0C 4E 03 0F 0D

--------------------------------
Process exited after 0.02284 seconds with return value 0
请按任意键继续. . .



我们再次用 UltraEditor 对 "ya.do" 文件进行修改,如下图所示:
103.png
修改完后,保存文件。

然后再一次到 CrackMe 界面上点”Register“,断下后,直接按”F9"运行,弹出如下消息框:
104.png

表示注册成功!!!成功!!!改得好辛苦呀!!!


为了检查改动后的程序,在 Windows 9x 下是否也能运行,在虚拟机下测试,如下图所示:
110.png
仍然可以正常运行,表示程序现在可以运行在 Win9x和WinNT两种系列的内核下了,保证了100%的兼容性,虽然这没什么卵用。。。。。。


分析完毕!!!


免费评分

参与人数 11威望 +2 吾爱币 +16 热心值 +11 收起 理由
Hmily + 2 + 7 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
笙若 + 1 + 1 谢谢@Thanks!
mchankun + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
wei5383079 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
jinyan + 1 + 1 热心回复!
F0rM + 1 + 1 谢谢@Thanks!
huzpsb + 1 我很赞同!
simakuangbiao + 1 + 1 太牛了。
ZMZwise + 1 + 1 牛逼的大佬,厉害厉害
天空藍 + 1 + 1 太疯狂,凌晨2点还在做逆工。
FleTime + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

天空藍 发表于 2019-12-1 04:19
回写保护是什么意思?
ianhor 发表于 2019-12-1 07:03
dutyzqly 发表于 2019-12-1 07:54
 楼主| solly 发表于 2019-12-1 10:17
本帖最后由 solly 于 2019-12-1 10:20 编辑

天空藍 发表于 2019-12-1 04:19
回写保护是什么意思?

随便取个名字,大概就是动态重写指令代码来解码恢复到正常指令代码或者改变指令执行流程的意思。。。。。
写贴花了几个小时,大概有4小时才写成并改好。
李现在哪 发表于 2019-12-1 11:22
感谢分享
wisoft 发表于 2019-12-2 12:45
厉害,感谢分享
louties 发表于 2019-12-3 08:46
厉害,有几个地方没看懂
 楼主| solly 发表于 2019-12-3 17:21
louties 发表于 2019-12-3 08:46
厉害,有几个地方没看懂

哪几个地方呀?
hesqiang 发表于 2020-12-23 09:57
感谢 ,吾爱破解论坛因你更精彩!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 13:59

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表