playboysen 发表于 2013-12-28 16:23

【吾爱2013CM大赛解答】-- MK的杀手锏 算法分析+PATCH一码复用(复杂)

本帖最后由 playboysen 于 2013-12-30 22:34 编辑

本文针对以下CM:
http://www.52pojie.cn/thread-230220-1-1.html

主程序加了UPX壳、简单自校验什么的,直接下断GetFileSize即可轻松找到自校验
(或者根据异常提示也可以轻松定位自校验,这种方法仅限XP,Win7不显示错误信息)
XP上错误提示

自校验代码(以下截图均出自Win7X64,所以地址显示可能有异)



注册类型是机器码对应注册码,F9运行程序打开OD的Windows窗口看看控件ID

找到Edit框ID,在代码窗口直接搜索常量来定位相关处理代码
010216C7   .51            PUSH    ECX                                          ; /lParam
010216C8   .68 00010000   PUSH    0x100                                          ; |wParam = 0x100
010216CD   .0FB7F3      MOVZX   ESI, BX                                        ; |
010216D0   .33C0          XOR   EAX, EAX                                       ; |
010216D2   .6A 0D         PUSH    0xD                                          ; |Message = WM_GETTEXT
010216D4   .895C24 34   MOV   DWORD PTR SS:, EBX                   ; |
010216D8   .8BD8          MOV   EBX, EAX                                       ; |
010216DA   .83C6 01       ADD   ESI, 0x1                                       ; |
010216DD   .68 EA030000   PUSH    0x3EA                                          ; |ControlID = 3EA (1002.)
010216E2   .13C3          ADC   EAX, EBX                                       ; |
010216E4   .52            PUSH    EDX                                          ; |hWnd => 0010070E ('crack me2:MK的杀手锏 by:MK',class='#32770')
010216E5   .893D D8FA2301 MOV   DWORD PTR DS:, EDI                  ; |
010216EB   .894424 40   MOV   DWORD PTR SS:, EAX                   ; |
010216EF   .FF15 3CB10201 CALL    NEAR DWORD PTR DS:                  ; \SendDlgItemMessageA
010216F5   .68 00010000   PUSH    0x100                                          ;0x3EA是注册码EDIT框
......
01021774   .8B4C24 14   MOV   ECX, DWORD PTR SS:
01021778   >0FB6940C 6801>MOVZX   EDX, BYTE PTR SS:               ;regcode
01021780   .885424 11   MOV   BYTE PTR SS:, DL
01021784   .0FB69434 7101>MOVZX   EDX, BYTE PTR SS:               ;regcode
0102178C   .885424 13   MOV   BYTE PTR SS:, DL
01021790   .0FB69404 7A01>MOVZX   EDX, BYTE PTR SS:               ;regcode
01021798   .885424 12   MOV   BYTE PTR SS:, DL
0102179C   .0FB6943C 8301>MOVZX   EDX, BYTE PTR SS:
010217A4   .C6840C 680100>MOV   BYTE PTR SS:, 0x0               ;以上四字节置零
010217AC   .C68434 710100>MOV   BYTE PTR SS:, 0x0
010217B4   .C68404 7A0100>MOV   BYTE PTR SS:, 0x0
010217BC   .885424 10   MOV   BYTE PTR SS:, DL
010217C0   .C6843C 830100>MOV   BYTE PTR SS:, 0x0
010217C8   .33C0          XOR   EAX, EAX
010217CA   .8D8C24 680200>LEA   ECX, DWORD PTR SS:
010217D1   >8A9404 680100>MOV   DL, BYTE PTR SS:
010217D8   .84D2          TEST    DL, DL
010217DA   .74 03         JE      SHORT MKssj.010217DF
010217DC   .8811          MOV   BYTE PTR DS:, DL
010217DE   .41            INC   ECX
010217DF   >40            INC   EAX
010217E0   .83F8 24       CMP   EAX, 0x24                                    ;连接字符串 去除0x00共32位
010217E3   .^ 7C EC         JL      SHORT MKssj.010217D1
010217E5   .8D8424 680200>LEA   EAX, DWORD PTR SS:
010217EC   .899C24 040100>MOV   DWORD PTR SS:, EBX
010217F3   .899C24 000100>MOV   DWORD PTR SS:, EBX
010217FA   .C78424 080100>MOV   DWORD PTR SS:, 0x67452301         ;这几组数字,标准的MD5函数
01021805   .C78424 0C0100>MOV   DWORD PTR SS:, 0xEFCDAB89
01021810   .C78424 100100>MOV   DWORD PTR SS:, 0x98BADCFE
0102181B   .C78424 140100>MOV   DWORD PTR SS:, 0x10325476
01021826   .8D48 01       LEA   ECX, DWORD PTR DS:
01021829   .8DA424 000000>LEA   ESP, DWORD PTR SS:
01021830   >8A10          MOV   DL, BYTE PTR DS:
01021832   .40            INC   EAX
01021833   .84D2          TEST    DL, DL
01021835   .^ 75 F9         JNZ   SHORT MKssj.01021830
01021837   .2BC1          SUB   EAX, ECX
01021839   .8D8C24 680200>LEA   ECX, DWORD PTR SS:
01021840   .51            PUSH    ECX
01021841   .8DB424 040100>LEA   ESI, DWORD PTR SS:
01021848   .E8 83120000   CALL    MKssj.01022AD0
0102184D   .8BC6          MOV   EAX, ESI
0102184F   .E8 8C130000   CALL    MKssj.01022BE0
01021854   .8D9424 5C0100>LEA   EDX, DWORD PTR SS:
0102185B   .52            PUSH    EDX
0102185C   .B8 10000000   MOV   EAX, 0x10
01021861   .8D7424 38   LEA   ESI, DWORD PTR SS:
01021865   .895C24 3C   MOV   DWORD PTR SS:, EBX
01021869   .895C24 38   MOV   DWORD PTR SS:, EBX
0102186D   .C74424 40 012>MOV   DWORD PTR SS:, 0x67452301            ;第二次MD5
01021875   .C74424 44 89A>MOV   DWORD PTR SS:, 0xEFCDAB89
0102187D   .C74424 48 FED>MOV   DWORD PTR SS:, 0x98BADCFE
01021885   .C74424 4C 765>MOV   DWORD PTR SS:, 0x10325476
0102188D   .E8 3E120000   CALL    MKssj.01022AD0
01021892   .8BC6          MOV   EAX, ESI
01021894   .E8 47130000   CALL    MKssj.01022BE0
01021899   .8D8424 900000>LEA   EAX, DWORD PTR SS:
010218A0   .50            PUSH    EAX
010218A1   .B8 10000000   MOV   EAX, 0x10
010218A6   .8DB424 A40000>LEA   ESI, DWORD PTR SS:
010218AD   .899C24 A80000>MOV   DWORD PTR SS:, EBX
010218B4   .899C24 A40000>MOV   DWORD PTR SS:, EBX
010218BB   .C78424 AC0000>MOV   DWORD PTR SS:, 0x67452301
010218C6   .C78424 B00000>MOV   DWORD PTR SS:, 0xEFCDAB89
010218D1   .C78424 B40000>MOV   DWORD PTR SS:, 0x98BADCFE
010218DC   .C78424 B80000>MOV   DWORD PTR SS:, 0x10325476            ;第三次MD5
010218E7   .E8 E4110000   CALL    MKssj.01022AD0
010218EC   .8BC6          MOV   EAX, ESI
010218EE   .E8 ED120000   CALL    MKssj.01022BE0                                 
010218F3   .68 00010000   PUSH    0x100
010218F8   .8D8C24 780200>LEA   ECX, DWORD PTR SS:
010218FF   .53            PUSH    EBX
01021900   .51            PUSH    ECX
01021901   .E8 BA610000   CALL    MKssj.01027AC0
01021906   .83C4 18       ADD   ESP, 0x18
01021909   .33F6          XOR   ESI, ESI
0102190B   .8935 DCFA2301 MOV   DWORD PTR DS:, ESI
01021911   >68 00010000   PUSH    0x100                                          ;一个大循环
01021916   .53            PUSH    EBX
01021917   .68 D8F92301   PUSH    MKssj.0123F9D8                                 ;ASCII "%X%x"
0102191C   .E8 9F610000   CALL    MKssj.01027AC0
01021921   .8A0D E0EC0201 MOV   CL, BYTE PTR DS:                  ;CL = 0x4A ‘J’
01021927   .83C4 0C       ADD   ESP, 0xC
0102192A   .80F9 6F       CMP   CL, 0x6F
0102192D   .74 17         JE      SHORT MKssj.01021946
0102192F   .33C0          XOR   EAX, EAX
01021931   >80F1 6F       XOR   CL, 0x6F                                       ;解码出"%x%x"
01021934   .8888 D8F92301 MOV   BYTE PTR DS:, CL
0102193A   .8A88 E1EC0201 MOV   CL, BYTE PTR DS:
01021940   .40            INC   EAX
01021941   .80F9 6F       CMP   CL, 0x6F
01021944   .^ 75 EB         JNZ   SHORT MKssj.01021931
01021946   >0FB68434 F000>MOVZX   EAX, BYTE PTR SS:
0102194E   .8BD0          MOV   EDX, EAX
01021950   .81E2 0F000080 AND   EDX, 0x8000000F
01021956   .79 05         JNS   SHORT MKssj.0102195D
01021958   .4A            DEC   EDX
01021959   .83CA F0       OR      EDX, 0xFFFFFFF0
0102195C   .42            INC   EDX
0102195D   >8B35 38B10201 MOV   ESI, DWORD PTR DS:                  ;user32.wsprintfA
01021963   .52            PUSH    EDX
01021964   .C1E8 04       SHR   EAX, 0x4
01021967   .50            PUSH    EAX                                          ; /<%d>
01021968   .68 D8F92301   PUSH    MKssj.0123F9D8                                 ; |Format = "%X%x"
0102196D   .68 E4FA2301   PUSH    MKssj.0123FAE4                                 ; |s = MKssj.0123FAE4
01021972   .FFD6          CALL    NEAR ESI                                       ; \wsprintfA
01021974   .68 00010000   PUSH    0x100
01021979   .53            PUSH    EBX
0102197A   .68 D8F92301   PUSH    MKssj.0123F9D8                                 ;ASCII "%X%x"
0102197F   .E8 3C610000   CALL    MKssj.01027AC0
01021984   .8A0D E8EC0201 MOV   CL, BYTE PTR DS:
0102198A   .83C4 1C       ADD   ESP, 0x1C
0102198D   .80F9 6F       CMP   CL, 0x6F
01021990   .74 23         JE      SHORT MKssj.010219B5
01021992   .33C0          XOR   EAX, EAX
01021994   .EB 0A         JMP   SHORT MKssj.010219A0
01021996   .8DA424 000000>LEA   ESP, DWORD PTR SS:
0102199D   .8D49 00       LEA   ECX, DWORD PTR DS:
010219A0   >80F1 6F       XOR   CL, 0x6F                                       ;解码出"%s%s"
010219A3   .8888 D8F92301 MOV   BYTE PTR DS:, CL
010219A9   .8A88 E9EC0201 MOV   CL, BYTE PTR DS:
010219AF   .40            INC   EAX
010219B0   .80F9 6F       CMP   CL, 0x6F
010219B3   .^ 75 EB         JNZ   SHORT MKssj.010219A0
010219B5   >68 E4FA2301   PUSH    MKssj.0123FAE4
010219BA   .8D8424 6C0200>LEA   EAX, DWORD PTR SS:
010219C1   .50            PUSH    EAX
010219C2   .8BC8          MOV   ECX, EAX
010219C4   .68 D8F92301   PUSH    MKssj.0123F9D8                                 ;ASCII "%X%x"
010219C9   .51            PUSH    ECX
010219CA   .FFD6          CALL    NEAR ESI
010219CC   .8B35 DCFA2301 MOV   ESI, DWORD PTR DS:
010219D2   .46            INC   ESI
010219D3   .83C4 10       ADD   ESP, 0x10
010219D6   .83FE 10       CMP   ESI, 0x10
010219D9   .8935 DCFA2301 MOV   DWORD PTR DS:, ESI
010219DF   .^ 0F8C 2CFFFFFF JL      MKssj.01021911
010219E5   .8B5424 28   MOV   EDX, DWORD PTR SS:
010219E9   .52            PUSH    EDX                                          ; /String2
010219EA   .8D8424 6C0200>LEA   EAX, DWORD PTR SS:                  ; |
010219F1   .50            PUSH    EAX                                          ; |String1
010219F2   .FF15 18B00201 CALL    NEAR DWORD PTR DS:                  ; \lstrcmpA
010219F8   .85C0          TEST    EAX, EAX
010219FA   .0F85 5E010000 JNZ   MKssj.01021B5E                                 ;跳转失败
......
01021B34   .05 A0F92301   ADD   EAX, MKssj.0123F9A0                            ; |
01021B39   .FF15 3CB10201 CALL    NEAR DWORD PTR DS:                  ; \SendDlgItemMessageA
01021B3F   .8B0D ACF92301 MOV   ECX, DWORD PTR DS:
01021B45   .6A 01         PUSH    0x1                                          ; /ShowState = SW_SHOWNORMAL
01021B47   .68 EC030000   PUSH    0x3EC                                          ; |/ControlID = 3EC (1004.)
01021B4C   .51            PUSH    ECX                                          ; ||hWnd => 0010070E ('crack me2:MK的杀手锏 by:MK',class='#32770')
01021B4D   .FF15 40B10201 CALL    NEAR DWORD PTR DS:                  ; |\GetDlgItem
01021B53   .50            PUSH    EAX                                          ; |hWnd
01021B54   .FF15 48B10201 CALL    NEAR DWORD PTR DS:                  ; \ShowWindow
......
01021C25   .8BE5          MOV   ESP, EBP
01021C27   .5D            POP   EBP
01021C28   .C2 1400       RETN    0x14
大概流程就是SendDlgItemMessageA来获取并简单处理注册码EDIT文本,然后三次MD5加密运算得出的值与程序内置码表对应位置的值作比较
由于MD5为不可逆运算(更何况还变形后做了多次MD5),所以即使可以轻松找到内置码表(在010219E9断点查看数据窗口即可)也很难还原出注册码,逆向出注册机更不用说了(当然拼人品暴力算号不在讨论范围),有心之人在这里试一试爆破吧(提示:简单修改跳转是行不通的后面还有一些校验)

(这种MD5查表注册法N年前好像在Quick Batch File Compiler时遇到过,注册验证逻辑基本一致,不过QBFC是注册码一次MD5值查表对照,幸好QBFC爆破容易(一字节搞定)当初也并未深究
没想到几年后在这里又遇到了其加强改进版,颇有种“他乡遇故知”的感觉,进而想到了那句词“物是人非事事休,欲语泪先流”忽然有些伤感……)

这里不得不学习下@qq54007 的一个“猥琐”伎俩
程序枚举进程模块查找可疑点,如被调试等不提示不退出而是偷偷修改解码关键Key致使无论输入注册码正确与否均提示失败

0040221C    50            ||push eax
0040221D    68 D8F96100   ||push a_a.0061F9D8                              ; ASCII "ollydbg.ini"
00402222    FF15 30B04000 ||call dword ptr ds:[<&kernel32.lstrcmpi>]         ; kernel32.lstrcmpiA
00402228    85C0          ||test eax,eax
0040222A    75 22         ||jnz short a_a.0040224E
0040222C    B9 45651352   ||mov ecx,52136545                                 ; 这里开始搞破坏了!!!
00402231    310D B0EC4000 ||xor dword ptr ds:,ecx                  ; 等等是用于注册解码的关键Key
00402237    310D B8EC4000 ||xor dword ptr ds:,ecx                  ; KEY被改的面目全非
0040223D    B8 74981685   ||mov eax,85169874
00402242    3105 B4EC4000 ||xor dword ptr ds:,eax                  ; “偷偷的进村,打枪的不要!”
00402248    3105 BCEC4000 ||xor dword ptr ds:,eax                  ; 太猥琐鸟儿o_0
0040224E    8D8C24 2C1000>||lea ecx,dword ptr ss:
00402255    51            ||push ecx
00402256    57            ||push edi
00402257    FF15 40B04000 ||call dword ptr ds:[<&kernel32.FindNextFileA>]    ; kernel32.FindNextFileA
0040225D    85C0          ||test eax,eax
0040225F^ 0F85 1BFFFFFF |\jnz a_a.00402180
00402265    57            |push edi
00402266    FF15 34B04000 |call dword ptr ds:[<&kernel32.FindClose>]         ; kernel32.FindClose
既然无法还原注册机,能否替换机器码来实现一码多用?那首先得知道机器码在哪里计算出来的
如何快速定位机器码计算部分呢?程序运算出机器码后会在主界面显示出来,下端点SetDlgItemTextA或者代码段搜索Edit框ID均可
01021DC4   > \8B7424 14   MOV   ESI, DWORD PTR SS:   ;Case 110 (WM_INITDIALOG) of switch 01021D14
01021DC8   .BF B0F92301   MOV   EDI, MKssj.0123F9B0
01021DCD   .8935 ACF92301 MOV   DWORD PTR DS:, ESI
01021DD3   .E8 38F7FFFF   CALL    MKssj.01021510
01021DD8   .33FF          XOR   EDI, EDI
01021DDA   .803D B0F92301>CMP   BYTE PTR DS:, 0x0
01021DE1   .893D D8FA2301 MOV   DWORD PTR DS:, EDI
01021DE7   .0F84 5C010000 JE      MKssj.01021F49
01021DED   .8B2D 4CB10201 MOV   EBP, DWORD PTR DS:    ;user32.GetDlgItemTextA
01021DF3   .8B1D 24B00201 MOV   EBX, DWORD PTR DS:    ;kernel32.lstrcatA
01021DF9   >68 00010000   PUSH    0x100                            ;循环计算机器码
01021DFE   .6A 00         PUSH    0x0
01021E00   .68 D8F92301   PUSH    MKssj.0123F9D8                   ;ASCII "%X%x"
01021E05   .C64424 20 00MOV   BYTE PTR SS:, 0x0
01021E0A   .C64424 21 00MOV   BYTE PTR SS:, 0x0
01021E0F   .C64424 22 00MOV   BYTE PTR SS:, 0x0
01021E14   .E8 A75C0000   CALL    MKssj.01027AC0
01021E19   .8A0D D8EC0201 MOV   CL, BYTE PTR DS:
01021E1F   .83C4 0C       ADD   ESP, 0xC
01021E22   .80F9 6F       CMP   CL, 0x6F
01021E25   .74 1E         JE      SHORT MKssj.01021E45
01021E27   .33C0          XOR   EAX, EAX
01021E29   .8DA424 000000>LEA   ESP, DWORD PTR SS:
01021E30   >80F1 6F       XOR   CL, 0x6F
01021E33   .8888 D8F92301 MOV   BYTE PTR DS:, CL
01021E39   .8A88 D9EC0201 MOV   CL, BYTE PTR DS:
01021E3F   .40            INC   EAX
01021E40   .80F9 6F       CMP   CL, 0x6F
01021E43   .^ 75 EB         JNZ   SHORT MKssj.01021E30             ;***begin***
01021E45   >0FB687 B0F923>MOVZX   EAX, BYTE PTR DS: ;MD5("   WD-WMC1S4965023") 占16字节
01021E4C   .8BC8          MOV   ECX, EAX
01021E4E   .81E1 0F000080 AND   ECX, 0x8000000F                  ;机器码计算过程见python代码
01021E54   .79 05         JNS   SHORT MKssj.01021E5B
01021E56   .49            DEC   ECX
01021E57   .83C9 F0       OR      ECX, 0xFFFFFFF0
01021E5A   .41            INC   ECX
01021E5B   >8D1449      LEA   EDX, DWORD PTR DS:    ;EDX = 3*ECX
01021E5E   .81E2 0F000080 AND   EDX, 0x8000000F
01021E64   .79 05         JNS   SHORT MKssj.01021E6B
01021E66   .4A            DEC   EDX
01021E67   .83CA F0       OR      EDX, 0xFFFFFFF0
01021E6A   .42            INC   EDX
01021E6B   >C1E8 04       SHR   EAX, 0x4                         ;md5_16
01021E6E   .8D0440      LEA   EAX, DWORD PTR DS:    ;EAX = 3*EAX
01021E71   .25 0F000080   AND   EAX, 0x8000000F
01021E76   .52            PUSH    EDX
01021E77   .79 05         JNS   SHORT MKssj.01021E7E
01021E79   .48            DEC   EAX
01021E7A   .83C8 F0       OR      EAX, 0xFFFFFFF0
01021E7D   .40            INC   EAX
01021E7E   >50            PUSH    EAX                              ; /***end***
01021E7F   .8D4C24 1C   LEA   ECX, DWORD PTR SS:   ; |
01021E83   .68 D8F92301   PUSH    MKssj.0123F9D8                   ; |Format = "%X%x"
01021E88   .51            PUSH    ECX                              ; |s
01021E89   .FF15 38B10201 CALL    NEAR DWORD PTR DS:    ; \wsprintfA
01021E8F   .83C4 10       ADD   ESP, 0x10
01021E92   .807C24 14 41CMP   BYTE PTR SS:, 0x41
01021E97   .7C 05         JL      SHORT MKssj.01021E9E
01021E99   .804424 14 0AADD   BYTE PTR SS:, 0xA
01021E9E   >807C24 15 41CMP   BYTE PTR SS:, 0x41
01021EA3   .7C 05         JL      SHORT MKssj.01021EAA
01021EA5   .804424 15 0AADD   BYTE PTR SS:, 0xA
01021EAA   >68 00010000   PUSH    0x100
01021EAF   .68 98F82301   PUSH    MKssj.0123F898                   ;ASCII "951768P9-0883351n-P25n33O3-9mM281"
01021EB4   .68 E9030000   PUSH    0x3E9                            ;0x3E9是机器码EDIT框
01021EB9   .56            PUSH    ESI
01021EBA   .FFD5          CALL    NEAR EBP                         ;GetDlgItemTextA
01021EBC   .8D5424 14   LEA   EDX, DWORD PTR SS:
01021EC0   .52            PUSH    EDX
01021EC1   .68 98F82301   PUSH    MKssj.0123F898                   ;ASCII "951768P9-0883351n-P25n33O3-9mM281"
01021EC6   .FFD3          CALL    NEAR EBX                         ;lstrcatA
01021EC8   .68 98F82301   PUSH    MKssj.0123F898                   ; /Text = "951768P9-0883351n-P25n33O3-9mM281"
01021ECD   .68 E9030000   PUSH    0x3E9                            ; |ControlID = 3E9 (1001.)
01021ED2   .56            PUSH    ESI                              ; |hWnd
01021ED3   .FF15 54B10201 CALL    NEAR DWORD PTR DS:    ; \SetDlgItemTextA
01021ED9   .8B3D D8FA2301 MOV   EDI, DWORD PTR DS:    ;0x3E9是机器码EDIT框的ControlID
01021EDF   .8D47 01       LEA   EAX, DWORD PTR DS:
01021EE2   .25 03000080   AND   EAX, 0x80000003
01021EE7   .79 05         JNS   SHORT MKssj.01021EEE
01021EE9   .48            DEC   EAX
01021EEA   .83C8 FC       OR      EAX, 0xFFFFFFFC
01021EED   .40            INC   EAX
01021EEE   >75 45         JNZ   SHORT MKssj.01021F35
01021EF0   .8D4F FF       LEA   ECX, DWORD PTR DS:
01021EF3   .83F9 0D       CMP   ECX, 0xD
01021EF6   .77 3D         JA      SHORT MKssj.01021F35
01021EF8   .68 00010000   PUSH    0x100
01021EFD   .68 98F82301   PUSH    MKssj.0123F898                   ;ASCII "951768P9-0883351n-P25n33O3-9mM281"
01021F02   .68 E9030000   PUSH    0x3E9
01021F07   .56            PUSH    ESI
01021F08   .C74424 28 2D0>MOV   DWORD PTR SS:, 0x2D
01021F10   .FFD5          CALL    NEAR EBP
01021F12   .8D5424 18   LEA   EDX, DWORD PTR SS:
01021F16   .52            PUSH    EDX
01021F17   .68 98F82301   PUSH    MKssj.0123F898                   ;ASCII "951768P9-0883351n-P25n33O3-9mM281"
01021F1C   .FFD3          CALL    NEAR EBX
01021F1E   .68 98F82301   PUSH    MKssj.0123F898                   ; /Text = "951768P9-0883351n-P25n33O3-9mM281"
01021F23   .68 E9030000   PUSH    0x3E9                            ; |ControlID = 3E9 (1001.)
01021F28   .56            PUSH    ESI                              ; |hWnd
01021F29   .FF15 54B10201 CALL    NEAR DWORD PTR DS:    ; \SetDlgItemTextA
01021F2F   .8B3D D8FA2301 MOV   EDI, DWORD PTR DS:
01021F35   >47            INC   EDI
01021F36   .80BF B0F92301>CMP   BYTE PTR DS:, 0x0
01021F3D   .893D D8FA2301 MOV   DWORD PTR DS:, EDI
01021F43   .^ 0F85 B0FEFFFF JNZ   MKssj.01021DF9
01021F49   >6A 01         PUSH    0x1
01021F4B   .6A 20         PUSH    0x20
01021F4D   .68 50160201   PUSH    MKssj.01021650                   ;回调函数地址
01021F52   .68 E8030000   PUSH    0x3E8
01021F57   .6A 64         PUSH    0x64
01021F59   .FF15 5CB10201 CALL    NEAR DWORD PTR DS:    ;winmm.timeSetEvent
01021F5F   .B8 01000000   MOV   EAX, 0x1
01021F64   .5F            POP   EDI
01021F65   .5E            POP   ESI
01021F66   .5D            POP   EBP
01021F67   .5B            POP   EBX
01021F68   .C2 1000       RETN    0x10

一个大循环逐位计算出机器码并写入Edit(具体计算过程见后面Python代码),最后timeSetEvent设置回调函数(就是上面那段注册码验证函数)
上面的计算都是基于字符串"   WD-WMC1S4965023",看起来好像磁盘信息,不知道怎么计算出来的,下断点CreateFileA看看
01021345   > \53            PUSH    EBX                              ; /<%d>
01021346   .8D8424 3C0400>LEA   EAX, DWORD PTR SS:    ; |
0102134D   .68 D8F92301   PUSH    MKssj.0123F9D8                   ; |Format = "\\.\PhysicalDrive%d"
01021352   .50            PUSH    EAX                              ; |s
01021353   .FF15 38B10201 CALL    NEAR DWORD PTR DS:    ; \wsprintfA
01021359   .83C4 0C       ADD   ESP, 0xC
0102135C   .53            PUSH    EBX                              ; /hTemplateFile
0102135D   .53            PUSH    EBX                              ; |Attributes
0102135E   .6A 03         PUSH    0x3                              ; |Mode = OPEN_EXISTING
01021360   .53            PUSH    EBX                              ; |pSecurity
01021361   .6A 03         PUSH    0x3                              ; |ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE
01021363   .68 000000C0   PUSH    0xC0000000                     ; |Access = GENERIC_READ|GENERIC_WRITE
01021368   .8D8C24 500400>LEA   ECX, DWORD PTR SS:    ; |
0102136F   .51            PUSH    ECX                              ; |FileName
01021370   .FF15 00B00201 CALL    NEAR DWORD PTR DS:    ; \CreateFileA
01021376   .8BF0          MOV   ESI, EAX
01021378   .83FE FF       CMP   ESI, -0x1
0102137B   .75 07         JNZ   SHORT MKssj.01021384
......
010213C9   .53            PUSH    EBX                              ; /pOverlapped
010213CA   .8D4424 14   LEA   EAX, DWORD PTR SS:   ; |
010213CE   .50            PUSH    EAX                              ; |pBytesReturned
010213CF   .68 13020000   PUSH    0x213                            ; |OutBufferSize = 213 (531.)
010213D4   .8D8C24 440500>LEA   ECX, DWORD PTR SS:    ; |
010213DB   .51            PUSH    ECX                              ; |OutBuffer
010213DC   .6A 23         PUSH    0x23                           ; |InBufferSize = 23 (35.)
010213DE   .8D9424 280400>LEA   EDX, DWORD PTR SS:    ; |
010213E5   .52            PUSH    EDX                              ; |InBuffer
010213E6   .68 88C00700   PUSH    0x7C088                        ; |IoControlCode = SMART_RCV_DRIVE_DATA
010213EB   .56            PUSH    ESI                              ; |hDevice
010213EC   .889C24 380400>MOV   BYTE PTR SS:, BL      ; |
010213F3   .C68424 390400>MOV   BYTE PTR SS:, 0x1   ; |
010213FB   .889C24 3B0400>MOV   BYTE PTR SS:, BL      ; |
01021402   .889C24 3C0400>MOV   BYTE PTR SS:, BL      ; |
01021409   .C68424 3D0400>MOV   BYTE PTR SS:, 0xA0    ; |
01021411   .C68424 3E0400>MOV   BYTE PTR SS:, 0xEC    ; |
01021419   .889C24 400400>MOV   BYTE PTR SS:, BL      ; |
01021420   .C78424 340400>MOV   DWORD PTR SS:, 0x200; |
0102142B   .FF15 0CB00201 CALL    NEAR DWORD PTR DS:    ; \DeviceIoControl
01021431   .85C0          TEST    EAX, EAX
01021433   .74 32         JE      SHORT MKssj.01021467
01021435   .33C0          XOR   EAX, EAX
01021437   .EB 07         JMP   SHORT MKssj.01021440
01021439   .8DA424 000000>LEA   ESP, DWORD PTR SS:
01021440   >0FB78C44 4805>MOVZX   ECX, WORD PTR SS:[ESP+EAX*2+0x54>;Copy DeviceIoControl的OutBuffer
01021448   .894C84 14   MOV   DWORD PTR SS:, E>
0102144C   .40            INC   EAX
0102144D   .3D 00010000   CMP   EAX, 0x100
01021452   .^ 7C EC         JL      SHORT MKssj.01021440
01021454   .8BC5          MOV   EAX, EBP
01021456   .8D4C24 14   LEA   ECX, DWORD PTR SS:   ;Copy后的地址:Addr
0102145A   .895D 00       MOV   DWORD PTR SS:, EBX
0102145D   .E8 CEFBFFFF   CALL    MKssj.01021030                   ;加工Addr数据
01021462   .BF 01000000   MOV   EDI, 0x1
01021467   >56            PUSH    ESI                              ; /hObject
01021468   .FF15 10B00201 CALL    NEAR DWORD PTR DS:    ; \CloseHandle
看API也基本明了,具体API参数如下
0020DC30   01021376/CALL 到 CreateFileA 来自 MKssj.01021370
0020DC34   0020E088|FileName = "\\.\PhysicalDrive0"
0020DC38   C0000000|Access = GENERIC_READ|GENERIC_WRITE
0020DC3C   00000003|ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE
0020DC40   00000000|pSecurity = NULL
0020DC44   00000003|Mode = OPEN_EXISTING
0020DC48   00000000|Attributes = 0
0020DC4C   00000000\hTemplateFile = NULL

0061DF4C   00121431/CALL 到 DeviceIoControl 来自 MKssj.0012142B
0061DF50   00000094|hDevice = 00000094 (window)
0061DF54   0007C088|IoControlCode = SMART_RCV_DRIVE_DATA
0061DF58   0061E384|InBuffer = 0061E384
0061DF5C   00000023|InBufferSize = 23 (35.)
0061DF60   0061E4A8|OutBuffer = 0061E4A8
0061DF64   00000213|OutBufferSize = 213 (531.)
0061DF68   0061DF80|pBytesReturned = 0061DF80
0061DF6C   00000000\pOverlapped = NULL
0102145D处对DeviceIoControl得出信息进行了加工
(这里要注意:如果在虚拟机中DeviceIoControl读取失败则将取"\\.\Scsi0:"值来计算,届时不触及下面的处理函数)
00311030    8B51 28         MOV   EDX, DWORD PTR DS:      ; 以字节组合
00311033    C1EA 08         SHR   EDX, 0x8
00311036    8810            MOV   BYTE PTR DS:, DL
00311038    0FB651 28       MOVZX   EDX, BYTE PTR DS:
0031103C    8850 01         MOV   BYTE PTR DS:, DL
......
003110BF    8B51 4C         MOV   EDX, DWORD PTR DS:
003110C2    8A49 4C         MOV   CL, BYTE PTR DS:
003110C5    C1EA 08         SHR   EDX, 0x8
003110C8    8850 12         MOV   BYTE PTR DS:, DL
003110CB    8848 13         MOV   BYTE PTR DS:, CL      ; 生成磁盘号字符串
003110CE    C640 14 00      MOV   BYTE PTR DS:, 0x0       ; '\x00'截断字符串
003110D2    B9 13000000   MOV   ECX, 0x13
003110D7    803C01 20       /CMP   BYTE PTR DS:, 0x20      ; 从字符串的最后一位依次处理
003110DB    75 09         |JNZ   SHORT MKssj.003110E6             ; 简单的说就是删除字符串后面的空格
003110DD    C60401 00       |MOV   BYTE PTR DS:, 0x0
003110E1    49            |DEC   ECX
003110E2    85C9            |TEST    ECX, ECX
003110E4^ 7F F1         \JG      SHORT MKssj.003110D7
003110E6    C3            RETN

DeviceIoControl_OutBuffer处理函数大致如下

将DeviceIoControl得出并二次处理过的磁盘号字符串MD5运算一次,值再经过一些运算和处理最终生成了机器码,代码见下
import md5
from binascii import hexlify
from string import upper

#为方便运算,变量md5_16故意多设置了一位(首字节无意义可忽略)
md5_16 ='!' + md5.new("   WD-WMC1S4965023").digest()
tempID = {}
machineID = ''

for j in range(1,17):
      tempID= chr(((ord(md5_16) >> 0x4)*3) & 0x8000000F)
      if tempID<=0:
                tempID = chr(ord(tempID) - 1)
                tempID = chr(ord(tempID) | 0xFFFFFFF0)
                tempID = chr(ord(tempID) + 1)
      tempID = upper(hexlify(tempID))
      if ord(tempID)>=0x41:
                tempID = chr(ord(tempID) + 0xA)

      tempID = chr(ord(md5_16) & 0x8000000F)
      if tempID<=0:
                tempID = chr(ord(tempID) - 1)
                tempID = chr(ord(tempID) | 0xFFFFFFF0)
                tempID = chr(ord(tempID) + 1)

      tempID = chr((ord(tempID) * 3) & 0x8000000F)
      if tempID<=0:
                tempID = chr(ord(tempID) - 1)
                tempID = chr(ord(tempID) | 0xFFFFFFF0)
                tempID = chr(ord(tempID) + 1)
      tempID = hexlify(tempID)
      if ord(tempID)>=0x41:
                tempID = chr(ord(tempID) + 0xA)

#最终显示出的机器码共32位,使用"-"均分四段
for j in range(1,33):
    if j in (9,17,25):
      machineID = machineID + '-'
    machineID = machineID +tempID

print u'本机机器码是:%s' % machineID

在题目原帖第二页看到@xiaobai 和@qq54007 提供的一对机器码和注册码
http://www.52pojie.cn/thread-230220-2-1.html
机器码:Om503m10-L7K46494-2n44N8M0-1pO8L8M0
注册码:m5CYe7j3bnsW4NArE8kTA2Se6fbfNmNIKXV4

这下被我们抓住了小辫儿{:301_1000:}
经过前面分析DeviceIoControl_OutBuffer处理函数结尾处生成了磁盘号字符串,而在我的虚拟XP中该字符串为“00000000000000000001”,机器码恰好是Om503m10-L7K46494-2n44N8M0-1pO8L8M0
这就好办了,脱壳后SM主程序强制修改DeviceIoControl_OutBuffer处理函数来PATCH(即强制修改磁盘号字符串为“00000000000000000001”),PATCH前后对比如图
(PATCH的时机可以自己考虑,比如也可以尝试在机器码生成处(断点winmm.timeSetEvent直接定位)直接PATCH机器码)
PATCH前

PATCH后


为了防止DeviceIoControl读取失败导致程序不执行PATCH函数,再做个小修改


PATCH两处代码后无论在哪台电脑运行机器码都是固定的,成功注册——搞定!


查表注册固有缺点就是码表会增加程序体积、码表易受攻击、注册码数量有限(同码表值对应),且防窜改机制显得尤为重要!

本文采用机器码ID的PATCH攻击,而话音刚落@MistHill就放出了码表攻击思路(具体见28楼),@qq54007可以考虑查缺补漏再次加强

代码运算结果截图如下:

夜的静night 发表于 2013-12-28 16:44

膜拜会C++的大牛

小淫仙 发表于 2013-12-28 16:53

膜拜大神

xiaobai 发表于 2013-12-29 00:09

找关键位置的方法学习了,感谢

L4Nce 发表于 2013-12-29 14:27

你好你的分析写的很详细,脱壳其实很简单,他的自校验很失败,他其实本想用内存读取错误来代替ExitProcess,结果报错的时候直接出现错误地址了,定位一下改个跳转就行了(就是你图片的那个)。就能脱了。
他有个致命失误是用了api来比较,所以 比较容易定位关键
最后的比较位置是
004019D3    83C4 10         add esp,0x10
004019D6    83FE 10         cmp esi,0x10
004019D9    8935 DCFA6100   mov dword ptr ds:,esi
004019DF^ 0F8C 2CFFFFFF   jl 123.00401911
004019E5    8B5424 28       mov edx,dword ptr ss:
004019E9    52            push edx
004019EA    8D8424 6C020000 lea eax,dword ptr ss:
004019F1    50            push eax
004019F2    FF15 18B04000   call dword ptr ds:[<&kernel32.lstrcmp>]; kernel32.lstrcmpA;对比了两个md5
004019F8    85C0            test eax,eax
004019FA    0F85 5E010000   jnz 123.00401B5E ;nop进入解码部分
00401A00    F3:             prefix rep:
00401A01    0F7E05 B0EC4000 movd dword ptr ds:,mm0
00401A08    8A4424 11       mov al,byte ptr ss:
00401A0C    3C 61         cmp al,0x61
00401A0E    66:0FD6         ???                                    ; 未知命令
00401A11    05 C0EC4000   add eax,123.0040ECC0
00401A16    F3:             prefix rep:
00401A17    0F7E05 B8EC4000 movd dword ptr ds:,mm0
00401A1E    66:0FD6         ???                                    ; 未知命令
00401A21    05 C8EC4000   add eax,123.0040ECC8
00401A26    0FBED0          movsx edx,al
00401A29    7E 05         jle X123.00401A30
00401A2B    83EA 57         sub edx,0x57
00401A2E    EB 0C         jmp X123.00401A3C
00401A30    3C 41         cmp al,0x41

看代码应该是加了花,我并没发现的你分析里有着一段,MD5校验前的数值应该是来解码的。
接下来就是解码的过程。而且是不断的解码。我估计是用来防止爆破的。
0102FB54   00000009
0102FB58   00000009
0102FB5C   00000009
应该是循环的次数
你把那个跳nop之后
004019FA    0F85 5E010000   jnz 123.00401B5E
会不断的去解码,结果就变成了乱码。

当然也许要是真码的话,是解码多次出来的。不清楚
结过凑了一个值123123再在那个位置修改标志,而不是nop就是说解码一次,尼玛就恭喜了。
这个cm要写注册机,完全分析很耗体力,果然挡住破解就是耗cracker体力的办法。



playboysen 发表于 2013-12-29 17:53

本帖最后由 playboysen 于 2013-12-29 18:59 编辑

L4Nce 发表于 2013-12-29 14:27 static/image/common/back.gif
你好你的分析写的很详细,脱壳其实很简单,他的自校验很失败,他其实本想用内存读取错误来代替ExitProcess, ...
L4Nce这一刀补的很及时!

关于脱壳,我想说的是64位系统真的不适合调试!!!坑死哥了!
本机Win7 X64脱壳N次IAT修复总是错误,手工修复也不行害得我每次都要带壳调试⊙﹏⊙b

关于爆破,直接NOP跳转肯定不行毕竟这是个解码程序
不过就算将解码次数修改为1次,想要凑出“恭喜”对应的明文注册码也不容易
考虑下出篇破文吧

qq54007 发表于 2013-12-29 18:24

L4Nce 发表于 2013-12-29 14:27 static/image/common/back.gif
你好你的分析写的很详细,脱壳其实很简单,他的自校验很失败,他其实本想用内存读取错误来代替ExitProcess, ...

完整的字符串因该是:“恭喜你注册成功”,字串加密这里只是简单的异或加密,所以很容易穷举破解(以后会考虑其他算法),如果再细心一点,可以发现加密的位置就在程序初始化的时候(考虑程序的可解性),程序之所以多次验证(4096次),是为了找到注册码中正确的解码因子,以及让验证代码数量大于破解者可以接受的单步跟踪次数。最阴险的暗桩在于检测调试器到后并不报警,而是悄悄的再一次加密关键代码,以至于即使注册码正确,依然无法正确解密。程序并没有加花,自校验也如你所说,在xp下直接暴漏关键位置(在win7下只显示程序停止)。如果程序关键加密部分分析的清楚,爆破起来还是挺容易的,并没有太多的暗桩。

qq54007 发表于 2013-12-29 18:29

playboysen 发表于 2013-12-29 17:53 static/image/common/back.gif
L4Nce这一刀补的很及时!

不过关于脱壳能否说的再详细点?


应该是你系统的问题吧,脱壳就正常脱即可,只有一处自校验而已。
关于你的4个方案,第3个事最靠谱的、最无敌的,不过得首先得有一套正确的机器码和注册码。
分析的很好,只有解码那里差了一点点。十分佩服。

playboysen 发表于 2013-12-29 18:51

本帖最后由 playboysen 于 2013-12-29 23:38 编辑

qq54007 发表于 2013-12-29 18:29 static/image/common/back.gif
应该是你系统的问题吧,脱壳就正常脱即可,只有一处自校验而已。
关于你的4个方案,第3个事最靠谱的、最 ...
Win7 X64害死人了{:301_995:}
以后调试还是要建个XP虚拟机才行

因为考虑算法不可逆性,也懒得耗费大量精力关注解码部分
你提到的那个“最阴险的暗桩”确实效果非凡,折腾了几次都不正确我都想干脆放弃了⊙﹏⊙b

qq54007 发表于 2013-12-29 19:40

playboysen 发表于 2013-12-29 18:51 static/image/common/back.gif
Win7 X64害死人了
以后调试还是要建个XP虚拟机才行


凡是调用CopyMemory函数,代码都被编译成这个模样,应该是因为这个函数是个内联函数?最有效率的执行方式就是这样?

页: [1] 2 3 4 5
查看完整版本: 【吾爱2013CM大赛解答】-- MK的杀手锏 算法分析+PATCH一码复用(复杂)