飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 9215|回复: 27

[原创] Nisy's Second CrackMe 简单分析

  [复制链接]
  • TA的每日心情
    开心
    2015-8-2 16:07
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-11-24 11:16:56 | 显示全部楼层 |阅读模式
    本帖最后由 F8LEFT 于 2014-11-24 11:15 编辑

           2014PYG10周年庆典,Nisy校长发了个异常强大的cm,我是菜鸟一个,不过在机缘巧合之下还是弄出来了,发一下分析,来加深印象。这个cm的想法还是挺不错的。
           简单的东西就不多提了。我直接用一组key来进行讲解:
    Name:F8LEFT
    Pass   :   NS-oZQe7Eru-8EE8
          切入算法流程可以直接使用GetWindowTextW断点,直接在命令行进行bpx GetWindowTextW就可以同时在两个验证段断下了。然后单步跟踪。
          进入第一步验证,除去基础长度判断后,会来到下面一个小buff
    1. 0040E43E  |.  50            PUSH    EAX                                     ;  Push Pass
    2. 0040E43F  |.  8D85 D0FBFFFF LEA     EAX, [LOCAL.268]
    3. 0040E445  |.  50            PUSH    EAX                                     ;  Push Name
    4. 0040E446  |.  8D45 FC       LEA     EAX, [LOCAL.1]
    5. 0040E449  |.  8038 00       CMP     BYTE PTR DS:[EAX], 0x0                  ;  [eax] = 0
    6. 0040E44C  |.  75 05         JNZ     SHORT NsCrackM.0040E453
    7. 0040E44E  |.  8B00          MOV     EAX, DWORD PTR DS:[EAX]                 ;  Err1
    8. 0040E450  |.  C600 CC       MOV     BYTE PTR DS:[EAX], 0xCC                 ;  Err2
    9. 0040E453  |>  FF10          CALL    NEAR DWORD PTR DS:[EAX]                 ;  --> Func (In SEH)
    复制代码
          这里入栈了 Pass 与 Name ,没啥的,关键是下面:
    CMP     BYTE PTR DS:[EAX], 0x0                  ;  [eax] = 0
    JNZ     SHORT NsCrackM.0040E453
    MOV     EAX, DWORD PTR DS:[EAX]                 ;  Err1
    MOV     BYTE PTR DS:[EAX], 0xCC                 ;  Err2
    ---------------------------->--------------------------->--------------------------->
         cmp [eax],0    => jnz XXXXXXXX,  这里保证了[eax]里面的值是0,也即 BYTE: [eax] = 0

         MOV     EAX, DWORD :[EAX], 这里取了[EAX],于是,EAX = 0
         那么问题就来了,下一句
         MOV     BYTE PTR DS:[EAX], 0xCC , 此时EAX = 0,这就相当于 MOV DS:[0], 0xCC,显然是无法进行的。因此,程序到了这里,便会产生异常。
         既然有异常,那么就自然可以想到异常处理函数,直接查看OD的SEH链窗体,可以看到以下几个异常处理函数:


        只要一个函数是属于程序段的,这个便是处理函数了,可以在这个函数上面下个断点,接着F9,便会停在004127C0处,此时便可以进行下一步的跟踪了(不过,暂时用不上)。这时候可以再一次F9,因为前面下了GetWindowTextW断点,此时会停留在第二段验证处。0040DAB0
        跟踪下去就是第一段比较了:
    1. 0040DB7A   .  50            PUSH    EAX                                     ;  Push Name
    2. 0040DB7B   .  8D4D E4       LEA     ECX, DWORD PTR SS:[EBP-0x1C]
    3. 0040DB7E   .  E8 BD6FFFFF   CALL    <NsCrackM.N_Strcpy>
    4. 0040DB83   .  8D8D D0FDFFFF LEA     ECX, DWORD PTR SS:[EBP-0x230]
    5. 0040DB89   .  51            PUSH    ECX                                     ;  Push Pass
    6. 0040DB8A   .  8D8D C8FDFFFF LEA     ECX, DWORD PTR SS:[EBP-0x238]
    7. 0040DB90   .  E8 AB6FFFFF   CALL    <NsCrackM.N_Strcpy>
    8. 0040DB95   .  C745 FC 01000>MOV     DWORD PTR SS:[EBP-0x4], 0x1
    9. 0040DB9C   .  BA 4E000000   MOV     EDX, 0x4E                               ;  N
    10. 0040DBA1   .  66:8995 B0FBF>MOV     WORD PTR SS:[EBP-0x450], DX
    11. 0040DBA8   .  B8 53000000   MOV     EAX, 0x53
    12. 0040DBAD   .  66:8985 B2FBF>MOV     WORD PTR SS:[EBP-0x44E], AX             ;  S
    13. 0040DBB4   .  33C9          XOR     ECX, ECX
    14. 0040DBB6   .  66:898D B4FBF>MOV     WORD PTR SS:[EBP-0x44C], CX             ;  创建字符串 NS
    15. 0040DBBD   .  8D8D C8FDFFFF LEA     ECX, DWORD PTR SS:[EBP-0x238]           ;  Pass
    16. 0040DBC3   .  E8 F893FFFF   CALL    <NsCrackM.N_Strlen>                     ;  求密码长度
    17. 0040DBC8   .  83F8 03       CMP     EAX, 0x3                                ;  长度>=3
    18. 0040DBCB   .  7C 39         JL      SHORT NsCrackM.0040DC06
    19. 0040DBCD   .  8D95 B0FBFFFF LEA     EDX, DWORD PTR SS:[EBP-0x450]
    20. 0040DBD3   .  52            PUSH    EDX
    21. 0040DBD4   .  6A 02         PUSH    0x2                                     ;  长度为2
    22. 0040DBD6   .  8D85 94FBFFFF LEA     EAX, DWORD PTR SS:[EBP-0x46C]
    23. 0040DBDC   .  50            PUSH    EAX
    24. 0040DBDD   .  8D8D C8FDFFFF LEA     ECX, DWORD PTR SS:[EBP-0x238]
    25. 0040DBE3   .  E8 380A0000   CALL    <NsCrackM.N_StrSub>                     ;  取Pass的子窜,这里是取头两个字符
    26. 0040DBE8   .  838D 80FBFFFF>OR      DWORD PTR SS:[EBP-0x480], 0x1
    27. 0040DBEF   .  8BC8          MOV     ECX, EAX
    28. 0040DBF1   .  E8 6A090000   CALL    <NsCrackM.N_Strcmp?>                    ;  与前面创建的字符串NS比较
    复制代码
           这里可以知道密码的前2个字符为NS。再继续跟踪。
    1. 0040DC44   .  8B0D 90664200 MOV     ECX, DWORD PTR DS:[0x426690]            ;  [426690] = 0
    2. 0040DC4A   .  C701 01000000 MOV     DWORD PTR DS:[ECX], 0x1                 ;  SEH => 2
    复制代码
           喜闻乐见+丧心病狂,这里又一次触发了SEH异常,函数函数哪一个,下好断点,然后F9吧。
            断在异常处理函数后F8跟踪,注意大致的浏览一下每一个字call,此时可以定位到一个非常可疑的Call中:
    1. 00412927  |.  E8 A5030000   CALL    NsCrackM.00412CD1                       ;  In (函数分派) ECX = 跳转目标地址
    复制代码
          这个Call的里面是这样的。:
    1. 00412CD1   nbsp; 8BEA          MOV     EBP, EDX
    2. 00412CD3   .  8BF1          MOV     ESI, ECX                                ;  复制跳转地址
    3. 00412CD5   .  8BC1          MOV     EAX, ECX                                ;  取跳转地址
    4. 00412CD7   .  6A 01         PUSH    0x1
    5. 00412CD9   .  E8 B74A0000   CALL    NsCrackM.00417795
    6. 00412CDE   .  33C0          XOR     EAX, EAX                                ;  NsCrackM.0040DC62
    7. 00412CE0   .  33DB          XOR     EBX, EBX
    8. 00412CE2   .  33C9          XOR     ECX, ECX
    9. 00412CE4   .  33D2          XOR     EDX, EDX
    10. 00412CE6   .  33FF          XOR     EDI, EDI
    11. 00412CE8   .  FFE6          JMP     NEAR ESI                                ;  jmp Func
    复制代码
        清空了一下寄存器的内容,紧接着就直接跳走了,这个显然是人为用汇编代码写上去的,非常的可疑。实际上这里是非常重要的函数分配段,后面还有一次验证会用到这里,下好断点了,然后jmp ESI,跳到相应的处理段中。来到第3段验证:0040DC62
    1. 0040DC62   .  8B65 E8       MOV     ESP, DWORD PTR SS:[EBP-0x18]            ;  3
    2. 0040DC65   .  8D95 D0FDFFFF LEA     EDX, DWORD PTR SS:[EBP-0x230]
    3. 0040DC6B   .  52            PUSH    EDX
    4. 0040DC6C   .  8D8D ACFBFFFF LEA     ECX, DWORD PTR SS:[EBP-0x454]
    5. 0040DC72   .  E8 C96CFFFF   CALL    <NsCrackM.N_Strcpy>                     ;  复制Pass
    6. 0040DC77   .  8D8D A8FBFFFF LEA     ECX, DWORD PTR SS:[EBP-0x458]
    7. 0040DC7D   .  E8 CE92FFFF   CALL    NsCrackM.00406F50
    8. 0040DC82   .  8D8D ACFBFFFF LEA     ECX, DWORD PTR SS:[EBP-0x454]           ;  Pass
    9. 0040DC88   .  E8 3393FFFF   CALL    <NsCrackM.N_Strlen>                     ;  PassLen
    10. 0040DC8D   .  83F8 03       CMP     EAX, 0x3
    11. 0040DC90   .  0F8E 2D010000 JLE     NsCrackM.0040DDC3
    12. 0040DC96   .  6A 2D         PUSH    0x2D                                    ;  0x2D = "-"
    13. 0040DC98   .  8D8D ACFBFFFF LEA     ECX, DWORD PTR SS:[EBP-0x454]           ;  Pass
    14. 0040DC9E   .  E8 6D0A0000   CALL    <NsCrackM.N_StrIndex>                   ;  取-在Pass中的第一个位置
    15. 0040DCA3   .  8985 A0FBFFFF MOV     DWORD PTR SS:[EBP-0x460], EAX
    16. 0040DCA9   .  8B85 A0FBFFFF MOV     EAX, DWORD PTR SS:[EBP-0x460]
    17. 0040DCAF   .  83C0 01       ADD     EAX, 0x1
    18. 0040DCB2   .  50            PUSH    EAX
    19. 0040DCB3   .  6A 2D         PUSH    0x2D
    20. 0040DCB5   .  8D8D ACFBFFFF LEA     ECX, DWORD PTR SS:[EBP-0x454]
    21. 0040DCBB   .  E8 C00A0000   CALL    <NsCrackM.IndexOfStr>                   ;  取第二个-在Pass的位置
    22. 0040DCC0   .  8985 A4FBFFFF MOV     DWORD PTR SS:[EBP-0x45C], EAX
    23. 0040DCC6   .  8B8D A4FBFFFF MOV     ECX, DWORD PTR SS:[EBP-0x45C]           ;  Len
    24. 0040DCCC   .  2B8D A0FBFFFF SUB     ECX, DWORD PTR SS:[EBP-0x460]           ;  -2
    25. 0040DCD2   .  83E9 01       SUB     ECX, 0x1                                ;  -1(-3)
    26. 0040DCD5   .  51            PUSH    ECX                                     ;  第二个-位置
    27. 0040DCD6   .  8B95 A0FBFFFF MOV     EDX, DWORD PTR SS:[EBP-0x460]
    28. 0040DCDC   .  83C2 01       ADD     EDX, 0x1
    29. 0040DCDF   .  52            PUSH    EDX                                     ;  第一个-位置
    30. 0040DCE0   .  8D85 90FBFFFF LEA     EAX, DWORD PTR SS:[EBP-0x470]
    31. 0040DCE6   .  50            PUSH    EAX
    32. 0040DCE7   .  8D8D ACFBFFFF LEA     ECX, DWORD PTR SS:[EBP-0x454]
    33. 0040DCED   .  E8 8E080000   CALL    <NsCrackM.N_SubStr>                     ;  Pass取两个-中间的字符串
    34. 0040DCF2   .  8B08          MOV     ECX, DWORD PTR DS:[EAX]
    35. 0040DCF4   .  51            PUSH    ECX
    36. 0040DCF5   .  8B95 A4FBFFFF MOV     EDX, DWORD PTR SS:[EBP-0x45C]
    37. 0040DCFB   .  52            PUSH    EDX
    38. 0040DCFC   .  8B85 A0FBFFFF MOV     EAX, DWORD PTR SS:[EBP-0x460]
    39. 0040DD02   .  50            PUSH    EAX
    40. 0040DD03   .  68 9C0C4200   PUSH    NsCrackM.00420C9C                       ;  %d %d %s
    41. 0040DD08   .  8D8D A8FBFFFF LEA     ECX, DWORD PTR SS:[EBP-0x458]
    42. 0040DD0E   .  51            PUSH    ECX
    43. 0040DD0F   .  E8 DC0A0000   CALL    NsCrackM.0040E7F0                       ;  (格式化字符串)第一个-位置 第二个-位置 两个-中间的字符串
    44. 0040DD14   .  83C4 14       ADD     ESP, 0x14
    45. 0040DD17   .  8D8D 90FBFFFF LEA     ECX, DWORD PTR SS:[EBP-0x470]
    46. 0040DD1D   .  E8 7E70FFFF   CALL    <NsCrackM.ToString>
    47. 0040DD22   .  8B95 A4FBFFFF MOV     EDX, DWORD PTR SS:[EBP-0x45C]
    48. 0040DD28   .  3B95 A0FBFFFF CMP     EDX, DWORD PTR SS:[EBP-0x460]
    49. 0040DD2E      0F8E 8F000000 JLE     NsCrackM.0040DDC3
    50. 0040DD34   .  8B85 A4FBFFFF MOV     EAX, DWORD PTR SS:[EBP-0x45C]           ;  同上
    51. 0040DD3A   .  2B85 A0FBFFFF SUB     EAX, DWORD PTR SS:[EBP-0x460]
    52. 0040DD40   .  83E8 01       SUB     EAX, 0x1
    53. 0040DD43   .  50            PUSH    EAX
    54. 0040DD44   .  8B8D A0FBFFFF MOV     ECX, DWORD PTR SS:[EBP-0x460]
    55. 0040DD4A   .  83C1 01       ADD     ECX, 0x1
    56. 0040DD4D   .  51            PUSH    ECX
    57. 0040DD4E   .  8D95 8CFBFFFF LEA     EDX, DWORD PTR SS:[EBP-0x474]
    58. 0040DD54   .  52            PUSH    EDX
    59. 0040DD55   .  8D8D ACFBFFFF LEA     ECX, DWORD PTR SS:[EBP-0x454]
    60. 0040DD5B   .  E8 20080000   CALL    <NsCrackM.N_SubStr>                     ;  继续取两个-中间的字符串
    61. 0040DD60   .  50            PUSH    EAX
    62. 0040DD61   .  8D8D A8FBFFFF LEA     ECX, DWORD PTR SS:[EBP-0x458]
    63. 0040DD67   .  E8 44B4FFFF   CALL    NsCrackM.004091B0
    64. 0040DD6C   .  8D8D 8CFBFFFF LEA     ECX, DWORD PTR SS:[EBP-0x474]           ;  取中间的字符串
    65. 0040DD72   .  E8 2970FFFF   CALL    <NsCrackM.ToString>
    66. 0040DD77   .  8D85 A8FBFFFF LEA     EAX, DWORD PTR SS:[EBP-0x458]
    67. 0040DD7D   .  50            PUSH    EAX                                     ;  str2
    68. 0040DD7E   .  8D8D 88FBFFFF LEA     ECX, DWORD PTR SS:[EBP-0x478]
    69. 0040DD84   .  51            PUSH    ECX                                     ;  str2
    70. 0040DD85   .  E8 A689FFFF   CALL    NsCrackM.00406730                       ;  进行某种变换
    71. 0040DD8A   .  83C4 08       ADD     ESP, 0x8
    72. 0040DD8D   .  50            PUSH    EAX
    73. 0040DD8E   .  8D8D A8FBFFFF LEA     ECX, DWORD PTR SS:[EBP-0x458]
    74. 0040DD94   .  E8 17B4FFFF   CALL    NsCrackM.004091B0
    75. 0040DD99   .  8D8D 88FBFFFF LEA     ECX, DWORD PTR SS:[EBP-0x478]
    76. 0040DD9F   .  E8 FC6FFFFF   CALL    <NsCrackM.ToString>
    77. 0040DDA4   .  8D95 B8FBFFFF LEA     EDX, DWORD PTR SS:[EBP-0x448]
    78. 0040DDAA   .  52            PUSH    EDX                                     ;  Push Name
    79. 0040DDAB   .  8D8D A8FBFFFF LEA     ECX, DWORD PTR SS:[EBP-0x458]
    80. 0040DDB1   .  E8 AA070000   CALL    <NsCrackM.N_Strcmp?>                    ;  与用户名比较
    复制代码
          代码虽然比较长,但实际上就做了几件事。首先,用-分割Pass为3段,然后取中间的那一段,进行某种变换,并把变换结果与用户名比较。所以,我们得知Pass的大致结构如下:
    NS-Code(Name)-Str3
           这里先不管加密方式,继续跟踪下去:
           下面几步F8后,达到一个call
    1. 0040DDE7   .  E8 05000000   CALL    NsCrackM.0040DDF1                       ;  OneCheck F7进去
    复制代码
         F7跟踪进去:
    1. 0040DDF1  /nbsp; 6A 02         PUSH    0x2
    2. 0040DDF3  |.  8D8D C8FDFFFF LEA     ECX, [LOCAL.142]
    3. 0040DDF9  |.  E8 E2060000   CALL    NsCrackM.0040E4E0                       ;  取Pass[2]
    4. 0040DDFE  |.  0FB7C0        MOVZX   EAX, AX
    5. 0040DE01  |.  83F8 2D       CMP     EAX, 0x2D                               ;  Pass[2] = 0x2D('-')
    6. 0040DE04      75 77         JNZ     SHORT NsCrackM.0040DE7D
    7. 0040DE06  |.  83BD CCFDFFFF>CMP     [LOCAL.141], 0x1                        ;  bool
    8. 0040DE0D  |.  75 6E         JNZ     SHORT NsCrackM.0040DE7D
    9. 0040DE0F  |.  8D4D E4       LEA     ECX, [LOCAL.7]
    10. 0040DE12  |.  51            PUSH    ECX
    11. 0040DE13  |.  8D8D 9CFBFFFF LEA     ECX, [LOCAL.281]
    12. 0040DE19  |.  E8 5291FFFF   CALL    NsCrackM.00406F70                       ;  Name
    13. 0040DE1E  |.  68 B00C4200   PUSH    NsCrackM.00420CB0                       ;  -
    14. 0040DE23  |.  8D8D 9CFBFFFF LEA     ECX, [LOCAL.281]
    15. 0040DE29  |.  E8 02070000   CALL    NsCrackM.0040E530
    16. 0040DE2E  |.  8D95 C8FDFFFF LEA     EDX, [LOCAL.142]
    17. 0040DE34  |.  52            PUSH    EDX
    18. 0040DE35  |.  8D8D 9CFBFFFF LEA     ECX, [LOCAL.281]                        ;  Pass
    19. 0040DE3B  |.  E8 C0060000   CALL    NsCrackM.0040E500
    20. 0040DE40  |.  8D8D 9CFBFFFF LEA     ECX, [LOCAL.281]
    21. 0040DE46  |.  E8 E573FFFF   CALL    <NsCrackM.*p>                           ;  用 - 链接Name与Pass
    22. 0040DE4B  |.  50            PUSH    EAX
    23. 0040DE4C  |.  68 04010000   PUSH    0x104
    24. 0040DE51  |.  68 A0664200   PUSH    NsCrackM.004266A0
    25. 0040DE56  |.  E8 35060000   CALL    NsCrackM.0040E490
    26. 0040DE5B  |.  6A 00         PUSH    0x0                                     ; /lParam = 0x0
    27. 0040DE5D  |.  6A 00         PUSH    0x0                                     ; |wParam = 0x0
    28. 0040DE5F  |.  A1 AC684200   MOV     EAX, DWORD PTR DS:[0x4268AC]            ; |
    29. 0040DE64  |.  50            PUSH    EAX                                     ; |Message => MSG(0xC1A3)
    30. 0040DE65  |.  8B0D B0684200 MOV     ECX, DWORD PTR DS:[0x4268B0]            ; |
    31. 0040DE6B  |.  51            PUSH    ECX                                     ; |hWnd => 0xB02A6
    32. 0040DE6C  |.  FF15 B0014200 CALL    NEAR DWORD PTR DS:[<&USER32.PostMessage>; \PostMessageW
    33. 0040DE72  |.  8D8D 9CFBFFFF LEA     ECX, [LOCAL.281]
    34. 0040DE78  |.  E8 236FFFFF   CALL    <NsCrackM.ToString>
    35. 0040DE7D  \>  C3            RETN
    复制代码
         这里发送了一个我们不知道的消息,显然这个消息是Nisy校长自己定义的。跟踪之下,会发现是发给主窗体的,于是,需要在主窗体相应的Msg处理的地方下一个断点,才能继续跟踪。
          在0040DE5F处,右键,查找参考,地址常量,找到一处  CMP     EDX, DWORD PTR DS:[0x4268AC], (00407441) 可以快速的到底处理的地方,在 CMP...JNZ...的下面下个int3断点,F9运行,便会断下来。到底第4处验证(真多。。。。)
         这里用F7跟踪,进入一个CALL后,便会看到希望了。

        紧接着马上对这个字符串进行某种变换得到: 恭喜,注册成功!@>---    (Nice!!!!)
         然后继续初始化另外一个字符串: EOo&xA^W
         变换后得到:恭喜!
         Good Job!!于是,这里就成功了吗?不是的,必须得再留心一下,前面的Pass还有第三段没有进行验证呢!肯定还有下一个验证点!慢慢跟踪下去,会发现一个非常典型的跳转:
    1. 004079DD  |.  E8 CE660000   CALL    NsCrackM.0040E0B0                       ;  4
    2. 004079E2  |.  85C0          TEST    EAX, EAX
    3. 004079E4      74 27         JE      SHORT NsCrackM.00407A0D
    复制代码
         这个CALL便是最后一段验证,下面的JE Nop掉就直接成功了,当然,我们继续跟进这个call,看一下它做了什么。
          这个call便是处理Pass第三段的验证段。
    1. 0040E0B0   $  55            PUSH    EBP
    2. 0040E0B1   .  8BEC          MOV     EBP, ESP
    3. 0040E0B3   .  6A FE         PUSH    -0x2
    4. 0040E0B5   .  68 48354200   PUSH    NsCrackM.00423548
    5. 0040E0BA   .  68 C0274100   PUSH    NsCrackM.004127C0
    6. 0040E0BF   .  64:A1 0000000>MOV     EAX, DWORD PTR FS:[0]
    7. 0040E0C5   .  50            PUSH    EAX
    8. 0040E0C6   .  83C4 C0       ADD     ESP, -0x40
    9. 0040E0C9   .  53            PUSH    EBX
    10. 0040E0CA   .  56            PUSH    ESI
    11. 0040E0CB   .  57            PUSH    EDI
    12. 0040E0CC   .  A1 74534200   MOV     EAX, DWORD PTR DS:[0x425374]
    13. 0040E0D1   .  3145 F8       XOR     DWORD PTR SS:[EBP-0x8], EAX
    14. 0040E0D4   .  33C5          XOR     EAX, EBP
    15. 0040E0D6   .  50            PUSH    EAX
    16. 0040E0D7   .  8D45 F0       LEA     EAX, DWORD PTR SS:[EBP-0x10]
    17. 0040E0DA   .  64:A3 0000000>MOV     DWORD PTR FS:[0], EAX
    18. 0040E0E0   .  8965 E8       MOV     DWORD PTR SS:[EBP-0x18], ESP
    19. 0040E0E3   .  C745 DC 00000>MOV     DWORD PTR SS:[EBP-0x24], 0x0
    20. 0040E0EA   .  C745 D4 00000>MOV     DWORD PTR SS:[EBP-0x2C], 0x0
    21. 0040E0F1   .  C745 E0 00000>MOV     DWORD PTR SS:[EBP-0x20], 0x0     ;  取前面链接的 Name-Pass
    22. 0040E0F8   .  68 A0664200   PUSH    NsCrackM.004266A0                ;  F8LEFT-NS-oZQe7Eru-8EE8
    23. 0040E0FD   .  8D4D E4       LEA     ECX, DWORD PTR SS:[EBP-0x1C]
    24. 0040E100   .  E8 3B68FFFF   CALL    <NsCrackM.N_Strcpy>
    25. 0040E105   .  8D4D D8       LEA     ECX, DWORD PTR SS:[EBP-0x28]
    26. 0040E108   .  E8 438EFFFF   CALL    NsCrackM.00406F50
    27. 0040E10D   .  C745 FC 00000>MOV     DWORD PTR SS:[EBP-0x4], 0x0
    28. 0040E114   .  C745 FC 01000>MOV     DWORD PTR SS:[EBP-0x4], 0x1
    29. 0040E11B   .  8D4D E4       LEA     ECX, DWORD PTR SS:[EBP-0x1C]
    30. 0040E11E   .  E8 9D8EFFFF   CALL    <NsCrackM.N_Strlen>              ;  buffLen
    31. 0040E123   .  85C0          TEST    EAX, EAX                         ;  判断长度是否为0
    32. 0040E125   .  75 05         JNZ     SHORT NsCrackM.0040E12C
    33. 0040E127   .  E9 AB000000   JMP     NsCrackM.0040E1D7
    34. 0040E12C   >  68 08020000   PUSH    0x208
    35. 0040E131   .  6A 00         PUSH    0x0
    36. 0040E133   .  68 A0664200   PUSH    NsCrackM.004266A0
    37. 0040E138   .  E8 23400000   CALL    <NsCrackM.memset?>               ;  清除空间
    38. 0040E13D   .  83C4 0C       ADD     ESP, 0xC
    39. 0040E140   .  6A 2D         PUSH    0x2D                             ;  '-'
    40. 0040E142   .  8D4D E4       LEA     ECX, DWORD PTR SS:[EBP-0x1C]     ;  Name-Pass链接
    41. 0040E145   .  E8 E6050000   CALL    <NsCrackM.StrLastIndex>          ;  取最后一个-的位置
    42. 0040E14A   .  8945 D0       MOV     DWORD PTR SS:[EBP-0x30], EAX
    43. 0040E14D   .  8B45 D0       MOV     EAX, DWORD PTR SS:[EBP-0x30]
    44. 0040E150   .  50            PUSH    EAX
    45. 0040E151   .  8D4D CC       LEA     ECX, DWORD PTR SS:[EBP-0x34]
    46. 0040E154   .  51            PUSH    ECX
    47. 0040E155   .  8D4D E4       LEA     ECX, DWORD PTR SS:[EBP-0x1C]
    48. 0040E158   .  E8 C3040000   CALL    <NsCrackM.N_StrSub>              ;  取最后一个-前面的所有数据
    49. 0040E15D   .  51            PUSH    ECX                              ;  F8LEFT-NS-oZQe7Eru
    50. 0040E15E   .  8BCC          MOV     ECX, ESP
    51. 0040E160   .  8D55 CC       LEA     EDX, DWORD PTR SS:[EBP-0x34]
    52. 0040E163   .  52            PUSH    EDX
    53. 0040E164   .  E8 078EFFFF   CALL    NsCrackM.00406F70                ;  利用上面取出的字符串
    54. 0040E169   .  E8 8287FFFF   CALL    NsCrackM.004068F0                ;  计算出加密key (DWORD)
    55. 0040E16E   .  83C4 04       ADD     ESP, 0x4
    56. 0040E171   .  8945 E0       MOV     DWORD PTR SS:[EBP-0x20], EAX     ;  保存DWORD
    57. 0040E174   .  8D4D E4       LEA     ECX, DWORD PTR SS:[EBP-0x1C]
    58. 0040E177   .  E8 448EFFFF   CALL    <NsCrackM.N_Strlen>
    59. 0040E17C   .  2B45 D0       SUB     EAX, DWORD PTR SS:[EBP-0x30]
    60. 0040E17F   .  83E8 01       SUB     EAX, 0x1
    61. 0040E182   .  50            PUSH    EAX
    62. 0040E183   .  8D45 C0       LEA     EAX, DWORD PTR SS:[EBP-0x40]
    63. 0040E186   .  50            PUSH    EAX
    64. 0040E187   .  8D4D E4       LEA     ECX, DWORD PTR SS:[EBP-0x1C]
    65. 0040E18A   .  E8 01050000   CALL    NsCrackM.0040E690                ;  取Pass的最后的一个buff
    66. 0040E18F   .  50            PUSH    EAX
    67. 0040E190   .  8D4D D8       LEA     ECX, DWORD PTR SS:[EBP-0x28]
    68. 0040E193   .  E8 18B0FFFF   CALL    NsCrackM.004091B0
    69. 0040E198   .  8D4D C0       LEA     ECX, DWORD PTR SS:[EBP-0x40]
    70. 0040E19B   .  E8 006CFFFF   CALL    <NsCrackM.ToString>
    71. 0040E1A0   .  8D4D D8       LEA     ECX, DWORD PTR SS:[EBP-0x28]
    72. 0040E1A3   .  E8 188EFFFF   CALL    <NsCrackM.N_Strlen>              ;  取长度,与4比较
    73. 0040E1A8   .  83F8 04       CMP     EAX, 0x4
    74. 0040E1AB   .  74 02         JE      SHORT NsCrackM.0040E1AF
    75. 0040E1AD   .  EB 28         JMP     SHORT NsCrackM.0040E1D7
    76. 0040E1AF   >  8D4D D8       LEA     ECX, DWORD PTR SS:[EBP-0x28]
    77. 0040E1B2   .  E8 098EFFFF   CALL    <NsCrackM.N_Strlen>
    78. 0040E1B7   .  83F8 04       CMP     EAX, 0x4
    79. 0040E1BA   .  75 13         JNZ     SHORT NsCrackM.0040E1CF
    80. 0040E1BC   .  C745 D4 01000>MOV     DWORD PTR SS:[EBP-0x2C], 0x1     ;  bool Continue = 1
    81. 0040E1C3   .  8B0D 90664200 MOV     ECX, DWORD PTR DS:[0x426690]     ;  ECX = 0
    82. 0040E1C9   .  C701 01000000 MOV     DWORD PTR DS:[ECX], 0x1          ;  Err3 (To SEH)
    复制代码
         处理了一下用户名与密码,计算出一个加密key,判断Pass的最后一段长度是否为4,是的话就触发新的异常。异常处理函数还是哪一个,就连分配的地点也是一样的。这下知道了我前面下分配函数的那个断点的作用了吧。慢慢跟踪下去,来到最后一段验证: 0040E1E9
         
    1. 0040E1E9   .  8B65 E8       MOV     ESP, DWORD PTR SS:[EBP-0x18]
    2. 0040E1EC   .  837D D4 00    CMP     DWORD PTR SS:[EBP-0x2C], 0x0     ;  if bool = 0?
    3. 0040E1F0   .  74 74         JE      SHORT NsCrackM.0040E266
    4. 0040E1F2   .  51            PUSH    ECX
    5. 0040E1F3   .  8BCC          MOV     ECX, ESP
    6. 0040E1F5   .  8D55 D8       LEA     EDX, DWORD PTR SS:[EBP-0x28]
    7. 0040E1F8   .  52            PUSH    EDX
    8. 0040E1F9   .  E8 728DFFFF   CALL    NsCrackM.00406F70                ;  取Pass最后一段
    9. 0040E1FE   .  E8 1D88FFFF   CALL    <NsCrackM.atoi>                  ;  Str 转换 为 DWORD = Temp
    10. 0040E203   .  83C4 04       ADD     ESP, 0x4
    11. 0040E206   .  8945 C8       MOV     DWORD PTR SS:[EBP-0x38], EAX
    12. 0040E209   .  8B45 E0       MOV     EAX, DWORD PTR SS:[EBP-0x20]     ;  取出刚才算出的key
    13. 0040E20C   .  25 0000FFFF   AND     EAX, 0xFFFF0000
    14. 0040E211      C1E8 10       SHR     EAX, 0x10                        ;  a = (key & 0xFFFF0000) >> 10
    15. 0040E214   .  8B4D E0       MOV     ECX, DWORD PTR SS:[EBP-0x20]
    16. 0040E217   .  81E1 FFFF0000 AND     ECX, 0xFFFF                      ;  b = key & 0x0000FFFF
    17. 0040E21D   .  33C1          XOR     EAX, ECX                         ;  c = a ^ b, 也就是key高地位异或
    18. 0040E21F   .  8945 E0       MOV     DWORD PTR SS:[EBP-0x20], EAX
    19. 0040E222   .  8B55 C8       MOV     EDX, DWORD PTR SS:[EBP-0x38]
    20. 0040E225   .  0355 E0       ADD     EDX, DWORD PTR SS:[EBP-0x20]     ;  d = Temp + c
    21. 0040E228   .  33C0          XOR     EAX, EAX
    22. 0040E22A   .  81FA 00000100 CMP     EDX, 0x10000                     ;  cmp d, 0x10000
    23. 0040E230   .  0F94C0        SETE    AL                               ;  Set Flag
    复制代码
          这下终于弄完大致的流程了,终结一下,程序现在有两段加密的算法没有弄出来,记为Encode1, Encode2.那么加密的数据为
    Pass1 = NS
    Name = Encode1(Pass2)
    Pass3 = Encode2(Name-Pass1-Pass2)
           最后就剩下Encode1与Encode2要判断了。先来看Encode2,只是一个简单的查表变换,很简单的。
    1. 00406890  /$  55            PUSH    EBP
    2. 00406891  |.  8BEC          MOV     EBP, ESP
    3. 00406893  |.  83EC 08       SUB     ESP, 0x8
    4. 00406896  |.  8B45 08       MOV     EAX, [ARG.1]
    5. 00406899  |.  83F0 FF       XOR     EAX, 0xFFFFFFFF
    6. 0040689C  |.  8945 FC       MOV     [LOCAL.1], EAX                   ;  sum = -1
    7. 0040689F  |.  C745 F8 00000>MOV     [LOCAL.2], 0x0
    8. 004068A6  |.  EB 09         JMP     SHORT NsCrackM.004068B1
    9. 004068A8  |>  8B4D F8       /MOV     ECX, [LOCAL.2]
    10. 004068AB  |.  83C1 01       |ADD     ECX, 0x1
    11. 004068AE  |.  894D F8       |MOV     [LOCAL.2], ECX
    12. 004068B1  |>  8B55 F8        MOV     EDX, [LOCAL.2]
    13. 004068B4  |.  3B55 10       |CMP     EDX, [ARG.3]                    ;  while(i < iPasslen)
    14. 004068B7  |.  73 24         |JNB     SHORT NsCrackM.004068DD
    15. 004068B9  |.  8B45 0C       |MOV     EAX, [ARG.2]
    16. 004068BC  |.  0345 F8       |ADD     EAX, [LOCAL.2]
    17. 004068BF  |.  0FBE08        |MOVSX   ECX, BYTE PTR DS:[EAX]          ;  UCHAR a = Str[i]
    18. 004068C2  |.  334D FC       |XOR     ECX, [LOCAL.1]                  ;  a ^= sum
    19. 004068C5  |.  81E1 FF000000 |AND     ECX, 0xFF
    20. 004068CB  |.  8B55 FC       |MOV     EDX, [LOCAL.1]
    21. 004068CE  |.  C1EA 08       |SHR     EDX, 0x8                        ;  sum >>= 8
    22. 004068D1  |.  33148D C80342>|XOR     EDX, DWORD PTR DS:[ECX*4+0x4203>;  sum ^= CheckTable[a] (查表变换)
    23. 004068D8  |.  8955 FC       |MOV     [LOCAL.1], EDX
    24. 004068DB  |.^ EB CB         \JMP     SHORT NsCrackM.004068A8
    25. 004068DD  |>  8B45 FC       MOV     EAX, [LOCAL.1]
    26. 004068E0  |.  83F0 FF       XOR     EAX, 0xFFFFFFFF                  ;  sum ^= -1
    27. 004068E3  |.  8BE5          MOV     ESP, EBP
    28. 004068E5  |.  5D            POP     EBP
    29. 004068E6  \.  C3            RETN
    复制代码
         接着来看Encode1,直接说结论,这是一个变形Base64解密的代码,变换表变了,数据组合方式也有一点改变。
          假设原始数据为 A,B,C 分组后的数据为 a,b,c,d。 其中A,B,C都是8bit的数据,a,b,c,d 都是6bit的数据。那么他们的组合为
         d     |       c     |      b      |       a
    111111  111111   111111  111111
       C           |          B       |        A     
          与标准的组合算法恰好相反。注意一下就可以了。另外,解密的DecodeTable为:
    1. base64:         |Start   Y为结束标记,解密表为 0012E4B5 ~ 0012E535 长0x80 * 2
    2. 0012E4B3   59 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  Y...............
    3. 0012E4C3   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
    4. 0012E4D3   00 00 00 00 02 37 00 3A 00 00 00 00 0F 00 00 00  ....7.:.......
    5. 0012E4E3   3E 30 11 10 28 17 24 00 05 25 0A 00 00 36 3D 00  >0($.%...6=.
    6. 0012E4F3   00 1A 00 00 1F 07 19 1E 09 1C 2F 0C 31 29 38 00  .32.../.1)8.
    7. 0012E503   00 2A 03 27 0B 00 33 12 32 00 00 21 00 2B 1B 16  .*' .32..!.+
    8. 0012E513   08 00 22 2D 01 34 13 18 35 00 26 14 1D 00 2C 39  ."-45.&.,9
    9. 0012E523   06 00 2E 04 0D 20 15 23 3C 0E 3F 3B 00 00 00 00  ... #<?;....
    10. 0012E533   00 00      
    复制代码
           变换一下:
    1. unsigned char CodeTable[0x40] = {0};
    2.         int i;
    3.         for(i = 0; i < 0x80; i++) {
    4.                 CodeTable[DeCodeTable[i]] = i;
    5.         }
    复制代码
         得到原始的加密表为:
    1. char table[] = {               
    2.                 0x36, 0x63, 0x23, 0x51, 0x72, 0x37, 0x6F, 0x44, 0x5F, 0x47, 0x39, 0x53, 0x4A, 0x73, 0x78, 0x2B,
    3.                 0x32, 0x31, 0x56, 0x65, 0x6A, 0x75, 0x5E, 0x34, 0x66, 0x45, 0x40, 0x5D, 0x48, 0x6B, 0x46, 0x43,
    4.                 0x74, 0x5A, 0x61, 0x76, 0x35, 0x38, 0x69, 0x52, 0x33, 0x4C, 0x50, 0x5C, 0x6D, 0x62, 0x71, 0x49,
    5.                 0x30, 0x4B, 0x57, 0x55, 0x64, 0x67, 0x3C, 0x24, 0x4D, 0x6E, 0x26, 0x7A, 0x77, 0x3D, 0x2F, 0x79
    6.         };
    复制代码
          到此,这个算法也就得到了,CM中相应的分析就不发了,因为我本身也没有做多少,知道是Base64后就直接弄出结果来了。。。
           KeyGen源码见附件,相信也是不难的。要爆破的话就把上面相应的点给修改一下足以。这里在说一下程序的自校验(暗桩)。
           程序在点击注册的时候会验证代码是否被修改(KMP),如果改了的话就直接退出程序。首先异常的地方在上面说过PostMessage处,哪里变成这样了。
    1. 0040DE5B  |.  6A 00         PUSH    0x0                              ; /lParam = 0x0
    2. 0040DE5D  |.  6A 00         PUSH    0x0                              ; |wParam = 0x0
    3. 0040DE5F  |.  A1 AC684200   MOV     EAX, DWORD PTR DS:[0x4268AC]     ; |
    4. 0040DE64  |.  50            PUSH    EAX                              ; |Message => WM_CLOSE
    5. 0040DE65  |.  8B0D B0684200 MOV     ECX, DWORD PTR DS:[0x4268B0]     ; |
    6. 0040DE6B  |.  51            PUSH    ECX                              ; |hWnd => 0x130204
    7. 0040DE6C  |.  FF15 B0014200 CALL    NEAR DWORD PTR DS:[<&USER32.Post>; \PostMessageW
    复制代码
          这次变成了发送WM_CLOSE消息了。。。继续的查找地址常量参考,来到赋值处
    1. 00401853  |.  E8 E8F9FFFF   CALL    Crack.00401240                   ;  自校验
    2. 00401858  |.  85C0          TEST    EAX, EAX
    3. 0040185A      75 0A         JNZ     SHORT Crack.00401866
    4. 0040185C  |.  C705 AC684200>MOV     DWORD PTR DS:[0x4268AC], 0x10    ;  WM_CLOSE
    复制代码
        该怎么搞就怎么搞,call里面是使用KMP算法来验证程序段某些部分是否被修改掉了。
         keygen附上,大家来指点一下吧。


    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?加入我们

    x

    评分

    参与人数 8威望 +84 飘云币 +76 收起 理由
    small-q + 8 + 8 很给力!
    crackvip + 8 + 8 很给力!
    beijingren + 4 + 4 很给力!
    Nisy + 40 + 40 赞一个!
    sndncel + 4 真心牛X呀。。。。支持一下。
    iamok + 8 很给力!
    tree_fly + 8 + 8 神马都是浮云
    wgz001 + 4 + 8 很给力!

    查看全部评分

    PYG19周年生日快乐!
  • TA的每日心情
    开心
    2019-2-26 11:14
  • 签到天数: 459 天

    [LV.9]以坛为家II

    发表于 2014-11-24 11:18:31 | 显示全部楼层
    本帖最后由 wgz001 于 2014-11-24 11:33 编辑

    沙发

    明显自己功力还不够,看了文章还是不懂 {:soso_e149:}

    点评

    真快!!!  发表于 2014-11-24 11:19
    PYG19周年生日快乐!
  • TA的每日心情
    开心
    2024-3-30 09:43
  • 签到天数: 155 天

    [LV.7]常住居民III

    发表于 2014-11-24 11:20:31 | 显示全部楼层
    大赞!太厉害了!!
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2014-11-24 11:21:54 | 显示全部楼层
    膜拜中,纯粹是来膜拜的
    PYG19周年生日快乐!
  • TA的每日心情
    开心
    2019-3-15 21:05
  • 签到天数: 5 天

    [LV.2]偶尔看看I

    发表于 2014-11-24 11:27:59 | 显示全部楼层
    膜拜把校长的CM玩的如此透彻。。。
    PYG19周年生日快乐!
  • TA的每日心情
    开心
    2024-1-4 14:31
  • 签到天数: 73 天

    [LV.6]常住居民II

    发表于 2014-11-24 11:58:34 来自手机 | 显示全部楼层
    写的太精彩了,谢谢分享
    PYG19周年生日快乐!
  • TA的每日心情
    奋斗
    2019-6-22 21:37
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    发表于 2014-11-24 12:06:17 | 显示全部楼层
    分析清晰   表述详细 。。LZ异常的叼
    PYG19周年生日快乐!
  • TA的每日心情
    开心
    昨天 08:46
  • 签到天数: 1478 天

    [LV.10]以坛为家III

    发表于 2014-11-24 12:07:32 | 显示全部楼层
    分析的很不错,厉害。功底很深呀。
    PYG19周年生日快乐!
  • TA的每日心情
    开心
    2019-3-17 22:44
  • 签到天数: 132 天

    [LV.7]常住居民III

    发表于 2014-11-24 12:20:26 | 显示全部楼层
    分析很好,各种膜拜
    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

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