首页
社区
课程
招聘
[原创]riijj Crackme (4)的详解
发表于: 2005-2-4 15:44 12366

[原创]riijj Crackme (4)的详解

2005-2-4 15:44
12366

【破文标题】riijj Crackme (4) 的详解
【对  象】中级新手
【下载地址】http://bbs.pediy.com/upload/file/2004/12/riijj_cm_20041217.zip_783.zip
【破解工具】OD, softice
【保护方式】序号
【任  务】找出序号
【破文作者】riijj
【组  织】没有
【破解声明】我的破解很菜,写这篇东西是给对这个 crackme 有兴趣的兄弟们,分享一下破解心得
【电  邮】je6543@yahoo.com
【调试环境】w2k
【破解过程】

       
        这个 crackme 是一个自调试程序的例子。当一个程序被调试时,其它程序不可以对它进行调试,这种做法是防止破解者用 ring3 调试器加载。

        这篇文章会讨论这个 crackme 使用的方法与结构,希望让不熟悉自调试的兄弟们有一点初部印象。

[ Part I.  观察 ]

        刚下载了这个 crackme,看见它包含 5 个档案,其中一个是执行档 Crackme4.exe (外表像一只魔鬼),另外有 3 个 sub 档,还有一个 zip 档,它是一张图片的压缩文件,只要破解成功便可以取得解压的密码。

        我们尝试用 OD 打开 Crackme4.exe ,只忽略 KERNEL32 内存异常, F9 运行,程序很顺利地打开,似乎这个 crackme 没有设置反调试 (的确是这样)

        我们输入注册名字 "riijj" ,序号 "AAAABBBB"

        现在开始动手,先试试简单的断点

        bp GetWindowTextA

        现在输入序号,按下 register,没有反应。

        我们怀疑这个程序的真正核心不是在 Crackme4.exe 里,我们现在检查一下,在 OD 里按一下 F12 (暂停程序)

        很奇怪,OD 显示程序是停止了,现在身处 ntdll 的 77F82870 ,可是 crackme 依然正常运作,窗口和 resgister 按钮也有反应。我们按 OD 上方的 View > Threads  (查看线程),看见这个 crackme4.exe 只有一个线程,现在这个线程已经停止了。

        我们打开工作管理员,可以看见 sub1.ooo sub2.ooo 和 sub3.ooo 的名字,很明显它们才是真正运行的东西。

[ Part II.  结构分析 ]

        我们把 crackme 再新加载,设定断点

        bp CreateProcessA

        现在 F9 运行

KERNEL32
       
77E73F8F > 55               PUSH EBP   <------ 停在这里
77E73F90   8BEC             MOV EBP,ESP
77E73F92   FF75 2C          PUSH DWORD PTR SS:[EBP+2C]
77E73F95   FF75 28          PUSH DWORD PTR SS:[EBP+28]
77E73F98   FF75 24          PUSH DWORD PTR SS:[EBP+24]
77E73F9B   FF75 20          PUSH DWORD PTR SS:[EBP+20]

        按 Alt + F9 返回 crackme

00401012  |. 50             PUSH EAX                                 ; /pStartupinfo
00401013  |. FF15 0C404000  CALL DWORD PTR DS:[<&KERNEL32.GetStartup>; \GetStartupInfoA
00401019  |. 8D4C24 00      LEA ECX,DWORD PTR SS:[ESP]
0040101D  |. 8D5424 10      LEA EDX,DWORD PTR SS:[ESP+10]
00401021  |. 51             PUSH ECX                                 ; /pProcessInfo
00401022  |. 52             PUSH EDX                                 ; |pStartupInfo
00401023  |. 6A 00          PUSH 0                                   ; |CurrentDir = NULL
00401025  |. 6A 00          PUSH 0                                   ; |pEnvironment = NULL
00401027  |. 6A 03          PUSH 3                                   ; |CreationFlags = DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS
00401029  |. 6A 00          PUSH 0                                   ; |InheritHandles = FALSE
0040102B  |. 6A 00          PUSH 0                                   ; |pThreadSecurity = NULL
0040102D  |. 6A 00          PUSH 0                                   ; |pProcessSecurity = NULL
0040102F  |. 6A 00          PUSH 0                                   ; |CommandLine = NULL
00401031  |. 68 4C504000    PUSH Crackme4.0040504C                   ; |ModuleFileName = "sub3.ooo"  <---看见这个
00401036  |. FF15 08404000  CALL DWORD PTR DS:[<&KERNEL32.CreateProc>; \CreateProcessA
0040103C  |. 85C0           TEST EAX,EAX                            <-------我们在这里
0040103E  |. 75 09          JNZ SHORT Crackme4.00401049
00401040  |. 81C4 B4000000  ADD ESP,0B4
00401046  |. C2 1000        RETN 10
00401049  |> 56             PUSH ESI
0040104A  |. 57             PUSH EDI
0040104B  |. 68 30504000    PUSH Crackme4.00405030                   ; /Title = "Riijj Crackme - 20041217"
00401050  |. 6A 00          PUSH 0                                   ; |Class = 0
00401052  |. FF15 A4404000  CALL DWORD PTR DS:[<&USER32.FindWindowA>>; \FindWindowA
00401058  |. 6A 03          PUSH 3                                   ; /Flags = SWP_NOSIZE|SWP_NOMOVE
0040105A  |. 6A 00          PUSH 0                                   ; |Height = 0
0040105C  |. 6A 00          PUSH 0                                   ; |Width = 0
0040105E  |. 6A 00          PUSH 0                                   ; |Y = 0
00401060  |. 6A 00          PUSH 0                                   ; |X = 0
00401062  |. 6A 00          PUSH 0                                   ; |InsertAfter = HWND_TOP
00401064  |. 50             PUSH EAX                                 ; |hWnd
00401065  |. FF15 A0404000  CALL DWORD PTR DS:[<&USER32.SetWindowPos>; \SetWindowPos
0040106B  |. 8B35 04404000  MOV ESI,DWORD PTR DS:[<&KERNEL32.WaitFor>;  KERNEL32.WaitForDebugEvent
00401071  |. 8B3D 54404000  MOV EDI,DWORD PTR DS:[<&KERNEL32.Continu>;  KERNEL32.ContinueDebugEvent
00401077  |> 8D4424 5C      /LEA EAX,DWORD PTR SS:[ESP+5C]
0040107B  |. 6A FF          |PUSH -1

        这个 crackme4.exe 创建新进程,档案是 sub3.ooo ,以 DEBUG_PROCESS 的方式产生,也就是说现在 crackme4.exe 是它的调试程序。

        一般调试程序的方法有两种,分别是以 CreateProcess 产生,或以 DebugActiveProcess 连接到运行中的程序。一般来说调试程序在使用 CreateProcess 后,便会使用 WaitForDebugEvent 来等待被调试者的 debug 事件发生 (例如 exception,进程开始或进程结束等 ) ,在处理事件后,用 ContinueDebugEvent 使被调试的程序继续运行

        我们在 0040106B 看见了 WaitForDebugEvent ,当程序执行到这里的时候,便会进入睡眠状态,即使我们停止它,也影响不到 sub3.ooo

        我们用 OD 把 sub3.ooo 加载,看看可不可以单独运行。

        加载后, F9 运行,果然我们看见了 crackme 的初始画面,可是运行了不久,程序便终止了。

77F8EE0F   C2 0800          RETN 8
77F8EE12   803D 0403FD77 00 CMP BYTE PTR DS:[77FD0304],0
77F8EE19   0F85 3E430000    JNZ ntdll.77F9315D
77F8EE1F   834D FC FF       OR DWORD PTR SS:[EBP-4],FFFFFFFF
77F8EE23   E8 0F000000      CALL ntdll.77F8EE37
77F8EE28   8B4D F0          MOV ECX,DWORD PTR SS:[EBP-10]

        OD 的下方写上 Process terminated

        我们估计,这个 crackme 在运行的时候产生了某种 exception,使程序运行的时候会把执行权交到父进程里,并在父进程运时做了一些必要工作,如果我们单独把 crackme 的子程序 (例如 sub3.ooo) 运行,便会导致运行不正常。

        这时时候,我们把 sub3 重新加载,依旧设断点在 CreateProcess

        bp CreateProcessA

        F9 运行

        果然,断下来了, alt+F9 返回 crackme ,看到

00401013  |. FF15 0C404000  CALL DWORD PTR DS:[<&KERNEL32.GetStartup>; \GetStartupInfoA
00401019  |. 8D4C24 00      LEA ECX,DWORD PTR SS:[ESP]
0040101D  |. 8D5424 10      LEA EDX,DWORD PTR SS:[ESP+10]
00401021  |. 51             PUSH ECX                                 ; /pProcessInfo
00401022  |. 52             PUSH EDX                                 ; |pStartupInfo
00401023  |. 6A 00          PUSH 0                                   ; |CurrentDir = NULL
00401025  |. 6A 00          PUSH 0                                   ; |pEnvironment = NULL
00401027  |. 6A 03          PUSH 3                                   ; |CreationFlags = DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS
00401029  |. 6A 00          PUSH 0                                   ; |InheritHandles = FALSE
0040102B  |. 6A 00          PUSH 0                                   ; |pThreadSecurity = NULL
0040102D  |. 6A 00          PUSH 0                                   ; |pProcessSecurity = NULL
0040102F  |. 6A 00          PUSH 0                                   ; |CommandLine = NULL
00401031  |. 68 30504000    PUSH sub3.00405030                       ; |ModuleFileName = "sub2.ooo"
00401036  |. FF15 08404000  CALL DWORD PTR DS:[<&KERNEL32.CreateProc>; \CreateProcessA
0040103C  |. 85C0           TEST EAX,EAX
0040103E  |. 75 09          JNZ SHORT sub3.00401049
00401040  |. 81C4 B4000000  ADD ESP,0B4

        sub3 在调试 sub2,我们估计 sub2 会调试 sub1

        现在我们用 OD 加载 sub2.ooo,设断点在 CreateProcessA

        bp CreateProcessA

        F9 运行

        我们断下来了,按 Alt+F9 返回 crackme,我们身处

00401169  |. FF15 DC674000  CALL DWORD PTR DS:[4067DC]
0040116F  |. 8D4C24 10      LEA ECX,DWORD PTR SS:[ESP+10]
00401173  |. 8D9424 8000000>LEA EDX,DWORD PTR SS:[ESP+80]
0040117A  |. 51             PUSH ECX
0040117B  |. 52             PUSH EDX
0040117C  |. 6A 00          PUSH 0
0040117E  |. 6A 00          PUSH 0
00401180  |. 6A 03          PUSH 3
00401182  |. 6A 00          PUSH 0
00401184  |. 6A 00          PUSH 0
00401186  |. 6A 00          PUSH 0
00401188  |. 6A 00          PUSH 0
0040118A  |. 68 30604000    PUSH sub2.00406030                       ;  ASCII "sub1.ooo"
0040118F  |. FF15 D4674000  CALL DWORD PTR DS:[4067D4]
00401195  |. 85C0           TEST EAX,EAX                <---------- 我们在这里
00401197  |. 0F84 9F020000  JE sub2.0040143C
0040119D  |. 8B7424 0C      MOV ESI,DWORD PTR SS:[ESP+C]
004011A1  |. 8B7C24 0C      MOV EDI,DWORD PTR SS:[ESP+C]
004011A5  |. BB 01000100    MOV EBX,10001
004011AA  |> 8D4424 20      /LEA EAX,DWORD PTR SS:[ESP+20]
004011AE  |. 6A FF          |PUSH -1
004011B0  |. 50             |PUSH EAX
004011B1  |. FF15 D0674000  |CALL DWORD PTR DS:[4067D0]
004011B7  |. 8B4424 20      |MOV EAX,DWORD PTR SS:[ESP+20]

        我们看见了 sub1 ,可是这里比较奇怪的是,我们看不见 CreateProcessA 的名字

        我们知道 0040118F 呼叫的 call 是呼叫 CreateProcessA,这表示 [4067D4] 这里存放了 CreateProcessA 的 API 位置

        API 的呼叫看来是经过处理的

        现在我们知道  crackme4.exe -> sub3.ooo -> sub2.ooo -> sub1.ooo ,我们估计程序的真正部分在 sub1.ooo 里,我们尝试单独用 OD 加载 sub1

        这时候,程序运行了,可是发生了 int 3 异常

00401D60  /$ 55             PUSH EBP
00401D61  |. 8BEC           MOV EBP,ESP
00401D63  |. 51             PUSH ECX
00401D64  |. 68 00010000    PUSH 100
00401D69  |. C745 FC A01440>MOV DWORD PTR SS:[EBP-4],sub1.004014A0
00401D70  |. E8 0D020000    CALL sub1.00401F82
00401D75  |. 83C4 04        ADD ESP,4
00401D78  |. A3 E0674000    MOV DWORD PTR DS:[4067E0],EAX
00401D7D  |. 60             PUSHAD
00401D7E  |. B8 FF000000    MOV EAX,0FF
00401D83  |. 8B15 E0674000  MOV EDX,DWORD PTR DS:[4067E0]
00401D89  |. 8B4D FC        MOV ECX,DWORD PTR SS:[EBP-4]
00401D8C     CC             INT3           <---------在这里
00401D8D  |. 8BE5           MOV ESP,EBP
00401D8F  |. 5D             POP EBP
00401D90  \. C3             RETN

        我们想象,这个 int 3 是故意放进去的,目的是产生异常,当异常出现时, sub1 停止运行,sub2 的 WaitForDebugEvent 会返回, sub2 开始运行,对于 WaitForDebugEvent 接收到的异常进行处理,当处理完成后,便使用 ContinueDebugEvent 继续 sub1。

       

[ Part III.  调试 ]

       
        对于这种多进程的防护,使用 softice 是比较直接的。

        从取得字符串的地方开始跟踪,Ctrl + D 打开 softice,设断点

:bpx getwindowtexta

        离开后,按一下 "Register" 按钮,可是 softice 没有反应,可能这个程序没有使用 GetWindowTextA 来得到字符串。

        一般 windows 程序 (除了 delphi 以外),文字方块的取得字符串方法有以下几种 :

        1. GetWindowTextA  (送出 WM_GETTEXT)
        2. GetDlgItemTextA (内里使用 GetWindowTextA )
        3. SendMessage 送出 WM_GETTEXT
        4. SendMessage 送出 EM_GETLINE
        5. 程序拦截 WM_KEYDOWN ,把使用者按键纪录
        6. 直接取得文字内存 handle,Lock 后读取

        我们尝试在内存搜索字符串, Ctrl+D 打开 softice,

        选择 sub1 的领空

:addr sub1

        搜索字符串从 0 至 ffffffff

:s 0 L ffffffff "AAAABBBB"

        这时候, softice 提示

Pattern found at 0010:0012F5EC (0012F5EC)

        在 0012F5EC 发现了序号字符串,我们设定内存断点在那里

:bpm 0012f5ec
       
        离开 softice 后,立即断在

001B:77DFFE62  F3A5                REPZ MOVSD
001B:77DFFE64  FF7508              PUSH      DWORD PTR [EBP+08]  <---这里
001B:77DFFE67  8BC8                MOV       ECX,EAX
001B:77DFFE69  83E103              AND       ECX,03
001B:77DFFE6C  F3A4                REPZ MOVSB
001B:77DFFE6E  E8110D0000          CALL      77E00B84
001B:77DFFE73  5E                  POP       ESI
001B:77DFFE74  5F                  POP       EDI
001B:77DFFE75  8BC3                MOV       EAX,EBX
001B:77DFFE77  5B                  POP       EBX
001B:77DFFE78  5D                  POP       EBP
001B:77DFFE79  C21000              RET       0010
001B:77DFFE7C  880C1F              MOV       [EBX+EDI],CL
001B:77DFFE7F  EBCD                JMP       77DFFE4E
001B:77DFFE81  55                  PUSH      EBP
001B:77DFFE82  8BEC                MOV       EBP,ESP
001B:77DFFE84  83EC3C              SUB       ESP,3C
001B:77DFFE87  53                  PUSH      EBX

        看看 code window 上方的提示,我们身处 User32!DrawStateA 里,我们看看当前的 call stack

:stack
FrameEBP  RetEIP     Symbol
0012F56C  77E006AC   USER32!DrawStateA+1D08
0012F5A8  77E004EA   USER32!EditWndProc+00D5
0012F5CC  77DF597E   USER32!DrawStateA+238E
0012FDF8  77FA15EF   USER32!PostMessageA+00CA
0012FE74  77DF70F3   ntdll!KiUserCallbackDispatcher+0013
0012FEB8  00401BA0   USER32!GetWindowTextA+0089
00000000  00000000   sub1!.text+0BA0

        我们可以看见 sub1 呼叫 GetWindowTextA,位置在 00401BA0

        到那里看看

:u 00401BA0

001B:00401B84  E827FAFFFF          CALL      004015B0
001B:00401B89  8B1534684000        MOV       EDX,[00406834]
001B:00401B8F  83C408              ADD       ESP,08
001B:00401B92  6A14                PUSH      14
001B:00401B94  6860684000          PUSH      00406860
001B:00401B99  52                  PUSH      EDX
001B:00401B9A  FF15A4684000        CALL      [004068A4]
001B:00401BA0  A1A0674000          MOV       EAX,[004067A0]  <---- 这里
001B:00401BA5  6A14                PUSH      14
001B:00401BA7  6880684000          PUSH      00406880
001B:00401BAC  50                  PUSH      EAX
001B:00401BAD  FF15A4684000        CALL      [004068A4]
001B:00401BB3  60                  PUSHAD
001B:00401BB4  B800000000          MOV       EAX,00000000
001B:00401BB9  CC                  INT       3
001B:00401BBA  61                  POPAD
001B:00401BBB  8B0DAC684000        MOV       ECX,[004068AC]
001B:00401BC1  51                  PUSH      ECX
001B:00401BC2  E879F6FFFF          CALL      00401240
001B:00401BC7  8B15AC684000        MOV       EDX,[004068AC]
001B:00401BCD  52                  PUSH      EDX
001B:00401BCE  E8DDF9FFFF          CALL      004015B0
001B:00401BD3  83C408              ADD       ESP,08
001B:00401BD6  6A01                PUSH      01
001B:00401BD8  6A00                PUSH      00
001B:00401BDA  6A00                PUSH      00
001B:00401BDC  6A00                PUSH      00
001B:00401BDE  68C0674000          PUSH      004067C0

        往上看,没有找到 GetWindowTextA,只见 CALL [004068A4]。 很明显 [004068A4] 是 GetWindowTextA 的位置,我们尝试过在 GetWindowTextA 下断,可是断不下来,估计断点被程序自行清除了。

       
[ Part IV.   解开断点清除]

        调试器设置普通断点时,在断点处放置 int 3 (0xcc) 来达到中断的效果,如果程序在执行前把 0xcc 恢复,断点便会消失

        我们要找出 GetWindowTextA 被存取的一刻,在它的位置设置内存断点

:bpm getwindowtexta

        离开 softice 后,我们立即断在

001B:004011AF  90                  NOP
001B:004011B0  8B442404            MOV       EAX,[ESP+04]
001B:004011B4  56                  PUSH      ESI
001B:004011B5  57                  PUSH      EDI
001B:004011B6  8B3D48684000        MOV       EDI,[00406848]
001B:004011BC  3BC7                CMP       EAX,EDI
001B:004011BE  7221                JB        004011E1
001B:004011C0  8B0D50684000        MOV       ECX,[00406850]
001B:004011C6  8D1439              LEA       EDX,[EDI+ECX]
001B:004011C9  3BC2                CMP       EAX,EDX
001B:004011CB  7714                JA        004011E1
001B:004011CD  8B3540684000        MOV       ESI,[00406840]
001B:004011D3  8BD1                MOV       EDX,ECX
001B:004011D5  C1E902              SHR       ECX,02
001B:004011D8  F3A5                REPZ MOVSD        <-------这里
001B:004011DA  8BCA                MOV       ECX,EDX
001B:004011DC  83E103              AND       ECX,03
001B:004011DF  F3A4                REPZ MOVSB
001B:004011E1  8B3DE8684000        MOV       EDI,[004068E8]
001B:004011E7  3BC7                CMP       EAX,EDI
001B:004011E9  7221                JB        0040120C

        这里是 sub1 的领空,奇怪的是,这里对 getwindowtexta 的内容进行读写  (REPZ MOVSD , 复制内存 )

        你中断的地方可能跟我不相同,如果不相同的话,你可以略过这里的描述,往下找找有没有你中断的地方

        我们按一下 F12 到达 call 的返回

001B:0040123F  90                  NOP
001B:00401240  8B442404            MOV       EAX,[ESP+04]
001B:00401244  8B4801              MOV       ECX,[EAX+01]
001B:00401247  51                  PUSH      ECX
001B:00401248  E863FFFFFF          CALL      004011B0
001B:0040124D  59                  POP       ECX   <-------这里
001B:0040124E  C3                  RET
001B:0040124F  90                  NOP
001B:00401250  83EC5C              SUB       ESP,5C
001B:00401253  B9DEFFFFFF          MOV       ECX,FFFFFFDE
001B:00401258  53                  PUSH      EBX
001B:00401259  BAE9FFFFFF          MOV       EDX,FFFFFFE9
001B:0040125E  56                  PUSH      ESI
001B:0040125F  894C241C            MOV       [ESP+1C],ECX
001B:00401263  894C2428            MOV       [ESP+28],ECX
001B:00401267  BEEDFFFFFF          MOV       ESI,FFFFFFED
001B:0040126C  89542414            MOV       [ESP+14],EDX
001B:00401270  B8DFFFFFFF          MOV       EAX,FFFFFFDF

        我们尝试把 00401248 的一行 nop 掉

:a 00401248

nop 掉 5 个元位

        现在离开 softice ,再中断在

001B:004014DF  33D2                XOR       EDX,EDX
001B:004014E1  F3A6                REPZ CMPSB    <------这里
001B:004014E3  7405                JZ        004014EA
001B:004014E5  1BD2                SBB       EDX,EDX
001B:004014E7  83DAFF              SBB       EDX,-01
001B:004014EA  8BF2                MOV       ESI,EDX
001B:004014EC  8B15E8684000        MOV       EDX,[004068E8]
001B:004014F2  3BC2                CMP       EAX,EDX
001B:004014F4  722A                JB        00401520
001B:004014F6  8B0DF0684000        MOV       ECX,[004068F0]
001B:004014FC  8D3C11              LEA       EDI,[EDX+ECX]
001B:004014FF  3BC7                CMP       EAX,EDI
001B:00401501  771D                JA        00401520
001B:00401503  8B3DE0684000        MOV       EDI,[004068E0]
001B:00401509  2BC8                SUB       ECX,EAX
001B:0040150B  2BFA                SUB       EDI,EDX
001B:0040150D  03CA                ADD       ECX,EDX

        这里是内存比较 (REPZ CMPSB ),程序把备份的内容与现在的内容比较,如果不相同,便可能不进行呼叫或干其它事。

        按一下 F12 ,来到

001B:00401560  56                  PUSH      ESI
001B:00401561  8B742408            MOV       ESI,[ESP+08]
001B:00401565  56                  PUSH      ESI
001B:00401566  E845FFFFFF          CALL      004014B0
001B:0040156B  83C404              ADD       ESP,04  <-----这里
001B:0040156E  85C0                TEST      EAX,EAX   <--看见这里有比较
001B:00401570  7413                JZ        00401585   <--- F8 单步,是跳的
001B:00401572  56                  PUSH      ESI
001B:00401573  E838FCFFFF          CALL      004011B0
001B:00401578  56                  PUSH      ESI
001B:00401579  E832FFFFFF          CALL      004014B0
001B:0040157E  83C408              ADD       ESP,08
001B:00401581  85C0                TEST      EAX,EAX
001B:00401583  75ED                JNZ       00401572
001B:00401585  80BEE0000000CC      CMP       BYTE PTR [ESI+000000E0],CC
001B:0040158C  7513                JNZ       004015A1
001B:0040158E  56                  PUSH      ESI
001B:0040158F  E81CFCFFFF          CALL      004011B0
001B:00401594  8A86E0000000        MOV       AL,[ESI+000000E0]
001B:0040159A  83C404              ADD       ESP,04
001B:0040159D  3CCC                CMP       AL,CC
001B:0040159F  74ED                JZ        0040158E
001B:004015A1  B801000000          MOV       EAX,00000001
001B:004015A6  5E                  POP       ESI
001B:004015A7  C3                  RET
       
        我们按 F8 单步,发现在没有断点的情况下,JZ 是跳的。我们把 00401566 的 call 修改

:a 00401566

        改成 xor eax,eax 和 3 个 nop

        现在离开 softice,再次中断在

001B:00401585  80BEE0000000CC      CMP       BYTE PTR [ESI+000000E0],CC
001B:0040158C  7513                JNZ       004015A1    <---这里
001B:0040158E  56                  PUSH      ESI
001B:0040158F  E81CFCFFFF          CALL      004011B0
001B:00401594  8A86E0000000        MOV       AL,[ESI+000000E0]
001B:0040159A  83C404              ADD       ESP,04
001B:0040159D  3CCC                CMP       AL,CC
001B:0040159F  74ED                JZ        0040158E
001B:004015A1  B801000000          MOV       EAX,00000001
001B:004015A6  5E                  POP       ESI
001B:004015A7  C3                  RET
       
        这一句  CMP BYTE PTR [ESI+000000E0],CC  是把 getwindowtexta 的第一个位跟 0xcc ( int 3) 比较,检查是否被设为断点

        我们把 00401585 (CMP) 和 0040158C (JNZ) 两句 nop 掉

:a 00401585
一直 nop 至 0040158C

        再离开 softice,又断在

001B:004011AF  90                  NOP
001B:004011B0  8B442404            MOV       EAX,[ESP+04]
001B:004011B4  56                  PUSH      ESI
001B:004011B5  57                  PUSH      EDI
001B:004011B6  8B3D48684000        MOV       EDI,[00406848]
001B:004011BC  3BC7                CMP       EAX,EDI
001B:004011BE  7221                JB        004011E1
001B:004011C0  8B0D50684000        MOV       ECX,[00406850]
001B:004011C6  8D1439              LEA       EDX,[EDI+ECX]
001B:004011C9  3BC2                CMP       EAX,EDX
001B:004011CB  7714                JA        004011E1
001B:004011CD  8B3540684000        MOV       ESI,[00406840]
001B:004011D3  8BD1                MOV       EDX,ECX
001B:004011D5  C1E902              SHR       ECX,02
001B:004011D8  F3A5                REPZ MOVSD        <-------这里
001B:004011DA  8BCA                MOV       ECX,EDX
001B:004011DC  83E103              AND       ECX,03
001B:004011DF  F3A4                REPZ MOVSB
001B:004011E1  8B3DE8684000        MOV       EDI,[004068E8]
001B:004011E7  3BC7                CMP       EAX,EDI
001B:004011E9  7221                JB        0040120C
       

        我们刚才来过的地方,看来是程序某一处也 call 这里

        按一下 F12 返回

001B:0040158D  90                  NOP
001B:0040158E  56                  PUSH      ESI
001B:0040158F  E81CFCFFFF          CALL      004011B0
001B:00401594  8A86E0000000        MOV       AL,[ESI+000000E0]  <--这里
001B:0040159A  83C404              ADD       ESP,04
001B:0040159D  3CCC                CMP       AL,CC
001B:0040159F  74ED                JZ        0040158E
001B:004015A1  B801000000          MOV       EAX,00000001
001B:004015A6  5E                  POP       ESI
001B:004015A7  C3                  RET
001B:004015A8  90                  NOP

        把 0040158F 的 call nop 掉

:a 0040158F
nop 5 个位

        再离开 softice,又断在刚刚的那里
       

001B:00401594  8A86E0000000        MOV       AL,[ESI+000000E0]
001B:0040159A  83C404              ADD       ESP,04   <--我们在这里
001B:0040159D  3CCC                CMP       AL,CC   <-- 把 getwindowtexta 与 0xcc 比较
001B:0040159F  74ED                JZ        0040158E  <-- 如果是 0xcc 便跳
001B:004015A1  B801000000          MOV       EAX,00000001
001B:004015A6  5E                  POP       ESI
001B:004015A7  C3                  RET
001B:004015A8  90                  NOP

        今次我们把 00401594 的 mov ,0040159D 的 cmp,和 0040159F 的 jz 全部 nop 掉

        现在我们离开 softice,没有再跳出来,成功把检查和恢复断点的地方清除。

        尝试下断 getwindowtexta

:bc *
:bpx getwindowtexta

        离开 softice,断在

001B:77DF7067  C21C00              RET       001C
USER32!GetWindowTextA
001B:77DF706A  55                  PUSH      EBP   <--这里
001B:77DF706B  8BEC                MOV       EBP,ESP
001B:77DF706D  6AFF                PUSH      FF
001B:77DF706F  68F870DF77          PUSH      77DF70F8
001B:77DF7074  68B71FE477          PUSH      77E41FB7
001B:77DF7079  64A100000000        MOV       EAX,FS:[00000000]
001B:77DF707F  50                  PUSH      EAX
001B:77DF7080  64892500000000      MOV       FS:[00000000],ESP
       
        程序成功断在 getwindowtexta,现在我们把程序关掉,打开 OD 加载 sub1.ooo,把刚才修改的地方写到 sub1.ooo 里

        ( sub1.ooo 的名字不可以改 )

[ Part V.  分析序号处理 ]

        全部修改后,打开 crackme4.exe ,用 softice 下断

        bpx getwindowtexta

        离开 softice,断在 getwindowtexta 里,

        F12 返回,开始跟踪序号

       
001B:00401B84  E827FAFFFF          CALL      004015B0
001B:00401B89  8B1534684000        MOV       EDX,[00406834]
001B:00401B8F  83C408              ADD       ESP,08
001B:00401B92  6A14                PUSH      14
001B:00401B94  6860684000          PUSH      00406860
001B:00401B99  52                  PUSH      EDX
001B:00401B9A  FF15A4684000        CALL      [004068A4]
001B:00401BA0  A1A0674000          MOV       EAX,[004067A0]  <---- 我们在这里
001B:00401BA5  6A14                PUSH      14
001B:00401BA7  6880684000          PUSH      00406880
001B:00401BAC  50                  PUSH      EAX
001B:00401BAD  FF15A4684000        CALL      [004068A4]
001B:00401BB3  60                  PUSHAD
001B:00401BB4  B800000000          MOV       EAX,00000000
001B:00401BB9  CC                  INT       3
001B:00401BBA  61                  POPAD
001B:00401BBB  8B0DAC684000        MOV       ECX,[004068AC]
001B:00401BC1  51                  PUSH      ECX
001B:00401BC2  E879F6FFFF          CALL      00401240
001B:00401BC7  8B15AC684000        MOV       EDX,[004068AC]
001B:00401BCD  52                  PUSH      EDX       

        我们看一下代码,看不见熟悉的 API 名字,感觉不是很好。

        我们知道 [004068A4] 是 getwindowtexta,看看下方,在 00401BAD 也呼叫了这里一次,很明显程序在读取注册名字和序号。

        我们发现 00401BB9 这一行使用了 INT 3 ,当程序执行 int 3 的时候,异常发生, sub1 停止运行, sub2 将会继续。在 int 3 的前面还有一个 PUSHAD,后面有一个 POPAD,分别是用来保留和恢复 stack

        sub1 得到序号字符串后,使用 int 3 来通知 sub2

        我们 F8 单步跟踪,跟进了 00401BAD 的 [004068A4] (getwindowtexta)

001B:0098000B  C3                  RET
001B:0098000C  B88A6FDF77          MOV       EAX,77DF6F8A  <--在这里
001B:00980011  05E0000000          ADD       EAX,000000E0
001B:00980016  50                  PUSH      EAX
001B:00980017  C3                  RET
001B:00980018  B81368DF77          MOV       EAX,77DF6813
001B:0098001D  05E0000000          ADD       EAX,000000E0
001B:00980022  50                  PUSH      EAX
001B:00980023  C3                  RET
001B:00980024  B85F54DF77          MOV       EAX,77DF545F
001B:00980029  05E0000000          ADD       EAX,000000E0
001B:0098002E  50                  PUSH      EAX
001B:0098002F  C3                  RET
001B:00980030  B84362E077          MOV       EAX,77E06243
001B:00980035  05E0000000          ADD       EAX,000000E0
001B:0098003A  50                  PUSH      EAX
001B:0098003B  C3                  RET
001B:0098003C  B8C52EDF77          MOV       EAX,77DF2EC5
001B:00980041  05E0000000          ADD       EAX,000000E0
001B:00980046  50                  PUSH      EAX
001B:00980047  C3                  RET

        看见这里的结构,我们便明白程序的 API 呼叫,都是通过这里的代码来计算出 API 的位置,再使用 PSUH 和 RET 来实现呼叫

001B:0098000C  B88A6FDF77          MOV       EAX,77DF6F8A  

        77DF6F8A 这个常数是 getwindowtexta 的位置 - 0xe0

001B:00980011  05E0000000          ADD       EAX,000000E0

        把位置 + 0xe0,变成 getwindowtexta 的位置

001B:00980016  50                  PUSH      EAX
001B:00980017  C3                  RET

        使 EIP 变成 getwindowtexta 的位置

        我们按两次 F12 返回,来到

001B:00401BB3  60                  PUSHAD   <---这里
001B:00401BB4  B800000000          MOV       EAX,00000000
001B:00401BB9  CC                  INT       3
001B:00401BBA  61                  POPAD

        这里程序把 eax 设为 0,再进行 int 3 中断。
        我们要在 sub2 的 WaitForDebugEvent 后面下断,先找出它的位置。

        用 OD 加载 sub2,在 WaitForDebguEvent 下断

                bp WaitForDebugEvent

        F9 运行,断在 KERNEL32 的领空里,按 ALt+F9 返回

004011B1  |. FF15 D0674000  |CALL DWORD PTR DS:[4067D0]
004011B7  |. 8B4424 20      |MOV EAX,DWORD PTR SS:[ESP+20]  <--这里
004011BB  |. 48             |DEC EAX                                 ;  Switch (cases 1..5)
004011BC  |. 74 0E          |JE SHORT sub2.004011CC
004011BE  |. 83E8 04        |SUB EAX,4
004011C1  |. 0F84 75020000  |JE sub2.0040143C
004011C7  |. E9 48020000    |JMP sub2.00401414

        把 004011B7 记下,离开 OD,打开 softice

        现在再回到 sub1,下断点 getwindowtexta

        离开 softice 后,断在 sub1 里,现在对 sub2 下断点

选择 sub2 的领空
:addr sub2

下断点
:bpx 004011B7

        我们让 sub1 继续运行,它将会执行 int3 ,使 sub2 的 WaitForDebugEvent 返回,停在我们的断点上

        离开 softice,便断在

001B:004011B1  FF15D0674000        CALL      [004067D0]
001B:004011B7  8B442420            MOV       EAX,[ESP+20]  SS:0012FBAC=00000001  <--这里
001B:004011BB  48                  DEC       EAX
001B:004011BC  740E                JZ        004011CC
001B:004011BE  83E804              SUB       EAX,04

        开始 F8 单步跟踪,沿途留意 WaitForDebugEvent 的第一参数 DEBUG_EVENT 结构

(DEBUG_EVENT 结构的 C definition)

typedef struct _DEBUG_EVENT { // de
    DWORD dwDebugEventCode;     // [ESP+20]
    DWORD dwProcessId;          // [ESP+24]
    DWORD dwThreadId;           // [ESP+28]
    union {
        EXCEPTION_DEBUG_INFO Exception;
        CREATE_THREAD_DEBUG_INFO CreateThread;
        CREATE_PROCESS_DEBUG_INFO CreateProcessInfo;
        EXIT_THREAD_DEBUG_INFO ExitThread;
        EXIT_PROCESS_DEBUG_INFO ExitProcess;
        LOAD_DLL_DEBUG_INFO LoadDll;
        UNLOAD_DLL_DEBUG_INFO UnloadDll;
        OUTPUT_DEBUG_STRING_INFO DebugString;
        RIP_INFO RipInfo;
    } u;
} DEBUG_EVENT;

001B:004011A5  BB01000100          MOV       EBX,00010001
001B:004011AA  8D442420            LEA       EAX,[ESP+20]   // [ESP+20] 是 DEBUG_EVENT
001B:004011AE  6AFF                PUSH      FF             // ff 代表永远等待返回 (INFINITE)
001B:004011B0  50                  PUSH      EAX
001B:004011B1  FF15D0674000        CALL      [004067D0]     // call WaitForDebugEvent
001B:004011B7  8B442420            MOV       EAX,[ESP+20]  SS:0012FBAC=00000001
001B:004011BB  48                  DEC       EAX
001B:004011BC  740E                JZ        004011CC  <-这里跳

        [ESP+20] 是 dwDebugEventCode,现在它的值是 1

        dwDebugEventCode 的 1 代表 EXCEPTION_DEBUG_EVENT

        根据 DEBUG_EVENT 的结构,当 dwDebugEventCode 是 EXCEPTION_DEBUG_EVENT 的时候, union 是 EXCEPTION_DEBUG_INFO Exception

        EXCEPTION_DEBUG_INFO 的结构如下 :

typedef struct _EXCEPTION_DEBUG_INFO { // exdi
    EXCEPTION_RECORD ExceptionRecord;    // [ESP+2C]
    DWORD dwFirstChance;
} EXCEPTION_DEBUG_INFO;

        EXCEPTION_RECORD 的结构 :

typedef struct _EXCEPTION_RECORD { // exr
    DWORD ExceptionCode;          // [ESP+2C]
    DWORD ExceptionFlags;         // [ESP+30]
    struct _EXCEPTION_RECORD *ExceptionRecord; // [ESP+34]
    PVOID ExceptionAddress;       // [ESP+38]
    DWORD NumberParameters;       // [ESP+4c]
    DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];   // [ESP+50]
} EXCEPTION_RECORD;

001B:004011BE  83E804              SUB       EAX,04
001B:004011C1  0F8475020000        JZ        0040143C
001B:004011C7  E948020000          JMP       00401414
001B:004011CC  8B44242C            MOV       EAX,[ESP+2C]   // 把 ExceptionCode 放到 EAX
001B:004011D0  3D03000080          CMP       EAX,80000003 // 与 STATUS_BREAKPOINT (int 3) 比较
001B:004011D5  0F872B020000        JA        00401406   <--不跳
001B:004011DB  741B                JZ        004011F8   <--这里跳
001B:004011DD  3D05000140          CMP       EAX,40010005
001B:004011E2  0F8454020000        JZ        0040143C
001B:004011E8  3D02000080          CMP       EAX,80000002 ; STATUS_DATATYPE_MISA
001B:004011ED  0F8449020000        JZ        0040143C
001B:004011F3  E91C020000          JMP       00401414
001B:004011F8  8B542414            MOV       EDX,[ESP+14]  <--这里继续
001B:004011FC  8D8C24C4000000      LEA       ECX,[ESP+000000C4]
001B:00401203  51                  PUSH      ECX
001B:00401204  52                  PUSH      EDX
001B:00401205  C78424CC000000020001MOV       DWORD PTR [ESP+000000CC],00010002
001B:00401210  FF15CC674000        CALL      [004067CC]   

        这个 call 跟进入后,会到达一个类似 sub1 跳转表的地方,几下 F8 走过 retn 后,

        发现这个 call 是 GetThreadContext ,用来取得被调试程序的 register 内容

        由此我们知道, [ESP+000000C4] 是 CONTEXT 结构

        x86 CONTEXT 结构如下 :

typedef struct _CONTEXT {

    DWORD ContextFlags;     // [ESP+000000C4]

    DWORD   Dr0;
    DWORD   Dr1;
    DWORD   Dr2;
    DWORD   Dr3;
    DWORD   Dr6;
    DWORD   Dr7;

    FLOATING_SAVE_AREA FloatSave;  //  这个结构的大小是 0x70

    DWORD   SegGs;          // [ESP+00000150]
    DWORD   SegFs;
    DWORD   SegEs;
    DWORD   SegDs;

    DWORD   Edi;
    DWORD   Esi;
    DWORD   Ebx;
    DWORD   Edx;
    DWORD   Ecx;
    DWORD   Eax;

    DWORD   Ebp;            // [ESP+00000178]
    DWORD   Eip;
    DWORD   SegCs;      
    DWORD   EFlags;      
    DWORD   Esp;
    DWORD   SegSs;

    BYTE    ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];

} CONTEXT;

001B:00401216  8B842474010000      MOV       EAX,[ESP+00000174] // 把 context.eax 放入 eax
001B:0040121D  3DF0000000          CMP       EAX,000000F0       // context.eax 与 f0 比较
001B:00401222  0F877D010000        JA        004013A5          // 不跳
001B:00401228  0F843A010000        JZ        00401368          // 不跳
001B:0040122E  83E800              SUB       EAX,00            // context.eax 与 0 比较
001B:00401231  0F84B4000000        JZ        004012EB          // <---跳
001B:00401237  48                  DEC       EAX
001B:00401238  0F85D6010000        JNZ       00401414
001B:0040123E  6880674000          PUSH      00406780

......

        如果 sub1 的 eax 是 0 ,进行 int 3 便来到这里

001B:004012E6  E929010000          JMP       00401414
001B:004012EB  8B1518674000        MOV       EDX,[00406718]   // <--继续  edx = 406860
001B:004012F1  8B442410            MOV       EAX,[ESP+10]   // eax = 28
001B:004012F5  8D4C240C            LEA       ECX,[ESP+0C]   // ecx = 12fb90
001B:004012F9  51                  PUSH      ECX            
001B:004012FA  6A15                PUSH      15            
001B:004012FC  6880674000          PUSH      00406780      
001B:00401301  52                  PUSH      EDX
001B:00401302  50                  PUSH      EAX
001B:00401303  FF15C0674000        CALL      [004067C0]     // ReadProcessMemory
001B:00401309  8B1570674000        MOV       EDX,[00406770] // edx = 406880
001B:0040130F  8D4C240C            LEA       ECX,[ESP+0C]   // ecx = 12fb98
001B:00401313  8B442410            MOV       EAX,[ESP+10]   // eax = 28
001B:00401317  51                  PUSH      ECX
001B:00401318  6A15                PUSH      15
001B:0040131A  68A0674000          PUSH      004067A0
001B:0040131F  52                  PUSH      EDX
001B:00401320  50                  PUSH      EAX
001B:00401321  FF15C0674000        CALL      [004067C0]      // ReadProcessMemory
001B:00401327  8B1518674000        MOV       EDX,[00406718]  // edx = 406860
001B:0040132D  8D4C240C            LEA       ECX,[ESP+0C]    // ecx = 12fb98
001B:00401331  8B442410            MOV       EAX,[ESP+10]    // eax = 28
001B:00401335  51                  PUSH      ECX
001B:00401336  6A15                PUSH      15
001B:00401338  6840654000          PUSH      00406540
001B:0040133D  52                  PUSH      EDX
001B:0040133E  50                  PUSH      EAX
001B:0040133F  FF15C4674000        CALL      [004067C4]      // WriteProcessMemory
001B:00401345  8B1570674000        MOV       EDX,[00406770]  // edx = 406880
001B:0040134B  8D4C240C            LEA       ECX,[ESP+0C]    // ecx = 12fb98
001B:0040134F  8B442410            MOV       EAX,[ESP+10]    // eax = 28
001B:00401353  51                  PUSH      ECX
001B:00401354  6A15                PUSH      15
001B:00401356  6858654000          PUSH      00406558
001B:0040135B  52                  PUSH      EDX
001B:0040135C  50                  PUSH      EAX
001B:0040135D  FF15C4674000        CALL      [004067C4]      // WriteProcessMemory
001B:00401363  E9AC000000          JMP       00401414

        sub2 使用了 2 次 ReadProcessMemory 和 2 次 WriteProcessMemory,对像都是 [ESP+10] (0x28),我们尝试找出 [ESP+10] 所代表的程序,在 softice 里往上寻找

        一直到达了这段程序开始的地方 :

001B:0040114E  90                  NOP
001B:0040114F  90                  NOP
001B:00401150  81EC84030000        SUB       ESP,00000384
001B:00401156  53                  PUSH      EBX
001B:00401157  56                  PUSH      ESI
001B:00401158  8D44247C            LEA       EAX,[ESP+7C]
001B:0040115C  57                  PUSH      EDI
001B:0040115D  50                  PUSH      EAX
001B:0040115E  C7842484000000440000MOV       DWORD PTR [ESP+00000084],00000044
001B:00401169  FF15DC674000        CALL      [004067DC]
001B:0040116F  8D4C2410            LEA       ECX,[ESP+10]  <---这里第一次使用 [ESP+10]
001B:00401173  8D942480000000      LEA       EDX,[ESP+00000080]
001B:0040117A  51                  PUSH      ECX
001B:0040117B  52                  PUSH      EDX
001B:0040117C  6A00                PUSH      00
001B:0040117E  6A00                PUSH      00
001B:00401180  6A03                PUSH      03
001B:00401182  6A00                PUSH      00
001B:00401184  6A00                PUSH      00
001B:00401186  6A00                PUSH      00
001B:00401188  6A00                PUSH      00
001B:0040118A  6830604000          PUSH      00406030
001B:0040118F  FF15D4674000        CALL      [004067D4]  //  跟踪后发现这是 CreateProcess
001B:00401195  85C0                TEST      EAX,EAX
001B:00401197  0F849F020000        JZ        0040143C
       
        由此可见, [ESP+10] 是 sub1 的 HANDLE, sub2 在 int 3 发生时对 sub1 读写

        我们在这里进行 ReadProcessMemory 后,用 softice 查看 00406780 和 004067A0

:d 00406780
:d 004067A0

        发现 00406780 正是我们输入的注册名字 "riijj" ,而 004067A0 是序号 "AAAABBBB"

        我们再查看 004067C4 和 00406558,发现它们是一个 DWORD 值,暂时不知道其意义

        我们按下 "Register" 按钮的时候,估计 sub1 会通知 sub2 把序号进行检查

        现在我们要知道 sub2 的甚么地方对序号进行处理,可以用硬件断点来实现

        先暂时把 2 个 ReadProcessMemory 的 call 和相关的 push 记下,然后 nop 掉,使 sub2 不再对缓冲区进行抄写

:a 004012F9
把第一个 push 至 call 的一段 nop 掉

:a 00401317
把第一个 push 至 call 的一段 nop 掉

        现在 sub2 的缓冲区内存有 "riijj" 和 "AAAABBBB",我们尝试下硬件断点,看看有没有其它地方对它进行读写

:bpm 00406780
:bpm 004067A0

        没有反应,表示没有其它地方读写该区

        现在我们按下 Register 按钮,立即断在

001B:00401050  83C9FF              OR        ECX,-01
001B:00401053  33D2                XOR       EDX,EDX
001B:00401055  8844241F            MOV       [ESP+1F],AL
001B:00401059  F2AE                REPNZ SCASB   <----在这里
001B:0040105B  F7D1                NOT       ECX
001B:0040105D  49                  DEC       ECX
0

        开始 F8 单步跟踪

001B:00401053  33D2                XOR       EDX,EDX
001B:00401055  8844241F            MOV       [ESP+1F],AL
001B:00401059  F2AE                REPNZ SCASB
001B:0040105B  F7D1                NOT       ECX
001B:0040105D  49                  DEC       ECX   
001B:0040105E  88542410            MOV       [ESP+10],DL
001B:00401062  85C9                TEST      ECX,ECX
001B:00401064  7E0F                JLE       00401075
001B:00401066  0FBE3428            MOVSX     ESI,BYTE PTR [EBP+EAX]
001B:0040106A  03F2                ADD       ESI,EDX
001B:0040106C  D1E6                SHL       ESI,1
001B:0040106E  40                  INC       EAX
001B:0040106F  8BD6                MOV       EDX,ESI
001B:00401071  3BC1                CMP       EAX,ECX
001B:00401073  7CF1                JL        00401066
001B:00401075  8BC2                MOV       EAX,EDX
001B:00401077  C1E005              SHL       EAX,05
001B:0040107A  2BC2                SUB       EAX,EDX
001B:0040107C  8D0440              LEA       EAX,[EAX*2+EAX]
001B:0040107F  8D0442              LEA       EAX,[EAX*2+EDX]
001B:00401082  C1E004              SHL       EAX,04
001B:00401085  03C2                ADD       EAX,EDX
001B:00401087  33FF                XOR       EDI,EDI
001B:00401089  8D3442              LEA       ESI,[EAX*2+EDX]
001B:0040108C  8BC7                MOV       EAX,EDI
001B:0040108E  99                  CDQ
001B:0040108F  F7F9                IDIV      ECX
001B:00401091  33C0                XOR       EAX,EAX
001B:00401093  8A042A              MOV       AL,[EBP+EDX]
001B:00401096  85C0                TEST      EAX,EAX
001B:00401098  7E1B                JLE       004010B5
001B:0040109A  8BD8                MOV       EBX,EAX
001B:0040109C  8BC6                MOV       EAX,ESI
001B:0040109E  33D2                XOR       EDX,EDX
001B:004010A0  69C0EF1E0000        IMUL      EAX,EAX,00001EEF
001B:004010A6  83C00D              ADD       EAX,0D
001B:004010A9  BEDF180000          MOV       ESI,000018DF
001B:004010AE  F7F6                DIV       ESI
001B:004010B0  4B                  DEC       EBX
001B:004010B1  8BF2                MOV       ESI,EDX
001B:004010B3  75E7                JNZ       0040109C
001B:004010B5  8BC6                MOV       EAX,ESI
001B:004010B7  33D2                XOR       EDX,EDX
001B:004010B9  BBFE000000          MOV       EBX,000000FE
001B:004010BE  F7F3                DIV       EBX
001B:004010C0  FEC2                INC       DL
001B:004010C2  88543C10            MOV       [EDI+ESP+10],DL
001B:004010C6  47                  INC       EDI
001B:004010C7  83FF0F              CMP       EDI,0F
001B:004010CA  7CC0                JL        0040108C
001B:004010CC  8D7C2410            LEA       EDI,[ESP+10]
001B:004010D0  83C9FF              OR        ECX,-01
001B:004010D3  33C0                XOR       EAX,EAX
001B:004010D5  C6450000            MOV       BYTE PTR [EBP+00],00
001B:004010D9  F2AE                REPNZ SCASB
001B:004010DB  F7D1                NOT       ECX
001B:004010DD  2BF9                SUB       EDI,ECX
001B:004010DF  8BD1                MOV       EDX,ECX
001B:004010E1  8BF7                MOV       ESI,EDI
001B:004010E3  8BFD                MOV       EDI,EBP
001B:004010E5  C1E902              SHR       ECX,02
001B:004010E8  F3A5                REPZ MOVSD
001B:004010EA  8BCA                MOV       ECX,EDX
001B:004010EC  83E103              AND       ECX,03
001B:004010EF  F3A4                REPZ MOVSB
001B:004010F1  5F                  POP       EDI
001B:004010F2  5E                  POP       ESI
001B:004010F3  5D                  POP       EBP
001B:004010F4  5B                  POP       EBX
001B:004010F5  83C410              ADD       ESP,10
001B:004010F8  C3                  RET

        算法很复杂,使用了很多 REPNZ SCASB 和 REPZ MOVSD,看来是一堆字符串处理,继续进 retn

001B:00401222  0F877D010000        JA        004013A5
001B:00401228  0F843A010000        JZ        00401368
001B:0040122E  83E800              SUB       EAX,00
001B:00401231  0F84B4000000        JZ        004012EB
001B:00401237  48                  DEC       EAX
001B:00401238  0F85D6010000        JNZ       00401414
001B:0040123E  6880674000          PUSH      00406780
001B:00401243  E8E8FDFFFF          CALL      00401030
001B:00401248  68A0674000          PUSH      004067A0   // <----来到这里
001B:0040124D  E8AEFDFFFF          CALL      00401000

        进去看看

001B:00401000  8B542404            MOV       EDX,[ESP+04]
001B:00401004  57                  PUSH      EDI
001B:00401005  8BFA                MOV       EDI,EDX
001B:00401007  83C9FF              OR        ECX,-01
001B:0040100A  33C0                XOR       EAX,EAX
001B:0040100C  F2AE                REPNZ SCASB
001B:0040100E  F7D1                NOT       ECX
001B:00401010  49                  DEC       ECX
001B:00401011  5F                  POP       EDI
001B:00401012  85C9                TEST      ECX,ECX
001B:00401014  7E10                JLE       00401026
001B:00401016  53                  PUSH      EBX
001B:00401017  8A1C10              MOV       BL,[EDX+EAX]  <--循环
001B:0040101A  80F359              XOR       BL,59        // 把字符组与 59 xor
001B:0040101D  881C10              MOV       [EDX+EAX],BL
001B:00401020  40                  INC       EAX
001B:00401021  3BC1                CMP       EAX,ECX
001B:00401023  7CF2                JL        00401017  <--往上跳
001B:00401025  5B                  POP       EBX
001B:00401026  C3                  RET
001B:00401027  90                  NOP

        这里循环里的 EDX 的值是 4067a0,用 softice 查看

:d 4067a0

        发现这里依次序填满了序号 AAAABBBB

        ret 返回,继续 F8

001B:00401252  8B0D1C674000        MOV       ECX,[0040671C]
001B:00401258  8B542418            MOV       EDX,[ESP+18]
001B:0040125C  83C408              ADD       ESP,08
001B:0040125F  8D44240C            LEA       EAX,[ESP+0C]
001B:00401263  83C110              ADD       ECX,10
001B:00401266  50                  PUSH      EAX
001B:00401267  6A15                PUSH      15
001B:00401269  6880674000          PUSH      00406780
001B:0040126E  51                  PUSH      ECX
001B:0040126F  52                  PUSH      EDX
001B:00401270  FF15C4674000        CALL      [004067C4]  // ReadProcessMemory
001B:00401276  8B0D1C674000        MOV       ECX,[0040671C]
001B:0040127C  8D44240C            LEA       EAX,[ESP+0C]
001B:00401280  8B542410            MOV       EDX,[ESP+10]
001B:00401284  50                  PUSH      EAX
001B:00401285  6A15                PUSH      15
001B:00401287  83C138              ADD       ECX,38
001B:0040128A  68A0674000          PUSH      004067A0
001B:0040128F  51                  PUSH      ECX
001B:00401290  52                  PUSH      EDX
001B:00401291  FF15C4674000        CALL      [004067C4]  // ReadProcessMemory
001B:00401297  8D8424C4000000      LEA       EAX,[ESP+000000C4]
001B:0040129E  899C24C4000000      MOV       [ESP+000000C4],EBX
001B:004012A5  8B4C2414            MOV       ECX,[ESP+14]
001B:004012A9  50                  PUSH      EAX
001B:004012AA  51                  PUSH      ECX
001B:004012AB  FF15CC674000        CALL      [004067CC]  // GetThreadContext

        我们可以推断 [ESP+000000C4] 是 context 结构

001B:004012B1  8D9424C4000000      LEA       EDX,[ESP+000000C4]  //把 context 的位置放入 edx
001B:004012B8  C78424C4000000030001MOV       DWORD PTR [ESP+000000C4],00010003

        // 把 10003 放进 context 的 ContextFlags 里

001B:004012C3  8B84247C010000      MOV       EAX,[ESP+0000017C] // 把 context.Eip 放进 eax
001B:004012CA  52                  PUSH      EDX                // *注意这里, esp 改变了
001B:004012CB  8BF0                MOV       ESI,EAX            // 把 context.Eip 放到 esi
001B:004012CD  89842478010000      MOV       [ESP+00000178],EAX //把 context.Eip 放到 context.Eax

001B:004012D4  8B442418            MOV       EAX,[ESP+18]  // eax = 2c
001B:004012D8  89BC2480010000      MOV       [ESP+00000180],EDI // 把 edi 放到 context.Eip,值是 4014a0
001B:004012DF  50                  PUSH      EAX
001B:004012E0  FF15C8674000        CALL      [004067C8]   // SetThreadContext
001B:004012E6  E929010000          JMP       00401414
001B:004012EB  8B1518674000        MOV       EDX,[00406718]
001B:004012F1  8B442410            MOV       EAX,[ESP+10]
001B:004012F5  8D4C240C            LEA       ECX,[ESP+0C]
001B:004012F9  90                  NOP
001B:004012FA  90                  NOP
001B:004012FB  90                  NOP

        这段程序把 sub1 的 eip 放到 eax 里,并把 eip 改变为 4014a0,这样会强行改变 sub1 流程到 4014a0 处继续

        我们现在到 sub1 里,设断点在 4014a0

:addr sub1
:bpx 4014a0

        在 sub2 中离开 softice,果然断在刚刚设在 sub1 的断点

        估计如果序号是正确的话,这里便会进行判断,显示成功信息

001B:0040149F  90                  NOP
001B:004014A0  50                  PUSH      EAX       //<----这里
001B:004014A1  E87AFEFFFF          CALL      00401320
001B:004014A6  C3                  RET
001B:004014A7  C3                  RET
001B:004014A8  90                  NOP
001B:004014A9  90                  NOP

        这里把 eax (sub1 原来的 eip) push 到 stack 去,再呼叫 00401320,我们不知它的原因

        F8 跟进去

001B:0040131F  90                  NOP
001B:00401320  83EC7C              SUB       ESP,7C
001B:00401323  33C9                XOR       ECX,ECX     
001B:00401325  33C0                XOR       EAX,EAX     
001B:00401327  894C2410            MOV       [ESP+10],ECX
001B:0040132B  53                  PUSH      EBX         
001B:0040132C  894C2418            MOV       [ESP+18],ECX
001B:00401330  89442404            MOV       [ESP+04],EAX
001B:00401334  55                  PUSH      EBP              
001B:00401335  894C2420            MOV       [ESP+20],ECX     
001B:00401339  56                  PUSH      ESI              
001B:0040133A  89442410            MOV       [ESP+10],EAX
001B:0040133E  57                  PUSH      EDI
001B:0040133F  894C242C            MOV       [ESP+2C],ECX
001B:00401343  89442418            MOV       [ESP+18],EAX
001B:00401347  B90A000000          MOV       ECX,0000000A
001B:0040134C  8D7C2464            LEA       EDI,[ESP+64]
001B:00401350  8B1DE0674000        MOV       EBX,[004067E0]
001B:00401356  F3AB                REPZ STOSD                 // 把 [ESP+64] 清 0
001B:00401358  B907000000          MOV       ECX,00000007
001B:0040135D  8D7C2444            LEA       EDI,[ESP+44]
001B:00401361  8944241C            MOV       [ESP+1C],EAX
001B:00401365  33D2                XOR       EDX,EDX
001B:00401367  F3AB                REPZ STOSD                 // 把 [ESP+44] 清 0
001B:00401369  66AB                STOSW
001B:0040136B  8D7B10              LEA       EDI,[EBX+10]
001B:0040136E  83C9FF              OR        ECX,-01
001B:00401371  33C0                XOR       EAX,EAX
001B:00401373  8D6C2410            LEA       EBP,[ESP+10]
001B:00401377  F2AE                REPNZ SCASB
001B:00401379  F7D1                NOT       ECX              // 估计是计算字符串长度
001B:0040137B  2BF9                SUB       EDI,ECX
001B:0040137D  8BC1                MOV       EAX,ECX
001B:0040137F  8BF7                MOV       ESI,EDI
001B:00401381  8BFD                MOV       EDI,EBP
001B:00401383  C1E902              SHR       ECX,02
001B:00401386  F3A5                REPZ MOVSD
001B:00401388  8BC8                MOV       ECX,EAX
001B:0040138A  33C0                XOR       EAX,EAX
001B:0040138C  83E103              AND       ECX,03
001B:0040138F  F3A4                REPZ MOVSB
001B:00401391  8D7B38              LEA       EDI,[EBX+38]
001B:00401394  83C9FF              OR        ECX,-01
001B:00401397  F2AE                REPNZ SCASB
001B:00401399  F7D1                NOT       ECX
001B:0040139B  2BF9                SUB       EDI,ECX
001B:0040139D  8D5C2420            LEA       EBX,[ESP+20]
001B:004013A1  8BC1                MOV       EAX,ECX
001B:004013A3  8BF7                MOV       ESI,EDI
001B:004013A5  8BFB                MOV       EDI,EBX
001B:004013A7  C1E902              SHR       ECX,02
001B:004013AA  F3A5                REPZ MOVSD
001B:004013AC  8BC8                MOV       ECX,EAX
001B:004013AE  33C0                XOR       EAX,EAX
001B:004013B0  83E103              AND       ECX,03
001B:004013B3  F3A4                REPZ MOVSB
001B:004013B5  8D7C2410            LEA       EDI,[ESP+10]
001B:004013B9  83C9FF              OR        ECX,-01
001B:004013BC  F2AE                REPNZ SCASB
001B:004013BE  F7D1                NOT       ECX
001B:004013C0  49                  DEC       ECX
001B:004013C1  85C9                TEST      ECX,ECX
001B:004013C3  7E10                JLE       004013D5
001B:004013C5  0FBE740410          MOVSX     ESI,BYTE PTR [EAX+ESP+10]
001B:004013CA  03F2                ADD       ESI,EDX
001B:004013CC  D1E6                SHL       ESI,1
001B:004013CE  40                  INC       EAX
001B:004013CF  8BD6                MOV       EDX,ESI
001B:004013D1  3BC1                CMP       EAX,ECX
001B:004013D3  7CF0                JL        004013C5
001B:004013D5  8BC2                MOV       EAX,EDX
001B:004013D7  C1E004              SHL       EAX,04
001B:004013DA  03C2                ADD       EAX,EDX
001B:004013DC  C1E004              SHL       EAX,04
001B:004013DF  03C2                ADD       EAX,EDX
001B:004013E1  33FF                XOR       EDI,EDI
001B:004013E3  8D0442              LEA       EAX,[EAX*2+EDX]
001B:004013E6  8D0480              LEA       EAX,[EAX*4+EAX]
001B:004013E9  8D3442              LEA       ESI,[EAX*2+EDX]
001B:004013EC  8BC7                MOV       EAX,EDI
001B:004013EE  33DB                XOR       EBX,EBX
001B:004013F0  99                  CDQ
001B:004013F1  F7F9                IDIV      ECX
001B:004013F3  8A5C1410            MOV       BL,[EDX+ESP+10]
001B:004013F7  85DB                TEST      EBX,EBX
001B:004013F9  7E19                JLE       00401414
001B:004013FB  8BC6                MOV       EAX,ESI
001B:004013FD  33D2                XOR       EDX,EDX
001B:004013FF  69C02F1E0000        IMUL      EAX,EAX,00001E2F
001B:00401405  83C00D              ADD       EAX,0D
001B:00401408  BEDB190000          MOV       ESI,000019DB
001B:0040140D  F7F6                DIV       ESI
001B:0040140F  4B                  DEC       EBX
001B:00401410  8BF2                MOV       ESI,EDX
001B:00401412  75E7                JNZ       004013FB
001B:00401414  8BC6                MOV       EAX,ESI
001B:00401416  33D2                XOR       EDX,EDX
001B:00401418  BB1A000000          MOV       EBX,0000001A
001B:0040141D  F7F3                DIV       EBX
001B:0040141F  80C241              ADD       DL,41
001B:00401422  88543C30            MOV       [EDI+ESP+30],DL
001B:00401426  47                  INC       EDI
001B:00401427  83FF0F              CMP       EDI,0F
001B:0040142A  7CC0                JL        004013EC
001B:0040142C  5F                  POP       EDI
001B:0040142D  5E                  POP       ESI
001B:0040142E  5D                  POP       EBP
001B:0040142F  C644243400          MOV       BYTE PTR [ESP+34],00
001B:00401434  33C0                XOR       EAX,EAX
001B:00401436  5B                  POP       EBX
001B:00401437  8A4C0410            MOV       CL,[EAX+ESP+10]
001B:0040143B  8A540420            MOV       DL,[EAX+ESP+20]
001B:0040143F  80F159              XOR       CL,59
001B:00401442  3ACA                CMP       CL,DL
001B:00401444  754F                JNZ       00401495   <-----这里往下跳至 ret,
001B:00401446  40                  INC       EAX

        上面部份算法比较复杂,在我们分析前,我们发现程序跟到这里后,便跳往 ret
       
        我们估计这里是检查序号的正确性,我们尝试用 softice 的 u 指令,到达下面的 call ,人手把它们的 API 翻译出来

001B:00401447  83F80F              CMP       EAX,0F
001B:0040144A  7CEB                JL        00401437
001B:0040144C  8D542454            LEA       EDX,[ESP+54]
001B:00401450  52                  PUSH      EDX
001B:00401451  E8FAFDFFFF          CALL      00401250      

  到 00401250

:u 00401250

001B:00401250  83EC5C              SUB       ESP,5C
001B:00401253  B9DEFFFFFF          MOV       ECX,FFFFFFDE
001B:00401258  53                  PUSH      EBX
001B:00401259  BAE9FFFFFF          MOV       EDX,FFFFFFE9
001B:0040125E  56                  PUSH      ESI
001B:0040125F  894C241C            MOV       [ESP+1C],ECX
001B:00401263  894C2428            MOV       [ESP+28],ECX
001B:00401267  BEEDFFFFFF          MOV       ESI,FFFFFFED
001B:0040126C  89542414            MOV       [ESP+14],EDX
001B:00401270  B8DFFFFFFF          MOV       EAX,FFFFFFDF
001B:00401275  8954242C            MOV       [ESP+2C],EDX
001B:00401279  B9EFFFFFFF          MOV       ECX,FFFFFFEF
001B:0040127E  BADDFFFFFF          MOV       EDX,FFFFFFDD
001B:00401283  8974240C            MOV       [ESP+0C],ESI
001B:00401287  89442418            MOV       [ESP+18],EAX
001B:0040128B  8944243C            MOV       [ESP+3C],EAX
001B:0040128F  894C2444            MOV       [ESP+44],ECX
001B:00401293  894C2448            MOV       [ESP+48],ECX
001B:00401297  8974244C            MOV       [ESP+4C],ESI
001B:0040129B  8B742468            MOV       ESI,[ESP+68]
001B:0040129F  89442450            MOV       [ESP+50],EAX
001B:004012A3  89442454            MOV       [ESP+54],EAX
001B:004012A7  C744240800000000    MOV       DWORD PTR [ESP+08],00000000
001B:004012AF  C7442410EBFFFFFF    MOV       DWORD PTR [ESP+10],FFFFFFEB
001B:004012B7  C7442420E0FFFFFF    MOV       DWORD PTR [ESP+20],FFFFFFE0
001B:004012BF  C7442424F1FFFFFF    MOV       DWORD PTR [ESP+24],FFFFFFF1
001B:004012C7  C7442430E3FFFFFF    MOV       DWORD PTR [ESP+30],FFFFFFE3
001B:004012CF  C7442434E4FFFFFF    MOV       DWORD PTR [ESP+34],FFFFFFE4
001B:004012D7  C744243832000000    MOV       DWORD PTR [ESP+38],00000032
001B:004012DF  89542440            MOV       [ESP+40],EDX
001B:004012E3  C7442458ECFFFFFF    MOV       DWORD PTR [ESP+58],FFFFFFEC
001B:004012EB  8954245C            MOV       [ESP+5C],EDX
001B:004012EF  C7442460E6FFFFFF    MOV       DWORD PTR [ESP+60],FFFFFFE6
001B:004012F7  33C0                XOR       EAX,EAX
001B:004012F9  8D4C2408            LEA       ECX,[ESP+08]
001B:004012FD  8A19                MOV       BL,[ECX]
001B:004012FF  B252                MOV       DL,52
001B:00401301  2AD3                SUB       DL,BL
001B:00401303  83C104              ADD       ECX,04
001B:00401306  881430              MOV       [ESI+EAX],DL
001B:00401309  40                  INC       EAX
001B:0040130A  83F817              CMP       EAX,17
001B:0040130D  7CEE                JL        004012FD
001B:0040130F  5E                  POP       ESI
001B:00401310  5B                  POP       EBX
001B:00401311  83C45C              ADD       ESP,5C
001B:00401314  C3                  RET
001B:00401315  90                  NOP

        很明显,这里不是 API 跳转表的位置,是程序的其它 call

        回到先前的部份

:u 00401456

001B:00401456  8D442438            LEA       EAX,[ESP+38]
001B:0040145A  50                  PUSH      EAX
001B:0040145B  E890FCFFFF          CALL      004010F0

        看看 004010F0

:u 004010F0

001B:004010F0  83EC4C              SUB       ESP,4C
001B:004010F3  B80A000000          MOV       EAX,0000000A
001B:004010F8  B95A000000          MOV       ECX,0000005A
001B:004010FD  89442408            MOV       [ESP+08],EAX
001B:00401101  89442410            MOV       [ESP+10],EAX
001B:00401105  B807000000          MOV       EAX,00000007
001B:0040110A  53                  PUSH      EBX
001B:0040110B  56                  PUSH      ESI
001B:0040110C  8B742458            MOV       ESI,[ESP+58]
001B:00401110  894C2414            MOV       [ESP+14],ECX
001B:00401114  89442420            MOV       [ESP+20],EAX
001B:00401118  89442424            MOV       [ESP+24],EAX
001B:0040111C  894C243C            MOV       [ESP+3C],ECX
001B:00401120  C744240800000000    MOV       DWORD PTR [ESP+08],00000000
001B:00401128  C744240C11000000    MOV       DWORD PTR [ESP+0C],00000011
001B:00401130  C744241C19000000    MOV       DWORD PTR [ESP+1C],00000019
001B:00401138  C744242803000000    MOV       DWORD PTR [ESP+28],00000003
001B:00401140  C744242C0B000000    MOV       DWORD PTR [ESP+2C],0000000B
001B:00401148  C744243008000000    MOV       DWORD PTR [ESP+30],00000008
001B:00401150  C744243416000000    MOV       DWORD PTR [ESP+34],00000016
001B:00401158  C744243840000000    MOV       DWORD PTR [ESP+38],00000040
001B:00401160  C744244014000000    MOV       DWORD PTR [ESP+40],00000014
001B:00401168  C744244406000000    MOV       DWORD PTR [ESP+44],00000006
001B:00401170  C744244810000000    MOV       DWORD PTR [ESP+48],00000010
001B:00401178  C744244C05000000    MOV       DWORD PTR [ESP+4C],00000005
001B:00401180  C744245013000000    MOV       DWORD PTR [ESP+50],00000013
001B:00401188  33C0                XOR       EAX,EAX
001B:0040118A  8D4C2408            LEA       ECX,[ESP+08]
001B:0040118E  8A19                MOV       BL,[ECX]
001B:00401190  B27A                MOV       DL,7A
001B:00401192  2AD3                SUB       DL,BL
001B:00401194  83C104              ADD       ECX,04
001B:00401197  881430              MOV       [ESI+EAX],DL
001B:0040119A  40                  INC       EAX
001B:0040119B  83F813              CMP       EAX,13
001B:0040119E  7CEE                JL        0040118E
001B:004011A0  5E                  POP       ESI
001B:004011A1  5B                  POP       EBX
001B:004011A2  83C44C              ADD       ESP,4C
001B:004011A5  C3                  RET
001B:004011A6  90                  NOP

        看来也不是 API 跳转表,再回去看看

:u 00401460

001B:00401460  8B1530684000        MOV       EDX,[00406830]
001B:00401466  83C408              ADD       ESP,08
001B:00401469  8D4C2454            LEA       ECX,[ESP+54]
001B:0040146D  6A00                PUSH      00
001B:0040146F  68C0654000          PUSH      004065C0
001B:00401474  51                  PUSH      ECX
001B:00401475  52                  PUSH      EDX
001B:00401476  FF15A0684000        CALL      [004068A0]

        看看 [004068A0]

:dd 004068A0

得到值 980000

:u 980000

001B:00980000  B86464E177          MOV       EAX,77E16464
001B:00980005  05E0000000          ADD       EAX,000000E0
001B:0098000A  50                  PUSH      EAX
001B:0098000B  C3                  RET
001B:0098000C  B80341DF77          MOV       EAX,77DF4103
001B:00980011  05E0000000          ADD       EAX,000000E0
001B:00980016  50                  PUSH      EAX
001B:00980017  C3                  RET
001B:00980018  B8AA57DF77          MOV       EAX,77DF57AA
001B:0098001D  05E0000000          ADD       EAX,000000E0
001B:00980022  50                  PUSH      EAX
001B:00980023  C3                  RET

        这里像 sub2 和 sub1 常用的 API 跳转表

        我们人手把 77E16464 的值加上 E0,得到 77e16384

:u 77e16544

USER32!MessageBoxA   // <--留意这里
001B:77E16544  55                  PUSH      EBP
001B:77E16545  8BEC                MOV       EBP,ESP
001B:77E16547  51                  PUSH      ECX
001B:77E16548  833D1893E47700      CMP       DWORD PTR [77E49318],00
001B:77E1654F  0F85EA220100        JNZ       77E2883F
001B:77E16555  6A00                PUSH      00
001B:77E16557  FF7514              PUSH      DWORD PTR [EBP+14]
001B:77E1655A  FF7510              PUSH      DWORD PTR [EBP+10]
001B:77E1655D  FF750C              PUSH      DWORD PTR [EBP+0C]
001B:77E16560  FF7508              PUSH      DWORD PTR [EBP+08]
001B:77E16563  E804000000          CALL      USER32!MessageBoxExA
001B:77E16568  C9                  LEAVE
001B:77E16569  C21000              RET       0010
USER32!MessageBoxExA
001B:77E1656C  55                  PUSH      EBP
001B:77E1656D  8BEC                MOV       EBP,ESP
001B:77E1656F  51                  PUSH      ECX
001B:77E16570  51                  PUSH      ECX
001B:77E16571  53                  PUSH      EBX

001B:77E16572  56                  PUSH      ESI
001B:77E16573  57                  PUSH      EDI
001B:77E16574  33FF                XOR       EDI,EDI
001B:77E16576  83CEFF              OR        ESI,-01
001B:77E16579  397D0C              CMP       [EBP+0C],EDI
001B:77E1657C  897DFC              MOV       [EBP-04],EDI
001B:77E1657F  897DF8              MOV       [EBP-08],EDI
001B:77E16582  7419                JZ        77E1659D
001B:77E16584  6A01                PUSH      01
001B:77E16586  8D45FC              LEA       EAX,[EBP-04]
001B:77E16589  56                  PUSH      ESI
001B:77E1658A  50                  PUSH      EAX

        我们看见这里是 KERNEL32.MessageBoxA 的领空,看来这个 call 的 MessageBoxA 的呼叫

        这里有可能是跳出成功注册信息的地方,我们现在想办法改变程序的流程,让 sub1 成功到达这里

[ Part VI.  最后决战 ]

        先把程序关掉,重新打开 crackme,确保上面两处 ReadProcessMemory 的位置可以正常通过,读取注册名字和序号

        现在,回到 sub1 的那个跳转看看,打开 softice 到 sub1 下断点直接到达

:addr sub1
:bpx 00401437

        按 register,断在

001B:00401437  8A4C0410            MOV       CL,[EAX+ESP+10]
001B:0040143B  8A540420            MOV       DL,[EAX+ESP+20]
001B:0040143F  80F159              XOR       CL,59
001B:00401442  3ACA                CMP       CL,DL
001B:00401444  754F                JNZ       00401495   <-----这里往下跳至 ret

        这个 JNZ 的上方是 CMP,当两者不相等,这个 JNZ 便会跳往完结处

        上面的 CL 和 DL 估计是用来储存单位字符组, CL 的值经过 xor 0x59 后,跟 DL 比较

        我们在 00401444 设断点,按 register

        断下时用 softice 看看 [EAX+ESP+10]

:db EAX+ESP+10

0023:0012FBAC 03 0C 09 0B 1B 1F 15 0A-1A 1A 14 14 13 11 0A 00  ................

        再看 [EAX+ESP+20]

:db EAX+ESP+20

0023:0012FBBC 5A 55 50 52 42 46 4C 53-43 43 4D 4D 4A 48 53 00  ZUPRBFLSCCMMJHS.

        这是一行特别的字符串  "ZUPRBFLSCCMMJHS"

        这样看来,假如所有 CMP 都是相等的话,便会注册成功

        我们试把 ZUPRBFLSCCMMJHS 用作序号来注册,使用未经修改的 crackme (包括 sub3 sub2 sub1)

        果然,当我们按下 register 的时候,跳出了成功信息

        Registration successful

        并而出现 zip 文件的密码

        ftjug       

        终于检到正确的序号了。

[ Part VII.  总结 ]

        这个 crackme 4 是我的一个自调试实试品,它的结构以 int 3 的手法作为阻碍破解者的主要手段,
        由于我写这篇破文时没有看源码,尽量以破解者的角度出发,所以破解起来是有很多不足之处,手法
        不够高明,我知道一些大侠们把 sub1 修改成独自运行来使用 OD 加载,这种无疑是较高明的手法。

        这个程序的一些算法部份没有很详细地描述,如果读者有兴趣的话,相信跟踪后发觉并不艰辛

        sub2 把注册名字的第一次转换 :

void encode(char *buf)
{
        int len;
        DWORD seed;
        int i, j;
        DWORD affect = 0;
        char bufout[16] = {0};

        len = strlen(buf);

    seed = 5987;

        for( i=0; i<len; i++)
        {
                affect = (affect + buf[i]) * 2;
        }

    seed = seed * affect;

        for( i=0; i<15; i++)
        {
                for( j=0; j< (unsigned char)buf[i % len]; j++)
                {
                        seed = ((seed * 7919) + 13) % 6367;
                }

                bufout[i] = 1 + (unsigned char)(seed % 254);
        }

        buf[0] = 0;
        strcpy(buf, bufout);
}

第二次转换:

void encode2(char *buf)
{
    int len;
        int i;

        len = strlen(buf);

        for( i=0; i<len; i++)
        {
        buf[i] = buf[i] ^ 0x59;
        }

}

        sub1 的算法与 sub2 的第一次算法是相同的,看懂后很容易明白。

        这个 crackme 的制作用了两星期,读者可能会觉得一些地方不够完美,例如为甚么整个序号
        处理只使用了 sub2 和 sub1,却没有使用 sub3 和 crackme4 的主体 ?  我在设计也觉得不够强硬,
        但是它的复杂性已经很大,我在修正了多个 bug 后,已经没有气力了。

        希望这篇文章对初入门的兄弟有用,这篇文章的后半部分使用了 softice ,对于不熟识 softice
        操作的兄弟可能会觉得十分不方便,可是在现实中,我们很多时候也是被迫使用 softice 来应付
        一些特别困难的情况。

       
[全文完]


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (14)
雪    币: 519
活跃值: (1223)
能力值: ( LV12,RANK:650 )
在线值:
发帖
回帖
粉丝
2
赞一个……
唉,现在大家都是“被迫”才用SOFTICE了,可我除了用它别的都不会
2005-2-4 15:50
0
雪    币: 2319
活跃值: (565)
能力值: (RANK:300 )
在线值:
发帖
回帖
粉丝
3
Softice 最不方便的,就是不懂得像 OD 那样,自动显示位置所代表的值或字符串

常常打 d 来看东西  
2005-2-4 15:59
0
雪    币: 2384
活跃值: (766)
能力值: (RANK:410 )
在线值:
发帖
回帖
粉丝
4
好文章,学习。
2005-2-4 17:04
0
雪    币: 898
活跃值: (4039)
能力值: ( LV9,RANK:3410 )
在线值:
发帖
回帖
粉丝
5
辛苦
2005-2-4 17:10
0
雪    币: 519
活跃值: (1223)
能力值: ( LV12,RANK:650 )
在线值:
发帖
回帖
粉丝
6
最初由 riijj 发布
Softice 最不方便的,就是不懂得像 OD 那样,自动显示位置所代表的值或字符串

常常打 d 来看东西


d 习惯了,感觉不出来了,这个D键早晚得让我按爆了
2005-2-5 16:41
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
真的有点复杂...
2005-2-5 16:45
0
雪    币: 107
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
riijj老大的文章我真得非常喜欢看,讲解得清除、详细。努力拜读中~
2005-2-6 10:10
0
雪    币: 389
活跃值: (912)
能力值: ( LV9,RANK:770 )
在线值:
发帖
回帖
粉丝
9
riijj的头像象个柔弱女子,可是文章写的精彩有力啊.
学习,支持!
2005-2-7 22:11
0
雪    币: 149
活跃值: (344)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
10
楼主的文章就像一个耐心的mm在手把手的教我们学习技术...

文章我转了...
2005-2-13 17:06
0
雪    币: 898
活跃值: (4039)
能力值: ( LV9,RANK:3410 )
在线值:
发帖
回帖
粉丝
11
估计还有N级、高级的东东在后面
提前说一句:偶不“敢”玩啦
2005-2-13 18:31
0
雪    币: 538
活跃值: (32)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
写的真好,学习学习啊
2005-3-14 22:12
0
雪    币: 235
活跃值: (191)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
13
做了这么强的Crackme真的是让人不得不佩服.
是我的话看见多线程就不玩了,呵呵~没时间也没耐心
2005-3-15 12:56
0
雪    币: 168
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
riijj的文章写的真是好啊,过程清楚,思路清晰,体贴观众,又不自我炫耀。很有大家风范。佩服佩服,要是能拜为师父就好了,呵呵。。。
2005-3-24 11:45
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
初学,关注!
2005-5-15 15:20
0
游客
登录 | 注册 方可回帖
返回
//