老文章档案 · 2003 年

Add/Remove 4Good v2.01 注册算法分析

破解教程 · 算法分析 · 2003-08-22 · 作者:炎之川 人气: · 出处:赢政天下整理收藏)

破解目标: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

声明: 此文仅用于学习及交流,若要转载请保持文章完整。

用 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

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

最后特别感谢小楼兄的指点:)

(出处:赢政天下整理收藏)

相关文章:

·语音界面2.0算法分析及注册机源码!

·侠客系统修改器1.21破解手记--算法分析

·中文拨号上网计时计费器 V4.12注册算法分析

·ClockWise 3.22e注册码算法分析

·CoolClock V1.02注册算法分析

·Directory Scanner v1.5 注册算法分析

·Disk Chief 1.2 简单注册算法分析

·EffeTech HTTP Sniffer 3.2注册算法分析

·eLib2.01算法分析

·EZ MP3 Recorder 1.15 注册算法分析

相关软件:

→ 特别推荐

→ 热点TOP10

我为人人《《==》》人人为我

关于我们 |

帮助(?)

| 广告服务 |

版权声明 |

商业合作 |

发展历程 |

加盟我们 |

联系我们

Copyright © 1999-2003

winzheng.com All Rights Reserved.

繁体版:由华琦数码技术提供

Powered

by:MeSky.Net

2003-2004 年,宽带刚刚普及,下载站的文章区是许多人学电脑的第一课堂。
🕰 → 🤖 从那时到现在

当年一篇教程能让一台电脑焕然一新;今天的效率工具换成了 AI。 想知道当下最可靠的 AI 模型怎么选?看 赢政指数——我们用了 28 年的选软件严谨,现在用来评测大模型。

档案性质声明:本页为赢政天下(1998-2011)老文章的历史档案复原, 内容反映当年发表时的原貌——包括当年的技术表述、软件版本与观点,部分方法在今天已不适用或不合规,仅作互联网历史记录与研究用途, 不提供任何形式的下载。原始数据经由公共网络存档(Internet Archive)复原。发现问题请联系我们
← 返回老文章档案 · 软件史档案馆 · 赢政天下站史