欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创] CTF2017 第2题 CrackMe 破解分析

[原创] CTF2017 第2题 CrackMe 破解分析

本文就纯OD手工完成算法分析,过程比较累,你有什么更好的办法请不吝分享。如果有猪蹄汤、排骨汤应该提前服用。

为了节省篇幅,本文直接拿事后算出来的注册码作为测试输入,更直观。功力有限,有些地方分析不到位,请见谅。

另外,我对本题作者无任何不敬之意,权当学习交流了。


一、首先,算法很绕,能破解出来也有一定的运气成分。看到群里有人提到是否可以直接修改CrackMe汇编代码,让它自己完成穷举,我觉得这个思路值得探索,事后补上了这章。开头先讲讲如何利用ODbgScript实现自动化穷举代码的写入和结果显示,就当开拓思维吧,以后在其他场合还是有用武之地的。

// Ctf.pediy.com crackme 2# Ollydbg 穷举脚本

// 本例测试穷举效率不高,每秒几千到一万多次,可能跟Crackme的算法很绕有关

// 所以直接通过本Crackme自身写入代码进行穷举需要几个小时时间才能完成

// OdbgScript 1.83

// Written by 爱琴海

// 2017/06/04

CMP $VERSION, "1.82"

//比较是否大于1.82版,脚本基于1.82版本以上

JAE Initialize

  MSG "需要1.82版本以上的ODbgScript才能支持本程序,请更新!"   

  RET      

Initialize:

  //定义变量  

  VAR Sn_address  

  //储存注册码地址

  VAR Eip_bak

  //备份恢复原始Eip

  PUSHA

  //高版本OdbgScript才支持该指令,保存寄存器现场  

Set_break:

  //设置相关断点,提示用户

  BP 4010BC 

  BPGOTO 4010BC,Catch_break

  //设置4010BC断点,接管算法流程  

  BP 401257 

  BPGOTO 401257,Succes  

  //设置401257断点,找到注册码时候接管流程

  MSG "请在CrackMe输入窗口输入8位非0数字并回车继续"  

  RUN

    

Catch_break:

  //捕捉到4010BC断点,让程序自己完成一些初始化工作再接管  

  BC 4010BC  

  //取消4010BC断点,有始有终  

  MOV Eip_bak,eip  

  //保存当前eip,穷举结束时得恢复eip

Start:

  //循环穷举主程序,为提高运行效率采用补丁方式,交给程序自己完成

  MOV Sn_address,ecx  

  //储存注册码地址,成功时需要调用显示

  MOV [ecx],#313131313131313000#

  //我已经测试CrackMe自身穷举效率较低,穷举需要几个小时才能完成

  //穷举初值11111110(接下里的累加1,将实际初值变为11111111)   

 

Inc_check:

  //写入代码,修改程序流程,实现穷举注册码功能    

  MOV [4010BC],#E95F660000909090909090#  

  // JMP 00407720 以及 nop 填充,接管算法流程   

  MOV [40122B],#909090909090E976FEFFFF#

  // NOP JE 004010FA

  // JMP 004010AC 错误时继续          

  MOV [407700],#60B80800000083F8017413807C08FF397609C64408FF31FE4408FE48EBE861C3FE4107E8D8FFFFFF8039397601C3E99499FFFF#

  //累加、检查进位子程序,选择407700位置写入代码

  // 407700:

  // PUSHAD

  // MOV EAX,0x8

  // CMP EAX,0x1

  // JE 0040771E

  // CMP BYTE PTR DS:[EAX+ECU-0x1],0x39 不是ECU而是ECX,显示乱码搞不懂

  // JBE 0040771B

  // MOV BYTE PTR DS:[EAX+ECU-0x1],0x31 不是ECU而是ECX,显示乱码搞不懂

  // INC BYTE PTR DS:[EAX+ECU-0x2]      不是ECU而是ECX,显示乱码搞不懂

  // DEC EAX

  // JMP 00407706

  // POPAD

  // RETN

  // 407720:

  // INC BYTE PTR DS:[ECX+0x7]

  // CALL 00407700

  // CMP BYTE PTR DS:[ECX],0x39  最高位超过9就结束

  // JBE 0040772E

  // RETN

  // 40772E:

  // JMP 004010C7 

  RUN 

Succes:

  //成功穷举到注册码  

  BC 401257

  //取消401257断点,有始有终

  MSG [Sn_address]   

  //显示注册码

End:

  //收尾工作      

  POPA

  //高版本OdbgScript才支持该指令,彻底恢复寄存器现场  

  MOV eip,Eip_bak  

  //穷举结束恢复eip

  MSG "穷举结束" 

  ret

  //结束脚本


你猜结果如何? 虽然能穷举到注册码,但每秒几千次到上万次,效率比较低,需进一步分析算法实现破解。这章事后补充的,希望能有启发。


二、查壳,Microsoft Visual C/C++(6.0)[libc],木有壳。

三、OD载入,查找字符串,定位到:“WELL DONE!”,往上翻翻就到了主要代码。



四、在401053设断点,运行。动态跟踪时发现有检测GetTickCount,记得设置返回为0,避免干扰分析。

00401021           |.  68 C0904000             PUSH 2.004090C0                                ;  =======PEDIY CTF 2017=======\n
00401026           |.  E8 B50B0000             CALL 2.00401BE0
0040102B           |.  68 A0904000             PUSH 2.004090A0                                ;  -----CrackMe by: lelfei-----\n
00401030           |.  E8 AB0B0000             CALL 2.00401BE0
00401035           |.  68 8C904000             PUSH 2.0040908C                                ;  Please input KEY:
0040103A           |.  E8 A10B0000             CALL 2.00401BE0
0040103F           |.  68 E0904000             PUSH 2.004090E0                                ;  \n
00401044           |.  8D4424 18               LEA EAX,DWORD PTR SS:[ESP+0x18]
00401048           |.  68 04010000             PUSH 0x104
0040104D           |.  50                      PUSH EAX
0040104E           |.  E8 7D0A0000             CALL 2.00401AD0                                ;  输入 "97654321"
00401053           |.  8D7C24 20               LEA EDI,DWORD PTR SS:[ESP+0x20]
五、输入“97654321”之后回车断下,一步步跟踪:
00401057           |.  83C9 FF                 OR ECX,0xFFFFFFFF
0040105A           |.  33C0                    XOR EAX,EAX
0040105C           |.  83C4 18                 ADD ESP,0x18
0040105F           |.  F2:AE                   REPNE SCAS BYTE PTR ES:[EDI]
00401061           |.  F7D1                    NOT ECX
00401063           |.  83C1 FE                 ADD ECX,-0x2
00401066           |.  83F9 08                 CMP ECX,0x8
00401069           |.  0F8C 0B020000           JL 2.0040127A                                  ;  低于8位完蛋
0040106F           |.  83F9 14                 CMP ECX,0x14
00401072           |.  0F8F 02020000           JG 2.0040127A                                  ;  高于20位完蛋
00401078           |.  33F6                    XOR ESI,ESI
0040107A           |.  33D2                    XOR EDX,EDX
0040107C           |.  85C9                    TEST ECX,ECX
0040107E           |.  88440C 08               MOV BYTE PTR SS:[ESP+ECX+0x8],AL
00401082           |.  7E 28                   JLE X2.004010AC
00401084           |>  8A4414 08               /MOV AL,BYTE PTR SS:[ESP+EDX+0x8]
00401088           |.  3C 30                   |CMP AL,0x30
0040108A           |.  7E 04                   |JLE X2.00401090                               ;  非0,且>0
0040108C           |.  3C 39                   |CMP AL,0x39
0040108E           |.  7E 01                   |JLE X2.00401091                               ;  <=9
00401090           |>  46                      |INC ESI
00401091           |>  42                      |INC EDX
00401092           |.  3BD1                    |CMP EDX,ECX
00401094           |.^ 7C EE                   \JL X2.00401084                                ;  字符串格式检查 1-9
00401096           |.  85F6                    TEST ESI,ESI
00401098           |.  74 12                   JE X2.004010AC
0040109A           |.  68 74904000             PUSH 2.00409074                                ;  key format error...\n
0040109F           |.  E8 3C0B0000             CALL 2.00401BE0
004010A4           |.  83C4 04                 ADD ESP,0x4
004010A7           |.  E9 DC010000             JMP 2.00401288
要求注册码为:8-20位,且1-9(非0数字)
六、跟踪到4010CF:
004010AC           |> \8D8C24 0C010000         LEA ECX,DWORD PTR SS:[ESP+0x10C]
004010B3           |.  E8 08020000             CALL 2.004012C0                                ;  0x400位乱序填充
004010B8           |.  8D4C24 08               LEA ECX,DWORD PTR SS:[ESP+0x8]
004010BC           |.  C78424 34410000 0000000>MOV DWORD PTR SS:[ESP+0x4134],0x0
004010C7           |.  51                      PUSH ECX
004010C8           |.  8D8C24 10010000         LEA ECX,DWORD PTR SS:[ESP+0x110]
004010CF           |.  E8 0C040000             CALL <2.change_decimal_1>                      ;  将用户输入字符串倒置按十进制逐位转换,12345679
004010D4           |.  8D8C24 0C010000         LEA ECX,DWORD PTR SS:[ESP+0x10C]
004010DB           |.  E8 D0010000             CALL <2.nothing>
此时感觉 CALL 4014E0 可疑,单步进入:
004014E0 <2.change>/$  53                      PUSH EBX                                       ;  将输入字符当做十进制,逐位存放,逐位检查格式、进位
004014E1           |.  55                      PUSH EBP
004014E2           |.  8B6C24 0C               MOV EBP,DWORD PTR SS:[ESP+0xC]
004014E6           |.  56                      PUSH ESI
004014E7           |.  57                      PUSH EDI
004014E8           |.  8BD9                    MOV EBX,ECX
004014EA           |.  8BFD                    MOV EDI,EBP                                    ;  -1
004014EC           |.  83C9 FF                 OR ECX,0xFFFFFFFF
004014EF           |.  33C0                    XOR EAX,EAX
004014F1           |.  33F6                    XOR ESI,ESI                                    ;  0
004014F3           |.  F2:AE                   REPNE SCAS BYTE PTR ES:[EDI]
004014F5           |.  F7D1                    NOT ECX
004014F7           |.  49                      DEC ECX                                        ;  位数
004014F8           |.  8973 04                 MOV DWORD PTR DS:[EBX+0x4],ESI
004014FB           |.  8BF9                    MOV EDI,ECX
004014FD           |.  3BFE                    CMP EDI,ESI                                    ;  输入的位数全部转换为止
004014FF           |.  7E 2E                   JLE X2.0040152F
00401501           |>  8A042E                  /MOV AL,BYTE PTR DS:[ESI+EBP]
00401504           |.  3C 30                   |CMP AL,0x30                                   ;  1-9
00401506           |.  7C 22                   |JL X2.0040152A
00401508           |.  3C 39                   |CMP AL,0x39
0040150A           |.  7F 1E                   |JG X2.0040152A
0040150C           |.  0FBEC0                  |MOVSX EAX,AL
0040150F           |.  83E8 30                 |SUB EAX,0x30                                  ;  转为所见十进制
00401512           |.  74 16                   |JE X2.0040152A
00401514           |.  85F6                    |TEST ESI,ESI
00401516           |.  74 0A                   |JE X2.00401522
00401518           |.  8BCE                    |MOV ECX,ESI
0040151A           |>  8D0480                  |/LEA EAX,DWORD PTR DS:[EAX+EAX*4]             ;  10*第2位 100*第3位 依次类推
0040151D           |.  03C0                    ||ADD EAX,EAX
0040151F           |.  49                      ||DEC ECX
00401520           |.^ 75 F8                   |\JNZ X2.0040151A
00401522           |>  50                      |PUSH EAX                                      ;  所见十进制数
00401523           |.  8BCB                    |MOV ECX,EBX
00401525           |.  E8 56000000             |CALL 2.00401580                               ;  将用户输入的字符当做十进制进行每位转换,EAX可以看到
0040152A           |>  46                      |INC ESI
0040152B           |.  3BF7                    |CMP ESI,EDI
0040152D           |.^ 7C D2                   \JL X2.00401501                                ;  没完,继续
0040152F           |>  8BCB                    MOV ECX,EBX
00401531           |.  E8 3A040000             CALL 2.00401970                                ;  检查格式,进位什么的
00401536           |.  5F                      POP EDI
00401537           |.  5E                      POP ESI
00401538           |.  5D                      POP EBP
00401539           |.  5B                      POP EBX
0040153A           \.  C2 0400                 RETN 0x4
原来此段代码是将输入字符当做十进制,逐位存放,逐位检查格式、进位,出题作者自己实现了最大0x400位十进制计算功能。
比如输入“97654321”得到 12345679。  CALL 00401970 各位可以自己跟踪看看,这里省点篇幅以免过于Up嗦。

七、返回到上一步,继续:
004010E0           |.  6A 09                   PUSH 0x9
004010E2           |.  8D8C24 10010000         LEA ECX,DWORD PTR SS:[ESP+0x110]
004010E9           |.  E8 42060000             CALL 2.00401730                                ;  乘法 12345679 * 9 = 111111111
004010EE           |.  8D8C24 0C010000         LEA ECX,DWORD PTR SS:[ESP+0x10C]
004010F5           |.  E8 B6010000             CALL <2.nothing>
此处 CALL 401730 明显得跟踪进入:
00401730           /$  6A FF                   PUSH -0x1                                      ;  乘法
00401732           |.  64:A1 00000000          MOV EAX,DWORD PTR FS:[0]
00401738           |.  68 D6754000             PUSH 2.004075D6
0040173D           |.  50                      PUSH EAX
0040173E           |.  B8 20400000             MOV EAX,0x4020
00401743           |.  64:8925 00000000        MOV DWORD PTR FS:[0],ESP
0040174A           |.  E8 B1070000             CALL 2.00401F00
0040174F           |.  53                      PUSH EBX
00401750           |.  55                      PUSH EBP
00401751           |.  56                      PUSH ESI
00401752           |.  8BE9                    MOV EBP,ECX
00401754           |.  57                      PUSH EDI
00401755           |.  8D4C24 10               LEA ECX,DWORD PTR SS:[ESP+0x10]
00401759           |.  E8 62FBFFFF             CALL 2.004012C0                                ;  填充
0040175E           |.  33FF                    XOR EDI,EDI
00401760           |.  8D8C24 20200000         LEA ECX,DWORD PTR SS:[ESP+0x2020]
00401767           |.  57                      PUSH EDI
00401768           |.  89BC24 3C400000         MOV DWORD PTR SS:[ESP+0x403C],EDI
0040176F           |.  E8 9CFBFFFF             CALL 2.00401310                                ;  填充
00401774           |.  8B8424 40400000         MOV EAX,DWORD PTR SS:[ESP+0x4040]
0040177B           |.  C68424 38400000 01      MOV BYTE PTR SS:[ESP+0x4038],0x1
00401783           |.  3BC7                    CMP EAX,EDI
00401785           |.  74 59                   JE X2.004017E0                                 ;  到了没
00401787           |>  99                      /CDQ
00401788           |.  B9 0A000000             |MOV ECX,0xA
0040178D           |.  F7F9                    |IDIV ECX                                      ;  取余
0040178F           |.  8BF2                    |MOV ESI,EDX
00401791           |.  8BD8                    |MOV EBX,EAX
00401793           |.  85F6                    |TEST ESI,ESI
00401795           |.  74 42                   |JE X2.004017D9
00401797           |.  55                      |PUSH EBP
00401798           |.  8D4C24 14               |LEA ECX,DWORD PTR SS:[ESP+0x14]
0040179C           |.  E8 9FFDFFFF             |CALL 2.00401540                               ;  读取十进制各位,检查格式
004017A1           |.  57                      |PUSH EDI
004017A2           |.  8D4C24 14               |LEA ECX,DWORD PTR SS:[ESP+0x14]
004017A6           |.  E8 B5FEFFFF             |CALL 2.00401660
004017AB           |.  56                      |PUSH ESI
004017AC           |.  8D4C24 14               |LEA ECX,DWORD PTR SS:[ESP+0x14]
004017B0           |.  E8 2BFFFFFF             |CALL 2.004016E0                               ;  乘法,得跟进去看看
004017B5           |.  8D5424 10               |LEA EDX,DWORD PTR SS:[ESP+0x10]
004017B9           |.  8D8C24 20200000         |LEA ECX,DWORD PTR SS:[ESP+0x2020]
004017C0           |.  52                      |PUSH EDX
004017C1           |.  E8 1AFEFFFF             |CALL 2.004015E0                               ;  加法,得跟进去看看
004017C6           |.  8D8C24 20200000         |LEA ECX,DWORD PTR SS:[ESP+0x2020]
004017CD           |.  E8 CEFBFFFF             |CALL <2.len()>                                ;  检查乘法之后的位数
004017D2           |.  3D 00040000             |CMP EAX,0x400                                 ;  0x400
004017D7           |.  7D 48                   |JGE X2.00401821
004017D9           |>  8BC3                    |MOV EAX,EBX
004017DB           |.  47                      |INC EDI
004017DC           |.  85C0                    |TEST EAX,EAX
004017DE           |.^ 75 A7                   \JNZ X2.00401787
004017E0           |>  8D8424 20200000         LEA EAX,DWORD PTR SS:[ESP+0x2020]
跟踪 CALL 00401540:
00401540                               /$  56                      PUSH ESI                                       ;  刚才的余,读取刚才用户输入的十进制各位
00401541                               |.  8B7424 08               MOV ESI,DWORD PTR SS:[ESP+0x8]
00401545                               |.  33D2                    XOR EDX,EDX
00401547                               |.  8B46 04                 MOV EAX,DWORD PTR DS:[ESI+0x4]                 ;  8 9
0040154A                               |.  85C0                    TEST EAX,EAX
0040154C                               |.  8941 04                 MOV DWORD PTR DS:[ECX+0x4],EAX
0040154F                               |.  7E 28                   JLE X2.00401579
00401551                               |.  53                      PUSH EBX
00401552                               |.  55                      PUSH EBP
00401553                               |.  57                      PUSH EDI
00401554                               |.  8BFE                    MOV EDI,ESI
00401556                               |.  8D81 08100000           LEA EAX,DWORD PTR DS:[ECX+0x1008]
0040155C                               |.  2BF9                    SUB EDI,ECX
0040155E                               |>  8B1C07                  /MOV EBX,DWORD PTR DS:[EDI+EAX]                ;  2f2
00401561                               |.  8B28                    |MOV EBP,DWORD PTR DS:[EAX]
00401563                               |.  42                      |INC EDX
00401564                               |.  83C0 04                 |ADD EAX,0x4
00401567 地址                            |.  8B5C9E 08               |MOV EBX,DWORD PTR DS:[ESI+EBX*4+0x8]          ;  取刚才结果
0040156B 密码                            |.  895CA9 08               |MOV DWORD PTR DS:[ECX+EBP*4+0x8],EBX
0040156F                               |.  8B59 04                 |MOV EBX,DWORD PTR DS:[ECX+0x4]
00401572                               |.  3BD3                    |CMP EDX,EBX
00401574                               |.^ 7C E8                   \JL X2.0040155E                                ;  完了么
00401576                               |.  5F                      POP EDI
00401577                               |.  5D                      POP EBP
00401578                               |.  5B                      POP EBX
00401579                               |>  5E                      POP ESI
0040157A                               \.  C2 0400                 RETN 0x4
留意到401567、40156B分别处理了当前计算结果所储存的地址和内容,为了方便后续分析,在这两处分别下条件记录断点记录
ECX+EBP*4+0x8、EBX,并命名“地址、密码”:


继续跟进 CALL 004016E0 定位核心功能:
004016E0           /$  57                      PUSH EDI
004016E1           |.  8B7C24 08               MOV EDI,DWORD PTR SS:[ESP+0x8]
004016E5           |.  85FF                    TEST EDI,EDI
004016E7           |.  7C 3D                   JL X2.00401726
004016E9           |.  83FF 0A                 CMP EDI,0xA
004016EC           |.  7D 38                   JGE X2.00401726
004016EE           |.  8B41 04                 MOV EAX,DWORD PTR DS:[ECX+0x4]
004016F1           |.  33D2                    XOR EDX,EDX
004016F3           |.  85C0                    TEST EAX,EAX
004016F5           |.  7E 24                   JLE X2.0040171B
004016F7           |.  53                      PUSH EBX
004016F8           |.  56                      PUSH ESI
004016F9           |.  8DB1 08100000           LEA ESI,DWORD PTR DS:[ECX+0x1008]
004016FF           |>  8B06                    /MOV EAX,DWORD PTR DS:[ESI]
00401701           |.  83C6 04                 |ADD ESI,0x4
00401704           |.  8B5C81 08               |MOV EBX,DWORD PTR DS:[ECX+EAX*4+0x8]
00401708 x         |.  8D4481 08               |LEA EAX,DWORD PTR DS:[ECX+EAX*4+0x8]
0040170C y         |.  0FAFDF                  |IMUL EBX,EDI                                  ;  *9 *7 *6 ......*3 *2 *1
0040170F x * y     |.  8918                    |MOV DWORD PTR DS:[EAX],EBX
00401711           |.  8B41 04                 |MOV EAX,DWORD PTR DS:[ECX+0x4]
00401714           |.  42                      |INC EDX
00401715           |.  3BD0                    |CMP EDX,EAX
00401717           |.^ 7C E6                   \JL X2.004016FF                                ;  都乘完了么
00401719           |.  5E                      POP ESI
0040171A           |.  5B                      POP EBX
0040171B           |>  E8 50020000             CALL 2.00401970                                ;  格式检查,进位
00401720           |.  33C0                    XOR EAX,EAX
00401722           |.  5F                      POP EDI
00401723           |.  C2 0400                 RETN 0x4
00401726           |>  B8 01000000             MOV EAX,0x1
0040172B           |.  5F                      POP EDI
0040172C           \.  C2 0400                 RETN 0x4
可以看到:
0040170C y         |.  0FAFDF                  |IMUL EBX,EDI                                  ;  *9 *7 *6 ......*3 *2 *1
这句就是作者实现自定义乘法的“乘法之根本法”,后续频繁调用这个子程序,为了减少劳动量,请设置401708、40170C、40170F条件记录断点,永不中断,分别永远记录EBX、EDI、EBX值,并标明表达式名称为“x、y、x * y”,以免后续搞混了。


在4017B5下断,清空记录窗口,运行,查看记录窗口:
Log data
地址       消息
00401567   COND: 地址 = 001289B0
0040156B   COND: 密码  = 00000009
00401567   COND: 地址 = 00128664
0040156B   COND: 密码  = 00000007
00401567   COND: 地址 = 0012823C
0040156B   COND: 密码  = 00000006
00401567   COND: 地址 = 00128D00
0040156B   COND: 密码  = 00000005
00401567   COND: 地址 = 00128234
0040156B   COND: 密码  = 00000004
00401567   COND: 地址 = 001284E0
0040156B   COND: 密码  = 00000003
00401567   COND: 地址 = 00127F94
0040156B   COND: 密码  = 00000002
00401567   COND: 地址 = 00128C14
0040156B   COND: 密码  = 00000001
00401708   COND: x     = 00000009
0040170C   COND: y     = 00000009
0040170F   COND: x * y = 00000051
00401708   COND: x     = 00000007
0040170C   COND: y     = 00000009
0040170F   COND: x * y = 0000003F
00401708   COND: x     = 00000006
0040170C   COND: y     = 00000009
0040170F   COND: x * y = 00000036
00401708   COND: x     = 00000005
0040170C   COND: y     = 00000009
0040170F   COND: x * y = 0000002D
00401708   COND: x     = 00000004
0040170C   COND: y     = 00000009
0040170F   COND: x * y = 00000024
00401708   COND: x     = 00000003
0040170C   COND: y     = 00000009
0040170F   COND: x * y = 0000001B
00401708   COND: x     = 00000002
0040170C   COND: y     = 00000009
0040170F   COND: x * y = 00000012
00401708   COND: x     = 00000001
0040170C   COND: y     = 00000009
0040170F   COND: x * y = 00000009
004017B5   断点位于 2.004017B5
取消4017B5断点,保留条件记录断点,跟踪 CALL 004015E0:
004015E0           /$  51                      PUSH ECX
004015E1           |.  8B51 04                 MOV EDX,DWORD PTR DS:[ECX+0x4]
004015E4           |.  53                      PUSH EBX
004015E5           |.  56                      PUSH ESI
004015E6           |.  8B7424 10               MOV ESI,DWORD PTR SS:[ESP+0x10]
004015EA           |.  895424 08               MOV DWORD PTR SS:[ESP+0x8],EDX
004015EE           |.  8B46 04                 MOV EAX,DWORD PTR DS:[ESI+0x4]                 ;  [123d9c]=9 [127DE4]=9
004015F1           |.  3BD0                    CMP EDX,EAX
004015F3           |.  7D 06                   JGE X2.004015FB
004015F5           |.  8BD0                    MOV EDX,EAX
004015F7           |.  895424 08               MOV DWORD PTR SS:[ESP+0x8],EDX
004015FB           |>  33DB                    XOR EBX,EBX
004015FD           |.  85D2                    TEST EDX,EDX
004015FF           |.  7E 50                   JLE X2.00401651
00401601           |.  55                      PUSH EBP
00401602           |.  57                      PUSH EDI
00401603           |.  8BFE                    MOV EDI,ESI
00401605           |.  8D81 08100000           LEA EAX,DWORD PTR DS:[ECX+0x1008]
0040160B           |.  2BF9                    SUB EDI,ECX
0040160D           |>  8B51 04                 /MOV EDX,DWORD PTR DS:[ECX+0x4]                ;  0 1
00401610           |.  3BDA                    |CMP EBX,EDX
00401612           |.  7C 1B                   |JL X2.0040162F
00401614           |.  8B2C07                  |MOV EBP,DWORD PTR DS:[EDI+EAX]                ;  2f2
00401617           |.  8B9491 08100000         |MOV EDX,DWORD PTR DS:[ECX+EDX*4+0x1008]
0040161E           |.  8B6CAE 08               |MOV EBP,DWORD PTR DS:[ESI+EBP*4+0x8]          ;  读取乘法结果
00401622           |.  896C91 08               |MOV DWORD PTR DS:[ECX+EDX*4+0x8],EBP
00401626           |.  8B51 04                 |MOV EDX,DWORD PTR DS:[ECX+0x4]
00401629           |.  42                      |INC EDX
0040162A           |.  8951 04                 |MOV DWORD PTR DS:[ECX+0x4],EDX
0040162D           |.  EB 14                   |JMP X2.00401643
0040162F           |>  3B5E 04                 |CMP EBX,DWORD PTR DS:[ESI+0x4]
00401632           |.  7D 0F                   |JGE X2.00401643
00401634           |.  8B10                    |MOV EDX,DWORD PTR DS:[EAX]
00401636           |.  8B2C07                  |MOV EBP,DWORD PTR DS:[EDI+EAX]
00401639           |.  8B6CAE 08               |MOV EBP,DWORD PTR DS:[ESI+EBP*4+0x8]
0040163D a         |.  8D5491 08               |LEA EDX,DWORD PTR DS:[ECX+EDX*4+0x8]
00401641 b         |.  012A                    |ADD DWORD PTR DS:[EDX],EBP                    ;  加法
00401643 EDX > 040>|>  8B5424 10               |MOV EDX,DWORD PTR SS:[ESP+0x10]
00401647           |.  43                      |INC EBX
00401648           |.  83C0 04                 |ADD EAX,0x4
0040164B           |.  3BDA                    |CMP EBX,EDX
0040164D           |.^ 7C BE                   \JL X2.0040160D
0040164F           |.  5F                      POP EDI
00401650           |.  5D                      POP EBP
00401651           |>  E8 1A030000             CALL 2.00401970                                ;  检查格式,进位
00401656           |.  5E                      POP ESI
00401657           |.  5B                      POP EBX
00401658           |.  59                      POP ECX
00401659           \.  C2 0400                 RETN 0x4
可以看到:
00401641 b         |.  012A                    |ADD DWORD PTR DS:[EDX],EBP                    ;  加法
这句就是作者实现自定义加法的“加法之根本法”,后续频繁调用这个子程序,为了减少劳动量,请设置40163D、401641、401643条件记录断点,永不中断,分别永远记录EBP、DWORD PTR DS:[EDX]、条件EDX>400记录DWORD PTR DS:[EDX]值,并标明表达式名称为“a、b、a + b”,以免后续搞混了。


此时还没到用到加法的时候,所以你也记录不到加法信息,别着急,保留条件记录断点,回到4010EE下断点,清空记录窗口,运行。
断下之后,查看记录窗口:
00401567   COND: 地址 = 0012CAF0
0040156B   COND: 密码  = 00000001
00401567   COND: 地址 = 0012C7A4
0040156B   COND: 密码  = 00000001
00401567   COND: 地址 = 0012C37C
0040156B   COND: 密码  = 00000001
00401567   COND: 地址 = 0012CE40
0040156B   COND: 密码  = 00000001
00401567   COND: 地址 = 0012C374
0040156B   COND: 密码  = 00000001
00401567   COND: 地址 = 0012C620
0040156B   COND: 密码  = 00000001
00401567   COND: 地址 = 0012C0D4
0040156B   COND: 密码  = 00000001
00401567   COND: 地址 = 0012CD54
0040156B   COND: 密码  = 00000001
00401567   COND: 地址 = 0012C4C0
0040156B   COND: 密码  = 00000001
004010EE   断点位于 2.004010EE
通过上述记录信息,很快就可以理解本步骤算法含义:12345679 * 9 = 111111111
八、从上文 4010EE 继续:
004010FA                               |> /8D5424 08               /LEA EDX,DWORD PTR SS:[ESP+0x8]
004010FE                               |. |8D8C24 1C210000         |LEA ECX,DWORD PTR SS:[ESP+0x211C]
00401105                               |. |52                      |PUSH EDX
00401106                               |. |E8 45020000             |CALL <2.change_decimal_2>                     ;  将用户输入字符串按十进制逐位转换,
12345679
0040110B                               |. |8D8424 1C210000         |LEA EAX,DWORD PTR SS:[ESP+0x211C]
00401112                               |. |8D8C24 0C010000         |LEA ECX,DWORD PTR SS:[ESP+0x10C]
00401119                               |. |50                      |PUSH EAX
0040111A                               |. |C68424 38410000 01      |MOV BYTE PTR SS:[ESP+0x4138],0x1
00401122                               |. |E8 19070000             |CALL 2.00401840                               ;  完成逐位乘法、加法,结果,
12345678987654321
00401127                               |. |6A 09                   |PUSH 0x9
00401129                               |. |8D8C24 10010000         |LEA ECX,DWORD PTR SS:[ESP+0x110]
00401130                               |. |8BF0                    |MOV ESI,EAX
00401132                               |. |E8 F9050000             |CALL 2.00401730                               ;  乘法 * 9
00401137                               |. |8D8C24 0C010000         |LEA ECX,DWORD PTR SS:[ESP+0x10C]
0040113E                               |. |03F0                    |ADD ESI,EAX
00401140                               |. |E8 6B010000             |CALL <2.nothing>
CALL 401840 和 CALL 401730 是算法的核心,分别实现了逐位乘法、加法,累加得到最终结果。(CALL 401730 在上文中已经分析过了)
00401840                               /$  6A FF                   PUSH -0x1
00401842                               |.  64:A1 00000000          MOV EAX,DWORD PTR FS:[0]
00401848                               |.  68 F6754000             PUSH 2.004075F6
0040184D                               |.  50                      PUSH EAX
0040184E                               |.  B8 24400000             MOV EAX,0x4024
00401853                               |.  64:8925 00000000        MOV DWORD PTR FS:[0],ESP
0040185A                               |.  E8 A1060000             CALL 2.00401F00
0040185F                               |.  53                      PUSH EBX
00401860                               |.  55                      PUSH EBP
00401861                               |.  56                      PUSH ESI
00401862                               |.  8BF1                    MOV ESI,ECX
00401864                               |.  57                      PUSH EDI
00401865                               |.  8D4C24 14               LEA ECX,DWORD PTR SS:[ESP+0x14]
00401869                               |.  E8 52FAFFFF             CALL 2.004012C0                                ;  填充
0040186E                               |.  33FF                    XOR EDI,EDI
00401870                               |.  8D8C24 24200000         LEA ECX,DWORD PTR SS:[ESP+0x2024]
00401877                               |.  57                      PUSH EDI
00401878                               |.  89BC24 40400000         MOV DWORD PTR SS:[ESP+0x4040],EDI
0040187F                               |.  E8 8CFAFFFF             CALL 2.00401310                                ;  填充
00401884                               |.  8B9C24 44400000         MOV EBX,DWORD PTR SS:[ESP+0x4044]
0040188B                               |.  8B4E 04                 MOV ECX,DWORD PTR DS:[ESI+0x4]
0040188E                               |.  C68424 3C400000 01      MOV BYTE PTR SS:[ESP+0x403C],0x1               ;  1
00401896                               |.  8B43 04                 MOV EAX,DWORD PTR DS:[EBX+0x4]                 ;  8
00401899                               |.  03C8                    ADD ECX,EAX
0040189B                               |.  81F9 00040000           CMP ECX,0x400                                  ;  8+9=17,检查可能的位数
004018A1                               |.  7E 1F                   JLE X2.004018C2
004018A3                               |>  8D8C24 24200000         LEA ECX,DWORD PTR SS:[ESP+0x2024]
004018AA                               |.  E8 E1FAFFFF             CALL 2.00401390
004018AF                               |.  8D4C24 14               LEA ECX,DWORD PTR SS:[ESP+0x14]
004018B3                               |.  E8 D8FAFFFF             CALL 2.00401390
004018B8                               |.  B8 01000000             MOV EAX,0x1
004018BD                               |.  E9 90000000             JMP 2.00401952
004018C2                               |>  3BC7                    CMP EAX,EDI
004018C4                               |.  7E 5F                   JLE X2.00401925                                ;  结束了么
004018C6                               |.  8D93 08100000           LEA EDX,DWORD PTR DS:[EBX+0x1008]
004018CC                               |.  895424 10               MOV DWORD PTR SS:[ESP+0x10],EDX
004018D0                               |>  8B4424 10               /MOV EAX,DWORD PTR SS:[ESP+0x10]
004018D4                               |.  56                      |PUSH ESI
004018D5                               |.  8B08                    |MOV ECX,DWORD PTR DS:[EAX]
004018D7                               |.  8B6C8B 08               |MOV EBP,DWORD PTR DS:[EBX+ECX*4+0x8]          ;  9 7 6 5 4 3 2 1
004018DB                               |.  8D4C24 18               |LEA ECX,DWORD PTR SS:[ESP+0x18]
004018DF                               |.  E8 5CFCFFFF             |CALL 2.00401540                               ;  检查格式
004018E4                               |.  57                      |PUSH EDI
004018E5                               |.  8D4C24 18               |LEA ECX,DWORD PTR SS:[ESP+0x18]
004018E9                               |.  E8 72FDFFFF             |CALL 2.00401660                               ;  -1
004018EE                               |.  55                      |PUSH EBP
004018EF                               |.  8D4C24 18               |LEA ECX,DWORD PTR SS:[ESP+0x18]
004018F3                               |.  E8 38FEFFFF             |CALL 2.00401730                               ;  乘法
004018F8                               |.  8D5424 14               |LEA EDX,DWORD PTR SS:[ESP+0x14]
004018FC                               |.  8D8C24 24200000         |LEA ECX,DWORD PTR SS:[ESP+0x2024]
00401903                               |.  52                      |PUSH EDX
00401904                               |.  E8 D7FCFFFF             |CALL 2.004015E0                               ;  加法
00401909                               |.  817E 04 00040000        |CMP DWORD PTR DS:[ESI+0x4],0x400
00401910                               |.^ 7D 91                   |JGE X2.004018A3
00401912                               |.  8B4C24 10               |MOV ECX,DWORD PTR SS:[ESP+0x10]
00401916                               |.  8B43 04                 |MOV EAX,DWORD PTR DS:[EBX+0x4]
00401919                               |.  47                      |INC EDI
0040191A                               |.  83C1 04                 |ADD ECX,0x4
0040191D                               |.  3BF8                    |CMP EDI,EAX                                   ;  8位结束了么
0040191F                               |.  894C24 10               |MOV DWORD PTR SS:[ESP+0x10],ECX
00401923                               |.^ 7C AB                   \JL X2.004018D0
00401925                               |>  8BCE                    MOV ECX,ESI
00401927                               |.  E8 34010000             CALL 2.00401A60
0040192C                               |.  8D8424 24200000         LEA EAX,DWORD PTR SS:[ESP+0x2024]
00401933                               |.  8BCE                    MOV ECX,ESI
00401935                               |.  50                      PUSH EAX
00401936                               |.  E8 05FCFFFF             CALL 2.00401540
0040193B                               |.  8D8C24 24200000         LEA ECX,DWORD PTR SS:[ESP+0x2024]
00401942                               |.  E8 49FAFFFF             CALL 2.00401390
00401947                               |.  8D4C24 14               LEA ECX,DWORD PTR SS:[ESP+0x14]
0040194B                               |.  E8 40FAFFFF             CALL 2.00401390
00401950                               |.  33C0                    XOR EAX,EAX
00401952                               |>  8B8C24 34400000         MOV ECX,DWORD PTR SS:[ESP+0x4034]
00401959                               |.  5F                      POP EDI
0040195A                               |.  5E                      POP ESI
0040195B                               |.  5D                      POP EBP
0040195C                               |.  5B                      POP EBX
0040195D                               |.  64:890D 00000000        MOV DWORD PTR FS:[0],ECX
00401964                               |.  81C4 30400000           ADD ESP,0x4030
0040196A                               \.  C2 0400                 RETN 0x4
清空记录窗口,在 401137 设置断点,运行,此时查看记录窗口正在迅速回显记录,条数很多,此时静下心来逐条查看计算记录,
因为条数太多,这里只罗列最后结果那几行,剩下的记录请见附件log:

00401567   COND: 地址 = 0012C728
0040156B   COND: 密码  = 00000001
00401567   COND: 地址 = 0012CCFC
0040156B   COND: 密码  = 00000002
00401567   COND: 地址 = 0012C584
0040156B   COND: 密码  = 00000003
00401567   COND: 地址 = 0012C48C
0040156B   COND: 密码  = 00000004
00401567   COND: 地址 = 0012C154
0040156B   COND: 密码  = 00000005
00401567   COND: 地址 = 0012C3EC
0040156B   COND: 密码  = 00000006
00401567   COND: 地址 = 0012CC8C
0040156B   COND: 密码  = 00000007
00401567   COND: 地址 = 0012C220
0040156B   COND: 密码  = 00000008
00401567   COND: 地址 = 0012C188
0040156B   COND: 密码  = 00000009
00401567   COND: 地址 = 0012C740
0040156B   COND: 密码  = 00000008
00401567   COND: 地址 = 0012BFD0
0040156B   COND: 密码  = 00000007
00401567   COND: 地址 = 0012C8D8
0040156B   COND: 密码  = 00000006
00401567   COND: 地址 = 0012C11C
0040156B   COND: 密码  = 00000005
00401567   COND: 地址 = 0012C0BC
0040156B   COND: 密码  = 00000004
00401567   COND: 地址 = 0012CBEC
0040156B   COND: 密码  = 00000003
00401567   COND: 地址 = 0012C598
0040156B   COND: 密码  = 00000002
00401567   COND: 地址 = 0012BFEC
0040156B   COND: 密码  = 00000001
00401137   断点位于 2.00401137
整理计算记录、步骤:
1、12345679*9=111111111
2、111111111*9=999999999
3、1111111110*7=7777777770
4、7777777770+999999999=8777777769
5、11111111100*6=66666666600
6、66666666600+8777777769=75444444369
7、111111111000*5=555555555000
8、555555555000+75444444369=630999999369
9、1111111110000*4=4444444440000
10、4444444440000+630999999369=5075444439369
11、11111111100000*3=33333333300000
12、33333333300000+5075444439369=38408777739369
13、111111111000000*2=222222222000000
14、222222222000000+38408777739369=260630999739369
15、1111111110000000*1=1111111110000000
16、1111111110000000+260630999739369=1371742109739369
17、1371742109739369*9=12345678987654321
输出:12345678987654321
根据追踪记录,不难看出本作品是以用户输入倒置为十进制数,自定义了0x400位十进制计算乘法、加法(从低位到高位,逐位乘法、加法并进行进位)
Python 实现该部分算法:

#计算用户输入转为十进制之后进行乘法和累加

def calchash(input):

    input_str = str(input)

    calchash1 = input * 9

    calchash2 = 0

    count2 = 1

    while count2 <= len(input_str):

        calchash2 = calchash2 + calchash1 * (input % 10)

        calchash1 *= 10

        input //= 10

        count2 += 1

    calchash2 *= 9

    return calchash2


先在Python中测试:
输入“11111111”--> 11111111 -- > 16位:9999999800000001
输入“87654321”--> 12345678 -- > 17位:12345676987654404
输入“99999999”--> 99999999 -- > 18位:809999983800000081
输入8位-->16-18位
输入9位-->18-21位
依次类推,先得到大概输入、输出位数的范围,便于后续选择。
九、跟踪关键比较程序:
0040114D                               |.  8D8C24 0C010000         |LEA ECX,DWORD PTR SS:[ESP+0x10C]
00401154                               |.  E8 47020000             |CALL <2.len()>                                ;  读取结果位数
00401159                               |.  25 01000080             |AND EAX,0x80000001
0040115E                               |.  79 05                   |JNS X2.00401165                               ;  最高位非0时跳转
00401160                               |.  48                      |DEC EAX
00401161                               |.  83C8 FE                 |OR EAX,0xFFFFFFFE
00401164                               |.  40                      |INC EAX
00401165                               |>  83F8 01                 |CMP EAX,0x1                                   ;  位数必须为奇数,不能跳
00401168                               |.  0F85 A7000000           |JNZ 2.00401215                                ;  当输入8位数时,结果16-18位,所以可以假设
17位
0040116E                               |.  8D8C24 0C010000         |LEA ECX,DWORD PTR SS:[ESP+0x10C]
00401175                               |.  E8 26020000             |CALL <2.len()>                                ;  取结果位数
0040117A                               |.  D1F8                    |SAR EAX,1                                     ;  算术右移1位,相当于/2取整,如果输入8位,
则结果8
0040117C                               |.  50                      |PUSH EAX
0040117D                               |.  8D8C24 10010000         |LEA ECX,DWORD PTR SS:[ESP+0x110]              ;  0012BF20 -- 计算结果
00401184                               |.  E8 27020000             |CALL 2.004013B0                               ;  如果17位结果,则取第9位
00401189                               |.  6A 00                   |PUSH 0x0
0040118B                               |.  8D8C24 20210000         |LEA ECX,DWORD PTR SS:[ESP+0x2120]             ;  0012DF30 -- 用户输入十进制
00401192                               |.  8BF8                    |MOV EDI,EAX
00401194                               |.  E8 17020000             |CALL 2.004013B0                               ;  用户输入的第1位(十进制的个位)
00401199                               |.  3BF8                    |CMP EDI,EAX                                   ;  用户输入的第1位(十进制个位)== 计算结果
的中间位
0040119B                               |.  8D8C24 1C210000         |LEA ECX,DWORD PTR SS:[ESP+0x211C]
004011A2                               |.  75 78                   |JNZ X2.0040121C                               ;  不能跳
004011A4                               |.  6A 00                   |PUSH 0x0
004011A6                               |.  E8 F5010000             |CALL <2.len()>                                ;  用户输入十进制位数,比如8位
004011AB                               |.  48                      |DEC EAX                                       ;  8-1 = 7
004011AC                               |.  8D8C24 20210000         |LEA ECX,DWORD PTR SS:[ESP+0x2120]             ;  0012DF30 -- 用户输入十进制
004011B3                               |.  50                      |PUSH EAX
004011B4                               |.  6A 01                   |PUSH 0x1
004011B6                               |.  E8 E5010000             |CALL <2.len()>                                ;  用户输入十进制位数,比如8位
004011BB                               |.  BE 01000000             |MOV ESI,0x1
004011C0                               |.  8D8C24 18010000         |LEA ECX,DWORD PTR SS:[ESP+0x118]              ;  0012BF20 -- 计算结果
004011C7                               |.  2BF0                    |SUB ESI,EAX                                   ;  1-8 = -7
004011C9                               |.  E8 D2010000             |CALL <2.len()>                                ;  计算结果的位数
004011CE                               |.  03F0                    |ADD ESI,EAX                                   ;  17-7=10
004011D0                               |.  8D8C24 28210000         |LEA ECX,DWORD PTR SS:[ESP+0x2128]             ;  0012DF30 -- 用户输入十进制
004011D7                               |.  56                      |PUSH ESI                                      ;  10
004011D8                               |.  51                      |PUSH ECX                                      ;  0012DF30 -- 用户输入十进制
004011D9                               |.  8D8C24 20010000         |LEA ECX,DWORD PTR SS:[ESP+0x120]              ;  0012BF20 -- 计算结果
004011E0                               |.  E8 FB010000             |CALL 2.004013E0                               ;  关键比较1,逐位比较用户输入的第2-8位是否
与计算结果的第7-1位相等
004011E5                               |.  6A 01                   |PUSH 0x1
004011E7                               |.  8D8C24 20210000         |LEA ECX,DWORD PTR SS:[ESP+0x2120]
004011EE                               |.  8BF0                    |MOV ESI,EAX
004011F0                               |.  E8 AB010000             |CALL <2.len()>
004011F5                               |.  48                      |DEC EAX
004011F6                               |.  8D9424 20210000         |LEA EDX,DWORD PTR SS:[ESP+0x2120]
004011FD                               |.  50                      |PUSH EAX
004011FE                               |.  6A 01                   |PUSH 0x1
00401200                               |.  6A 00                   |PUSH 0x0
00401202                               |.  52                      |PUSH EDX
00401203                               |.  8D8C24 20010000         |LEA ECX,DWORD PTR SS:[ESP+0x120]
0040120A                               |.  E8 D1010000             |CALL 2.004013E0                               ;  关键比较2,逐位比较用户输入的第8-2位是否
与计算结果的17-11位相等
0040120F                               |.  03F0                    |ADD ESI,EAX
00401211                               |.  74 44                   |JE X2.00401257                                ;  正确出口
其中:
00401168                               |. /0F85 A7000000           |JNZ 2.00401215                                ;  当输入8位数时,结果16-18位,所以可以假设
17位
提示了计算结果极有可能是奇数位。
004011A2                               |. /75 78                   |JNZ X2.0040121C                               ;  不能跳
提示了用户输入的第1位(十进制个位)== 计算结果的中间位。
CALL 004013E0 关键比较,逐位比较用户输入的第2-8位是否与计算结果的第7-1位相等;用户输入的第8-2位是否与计算结果的17-11位相等:
004013E0                               /$  51                      PUSH ECX                                       ;  0012BF20 -- 计算结果
004013E1                               |.  8B5424 14               MOV EDX,DWORD PTR SS:[ESP+0x14]                ;  用户输入的十进制位数-1,比如输入8位,则
这里是7
004013E5                               |.  56                      PUSH ESI                                       ;  A 怎么来的呢,计算结果位数用户输入位
数=178=10
004013E6                               |.  57                      PUSH EDI                                       ;  计算结果中间位(计算结果奇数位)
004013E7                               |.  8BF9                    MOV EDI,ECX                                    ;  0012BF20 -- 计算结果
004013E9                               |.  8B4C24 10               MOV ECX,DWORD PTR SS:[ESP+0x10]                ;  0012DF30 -- 用户输入十进制
004013ED                               |.  C74424 08 00000000      MOV DWORD PTR SS:[ESP+0x8],0x0                 ;  12BDF8 -- 初值0
004013F5                               |.  85D2                    TEST EDX,EDX
004013F7                               |.  7E 7E                   JLE X2.00401477
004013F9                               |.  8B4424 18               MOV EAX,DWORD PTR SS:[ESP+0x18]                ;  注意 12BE08 初值 1
004013FD                               |.  53                      PUSH EBX
004013FE                               |.  55                      PUSH EBP
004013FF                               |.  8B6C24 1C               MOV EBP,DWORD PTR SS:[ESP+0x1C]                ;  第A位(其实A+1,下标0)
00401403                               |.  8D5C10 FF               LEA EBX,DWORD PTR DS:[EAX+EDU-0x1]             ;  11
00401407                               |.  8BF0                    MOV ESI,EAX
00401409                               |.  895C24 24               MOV DWORD PTR SS:[ESP+0x24],EBX                ;  ebx=11
0040140D                               |.  2BE8                    SUB EBP,EAX                                    ;  10-1
0040140F                               |>  8B5F 04                 /MOV EBX,DWORD PTR DS:[EDI+0x4]                ;  计算结果位数17
00401412                               |.  8D042E                  |LEA EAX,DWORD PTR DS:[ESI+EBP]                ;  1+9 2+9 ...
00401415                               |.  3BC3                    |CMP EAX,EBX
00401417                               |.  7C 0D                   |JL X2.00401426                                ;  计算结果的比较完了么
00401419                               |.  8B4424 10               |MOV EAX,DWORD PTR SS:[ESP+0x10]
0040141D                               |.  40                      |INC EAX
0040141E                               |.  33DB                    |XOR EBX,EBX
00401420                               |.  894424 10               |MOV DWORD PTR SS:[ESP+0x10],EAX
00401424                               |.  EB 02                   |JMP X2.00401428
00401426                               |>  8BD8                    |MOV EBX,EAX
00401428                               |>  E8 73FFFFFF             |CALL <2.len()>                                ;  用户输入十进制位数
0040142D                               |.  3BF0                    |CMP ESI,EAX
0040142F                               |.  7C 0D                   |JL X2.0040143E                                ;  用户输入的比较完了么
00401431                               |.  8B4424 10               |MOV EAX,DWORD PTR SS:[ESP+0x10]
00401435                               |.  40                      |INC EAX
00401436                               |.  894424 10               |MOV DWORD PTR SS:[ESP+0x10],EAX
0040143A                               |.  33C0                    |XOR EAX,EAX
0040143C                               |.  EB 0E                   |JMP X2.0040144C
0040143E                               |>  8A4424 28               |MOV AL,BYTE PTR SS:[ESP+0x28]                 ;  注意 12BE10 0
00401442                               |.  84C0                    |TEST AL,AL
00401444                               |.  8B4424 24               |MOV EAX,DWORD PTR SS:[ESP+0x24]
00401448                               |.  75 02                   |JNZ X2.0040144C
0040144A                               |.  8BC6                    |MOV EAX,ESI
0040144C                               |>  8B9C9F 08100000         |MOV EBX,DWORD PTR DS:[EDI+EBX*4+0x1008]       ;  计算结果第7、6、5、4、3、2、1位;第17、
16、15、14、13、12、11位
00401453                               |.  8B8481 08100000         |MOV EAX,DWORD PTR DS:[ECX+EAX*4+0x1008]       ;  用户输入第2、3、4、5、6、7、8位;第8、7
、6、5、4、3、2位
0040145A                               |.  8B5C9F 08               |MOV EBX,DWORD PTR DS:[EDI+EBX*4+0x8]
0040145E                               |.  3B5C81 08               |CMP EBX,DWORD PTR DS:[ECX+EAX*4+0x8]          ;  关键比较,逐位比较用户输入的第2-8位是否
与计算结果的第7-1位相等;用户输入的第8-2位是否与计算结果的17-11位相等
00401462                               |.  74 04                   |JE X2.00401468
00401464                               |.  FF4424 10               |INC DWORD PTR SS:[ESP+0x10]
00401468                               |>  8B4424 24               |MOV EAX,DWORD PTR SS:[ESP+0x24]
0040146C                               |.  48                      |DEC EAX
0040146D                               |.  46                      |INC ESI
0040146E                               |.  4A                      |DEC EDX
0040146F                               |.  894424 24               |MOV DWORD PTR SS:[ESP+0x24],EAX
00401473                               |.^ 75 9A                   \JNZ X2.0040140F
00401475                               |.  5D                      POP EBP
00401476                               |.  5B                      POP EBX
00401477                               |>  8B81 0C200000           MOV EAX,DWORD PTR DS:[ECX+0x200C]
0040147D                               |.  8BB7 0C200000           MOV ESI,DWORD PTR DS:[EDI+0x200C]
00401483                               |.  8B4C24 08               MOV ECX,DWORD PTR SS:[ESP+0x8]
00401487                               |.  33C6                    XOR EAX,ESI
00401489                               |.  C1E8 07                 SHR EAX,0x7
0040148C                               |.  5F                      POP EDI
0040148D                               |.  03C1                    ADD EAX,ECX
0040148F                               |.  5E                      POP ESI
00401490                               |.  59                      POP ECX
00401491                               \.  C2 1400                 RETN 0x14
至此算法部分基本清楚了。
十、算法逆向:
输入:“97654321”--> 12345679
输出:12345678987654321
满足条件1:每个输入字符为1-9数字
满足条件2:输出结果奇数位
满足条件3:输出结果中间位必须等于输入第1位(十进制末位)
满足条件4:用户输入的第2-8位(十进制7-1位)必须与计算结果的第7-1位相等
满足条件5:用户输入的第8-2位(十进制1-7位)必须与计算结果的17-11位相等
考虑先从8位数开始穷举:(也许算法深入分析后会有一些简便运算方法或者效率提升,但是人生苦短,只要出答案即可,不浪费时间)
Python Keygen:

#!/usr/bin/env python3

# -*- coding: utf-8 -*-

# Ctf.pediy.com ctf2017 crackme 2 keygen

# python 3.6.0 32bit

# written by 爱琴海

# 2017/06/14

import time

def main():

    start_time = time.clock()

    for sn in range(11111111,100000000):

        if check_input(sn) == 1:

            if check_answer(sn,calchash(sn)) == 1:

                print ('found sn:',str(sn)[::-1])

                break

    print ('use time: %.3f second' % (time.clock()-start_time))

    return

#校验计算结果,假设输入8位,如果测试更多位数需要对程序做完善,这里图省事

def check_answer(input1,out1):

    input1_str = str(input1)

    out1_str = str(out1)

    count = len(out1_str) // 2

    if len(out1_str) % 2 == 1:

        if out1_str[count] == input1_str[7]:

            if out1_str[0:7] == input1_str[0:7]:

                input1_str = input1_str[::-1]

                if out1_str[10:17] == input1_str[1:8]:

                    return 1

            else:

                return 0

        else:

            return 0

    else:

        return 0

#检查输入是否包含0

def check_input(input2):

    input2_str = str(input2)

    count1 = 1

    while count1 <= len(input2_str):

        if input2 % 10 == 0:

            return 0

        else:

            input2 //= 10

        count1 += 1

    return 1

#计算用户输入转为十进制之后进行乘法和累加

def calchash(input):

    input_str = str(input)

    calchash1 = input * 9

    calchash2 = 0

    count2 = 1

    while count2 <= len(input_str):

        calchash2 = calchash2 + calchash1 * (input % 10)

        calchash1 *= 10

        input //= 10

        count2 += 1

    calchash2 *= 9

    return calchash2

if __name__=="__main__":

    main()


如果换好一些的电脑、不采用脚本计算,速度应该会有显著提升。


十一、总结:
本题作者自定义实现了最大0x400位十进制乘法、加法运算,注册码算法对原文和密文都有关联,一时半会儿我认为穷举是最合适的。
本题难点在于对众多汇编指令的跟踪、理解、总结,对模拟大数运算的了解,以及调试方法的恰当应用,否则会把你绕晕。

上传的附件 ctf2017_crackme_2.rar
算法条件记录_log.txt

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功