Add/Remove 4Good v2.01 注册算法分析
破解目标:Add/Remove 4Good v2.01
官方主页:http://www.4developers.com/
软件简介:是一个可以帮助你管理控制台中的新增/移除程序,除了可代替反安装软件外还会连同软件的清单移除,另外也可以清除以无效的软件清单等。
下载地址:http://www.4developers.com/software/addremove.exe
使用工具:W32Dasm、Ollydbg、Windows
自带的计算器、32bit Calculator 1.6 by cybult,用来临时报佛脚的汇编课本-_-b
作者:炎之川
时间:2003.3.21
主页:http://skipli.yeah.net/
声明: 此文仅用于学习及交流,若要转载请保持文章完整。
用 PEiD 0.8 检查可知文件未加壳。用 W32Dasm 反汇编并初步分析,先在串式参考中找到注册码错误的提示,双击来到下面的代码段:
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040402F(C)
|
:00404040 E80BFDFFFF
call 00403D50 //在这里设置断点
:00404045 85C0
test eax, eax
:00404047
0F84A8000000 je 004040F5
:0040404D
8D44240C lea eax, dword
ptr [esp+0C]
:00404051 8D4C2408
lea ecx, dword ptr [esp+08]
:00404055 33DB
xor ebx, ebx
:00404057 50
push eax
:00404058 51
push ecx
:00404059 53
push ebx
:0040405A 683F000F00
push 000F003F
:0040405F 53
push ebx
:00404060
53
push ebx
:00404061 53
push ebx
* Possible Reference to Dialog:
|
:00404062 68E84B4300
push 00434BE8
:00404067 6802000080
push 80000002
:0040406C 895C2430
mov dword ptr [esp+30], ebx
:00404070 895C242C mov
dword ptr [esp+2C], ebx
* Reference To: ADVAPI32.RegCreateKeyExA, Ord:01CDh
//以下是注册成功,将注册信息写入注册表
|
:00404074
FF1514904200 Call dword ptr [00429014]
:0040407A 3BC3
cmp eax, ebx
:0040407C 7530
jne 004040AE
:0040407E 8B542408
mov edx, dword ptr [esp+08]
:00404082
57
push edi
:00404083 6800020000
push 00000200
:00404088 68F88F4300
push 00438FF8
:0040408D 6A03
push 00000003
:0040408F 53
push ebx
* Possible
StringData Ref from Data Obj ->"4D"
|
:00404090 68E44B4300 push
00434BE4
:00404095 52
push edx
* Reference To: ADVAPI32.RegSetValueExA,
Ord:01F9h
|
:00404096 FF1510904200
Call dword ptr [00429010]
:0040409C 8BF8
mov edi, eax
:0040409E 8B44240C mov
eax, dword ptr [esp+0C]
:004040A2 50
push eax
* Reference To: ADVAPI32.RegCloseKey,
Ord:01C9h
|
:004040A3 FF1518904200
Call dword ptr [00429018]
:004040A9 3BFB
cmp edi, ebx
:004040AB 5F
pop edi
:004040AC 741B
je 004040C9
* Referenced by a (U)nconditional or
(C)onditional Jump at Address:
|:0040407C(C)
|
:004040AE 53
push ebx
:004040AF 53
push ebx
* Possible StringData Ref from Data Obj ->"Failed
to record registration "
->"information.
Please contact support@4dev.com"
|
:004040B0 68D04E4300
push 00434ED0
:004040B5 E8F2F10100
call 004232AC
:004040BA 6A01
push 00000001
:004040BC
8BCE mov
ecx, esi
:004040BE E801940100
call 0041D4C4
:004040C3 5E
pop esi
:004040C4 5B
pop ebx
:004040C5 83C408
add esp, 00000008
:004040C8 C3
ret
* Referenced by a (U)nconditional or (C)onditional
Jump at Address:
|:004040AC(C)
|
:004040C9 3BF3
cmp esi, ebx
:004040CB 7504
jne 004040D1
:004040CD 33C0
xor eax, eax
:004040CF EB03
jmp 004040D4
* Referenced by a (U)nconditional
or (C)onditional Jump at Address:
|:004040CB(C)
|
:004040D1 8B461C
mov eax, dword ptr [esi+1C]
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004040CF(U)
|
:004040D4 53
push ebx
* Possible Reference
to Dialog:
|
:004040D5
68C04E4300 push 00434EC0
* Possible StringData Ref from Data Obj ->"Welcome to the REGISTERED version
" //注册成功的提示
->"of Add/Remove 4Good.
Please restart "
->"Add/Remove 4Good so that all limitations "
->"are removed."
|
:004040DA 68404E4300
push 00434E40
:004040DF 50
push eax
* Reference
To: USER32.MessageBoxA, Ord:01DEh
|
:004040E0 FF158C944200 Call dword
ptr [0042948C]
:004040E6 6A01
push 00000001
:004040E8 8BCE
mov ecx, esi
:004040EA E8D5930100
call 0041D4C4
:004040EF 5E
pop esi
:004040F0 5B
pop ebx
:004040F1 83C408
add esp, 00000008
:004040F4 C3
ret
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00404047(C)
|
:004040F5 6AFF
push FFFFFFFF
* Reference To: USER32.MessageBeep, Ord:01DDh
|
:004040F7 FF1594944200
Call dword ptr [00429494]
:004040FD 85F6
test esi, esi
:004040FF 7403
je 00404104
:00404101 8B761C
mov esi, dword ptr [esi+1C]
* Referenced by a (U)nconditional
or (C)onditional Jump at Address:
|:004040FF(C)
|
:00404104 6A30
push 00000030
* Possible StringData Ref from Data Obj ->"UNREGISTERED User"
|
:00404106 682C4E4300
push 00434E2C
* Possible StringData Ref from Data
Obj ->"The registration information you " //注册失败的提示
->"have entered could not be validated.
Please "
->"re-enter
the registration code "
->"and user name you have legally "
->"obtained from 4Developers.
If "
->"you have not registered yet
you "
->"can click
one of the buttons below "
->"to see how to register Add/Remove "
->"4Good.
For help e-mail support@4dev.com"
|
:0040410B 68F44C4300
push 00434CF4
:00404110 56
push esi
* Reference
To: USER32.MessageBoxA, Ord:01DEh
|
:00404111 FF158C944200 Call dword
ptr [0042948C]
:00404117 5E
pop esi
:00404118 5B
pop ebx
:00404119 83C408
add esp, 00000008
:0040411C C3
ret
用 Ollydbg 载入文件,在 404040 处按 F2 下断点,然后 Ctrl+F2 重新开始,F9
运行程序,在 NAG 对话框中填入注册名和假注册码,我填入:
Name: lovefire (需要大于6个字符)
S/N: 6582-78787878
(为什么要这样写?原因见下面的分析)
按 Check,被 Ollydbg 断下,
(; 后是 Ollydbg 所分析的内容,//
后是我加的注释)
00404040 > E8 0BFDFFFF CALL AddRem.00403D50
//断在这里,关键call,F7进入
00404045 . 85C0
TEST EAX,EAX //eax 是否为0?
00404047 . 0F84 A8000000 JE AddRem.004040F5
//为0则跳到下面注册失败的messagebox
0040404D . 8D4424 0C LEA
EAX,DWORD PTR SS:[ESP+C]
00404051 . 8D4C24 08 LEA
ECX,DWORD PTR SS:[ESP+8]
00404055 . 33DB
XOR EBX,EBX
00404057 . 50
PUSH EAX
; /pDisposition
00404058
. 51 PUSH ECX
; |pHandle
00404059 . 53 PUSH
EBX
; |pSecurity => NULL
0040405A .
68 3F000F00 PUSH 0F003F
; |Access = KEY_ALL_ACCESS
0040405F . 53 PUSH EBX
; |Options => REG_OPTION_NON_VOLATILE
00404060
. 53 PUSH EBX
; |Class => NULL
00404061 . 53
PUSH EBX
; |Reserved => 0
00404062
. 68 E84B4300 PUSH AddRem.00434BE8
; |Subkey = "Software\4Developers\AddRemove"
00404067 . 68 02000080 PUSH 80000002
;
|hKey = HKEY_LOCAL_MACHINE
0040406C . 895C24 30
MOV DWORD PTR SS:[ESP+30],EBX ; |
00404070 . 895C24 2C MOV DWORD PTR SS:[ESP+2C],EBX
; |
00404074 . FF15 14904200
CALL DWORD PTR DS:[<&ADVAPI32.RegCreateK>; \RegCreateKeyExA
----------------------------------------------------------------
进入 404040
的call:
00403D50 /$ 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
00403D56 |. 6A FF PUSH -1
00403D58
|. 68 C87F4200 PUSH AddRem.00427FC8
00403D5D |. 50
PUSH EAX
00403D5E |. 64:8925 000000>MOV
DWORD PTR FS:[0],ESP
00403D65 |. 83EC 10
SUB ESP,10
00403D68 |. 83C9 FF OR ECX,FFFFFFFF
//ecx 或 FFFFFFFF,结果使 ecx = FFFFFFFF
00403D6B |. 33C0
XOR EAX,EAX //eax 清零
00403D6D |. 53
PUSH EBX
00403D6E |. 56
PUSH ESI
00403D6F |. 57
PUSH EDI
00403D70 |. BF F88F4300 MOV EDI,AddRem.00438FF8
; ASCII "lovefire"
//注册用户名放入 edi
00403D75 |. F2:AE REPNE
SCAS BYTE PTR ES:[EDI] //扫描字串,处理其长度。这个指令最后使 ecx=FFFFFFF6(因为填入的注册用户名是8位)
00403D77 |. F7D1 NOT ECX //ecx
逻辑非,得 00000009
00403D79 |. 49
DEC ECX //ecx-1=00000009-1=00000008。这是用户名的长度!
//以上操作到这里终于得到了注册用户名的长度!用了这么复杂的方法,有点晕~~~
00403D7A |. 83F9 06 CMP ECX,6
//注册名需要大于6位
00403D7D |. 73 12 JNB
SHORT AddRem.00403D91 //大于6则跳到下面,继续计算注册码
00403D7F |. 5F
POP EDI
00403D80 |. 5E
POP ESI
00403D81 |. 5B
POP EBX
00403D82 |. 8B4C24 10
MOV ECX,DWORD PTR SS:[ESP+10]
00403D86 |. 64:890D 000000>MOV DWORD
PTR FS:[0],ECX
00403D8D |. 83C4 1C ADD ESP,1C
00403D90 |. C3 RETN
00403D91
|> 68 084C4300 PUSH AddRem.00434C08
; ASCII "6582-" //默认的数“6582-”
00403D96 |. 8D4C24 18 LEA ECX,DWORD PTR SS:[ESP+18]
00403D9A |. E8 2ECB0100 CALL AddRem.004208CD
//注册码头5位“6582-”
00403D9F |. 8BF0
MOV ESI,EAX
00403DA1 |. BF F88F4300 MOV EDI,AddRem.00438FF8
//取注册名到edi
00403DA6 |. 83C9 FF OR ECX,FFFFFFFF
//ecx 或 FFFFFFFF,最后使ecx=FFFFFFFF
00403DA9 |. 33C0
XOR EAX,EAX //清零
00403DAB |. 33DB
XOR EBX,EBX //清零
00403DAD |. F2:AE
REPNE SCAS BYTE PTR ES:[EDI] //取输入的用户名第一个字符
00403DAF |. F7D1 NOT ECX
00403DB1
|. 49 DEC ECX
00403DB2 |.
33D2 XOR EDX,EDX //清零
00403DB4
|. 8BC1 MOV EAX,ECX //注册名长度送 wax
00403DB6 |. B9 0C000000 MOV ECX,0C
00403DBB |. F7F1
DIV ECX
00403DBD |. A1 9C484300
MOV EAX,DWORD PTR DS:[43489C] //将一个预设的数 87ae2401my69 送到 eax,下面将用到
00403DC2
|. 895C24 24 MOV DWORD PTR SS:[ESP+24],EBX
00403DC6
|. 8A0C02 MOV CL,BYTE PTR DS:[EDX+EAX] //edx=8,这里取上面的预设字串中第8个字符的下一位,即“m”
00403DC9 |. 8D5424 0C LEA EDX,DWORD PTR SS:[ESP+C]
00403DCD |. 51 PUSH ECX
00403DCE |. 56 PUSH ESI
00403DCF
|. 52 PUSH EDX
00403DD0 |.
E8 31710100 CALL AddRem.0041AF06 //将m连接到 6582- 之后,此时得到注册码第二部分的第一个字符“m”
//以上是一个片断,通过上面的代码可以知道,软件的注册码分为两个部分,第一部分是固定的“6582-”,第二部分的第一个字符由注册用户名的位数和软件预设的一串字符来决定,注册用户名几位,则从预设字串中找出对应位数的字符。例如注册用户名七位,则取“1”,11位则取“9”,12位从头取,取“8”
00403DD5 |. 8D4C24 14 LEA ECX,DWORD PTR SS:[ESP+14]
00403DD9 |. C64424 24 02 MOV BYTE PTR SS:[ESP+24],2
00403DDE
|. E8 7CCA0100 CALL AddRem.0042085F
00403DE3 |. BF F88F4300
MOV EDI,AddRem.00438FF8
; ASCII "lovefire"
00403DE8 |. 83C9 FF
OR ECX,FFFFFFFF
00403DEB |. 33C0
XOR EAX,EAX
00403DED |. F2:AE
REPNE SCAS BYTE PTR ES:[EDI]
00403DEF |. F7D1
NOT ECX
00403DF1 |. 49
DEC ECX
00403DF2 |. 0F84 8E000000 JE AddRem.00403E86
00403DF8 |> F6C3 01 /TEST BL,1 //test
BL,1 即 BL and 1
00403DFB |. 75 71
|JNZ SHORT AddRem.00403E6E //如果等于0,则结束循环,跳到 403E6E
//因为 test BL,1 即
BL and 1,所以当取注册名的双数位时,BL and 1 的结果为0,直接跳过循环。
//即软件 *只取注册名的单数位字符* 参与计算
//下面是计算注册码的过程
00403DFD |. 8A83 F88F4300 |MOV AL,BYTE PTR
DS:[EBX+438FF8] //第一位注册名送 al
00403E03 |. 3C 7F
|CMP AL,7F //al与 7F 比较
00403E05 |. 0F8F BF000000
|JG AddRem.00403ECA //小于方可继续
00403E0B |. 3C 20
|CMP AL,20 //al与 20 比较
00403E0D |. 0F8C B7000000
|JL AddRem.00403ECA //大于方可继续
//以上比较,是看注册用户名是否位于ASCII表中的非控制字符部分,即注册用户名只能是英文字母、数字和可打印字符。
00403E13 |. 0FBEC0 |MOVSX EAX,AL
//al送eax,此时al中是注册名的第一位字符,以第一位注册名字符“l”为例,此时 eax=6C
00403E16 |. 99
|CDQ //这里将edx清零(不过这个是什么指令?好像没有见过…)
00403E17 |. 2BC2 |SUB EAX,EDX //eax=
eax-edx = 6C-0 = 6C
00403E19 |. D1F8
|SAR EAX,1 //算术右移1位,等于一次除2运算,所以 eax= eax/2 = 6C/2 =36
00403E1B
|. 04 20 |ADD AL,20 //al= al+20 = 36+20
=56(即“V”)
//以下将求得的值作一系列的比较
00403E1D |. 3C 5A
|CMP AL,5A //al 与 5A(Z)比较
00403E1F |. 884424
10 |MOV BYTE PTR SS:[ESP+10],AL
00403E23 |. 7E
0A |JLE SHORT AddRem.00403E2F //小于则跳转到403E2F
00403E25 |. 3C 61 |CMP AL,61
//如果 al 大于 5A,则到此处,继续与 61 比较
00403E27 |. 7D 06
|JGE SHORT AddRem.00403E2F //大于等于 61 则跳转
00403E29
|. 04 06 |ADD AL,6 //如果al小于61,则 al+6
00403E2B |. 884424 10 |MOV BYTE PTR SS:[ESP+10],AL
00403E2F |> 3C 39 |CMP AL,39 //如果al小于5A,则跳到此处与
39 比较
00403E31 |. 7E 0A |JLE SHORT
AddRem.00403E3D //不大于39,则跳出比较循环
00403E33 |. 3C 41
|CMP AL,41 //如果小于 39,则继续于 41 比较
00403E35
|. 7D 06 |JGE SHORT AddRem.00403E3D //大于
41 则跳出比较循环
00403E37 |. 04 08 |ADD
AL,8 //如果 al 小于 41,则 al+8
//经过以上循环及比较,最后得到注册码第二部分的第二位字符“V”
//以上循环即是计算注册码的过程
00403E39 |. 884424 10 |MOV BYTE PTR SS:[ESP+10],AL
00403E3D |> 8B4424 10 |MOV EAX,DWORD PTR SS:[ESP+10]
00403E41 |. 8D4C24 0C |LEA ECX,DWORD PTR SS:[ESP+C]
00403E45 |. 50 |PUSH EAX
00403E46 |. 8D5424 1C |LEA EDX,DWORD PTR SS:[ESP+1C]
00403E4A |. 51 |PUSH ECX
00403E4B |. 52 |PUSH EDX
00403E4C
|. E8 B5700100 |CALL AddRem.0041AF06 //将算出的“V”加到之前算出的部分注册码之后,得“6582-mV”
00403E51 |. 50 |PUSH EAX
00403E52 |. 8D4C24 10 |LEA ECX,DWORD PTR SS:[ESP+10]
00403E56 |. C64424 28 03 |MOV BYTE PTR SS:[ESP+28],3
00403E5B
|. E8 38CB0100 |CALL AddRem.00420998
00403E60 |. 8D4C24
18 |LEA ECX,DWORD PTR SS:[ESP+18]
00403E64 |. C64424
24 02 |MOV BYTE PTR SS:[ESP+24],2
00403E69 |. E8 F1C90100
|CALL AddRem.0042085F
00403E6E |> BF F88F4300 |MOV
EDI,AddRem.00438FF8 ;
ASCII "lovefire"
00403E73 |. 83C9 FF |OR
ECX,FFFFFFFF
00403E76 |. 33C0 |XOR
EAX,EAX
00403E78 |. 43 |INC
EBX
00403E79 |. F2:AE |REPNE SCAS
BYTE PTR ES:[EDI]
00403E7B |. F7D1
|NOT ECX
00403E7D |. 49 |DEC
ECX //以上作为记数器
00403E7E |. 3BD9
|CMP EBX,ECX
00403E80 |.^0F82 72FFFFFF \JB AddRem.00403DF8
//跳回 403DF8 开始新的一次循环。
算法可以总结如下:
1、注册名只允许是位于 ASCII 码表 20~7E
之间的字符。(所以也不支持中文)
2、软件的注册码分为两个部分,第一部分是固定的字符“6582-”;第二部分的第一个字符由注册名的位数和一个预设的字串“87ae2401my69”决定,若注册名有N位(N>6),则取字串的N+1位字符,循环取。
3、注册码第二部分剩下的字符,由输入的注册名的单数位字符决定,其计算如下:
设 SN1 为通过注册名字符初步计算出来的值,SN
为正确的注册码字符,则:
SN1=((注册名单数位的字符的ASCII值-0)/2)+20
a) 若 SN1<5A,SN1<39,则
SN = SN1
b) 若 SN1<5A,SN1>39,SN1>41,则 SN = SN1
c) 若 SN1<5A,SN1>39,SN1<41,则
SN = SN1+8
d) 若 SN1>5A,SN1<61,则 SN = SN1+6
e) 若 SN1>5A,SN1>61,则 SN
= SN1(此项可排除)
又因为注册用户名介于[20,7F),所以 SN1 取值范围只能是[30,5F],画个简单的数轴就可以看出:
SN1 介于 [30,39] 与 [41,5A] 时,SN = SN1
SN1 介于 [39,41] 时,SN = SN1+8
SN1
介于 [5A,5F] 时,SN = SN1+6
反推回注册用户名可知:
在 ASCII 码表中,当用户名的值位于:
20~32 时,SN =((注册名字符的ASCII值-0)/2)+20
33~42 时,SN =(((注册名字符的ASCII值-0)/2)+20)+8
43~74 时,SN =(((注册名字符的ASCII值-0)/2)+20)
75~7E 时,SN =(((注册名字符的ASCII值-0)/2)+20)+6
为了证实以上算法,我们手工构造一个注册用户名,使之符合以上范围限制:+060S0z (双数位无作用,随便取)
+
0 6 0 S 0 z (字符)
2B 36
53 7A (ASCII 值)
则:
+: ((2B-0)/2)+20
= 35 = 5
6: (((36-0)/2)+20)+8 = 43 = C
S: ((53-0)/2)+20 = 49 = I
z: (((7A-0)/2)+20)+6 = 63 = c
再加上注册名7位,取“87ae2401my69”的第7+1位数“1”,最后构成注册码“6582-15CIc”,测试一下,注册成功!
注册信息保存在 HKEY_LOCAL_MACHINE\SOFTWARE\4Developers\AddRemove 下的“4D”子键中。
再往下是软件将输入的注册码和计算出的注册码做对比,与算法无关,所以这里不再详细分析。
至此算法分析完成,一个可用的注册码:Name:
lovefire S/N: 6582-mVaSY
最后特别感谢小楼兄的指点:)
- 标 题:Add/Remove 4Good v2.01 注册算法分析 (18千字)
- 作 者:炎之川
- 时 间:2003-3-21
23:43:18
- 链 接:http://bbs.pediy.com