【破解作者】 Ptero
【作者邮箱】 thestral@sina.com.cn
【使用工具】 PEiD,OllyDbg,Dede
【破解平台】 WinXp SP1
【软件名称】 Talisman Desktop 2.97  (build 2970)
【官方网址】 http://www.lighttek.com
【下载地址】 http://dlc.pconline.com.cn/filedown...&dltypeid=1
【编写语言】 Borland Delphi 4.0 - 5.0
【软件介绍】 一款桌面换肤工具,界面美观。(重点在破解,不在介绍)
【保护方式】 序列号+30天试用
【破解声明】 我是一只小菜鸟,偶得一点心得,愿与大家分享:)
【破解过程】

    首先用PEiD查壳,居然无壳,又拣了个软柿子。

    查出是Delphi的,自然用Dede分析看看了。

    注册码的输入是在about窗口中的,在TAboutBox的RCData中找到
'Register!'按钮名称是SpeedButton1,于是在TAboutBox的过程中找到
SpeedButton1Click,然后用OD加载目标程序,对照Dede来跑。

    在SpeedButton1Click处下断:

00497E64  /. >push ebp                       ;  TAboutBox.SpeedButton1Click
00497E65  |. >mov ebp,esp
00497E67  |. >push 0
00497E69  |. >push 0
00497E6B  |. >push 0
00497E6D  |. >push ebx
00497E6E  |. >push esi
00497E6F  |. >mov ebx,eax
00497E71  |. >xor eax,eax
00497E73  |. >push ebp
00497E74  |. >push talisman.00497F96
00497E79  |. >push dword ptr fs:[eax]
00497E7C  |. >mov fs:[eax],esp
00497E7F  |. >lea edx,[local.1]
00497E82  |. >mov eax,[ebx+2E0]              ;  control TAboutBox.edit_code : TEdit
00497E88  |. >call talisman.0042AE9C         ;  controls.TControl.GetText(TControl):TCaption;
00497E8D  |. >lea edx,[local.2]
00497E90  |. >mov eax,[ebx+2E0]              ;  control TAboutBox.edit_code : TEdit
00497E96  |. >call talisman.0042AE9C         ;  controls.TControl.GetText(TControl):TCaption;
00497E9B  |. >cmp [local.2],0                ;  注册码
00497E9F  |. >je talisman.00497F70
00497EA5  |. >cmp [local.1],0                ;  注册码
00497EA9  |. >je talisman.00497F70
00497EAF  |. >mov eax,[local.1]
00497EB2  |. >call talisman.00403DF8         ;  取得注册码长度
00497EB7  |. >mov esi,eax
00497EB9  |. >test esi,esi
00497EBB  |. >jle short talisman.00497EF6
00497EBD  |. >mov eax,1

    下面是一段循环,检验注册码中的每一位是否为数字。

    注意,刚才在00497E9B处比较注册码是否为空,为空当然是失败啦。
我们记住失败了跳到哪里。跳到00497F70。再往下看:

00497EF6  |> >mov eax,ebx
00497EF8  |. >call talisman.0049804C         ;  这里读取用户名并对用户名和注册码作简单加密
00497EFD  |. >call talisman.004C0418         ;  关键Call
00497F02  |. >test al,al                     ;  al==0就失败
00497F04  |. >je short talisman.00497F56
00497F06  |. >mov edx,12C
00497F0B  |. >mov eax,[4EAD68]
00497F10  |. >call talisman.0042A6CC
00497F15  |. >mov eax,[4D98A0]
00497F1A  |. >push dword ptr [eax]
00497F1C  |. >push talisman.00497FAC
00497F21  |. >mov eax,[4D944C]
00497F26  |. >push dword ptr [eax]
00497F28  |. >lea eax,[local.3]
00497F2B  |. >mov edx,3
00497F30  |. >call talisman.00403EB8
00497F35  |. >mov edx,[local.3]
00497F38  |. >mov eax,[4EAD68]
00497F3D  |. >mov eax,[eax+2E8]
00497F43  |. >call talisman.0042AECC
00497F48  |. >mov eax,[4D9900]
00497F4D  |. >mov eax,[eax]
00497F4F  |. >xor edx,edx
00497F51  |. >mov [eax+C],edx
00497F54  |. >jmp short talisman.00497F70
00497F56  |> >mov dl,1                       ;  这里再往下就就失败了
00497F58  |. >mov eax,[ebx+2FC]
00497F5E  |. >call talisman.0042ADB4
00497F63  |. >mov dl,1
00497F65  |. >mov eax,[ebx+300]
00497F6B  |. >call talisman.0044ADB4
00497F70  |> >xor eax,eax                    ;  到这里就失败

    00497EF8处的call中只有几行有用的信息:

00498135  |. >mov eax,[eax+2E0]              ;  control edit_code : TEdit
0049813B  |. >call talisman.0042AE9C         ;  controls.TControl.GetText(TControl):TCaption;
00498140  |. >cmp [local.3],0                ;  注册码长度
00498144  |. >je short talisman.00498153
00498146  |. >mov eax,[local.3]              ;  比较长度
0049814E  |. >cmp eax,14
00498151  |. >jge short talisman.0049818B

    从这里可以看出注册码的长度是0x14,即20位。

    00497EFD处有一个经典的call+cmp/test+je/jne模式,刚好跳到失败处,
这就是关键Call了。

    注意:爆破的话要让这个call返回非0值,不能只改下面的je,因为程序
在启动时还要再一次调用这个call。

    跟进关键Call:

004C0448  |. >mov eax,[44EF5C]               ;  class TRegistry
004C044D  |. >call talisman.0044F09C
004C0452  |. >mov edi,eax
004C0454  |. >mov edx,80000001
004C0459  |. >mov eax,edi
004C045B  |. >call talisman.0044F134
004C0460  |. >mov eax,[4D9328]
004C0465  |. >push dword ptr [eax]           ;  "\\Software\\Microsoft\\Windows\\CurrentVersion"
004C0467  |. >push talisman.004C0778         ;  ASCII "\\Explorer\\"
004C046C  |. >mov eax,[4D9608]
004C0471  |. >push dword ptr [eax]
004C0473  |. >lea eax,[local.70]
004C0479  |. >mov edx,3
004C047E  |. >call talisman.00403EB8
004C0483  |. >mov edx,[local.70]             ;  "\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"
004C0489  |. >mov cl,1
004C048B  |. >mov eax,edi
004C048D  |. >call talisman.0044F290
004C0492  |. >mov edx,talisman.004C078C      ;  ASCII "WCID"

    这里不觉得可疑么?好端端地访问注册表作甚?
    原来程序把已注册的用户名和注册码加密后藏在HKCU\Software\Microsoft
\CurrentVersion\Explorer\Advanced下的WCID键里,启动时再解密出来验证。
    如果找不到注册信息,就把00497EF8处call里加密的用户名和注册码解密。
    接下来就是比较、验证的过程了。

004C05A8  |. >lea eax,[local.5]
004C05AB  |. >push eax
004C05AC  |. >mov ecx,2
004C05B1  |. >mov edx,0E
004C05B6  |. >mov eax,[local.4]              ;  注册码
004C05B9  |. >call talisman.00403FFC         ;  从第0x0E位处取2位存入[local.5]
004C05BE  |. >mov eax,[local.5]              ;  第14-15位
004C05C1  |. >call talisman.004083B8         ;  把取出的2位转换成数字
004C05C6  |. >mov [local.1],eax
004C05C9  |. >lea eax,[local.5]
004C05CC  |. >push eax
004C05CD  |. >mov ecx,8
004C05D2  |. >mov edx,6
004C05D7  |. >mov eax,[local.4]              ;  注册码
004C05DA  |. >call talisman.00403FFC         ;  取第6-13位
004C05DF  |. >lea eax,[local.2]
004C05E2  |. >call talisman.00403B7C

    接着是解密用户名,并且对用户名的每一位ASCII值求和。

004C05E7  |. >mov ebx,95
004C05EC  |. >lea esi,[ebp-A9]                 ;  加密后的用户名
004C05F2  |> >/cmp byte ptr [esi],0            ;  我们不关心解密的具体过程
004C05F5  |. >|je short talisman.004C061B
004C05F7  |. >|lea eax,[local.70]
004C05FD  |. >|xor edx,edx
004C05FF  |. >|mov dl,[esi]
004C0601  |. >|add edx,0F
004C0604  |. >|call talisman.00403D20
004C0609  |. >|mov edx,[local.70]
004C060F  |. >|lea eax,[local.2]
004C0612  |. >|call talisman.00403E00
004C0617  |. >|inc esi
004C0618  |. >|dec ebx
004C0619  |.^>\jnz short talisman.004C05F2
004C061B  |> >xor esi,esi
004C061D  |. >mov eax,[local.2]                ;  用户名
004C0620  |. >call talisman.00403DF8           ;  取长度
004C0625  |. >test eax,eax
004C0627  |. >jle short talisman.004C063C
004C0629  |. >mov ebx,1
004C062E  |> >/mov edx,[local.2]               ;  用户名ASCII求和
004C0631  |. >|movzx edx,byte ptr [edx+ebx-1]
004C0636  |. >|add esi,edx
004C0638  |. >|inc ebx
004C0639  |. >|dec eax
004C063A  |.^>\jnz short talisman.004C062E

    用户名的最大长度是0x95,当然,一般没人会起这么长的名字的。

    下面,根据刚刚取出的注册码的14-15的两位查表。查表的结果是
一个8位数(十进制)。

004C063C  |> >lea edx,[local.3]                ;  开始分段查表
004C063F  |. >mov eax,[local.1]                ;  注册码中的两位数
004C0642  |. >call talisman.004BFD44           ;  表 0x1-0x15, 0x55-0x69
004C0647  |. >mov eax,[local.3]
004C064A  |. >call talisman.00403DF8           ;  取长度
004C064F  |. >cmp eax,8                        ;  比较结果
004C0652  |. >jge short talisman.004C0666
004C0654  |. >lea ecx,[local.3]
004C0657  |. >mov eax,[4D9900]
004C065C  |. >mov eax,[eax]
004C065E  |. >mov edx,[local.1]
004C0661  |. >call talisman.004C6F5C           ;  表 0x16-0x2A
004C0666  |> >mov eax,[local.3]
004C0669  |. >call talisman.00403DF8
004C066E  |. >cmp eax,8
004C0671  |. >jge short talisman.004C0685
004C0673  |. >lea ecx,[local.3]
004C0676  |. >mov eax,[4D9900]
004C067B  |. >mov eax,[eax]
004C067D  |. >mov edx,[local.1]
004C0680  |. >call talisman.004CF7A0           ;  表 0x2B-0x3F
004C0685  |> >mov eax,[local.3]
004C0688  |. >call talisman.00403DF8
004C068D  |. >cmp eax,8
004C0690  |. >jge short talisman.004C069D
004C0692  |. >lea edx,[local.3]
004C0695  |. >mov eax,[local.1]
004C0698  |. >call talisman.004BFA74           ;  表 0x40-0x54

    接下来的几行代码是处理查表的结果,在此省略。因为Delphi代码效率
比较低,经常做出画蛇添足再擦掉蛇足的事,这里也是一样,我们对此表示
谅解。

    下面就是最终判断注册成功与否的地方了:

004C06C5  |. >mov [local.71],esi               ;  用户名ASCII的和
004C06CB  |. >fild [local.71]                  ;  存入浮点寄存器
004C06D1  |. >call talisman.00402AD0           ;  再放入eax
004C06D6  |. >imul eax,eax,367
004C06DC  |. >add ebx,eax
004C06DE  |. >mov esi,ebx
004C06E0  |. >lea edx,[local.70]
004C06E6  |. >mov eax,esi
004C06E8  |. >call talisman.00408354           ;  转换成十进制(8位)
004C06ED  |. >mov edx,[local.70]               ;  查表结果加用户名
004C06F3  |. >mov eax,[local.5]                ;  注册码第5-13位
004C06F6  |. >call talisman.00403F08           ;  比较字符串
004C06FB  |. >jnz short talisman.004C071A      ;  跳就失败
004C06FD  |. >mov eax,[4D944C]
004C0702  |. >mov edx,[local.2]
004C0705  |. >call talisman.00403BD0
004C070A  |. >mov eax,[4D9900]
004C070F  |. >mov eax,[eax]
004C0711  |. >xor edx,edx
004C0713  |. >mov [eax+C],edx
004C0716  |. >mov bl,1                         ;  返回1,成功
004C0718  |. >jmp short talisman.004C072A
004C071A  |> >mov eax,[4D9900]
004C071F  |. >mov eax,[eax]
004C0721  |. >mov dword ptr [eax+C],1
004C0728  |. >xor ebx,ebx                      ;  返回0,失败

    看看,又画蛇添足了,从寄存器到内存,再到浮点寄存器,最后又返回
寄存器,兜了一大圈!好了,不说它了。且看用户名的ASCII和乘上0x367后
再加上查表的结果,和刚刚取的注册码的第6-13位比较,如果相等就OK了。

    现在总结一下注册算法:

    1. 取注册码的14-15位,根据取出的数查表。
    2. 算出用户名各位ASCII码之和,再乘以0x367。
    3. 以上两项相加,转换成一个8位十进制数。
    4. 再和注册码的6-13位比较,相等即成功。
    5. 注册码的其余各位为任意数字。

【破解总结】

    算法比较简单,编写注册机的唯一麻烦之处就是从软件中得到那个表。
输了好长时间……汗!


    另:

    注册成功后可将以下内容存为reg文件,导入注册表后解除注册。

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced]
"WCID"=-