PCWorker 破解(算法)分析
【破文标题】:PCWorker 破解(算法)分析
【破文作者】:Skyer
【软件名称】:PCWorker
【软件大小】:325 KB
【使用平台】:Win9x/Me/NT/2000/XP
【发布公司】:http://www.pcworker.net
【软件简介】:像按键精灵可自动按键 (可免费注册)
【加密方式】:License File
【编译语言】:VC 6
【功能限制】:时间限制
【调试环境】:WinXP, OllyDBG 1.10
【破解日期】:2005-04-02
【破解目的】:研究算法分析 (此软件注册不用钱, 作者只是想了解有那些人在使用这软件)
【作者声明】:初学Crack,只是感兴趣,没有其它目的。失误之处敬请诸位大侠赐教!
─────────────────────────────────
【破解过程】:
第一次发文,请多指教..
1. 先执行一次 pcworker,记下 PCKEY,并去除 -,关闭
2. OD 载入 pcworker.exe 执行到
PCWorker.ii 是注册档,向 PCWorker 注册后,作者会发 email 到你的信箱
00432BC2 > \68 24E74400 push PCWorker.0044E724 ; ASCII "\PCWorker.ii"
00432BC7 . 8D4424 1C lea eax,dword ptr ss:[esp+1C]
00432BCB . 68 4C144500 push offset <PCWorker.EXEPath>
00432BD0 . 50 push eax
00432BD1 . E8 3C570000 call <jmp.&MFC42.#924_operator+>
00432BD6 . 8B4C24 18 mov ecx,dword ptr ss:[esp+18]
00432BDA . C68424 C412000>mov byte ptr ss:[esp+12C4],8
00432BE2 . 51 push ecx
00432BE3 . FF15 80F84300 call dword ptr ds:[<&PCWorker.KMCF_Acc>; PCWork_1.KMCF_AccessFile
00432BE9 . 8B2D 54F84300 mov ebp,dword ptr ds:[<&PCWorker.CKMC_>; PCWork_1.CKMC_IniFile::GetValue
00432BEF . 83C4 04 add esp,4
00432BF2 . 84C0 test al,al
00432BF4 . 0F84 BC030000 je PCWorker.00432FB6
继续往下执行到
0043363B . 68 1CE74400 push PCWorker.0044E71C ; ASCII "PCKEY"
00433640 . E8 794C0000 call <jmp.&MFC42.#537_CString::CString>
00433645 . 8B15 D0E54400 mov edx,dword ptr ds:[44E5D0] ; PCWorker.0044E5D4
0043364B . 51 push ecx
0043364C . 8BCC mov ecx,esp
0043364E . 896424 40 mov dword ptr ss:[esp+40],esp
00433652 . 52 push edx
00433653 . C68424 D412000>mov byte ptr ss:[esp+12D4],34
0043365B . E8 5E4C0000 call <jmp.&MFC42.#537_CString::CString>
00433660 . 8D4424 1C lea eax,dword ptr ss:[esp+1C]
00433664 . 8BCD mov ecx,ebp
00433666 . 50 push eax
00433667 . C68424 D412000>mov byte ptr ss:[esp+12D4],7
0043366F . FF15 54F84300 call dword ptr ds:[<&PCWorker.CKMC_Ini>; PCWork_1.CKMC_IniFile::GetValue
这里会从 pcworker.ini 读取 [Registration] 下的注册信息,但我们的设定文件无此信息, 手动加上
[Registration]
PCKEY=填入第一次执行 pcworker 记录的 pckey
Name=Skyer
Birthday=1981/01/30
Serial=kKR7sky $
本文主要要找出 Serial 的算法
重新分析 pcworker.exe (Ctrl+F2),执行到
004337E1 . 8B0F mov ecx,dword ptr ds:[edi] ; Serial
004337E3 . BB 0A000000 mov ebx,0A ; 长度一定要为 10
004337E8 . 3959 F8 cmp dword ptr ds:[ecx-8],ebx
004337EB . 7D 1A jge short PCWorker.00433807
了解 Serial 长度必为 10
再往下到
004338E8 > /8A0408 mov al,byte ptr ds:[eax+ecx]
004338EB . |8B1D 24144500 mov ebx,dword ptr ds:[<PCKeyXOR>]
004338F1 . |884424 10 mov byte ptr ss:[esp+10],al
004338F5 . |8B4424 10 mov eax,dword ptr ss:[esp+10]
004338F9 . |25 FF000000 and eax,0FF
004338FE . |33D8 xor ebx,eax
00433900 . |41 inc ecx
00433901 . |891D 24144500 mov dword ptr ds:[<PCKeyXOR>],ebx
00433907 . |8B02 mov eax,dword ptr ds:[edx]
00433909 . |3B48 F8 cmp ecx,dword ptr ds:[eax-8]
0043390C .^\7C DA jl short PCWorker.004338E8
这里是算 pckey 的 xor 编码 (由左至右一个一个 xor) => 取名 PCKeyXOR
转成代码大概是:
int sum=0;
for (i=0; i<PCKeyLength; i++)
sum = sum ^ PCKey[ i ]
0043392C > /8A1408 mov dl,byte ptr ds:[eax+ecx]
0043392F . |8B2D 18144500 mov ebp,dword ptr ds:[<PCKeyAdd>]
00433935 . |885424 10 mov byte ptr ss:[esp+10],dl
00433939 . |8B5424 10 mov edx,dword ptr ss:[esp+10]
0043393D . |81E2 FF000000 and edx,0FF
00433943 . |03EA add ebp,edx
00433945 . |40 inc eax
00433946 . |892D 18144500 mov dword ptr ds:[<PCKeyAdd>],ebp
0043394C . |8B51 F8 mov edx,dword ptr ds:[ecx-8]
0043394F . |3BC2 cmp eax,edx
00433951 .^\7C D9 jl short PCWorker.0043392C
pckey 的 add 编码 (由左至右一个一个 add) => 取名 PCKeyAdd
转成代码大概是:
int sum=0;
for (i=0; i<PCKeyLength; i++)
sum = sum + PCKey[ i ]
00433955 . 8B96 11010000 mov edx,dword ptr ds:[esi+111] ; Serial
0043395B . 8BE8 mov ebp,eax
0043395D . 33C0 xor eax,eax
0043395F . B9 01000000 mov ecx,1
00433964 > 0FBE1C0A movsx ebx,byte ptr ds:[edx+ecx]
00433968 . 03C3 add eax,ebx
0043396A . 41 inc ecx
0043396B . 83F9 08 cmp ecx,8
0043396E .^ 7E F4 jle short PCWorker.00433964
00433970 . 8B8E 19010000 mov ecx,dword ptr ds:[esi+119]
00433976 . BB 5F000000 mov ebx,5F
0043397B . 41 inc ecx
0043397C . 898E 19010000 mov dword ptr ds:[esi+119],ecx
00433982 . 8A0A mov cl,byte ptr ds:[edx]
00433984 . 33D2 xor edx,edx
00433986 . F7F3 div ebx
00433988 . 0FBEC9 movsx ecx,cl
0043398B . 0FBEC2 movsx eax,dl ; 编码 / 5F 的余数
0043398E . 83C0 20 add eax,20
00433991 . 3BC8 cmp ecx,eax
00433993 . 74 08 je short PCWorker.0043399D
检查 Serial 是否正确
转成代码大概是:
int key1 = Serial[0];
int sum=0;
int key2;
for (i=1; i<9; i++)
sum += Serial[ i ]
key2 = (sum % 0x5f) + 0x20
if (key1 == key2)
正确!!
004339DA > \2BFD sub edi,ebp ; 比较执行时间!! 有没有低于 0.5 s
004339DC . 81FF F4010000 cmp edi,1F4
004339E2 . 76 08 jbe short PCWorker.004339EC
这里判断有没有被调试,强迫跳到 004339EC 吧
00433C55 > /8A0408 mov al,byte ptr ds:[eax+ecx]
00433C58 . |884424 10 mov byte ptr ss:[esp+10],al
00433C5C . |8B5424 10 mov edx,dword ptr ss:[esp+10]
00433C60 . |A1 28144500 mov eax,dword ptr ds:[<NameADD>]
00433C65 . |81E2 FF000000 and edx,0FF
00433C6B . |03C2 add eax,edx
00433C6D . |41 inc ecx
00433C6E . |A3 28144500 mov dword ptr ds:[<NameADD>],eax
00433C73 . |8B07 mov eax,dword ptr ds:[edi]
00433C75 . |3B48 F8 cmp ecx,dword ptr ds:[eax-8]
00433C78 .^\7C DB jl short PCWorker.00433C55
Name 的 add 编码 (由左至右一个一个 add) => 取名 NameADD
00433C7A > \A1 04144500 mov eax,dword ptr ds:[<PCKey>] ; PCKey
00433C7F . 8A48 02 mov cl,byte ptr ds:[eax+2]
00433C82 . 8D4424 10 lea eax,dword ptr ss:[esp+10]
00433C86 . 884C24 10 mov byte ptr ss:[esp+10],cl
00433C8A . 8B5424 10 mov edx,dword ptr ss:[esp+10]
00433C8E . 52 push edx ; 第 3 byte 为 rand key
00433C8F . 50 push eax
00433C90 . E8 8BE9FFFF call <PCWorker.算 PCKey>
00433C95 . 8B00 mov eax,dword ptr ds:[eax]
00433C97 . 8B8E 05010000 mov ecx,dword ptr ds:[esi+105]
00433C9D . 50 push eax
00433C9E . 51 push ecx
00433C9F . FFD5 call ebp
00433CA1 . 83C4 10 add esp,10
00433CA4 . 8D4C24 10 lea ecx,dword ptr ss:[esp+10]
00433CA8 . 85C0 test eax,eax
00433CAA . 0F95C3 setne bl
这里是验证 PCKey 的正确性,因为我们的 PCKey 是一开始执行时由 pcworker 产生的
一定正确! 有兴趣研究的朋友们,可进入 00433C90 这个 call 研究研究
00433CD1 > /8A1408 mov dl,byte ptr ds:[eax+ecx]
00433CD4 . |885424 10 mov byte ptr ss:[esp+10],dl
00433CD8 . |8B4424 10 mov eax,dword ptr ss:[esp+10]
00433CDC . |8B15 28144500 mov edx,dword ptr ds:[<NameXOR>]
00433CE2 . |25 FF000000 and eax,0FF
00433CE7 . |33D0 xor edx,eax
00433CE9 . |41 inc ecx
00433CEA . |8915 28144500 mov dword ptr ds:[<NameXOR>],edx
00433CF0 . |8B07 mov eax,dword ptr ds:[edi]
00433CF2 . |3B48 F8 cmp ecx,dword ptr ds:[eax-8]
00433CF5 .^\7C DA jl short PCWorker.00433CD1
Name 的 xor 编码 (由左至右一个一个 xor) => 取名 NameXOR
00433D9A . 8B96 11010000 mov edx,dword ptr ds:[esi+111]
00433DA0 . 33C0 xor eax,eax
00433DA2 . 8BCB mov ecx,ebx
00433DA4 > 0FBE3C11 movsx edi,byte ptr ds:[ecx+edx]
00433DA8 . 33C7 xor eax,edi
00433DAA . 41 inc ecx
00433DAB . 83F9 08 cmp ecx,8
00433DAE .^ 7E F4 jle short PCWorker.00433DA4
00433DB0 . 8A4A 09 mov cl,byte ptr ds:[edx+9]
00433DB3 . 33D2 xor edx,edx
00433DB5 . BF 5F000000 mov edi,5F
00433DBA . F7F7 div edi
00433DBC . 80C2 20 add dl,20
00433DBF . 3ACA cmp cl,dl
00433DC1 . 74 07 je short PCWorker.00433DCA
检查 Serial 是否正确
转成代码大概是:
int key1 = Serial[9];
int sum=0;
int key2;
for (i=1; i<9; i++)
sum = sum ^ Serial[ i ]
key2 = (sum % 0x5f) + 0x20
if (key1 == key2)
正确!!
004340FD > /8A0408 mov al,byte ptr ds:[eax+ecx]
00434100 . |8B1D 2C144500 mov ebx,dword ptr ds:[45142C]
00434106 . |884424 10 mov byte ptr ss:[esp+10],al
0043410A . |8B4424 10 mov eax,dword ptr ss:[esp+10]
0043410E . |25 FF000000 and eax,0FF
00434113 . |33D8 xor ebx,eax
00434115 . |41 inc ecx
00434116 . |891D 2C144500 mov dword ptr ds:[45142C],ebx
0043411C . |8B02 mov eax,dword ptr ds:[edx]
0043411E . |3B48 F8 cmp ecx,dword ptr ds:[eax-8]
00434121 .^\7C DA jl short PCWorker.004340FD
Birthday 的 xor 编码 (由左至右一个一个 xor) => 取名 BirthdayXOR
00434141 > /8A1408 mov dl,byte ptr ds:[eax+ecx]
00434144 . |8B1D 20144500 mov ebx,dword ptr ds:[<BirthdayAdd>]
0043414A . |885424 10 mov byte ptr ss:[esp+10],dl
0043414E . |8B5424 10 mov edx,dword ptr ss:[esp+10]
00434152 . |81E2 FF000000 and edx,0FF
00434158 . |03DA add ebx,edx
0043415A . |40 inc eax
0043415B . |891D 20144500 mov dword ptr ds:[<BirthdayAdd>],ebx
00434161 . |8B51 F8 mov edx,dword ptr ds:[ecx-8]
00434164 . |3BC2 cmp eax,edx
00434166 .^\7C D9 jl short PCWorker.00434141
Birthday 的 add 编码 (由左至右一个一个 add) => 取名 BirthdayAdd
在 4513f8 下内存访问断点,可找到所有比较 Serial 的规则
00408674 . 8B85 1B0C0000 mov eax,dword ptr ss:[ebp+C1B] ; PCKeyAdd编码
0040867A . 8B15 20144500 mov edx,dword ptr ds:[<BirthdayAdd编码>]
00408680 . 8B3D 1C144500 mov edi,dword ptr ds:[<NameAdd编码>]
00408686 . 03C2 add eax,edx
00408688 . 03C7 add eax,edi
0040868A . 33D2 xor edx,edx
0040868C . BE 5F000000 mov esi,5F
00408691 . 8B0D F8134500 mov ecx,dword ptr ds:[<Serial>]
00408697 . F7F6 div esi
00408699 . 8A49 01 mov cl,byte ptr ds:[ecx+1]
0040869C . 0FBEC1 movsx eax,cl
0040869F . 0FBED2 movsx edx,dl
004086A2 . 83C2 20 add edx,20
004086A5 . 3BC2 cmp eax,edx
004086A7 . 74 07 je short PCWorker.004086B0
这里是比较 Serial[1]
转换成代码如下..
int sum = PCKeyAdd + BirthdayAdd + NameAdd
char s1 = (sum % 0x5f) + 0x20
比较 Serial[2]
转换成代码如下..
int sum = PCKeyXor ^ BirthdayXor ^ NameXor
char s2 = (sum % 0x5f) + 0x20
比较 Serial[3]
转换成代码如下..
int sum = PCKeyAdd ^ BirthdayAdd ^ NameAdd
char s3 = (sum % 0x5f) + 0x20
比较 Serial[4]
转换成代码如下..
int sum = PCKeyXor + BirthdayXor + NameXor
char s4 = (sum % 0x5f) + 0x20
比较 Serial[8]
转换成代码如下..
int sum = BirthdayXor & NameAdd | PCKeyXor
char s8 = (sum % 0x5f) + 0x20
其中 Serial[5] ~ Serial[7] 随便,不重要
最后,来整理一下算法..
1. Serial 是依 PCKey, Name, Birthday 算出来的. 长度为 10 (Serial[0] ~ Serial[9])
2. 算出 pckey, name, birthday 的 add, xor 值
3. 算出 Serial[1], Serial[2], Serial[4], Serial[4], Serial[8]
4. Serial[5] ~ Serial[7] 随便填
5. 算出 Serial[0] & Serial[9]
6. 结束..
以下是 python 写的注册机 (python 2.4)
使用方式:
D:\Data\Python>python PcworkerReg.py F-QYUC-TFGY-NGBN Skyer 1932/01/34
会产生 pcworker.ii, 放到 pcworker 下即可
------------PcworkerReg.py-----------------
代码:
import sys, string
def CalAddSum(s):
sum = 0
smap = map(lambda x: ord(x), s)
for i in smap:
sum += i
return sum
def CalXorSum(s):
xors = 0
smap = map(lambda x: ord(x), s)
for i in smap:
xors = xors ^ i
return xors
def main(args):
if len(args) != 4:
print 'Usage: %s [PCKEY] [Name] [Birthday]' % (args[0])
return
pckey = string.replace(args[1], '-', '')
pckey = string.upper(pckey)
nameadd = CalAddSum(args[2])
namexor = CalXorSum(args[2])
birthadd = CalAddSum(args[3])
birthxor = CalXorSum(args[3])
pckeyadd = CalAddSum(pckey)
pckeyxor = CalXorSum(pckey)
#Serial, 2nd byte
c1 = chr(((nameadd + birthadd + pckeyadd) % 0x5f) + 0x20)
#Serial, 3rd byte
c2 = chr(((namexor ^ birthxor ^ pckeyxor) % 0x5f) + 0x20)
#Serial, 4th byte
c3 = chr(((nameadd ^ birthadd ^ pckeyadd) % 0x5f) + 0x20)
#Serial, 5th byte
c4 = chr(((namexor + birthxor + pckeyxor) % 0x5f) + 0x20)
#Serial, 9th byte
c8 = chr(((birthxor & nameadd | pckeyxor) % 0x5f) + 0x20)
key = c1+c2+c3+c4+'sky'+c8
c0 = chr((CalAddSum(key) % 0x5f) + 0x20)
c9 = chr((CalXorSum(key) % 0x5f) + 0x20)
key = c0 + key + c9
o = open('pcworker.ii', 'w')
o.write('[Registration]\n')
o.write('PCKEY=%s\n' % (pckey))
o.write('Name=%s\n' % (args[2]))
o.write('Birthday=%s\n' % (args[3]))
o.write('Serial=%s\n' % (key))
if __name__ == '__main__':
main(sys.argv)
-----------------------------------------------------