• 标 题:SuperCleaner算法分析----菜鸟级 (12千字)
  • 作 者:wolflh2002
  • 时 间:2002-9-5 22:38:58
  • 链 接:http://bbs.pediy.com

软件名称:SuperCleaner
最新版本:2.42
文件大小:276KB
软件简介:
  是帮助用户清洗他们的计算机硬盘内不必要的文件的程序。它能扫描你的系统让你选择不再需要的文件进行删除。并能备份文件已避免你误删除有用的文件,此备份功能将不必要的文件扔进再循环箱,这样可以让你再必要的时候恢复信息。

下载地址:http://gwbn.onlinedown.net/down/cleansetup.exe
软件信息:VC,无壳,30天使用限制.保护简单,明码比较.最适合我等菜鸟了
破解工具llyDbg,pw32dasmgold(在此篇破文中只用它来抓代码)
破解者:wolflh2002


破解过程:

以前在看雪老师的论坛上发表过一次,并有幸被看雪老师收入精华.但那次是在WIN98下,用TRW(我喜欢用这个工具了)可以很容易的跟出,注册码是用明码比较,且没有分析出算法.这次因为机器升级了,摒弃了WIN98.而WIN2K下TRW的"万能断点"(HMEMCPY)无用.所以只好借助OllyDbg了.

根据各种教程、破文的教导,用w32dasm反汇编.可找来找去,也找不着注册成功的标志;出错的信息倒有一个,不过多次双击却有多个结果,而我这个菜鸟也看不出哪一个对我有用的.
破罐子破摔了,用OllyDbg载入RUN,选择"Enter Registration"项,出现注册对话框.输入
用户名:wolflh2002
注册码:5378378(当然是假的,有真的我还用这么辛苦?)
回到OllyDbg界面,按CTRL+N或单击鼠标右键选择"Search for"->"Name(label) in current module"
.按明码比较的惯例选择"KERNEL32.lstrcmpA",回车.在第一项(00402005)上按F2设置断点.再回到注册界面,点击"OK".YEAH,被OllyDbg断下了.

* Possible Reference to Dialog: DialogID_0065, CONTROL_ID:03FC, ""
|
:00411DD3 68FC030000 push 000003FC
:00411DD8 56 push esi
:00411DD9 FFD7 call edi
:00411DDB 8D442408 lea eax, dword ptr [esp+08]
:00411DDF 8D8C2408010000 lea ecx, dword ptr [esp+00000108]
:00411DE6 50 push eax ----压入假注册码
:00411DE7 51 push ecx ----压入真用户名crazywolf(这就是用英文的好处,不然寄存器不可能显示中文的)
:00411DE8 E8B3050000 call 004123A0 ----停在这里,可疑!!!F7进入(在OllyDbg里相当于TRW的F8)
:00411DED 83C408 add esp, 00000008
:00411DF0 85C0 test eax, eax
:00411DF2 5F pop edi
:00411DF3 7443 je 00411E38 -----这里弹出出错对话框
:00411DF5 8D542404 lea edx, dword ptr [esp+04]
:00411DF9 8D842404010000 lea eax, dword ptr [esp+00000104]
:00411E00 52 push edx
:00411E01 50 push eax

.
.
.
.
(此处略去XXXXX个字节)

进入此CALL后:

* Referenced by a CALL at Addresses:
|:00411DE8 , :004122CE
|
:004123A0 81EC00010000 sub esp, 00000100
:004123A6 A080964200 mov al, byte ptr [00429680]
:004123AB 56 push esi
:004123AC 57 push edi
:004123AD 88442408 mov byte ptr [esp+08], al

* Possible Reference to String Resource ID=00063: "The location you specified does not contain a Netscape 4 pro"
|
:004123B1 B93F000000 mov ecx, 0000003F
:004123B6 33C0 xor eax, eax
:004123B8 8D7C2409 lea edi, dword ptr [esp+09]
:004123BC 8B94240C010000 mov edx, dword ptr [esp+0000010C]
:004123C3 F3 repz
:004123C4 AB stosd
:004123C5 66AB stosw
:004123C7 8D4C2408 lea ecx, dword ptr [esp+08]
:004123CB 33F6 xor esi, esi
:004123CD 51 push ecx
:004123CE 52 push edx
:004123CF AA stosb
:004123D0 E8AB000000 call 00412480 ----过了这里就出现我们所需要的注册码了.(虽然我不懂算法,进入看看总可以吧??)
:004123D5 8B8C2418010000 mov ecx, dword ptr [esp+00000118]
:004123DC 8D442410 lea eax, dword ptr [esp+10]
:004123E0 50 push eax ----真码
:004123E1 51 push ecx ----假码
:004123E2 E869FFFFFF call 00412350
:004123E7 83C410 add esp, 00000010
:004123EA 85C0 test eax, eax

* Possible Reference to String Resource ID=00001: "Registered to: %s"
|
:004123EC B801000000 mov eax, 00000001
:004123F1 7502 jne 004123F5
:004123F3 8BC6 mov eax, esi

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004123F1(C)
|
:004123F5 5F pop edi
:004123F6 5E pop esi
:004123F7 81C400010000 add esp, 00000100
:004123FD C3 ret
.
.
.
.
(继续略去XXXXX个字节)
.
.
.
.以下是完整的算法过程:

:00412480 81EC00010000 sub esp, 00000100
:00412486 A080964200 mov al, byte ptr [00429680]
:0041248B 53 push ebx
:0041248C 55 push ebp
:0041248D 56 push esi
:0041248E 57 push edi
:0041248F 88442410 mov byte ptr [esp+10], al

* Possible Reference to String Resource ID=00063: "The location you specified does not contain a Netscape 4 pro"
|
:00412493 B93F000000 mov ecx, 0000003F
:00412498 33C0 xor eax, eax
:0041249A 8D7C2411 lea edi, dword ptr [esp+11]
:0041249E F3 repz
:0041249F AB stosd
:004124A0 66AB stosw
:004124A2 AA stosb
:004124A3 8BBC2414010000 mov edi, dword ptr [esp+00000114] ----用户名送edi
:004124AA 57 push edi ----压入用户名

* Reference To: KERNEL32.lstrlenA, Ord:03AEh
|
:004124AB FF1538024200 Call dword ptr [00420238]    ----计算用户名长度
:004124B1 8BF0 mov esi, eax            ----用户名长度送esi
:004124B3 33C9 xor ecx, ecx ----ecx清零
:004124B5 33C0 xor eax, eax ----eax清零
:004124B7 85F6 test esi, esi
:004124B9 7E13 jle 004124CE
:004124BB 8B1508664200 mov edx, dword ptr [00426608] ----注册名送入edx

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004124CC(C)
|
:004124C1 0FBE1C38 movsx ebx, byte ptr [eax+edi] ----依次将用户名字节转换为ascii送ebx
:004124C5 03DA add ebx, edx ----ebx+edx的值送ebx (edx=26)
:004124C7 03CB add ecx, ebx            ----ecx+ebx的值送ecx   
:004124C9 40 inc eax ----eax加1
:004124CA 3BC6 cmp eax, esi ----是否计算完毕
:004124CC 7CF3 jl 004124C1 ----循环

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004124B9(C)
|
:004124CE 8B9C2418010000 mov ebx, dword ptr [esp+00000118] ----显示注册码的第一部分(这里是我自己猜的)
:004124D5 51 push ecx ----压入累加的值(十六进制)

* Possible StringData Ref from Data Obj ->"%ld-" ----加入分隔符"-"
|
:004124D6 681C664200 push 0042661C
:004124DB 53 push ebx

* Reference To: USER32.wsprintfA, Ord:02D6h
|
:004124DC FF1520034200 Call dword ptr [00420320]
:004124E2 83C40C add esp, 0000000C
:004124E5 33C9 xor ecx, ecx
:004124E7 33C0 xor eax, eax
:004124E9 85F6 test esi, esi
:004124EB 7E14 jle 00412501
:004124ED 8B150C664200 mov edx, dword ptr [0042660C]

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004124FF(C)
|
:004124F3 0FBE2C38 movsx ebp, byte ptr [eax+edi] ----依次将用户名字节转换为ascii送ebp
:004124F7 0FAFEA imul ebp, edx ----ebp*edx的值送ebp (edx=34)
:004124FA 03CD add ecx, ebp ----ecx+ebp的值送ecx
:004124FC 40 inc eax ----eax加1
:004124FD 3BC6 cmp eax, esi ----是否计算完毕
:004124FF 7CF2 jl 004124F3 ----循环

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004124EB(C)
|
:00412501 51 push ecx
:00412502 8D4C2414 lea ecx, dword ptr [esp+14]

* Possible StringData Ref from Data Obj ->"%ld-" ----加入分隔符"-"
|
:00412506 681C664200 push 0042661C
:0041250B 51 push ecx

* Reference To: USER32.wsprintfA, Ord:02D6h
|
:0041250C FF1520034200 Call dword ptr [00420320]
:00412512 83C40C add esp, 0000000C
:00412515 8D542410 lea edx, dword ptr [esp+10]
:00412519 52 push edx
:0041251A 53 push ebx

* Reference To: KERNEL32.lstrcatA, Ord:039Fh
|
:0041251B FF1520024200 Call dword ptr [00420220]
:00412521 33C9 xor ecx, ecx
:00412523 33C0 xor eax, eax
:00412525 85F6 test esi, esi
:00412527 7E13 jle 0041253C
:00412529 8B1510664200 mov edx, dword ptr [00426610]

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0041253A(C)
|
:0041252F 0FBE2C38 movsx ebp, byte ptr [eax+edi] ----依次将用户名字节转换为ascii送
:00412533 03EA add ebp, edx            ----ebp+edx的值送ebp (edx=0C)
:00412535 03CD add ecx, ebp        ----ecx+ebp的值送ecx
:00412537 40 inc eax            ----eax加1
:00412538 3BC6 cmp eax, esi            ----是否计算完毕
:0041253A 7CF3 jl 0041252F ----循环

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00412527(C)
|
:0041253C 51 push ecx
:0041253D 8D442414 lea eax, dword ptr [esp+14]

* Possible StringData Ref from Data Obj ->"%ld-"    ----加入分隔符"-"
|
:00412541 681C664200 push 0042661C
:00412546 50 push eax

* Reference To: USER32.wsprintfA, Ord:02D6h
|
:00412547 FF1520034200 Call dword ptr [00420320]
:0041254D 83C40C add esp, 0000000C
:00412550 8D4C2410 lea ecx, dword ptr [esp+10]
:00412554 51 push ecx
:00412555 53 push ebx

* Reference To: KERNEL32.lstrcatA, Ord:039Fh
|
:00412556 FF1520024200 Call dword ptr [00420220]
:0041255C 33C9 xor ecx, ecx
:0041255E 33C0 xor eax, eax
:00412560 85F6 test esi, esi
:00412562 7E14 jle 00412578
:00412564 8B1514664200 mov edx, dword ptr [00426614]

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00412576(C)
|
:0041256A 0FBE2C38 movsx ebp, byte ptr [eax+edi]
:0041256E 0FAFEA imul ebp, edx            ----ebp*edx的值送ebp (edx=0E)
:00412571 03CD add ecx, ebp        ----ecx+ebp的值送ecx
:00412573 40 inc eax            ----eax加1
:00412574 3BC6 cmp eax, esi            ----是否计算完毕
:00412576 7CF2 jl 0041256A            ----循环

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00412562(C)
|
:00412578 51 push ecx
:00412579 8D542414 lea edx, dword ptr [esp+14]

* Possible StringData Ref from Data Obj ->"%ld"        ----加入分隔符"-"
|
:0041257D 6818664200 push 00426618
:00412582 52 push edx

* Reference To: USER32.wsprintfA, Ord:02D6h
|
:00412583 FF1520034200 Call dword ptr [00420320]
:00412589 83C40C add esp, 0000000C
:0041258C 8D442410 lea eax, dword ptr [esp+10]
:00412590 50 push eax
:00412591 53 push ebx

* Reference To: KERNEL32.lstrcatA, Ord:039Fh
|
:00412592 FF1520024200 Call dword ptr [00420220]
:00412598 5F pop edi
:00412599 5E pop esi
:0041259A 5D pop ebp
:0041259B 5B pop ebx
:0041259C 81C400010000 add esp, 00000100
:004125A2 C3 ret
.
.
.
恕我刚加入"风飘雪",汇编知识不太丰富,所以大部分算法都是自己乱猜的.分析如有错误,欢迎指出.

#############################################################################################################################


因为对OllyDbg的使用还不熟悉,所以在对选择"KERNEL32.lstrcmpA"时使用了鼠标双击命令(没有使用回车),致使无法弹出"References in 'xxsoftwarename'"界面.一厢情愿的认为该命令无效,而采取了另外一种断点:

"Search for"->"All referenced text strings"查找出错提示信息,找不到!!!!(吐血)
从弹出出错的对话框入手,CTRL+N选择"USER32.GetDlgItemTextA",回车,选择最后一项(00411DAE)F2设断.因为总共有三项,估计前两项是检查是否输入用户名和注册码用的,所以不设.


* Reference To: USER32.GetDlgItemTextA, Ord:0113h
|
:00411DAE 8B3D9C024200 mov edi, dword ptr [0042029C] ----停在此处
:00411DB4 8D8C2408010000 lea ecx, dword ptr [esp+00000108]
:00411DBB 6800010000 push 00000100
:00411DC0 51 push ecx

* Possible Reference to Dialog: DialogID_0065, CONTROL_ID:0417, ""
|
:00411DC1 6817040000 push 00000417
:00411DC6 56 push esi
:00411DC7 FFD7 call edi
:00411DC9 8D542408 lea edx, dword ptr [esp+08]
:00411DCD 6800010000 push 00000100
:00411DD2 52 push edx

* Possible Reference to Dialog: DialogID_0065, CONTROL_ID:03FC, ""
|
:00411DD3 68FC030000 push 000003FC
:00411DD8 56 push esi
:00411DD9 FFD7 call edi
:00411DDB 8D442408 lea eax, dword ptr [esp+08] ----假注册码
:00411DDF 8D8C2408010000 lea ecx, dword ptr [esp+00000108] ----真用户名(呵呵)
:00411DE6 50 push eax ----压入假注册码
:00411DE7 51 push ecx ----压入用户名
:00411DE8 E8B3050000 call 004123A0 ----所以这里可疑F7进入,剩下的分析同上
:00411DED 83C408 add esp, 00000008
:00411DF0 85C0 test eax, eax
:00411DF2 5F pop edi
:00411DF3 7443 je 00411E38
:00411DF5 8D542404 lea edx, dword ptr [esp+04]
:00411DF9 8D842404010000 lea eax, dword ptr [esp+00000104]
:00411E00 52 push edx
:00411E01 50 push eax


总结:算法分析:
注册码算法由四个部分组成:

第一部分算法:依次取用户名各字节的ascii码,转换成十六进制,然后和26(十六进制)乘以用户名长度(十六进制)的积相加
(A1+A2+An)+(26*用户名长度),再转换为十进制.
第二部分算法:依次取用户名各字节的ascii码,转换成十六进制,相加之后的和乘以34(十六进制)
(A1+A2+An)*34
第三部分算法:依次取用户名各字节的ascii码,转换成十六进制,然后和0C(十六进制)乘以用户名长度(十六进制)的积相加
(A1+A2+An)+(0C*用户名长度),再转换为十进制.
第四部分算法:依次取用户名各字节的ascii码,转换成十六进制,相加之后的和乘以0E(十六进制)
(A1+A2+An)*0E
将四个部分的注册码使用分隔符"-"连接


将这个软件翻来覆去搞了一个下午.
突然发现用英文名注册才会出现以上破文所写的注册码,
但是中文却需要添加两个分隔符"--",而且注册码的首个字节也是"-"
黔驴技穷了!
这是我第一次写算法分析,每个算法部分都是靠多次使用OllyDbg演练猜测得出的结果,遗憾的是只能适合英文用户名注册.

后记:使用了OllyDbg,越发感觉它的强大和方便易用.真希望风飘雪老师能多写几篇OllyDbg的教程.