首页
社区
课程
招聘
[原创]CPP_Crackme1的破解和算法分析
发表于: 2006-8-21 01:29 5285

[原创]CPP_Crackme1的破解和算法分析

jdxyw 活跃值
19
2006-8-21 01:29
5285

【文章标题】: CPP_Crackme1的破解和算法分析
【文章作者】: jdxyw
【软件名称】: CPP_Crackme1
【下载地址】: 自己搜索下载
【加壳方式】: 无
【编写语言】: C/C++
【使用工具】: OD peid
【操作平台】: XP
【作者声明】: 如果先前有高手已经有破过,请告诉我,我会把附件删掉,给论坛省点空间。
--------------------------------------------------------------------------------
【详细过程】
  peid查壳,无壳
  
  点击运行,随便输入一个用户名和序列号,这里我的用户名是yutou 序列号随便
  
  运行od,将crack载入,F9运行,输入用户名和序列号
  
  CTRL+N 在GetWindowText下断点,一共有三个同样的函数,只要下其中的两个就可以了
  
  点击check后来到004016C6 F8运行几部后来到下面
  00401747  |>  8D95 50FFFFFF /LEA EDX,DWORD PTR SS:[EBP-B0]
  0040174D  |.  52            |PUSH EDX
  0040174E  |.  FFD6          |CALL ESI
  00401750  |.  3BD8          |CMP EBX,EAX
  00401752  |.  7D 16         |JGE SHORT CPP_Crac.0040176A
  00401754  |.  8A8C1D 50FFFF>|MOV CL,BYTE PTR SS:[EBP+EBX-B0]                      依次取用户名的字节
  0040175B  |.  8AC3          |MOV AL,BL
  0040175D  |.  FEC0          |INC AL
  0040175F  |.  32C8          |XOR CL,AL
  00401761  |.  888C1D 70FFFF>|MOV BYTE PTR SS:[EBP+EBX-90],CL                      计算结果保存
  00401768  |.  EB 19         |JMP SHORT CPP_Crac.00401783
  0040176A  |>  8B07          |MOV EAX,DWORD PTR DS:[EDI]                           依次取内存表中的双字
  0040176C  |.  B9 39000000   |MOV ECX,39
  00401771  |.  83F0 5A       |XOR EAX,5A
  00401774  |.  03C3          |ADD EAX,EBX
  00401776  |.  99            |CDQ                                                  edx=0
  00401777  |.  F7F9          |IDIV ECX                                          
  00401779  |.  80C2 41       |ADD DL,41
  0040177C  |.  88941D 70FFFF>|MOV BYTE PTR SS:[EBP+EBX-90],DL                      结果保存
  00401783  |>  83C7 04       |ADD EDI,4
  00401786  |.  43            |INC EBX
  00401787  |.  81FF A8704000 |CMP EDI,CPP_Crac.004070A8
  0040178D  |.^ 7C B8         \JL SHORT CPP_Crac.00401747
  
  上面这个循环一共循环30次,前五次循环是依次取用户名的一个字节,将此字节和循环次异或,再将异或的结果放到以0013FB68开始的
  堆栈。后二十五次的循环是,依次取出原本就在内存中一个表中DS:[EDI]的字到EAX中,使得((eax xor 5ah)+ebx)/39h
  所得的余数存入dl ,再将dl+41,所得存入堆栈中。这是通过用户计算所得的第一个数据
  0040178F  |.  8D55 90       LEA EDX,DWORD PTR SS:[EBP-70]
  00401792  |.  6A 1E         PUSH 1E
  00401794  |.  8D85 70FFFFFF LEA EAX,DWORD PTR SS:[EBP-90]
  0040179A  |.  52            PUSH EDX
  0040179B  |.  50            PUSH EAX
  0040179C  |.  C645 8E 00    MOV BYTE PTR SS:[EBP-72],0
  004017A0  |.  E8 EA050000   CALL CPP_Crac.00401D8F                        这个函数的调用是将上个循环算的数据复制一遍,
                                                                            所不同的是,没两个数据的位置是交换的,保存在0013fb88
  
  004017A5  |.  83C4 0C       ADD ESP,0C
  004017A8  |.  C645 AE 00    MOV BYTE PTR SS:[EBP-52],0
  004017AC  |.  33C0          XOR EAX,EAX
  004017AE  |.  33C9          XOR ECX,ECX
  004017B0  |>  8A540D 90     /MOV DL,BYTE PTR SS:[EBP+ECX-70]            
  004017B4  |.  8855 FF       |MOV BYTE PTR SS:[EBP-1],DL
  004017B7  |.  8A45 FF       |MOV AL,BYTE PTR SS:[EBP-1]
  004017BA  |.  D1C8          |ROR EAX,1
  004017BC  |.  8845 FF       |MOV BYTE PTR SS:[EBP-1],AL
  004017BF  |.  8A45 FF       |MOV AL,BYTE PTR SS:[EBP-1]
  004017C2  |.  88440D 90     |MOV BYTE PTR SS:[EBP+ECX-70],AL
  004017C6  |.  41            |INC ECX
  004017C7  |.  83F9 1E       |CMP ECX,1E
  
  这个循环同样循环30次,先是从堆栈0013fb88处依次取一个字节到AL处,右移动一位,再将算得的数据的AL送返回到原来堆栈处0013fb88
  004017CA  |.^ 7C E4         \JL SHORT CPP_Crac.004017B0
  004017CC  |.  33C9          XOR ECX,ECX
  004017CE  |.  8DBD D8FCFFFF LEA EDI,DWORD PTR SS:[EBP-328]
  004017D4  |>  0FBE840D 70FF>/MOVSX EAX,BYTE PTR SS:[EBP+ECX-90]                  依次 取0013fb68的一个字节
  004017DC  |.  0FBE540D 90   |MOVSX EDX,BYTE PTR SS:[EBP+ECX-70]                  依次 取0013fb88的一个字节
  004017E1  |.  8BF0          |MOV ESI,EAX
  004017E3  |.  0FAFC2        |IMUL EAX,EDX
  004017E6  |.  33F2          |XOR ESI,EDX
  004017E8  |.  83C7 04       |ADD EDI,4
  004017EB  |.  03F0          |ADD ESI,EAX
  004017ED  |.  41            |INC ECX
  004017EE  |.  8977 FC       |MOV DWORD PTR DS:[EDI-4],ESI
  004017F1  |.  83F9 1E       |CMP ECX,1E
  
  这个循环同样循环30次,依次取0013fb68和0013fb88的一个字节分别到eax和edx,做如下运算 (EAX*edx)+(eax xor edx) 把计算双字所得存入堆栈
  0013f8d0
  004017F4  |.^ 7C DE         \JL SHORT CPP_Crac.004017D4
  004017F6  |.  8D85 D8FCFFFF LEA EAX,DWORD PTR SS:[EBP-328]
  004017FC  |.  B9 0F000000   MOV ECX,0F
  00401801  |>  8B50 3C       /MOV EDX,DWORD PTR DS:[EAX+3C]                        依次 取0013f90c的一个双字
  00401804  |.  8B38          |MOV EDI,DWORD PTR DS:[EAX]                           依次 取0013f8d0的一个双字
  00401806  |.  03FA          |ADD EDI,EDX
  00401808  |.  8938          |MOV DWORD PTR DS:[EAX],EDI
  0040180A  |.  83C0 04       |ADD EAX,4
  0040180D  |.  49            |DEC ECX
  0040180E  |.^ 75 F1         \JNZ SHORT CPP_Crac.00401801
  
  这个循环是15次,分别从0013f8d0和0013f90c处依次取双字到eax 和edx 做如下计算 eax+edx 计算所得存入0013f8d0
  00401810  |.  33C0          XOR EAX,EAX
  00401812  |.  33C9          XOR ECX,ECX
  00401814  |.  8DBD D8FCFFFF LEA EDI,DWORD PTR SS:[EBP-328]
  0040181A  |>  8B07          /MOV EAX,DWORD PTR DS:[EDI]                           依次从0013f8d0取一个双字到eax
  0040181C  |.  8945 B0       |MOV DWORD PTR SS:[EBP-50],EAX                     
  0040181F  |.  8B45 B0       |MOV EAX,DWORD PTR SS:[EBP-50]
  00401822  |.  8845 B4       |MOV BYTE PTR SS:[EBP-4C],AL
  00401825  |.  8B45 B4       |MOV EAX,DWORD PTR SS:[EBP-4C]                        取其中的al到eax
  00401828  |.  BE 09000000   |MOV ESI,9
  0040182D  |.  25 FF000000   |AND EAX,0FF
  00401832  |.  83C7 04       |ADD EDI,4
  00401835  |.  99            |CDQ                                                   edx=0
  00401836  |.  F7FE          |IDIV ESI
  00401838  |.  80C2 30       |ADD DL,30
  0040183B  |.  88540D D4     |MOV BYTE PTR SS:[EBP+ECX-2C],DL
  0040183F  |.  41            |INC ECX
  00401840  |.  83F9 0F       |CMP ECX,0F
  00401843  |.^ 7C D5         \JL SHORT CPP_Crac.0040181A
  
  这个循环是15次,依次从0013f8d0取一个双字到eax,取其中的al到eax,做以下运算,(eax/9),所得余数加上30h,所得存入0013fbcc
  00401845  |.  B9 06000000   MOV ECX,6
  0040184A  |.  33C0          XOR EAX,EAX
  0040184C  |.  8D7D E4       LEA EDI,DWORD PTR SS:[EBP-1C]
  0040184F  |.  F3:AB         REP STOS DWORD PTR ES:[EDI]
  00401851  |.  8B0D 30704000 MOV ECX,DWORD PTR DS:[407030]
  00401857  |.  83F1 63       XOR ECX,63
  0040185A  |.  51            PUSH ECX
  0040185B  |.  AA            STOS BYTE PTR ES:[EDI]
  0040185C  |.  E8 62040000   CALL CPP_Crac.00401CC3                           此函数以上是生成加上一个字符‘U’
  00401861  |.  8B15 34704000 MOV EDX,DWORD PTR DS:[407034]
  00401867  |.  8845 E4       MOV BYTE PTR SS:[EBP-1C],AL
  0040186A  |.  83F2 63       XOR EDX,63
  0040186D  |.  52            PUSH EDX
  0040186E  |.  E8 50040000   CALL CPP_Crac.00401CC3                           此函数以上是生成加上一个字符‘L’
  00401873  |.  8845 E5       MOV BYTE PTR SS:[EBP-1B],AL
  00401876  |.  A1 38704000   MOV EAX,DWORD PTR DS:[407038]
  0040187B  |.  83F0 63       XOR EAX,63
  0040187E  |.  50            PUSH EAX
  0040187F  |.  E8 3F040000   CALL CPP_Crac.00401CC3                           此函数是将0013fbcc处得数据转为字符
  00401884  |.  8D4D D4       LEA ECX,DWORD PTR SS:[EBP-2C]
  00401887  |.  6A 0F         PUSH 0F
  00401889  |.  8D55 E4       LEA EDX,DWORD PTR SS:[EBP-1C]
  0040188C  |.  B3 2D         MOV BL,2D
  0040188E  |.  51            PUSH ECX
  0040188F  |.  52            PUSH EDX
  00401890  |.  8845 E6       MOV BYTE PTR SS:[EBP-1A],AL                       加上一个字符'T'
  
  00401893  |.  885D E7       MOV BYTE PTR SS:[EBP-19],BL                       加上一个字符‘-’
  00401896  |.  E8 05030000   CALL CPP_Crac.00401BA0
  0040189B  |.  8B0D 50974000 MOV ECX,DWORD PTR DS:[409750]
  004018A1  |.  83C4 18       ADD ESP,18
  004018A4  |.  8D45 B8       LEA EAX,DWORD PTR SS:[EBP-48]
  004018A7  |.  885D F7       MOV BYTE PTR SS:[EBP-9],BL
  004018AA  |.  6A 19         PUSH 19                                  ; /Count = 19 (25.)
  004018AC  |.  50            PUSH EAX                                 ; |Buffer
  004018AD  |.  51            PUSH ECX                                 ; |hWnd => NULL
  004018AE  |.  C645 F8 32    MOV BYTE PTR SS:[EBP-8],32               ; |               这里以下的四句分别在序列号后加上四个字符
                                                                                         这在下面将造成很大的迷惑                     
  004018B2  |.  C645 F9 34    MOV BYTE PTR SS:[EBP-7],34               ; |
  004018B6  |.  C645 FA 31    MOV BYTE PTR SS:[EBP-6],31               ; |
  004018BA  |.  C645 FB 33    MOV BYTE PTR SS:[EBP-5],33               ; |
  004018BE  |.  FF15 C8604000 CALL DWORD PTR DS:[<&USER32.GetWindowTex>; \GetWindowTextA
  004018C4  |.  83F8 01       CMP EAX,1
  004018C7  |.  5B            POP EBX
  004018C8  |.  7D 68         JGE SHORT CPP_Crac.00401932
  004018CA  |.  6A 18         PUSH 18
  004018CC  |.  68 18714000   PUSH CPP_Crac.00407118
  F8几步后,将到一个call处,
  004019BC  |.  E8 5F010000   CALL CPP_Crac.00401B20
  
  
  这个call可以跟进,你会发现一些问题
  00401B20  /$  56            PUSH ESI
  00401B21  |.  57            PUSH EDI
  00401B22  |.  B9 3F000000   MOV ECX,3F
  00401B27  |.  33C0          XOR EAX,EAX
  00401B29  |.  BF 54974000   MOV EDI,CPP_Crac.00409754
  00401B2E  |.  8B7424 10     MOV ESI,DWORD PTR SS:[ESP+10]
  00401B32  |.  F3:AB         REP STOS DWORD PTR ES:[EDI]
  00401B34  |.  66:AB         STOS WORD PTR ES:[EDI]
  00401B36  |.  AA            STOS BYTE PTR ES:[EDI]
  00401B37  |.  33C0          XOR EAX,EAX
  00401B39  |.  85F6          TEST ESI,ESI
  00401B3B  |.  7E 17         JLE SHORT CPP_Crac.00401B54
  00401B3D  |.  8B4C24 0C     MOV ECX,DWORD PTR SS:[ESP+C]
  00401B41  |>  8A11          /MOV DL,BYTE PTR DS:[ECX]
  00401B43  |.  83C1 04       |ADD ECX,4
  00401B46  |.  80F2 63       |XOR DL,63
  00401B49  |.  8890 54974000 |MOV BYTE PTR DS:[EAX+409754],DL
  00401B4F  |.  40            |INC EAX
  00401B50  |.  3BC6          |CMP EAX,ESI
  00401B52  |.^ 7C ED         \JL SHORT CPP_Crac.00401B41
  00401B54  |>  5F            POP EDI
  00401B55  |.  5E            POP ESI
  00401B56  \.  C3            RETN
  
  从这个循环你会发现,这个循环只循环20次,而序列号是要求24个的,最后4个,也就是上面最终加上的四个,也就是我们在内存中
  可以看到的似乎是真序列号的最后四位,是不在这里比较的。我们也可以看处,无论我们的用户名是什么,最后四位似乎都是一样的。
  
  继续,可以来到一个比较最后四位的地方
  00401A1C  |>  8A4D CC       MOV CL,BYTE PTR SS:[EBP-34]
  00401A1F  |.  80F1 63       XOR CL,63
  00401A22  |.  80F9 53       CMP CL,53
  00401A25  |.  0F85 86000000 JNZ CPP_Crac.00401AB1
  00401A2B  |.  8A55 CD       MOV DL,BYTE PTR SS:[EBP-33]
  00401A2E  |.  80F2 63       XOR DL,63
  00401A31  |.  80FA 52       CMP DL,52
  00401A34  |.  75 7B         JNZ SHORT CPP_Crac.00401AB1
  00401A36  |.  8A45 CE       MOV AL,BYTE PTR SS:[EBP-32]
  00401A39  |.  34 63         XOR AL,63
  00401A3B  |.  3C 57         CMP AL,57
  00401A3D  |.  75 72         JNZ SHORT CPP_Crac.00401AB1
  00401A3F  |.  8A4D CF       MOV CL,BYTE PTR SS:[EBP-31]
  00401A42  |.  80F1 63       XOR CL,63
  00401A45  |.  3ACA          CMP CL,DL
  00401A47  |.  75 68         JNZ SHORT CPP_Crac.00401AB1
  
  简单反向计算,最后四位应该是0141
  
  
  算法总结
  
  第一个循环,前五次循环是依次取用户名的一个字节,将此字节和循环次异或,再将异或的结果放到以0013FB68开始的
  堆栈。后二十五次的循环是,依次取出原本就在内存中一个表中DS:[EDI]的字到EAX中,使得((eax xor 5ah)+ebx)/39h
  所得的余数存入dl ,再将dl+41,所得存入堆栈中。这是通过用户计算所得的第一个数据。
  将上个循环算的数据复制一遍,所不同的是,没两个数据的位置是交换的,保存在0013fb88
  先是从堆栈0013fb88处依次取一个字节到AL处,右移动一位,再将算得的数据的AL送返回到原来堆栈处0013fb88
  依次取0013fb68和0013fb88的一个字节分别到eax和edx,做如下运算 (EAX*edx)+(eax xor edx) 把计算双字所得存入堆栈
  依次从0013f8d0取一个双字到eax,取其中的al到eax,做以下运算,(eax/9),所得余数加上30h,所得存入0013fbcc
  将存在0013FBCC处的数据转为字符,在前面加上“ULT-”在后面加上“-0141”
  
  
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2006年08月21日 1:27:46


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
支持
分享
最新回复 (2)
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
好文章,拜读了!
2006-8-21 15:03
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
汇编只学了点皮毛,看得还不是很懂
2006-8-21 21:12
0
游客
登录 | 注册 方可回帖
返回
//