【文章标题】: XXXX Graphics Suite X5 算法分析(二) activation code + 注册机
【文章作者】: Daniel
【作者邮箱】: vvcracker@gmail.com
【操作系统】: Windows 7
【生产日期】: 2010
【软件名称】: Graphics XXXXX XX SP3.v15.2.0.686
【软件介绍】: 一款著名的绘图软件
【加壳方式】: 无
【保护方式】: 注册码
【编写语言】: Microsoft Visual C++ 10.0
【使用工具】: OD + PEID + IDA Pro
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请各位大牛小牛原谅!
【讨论说明】
本文只讨论核心验证算法,由于涉及到函数处理较多,我只会将最重要的处理过程作说明,其他不作说明。
列出sha,blowfish算法只列出调用地方,算法的运作也不作说明。
验证入口:
100240ED 50 push eax eax输入的注册码
100240EE 51 push ecx ecx产品系列号的值
100240EF E8 CCED0000 call 10032EC0
过程I:硬件指纹
10051E94 8B7C24 48 mov edi, dword ptr ss:[esp+48]
10051E98 8D5424 10 lea edx, dword ptr ss:[esp+10]
10051E9C 52 push edx
10051E9D 8BCE mov ecx, esi
10051E9F C646 1A 01 mov byte ptr ds:[esi+1A], 1
10051EA3 897E 0C mov dword ptr ds:[esi+C], edi
10051EA6 E8 45220000 call 100540F0 产生硬件指纹
进入100540F0
1005410D 56 push esi
1005410E 53 push ebx
1005410F 8BF1 mov esi, ecx
10054111 E8 9AFEFFFF call 10053FB0 执行10053FB0,执行结果edx保存为硬件指纹的值
1005413E 50 push eax
1005413F 8D4C24 20 lea ecx, dword ptr ss:[esp+20]
10054143 E8 C5320000 call 1005740D sha Init
10054148 BE A43D1010 mov esi, 10103DA4
1005414D 33C0 xor eax, eax
1005414F 897424 1C mov dword ptr ss:[esp+1C], esi
10054153 884424 34 mov byte ptr ss:[esp+34], al
10054157 8D4C24 1C lea ecx, dword ptr ss:[esp+1C]
1005415B 51 push ecx
1005415C 8D4C24 10 lea ecx, dword ptr ss:[esp+10]
10054160 894424 44 mov dword ptr ss:[esp+44], eax
10054164 E8 B5390000 call 10057B1E
10054169 6A 04 push 4 产品系列号的值的长度
1005416B 8D5424 4C lea edx, dword ptr ss:[esp+4C]
1005416F 52 push edx edx产品系列号的值,此值为固定值
10054170 8D4424 14 lea eax, dword ptr ss:[esp+14]
10054174 50 push eax eax保存结果到eax + C中
10054175 8D4C24 28 lea ecx, dword ptr ss:[esp+28]
10054179 C64424 4C 01 mov byte ptr ss:[esp+4C], 1
1005417E E8 292C0000 call 10056DAC sha Hash
10054183 8B7C24 18 mov edi, dword ptr ss:[esp+18]
10054187 8A0F mov cl, byte ptr ds:[edi] ecx Hash后的数据
10054189 880B mov byte ptr ds:[ebx], cl ebx组成最后的硬件指纹数组
1005418B 8B4C24 14 mov ecx, dword ptr ss:[esp+14]
进入10053FB0,10053FB0 -> 100BA7C0, ->表示前者函数调用后者函数。
100BA998 52 push edx
100BA999 8859 04 mov byte ptr ds:[ecx+4], bl
100BA99C E8 9F76F4FF call 10002040
100BA9A1 E8 CAFAFFFF call 100BA470 读取4次硬件信息,分别进行SHA hash
100BAA73 50 push eax
100BAA74 8859 04 mov byte ptr ds:[ecx+4], bl
100BAA77 E8 C475F4FF call 10002040
100BAA7C E8 4FF3FFFF call 100B9DD0 对100BA470产生4次hash信息,串联起来再进行一次Hash
然后 100BA470 -> 100B96A0 -> 100BC8A0,一下4个函数调用分别是读取本机硬件信息,分别作 SHA Hash
100BC8D4 8BC8 mov ecx, eax
100BC8D6 E8 05470000 call 100C0FE0
100BC908 8BC8 mov ecx, eax
100BC90A E8 E13C0000 call 100C05F0
100BC937 8BC8 mov ecx, eax
100BC939 E8 92380000 call 100C01D0
100BC962 8BC8 mov ecx, eax
100BC964 E8 C7240000 call 100BEE30
先看100C0FE0,接着这函数会调用100C0D20
100C0DB6 8D5424 10 lea edx, dword ptr ss:[esp+10]
100C0DBA 52 push edx
100C0DBB 57 push edi edi保存读取的值
100C0DBC FFD6 call esi GetAdaptersInfo获取网卡的信息A
100C0E02 8D8E 94010000 lea ecx, dword ptr ds:[esi+194]
100C0E08 51 push ecx ecx hash网卡0x194处的信息,8字节
100C0E09 8BC8 mov ecx, eax
100C0E0B E8 10250000 call 100C3320 准备进行sha hash
100C3320 -> 100C3140,再看看100C3140具体如何进行sha hash
100C31F7 8B45 00 mov eax, dword ptr ss:[ebp]
100C31FA 8BCD mov ecx, ebp
100C31FC FF50 0C call dword ptr ds:[eax+C] 先读取该类存储的值
100C3282 50 push eax
100C3283 6A 01 push 1
100C3285 52 push edx
100C3286 8D4C24 20 lea ecx, dword ptr ss:[esp+20]
100C328A E8 A126F5FF call 10015930 与网卡0x194处的信息组装最后的字符串
100C32A5 8B45 04 mov eax, dword ptr ss:[ebp+4]
100C32A8 8D4D 04 lea ecx, dword ptr ss:[ebp+4]
100C32AB FF50 04 call dword ptr ds:[eax+4] 最终进行sha hash ,hash结果保存在[[ESI +C]+8]+c]处
至此第一处的硬件信息Hash结束,再看第二处的硬件信息Hash,100C05F0 -> 100C0360,
100C0360会获取系统的盘符并作为参数传给100C2450调用,100C2450 -> 100C2090,看100C2090的细致处理
100C21CF FF15 54321010 call dword ptr ds:[<&KERNEL32.GetVolu>; kernel32.GetVolumeInformationA
100C21F8 52 push edx
100C21F9 8D4C24 24 lea ecx, dword ptr ss:[esp+24]
100C21FD 51 push ecx
100C21FE 8D5424 1C lea edx, dword ptr ss:[esp+1C]
100C2202 52 push edx
100C2203 8D4C24 1C lea ecx, dword ptr ss:[esp+1C]
100C2207 51 push ecx
100C2208 50 push eax
100C2209 FF15 A8321010 call dword ptr ds:[<&KERNEL32.GetDisk>; kernel32.GetDiskFreeSpaceA
100C223C 8D8424 F4000000 lea eax, dword ptr ss:[esp+F4]
100C2243 68 B0A71110 push 1011A7B0 ; ASCII "%ld%ld%ld%ld"
100C2248 50 push eax
100C2249 E8 7161FEFF call 100A83BF 将数字转化为字符
100A83BF该处是将GetVolumeInformationA,GetDiskFreeSpaceA获取的SectorsPerCluster,BytesPerSector,VolumeSerialNumber
的值转化为字符串并保存到eax
100C2260 50 push eax
100C2261 E8 9A8CFFFF call 100BAF00 100BAF00读取该类存储的值A
100C22D4 6A FF push -1
100C22D6 53 push ebx
100C22D7 8D4424 54 lea eax, dword ptr ss:[esp+54]
100C22DB 8969 18 mov dword ptr ds:[ecx+18], ebp
100C22DE 8959 14 mov dword ptr ds:[ecx+14], ebx
100C22E1 50 push eax
100C22E2 8859 04 mov byte ptr ds:[ecx+4], bl
100C22E5 E8 56FDF3FF call 10002040 A与上述字符串组装最后的字符串
100C22EA 8B56 04 mov edx, dword ptr ds:[esi+4]
100C22ED 8D4E 04 lea ecx, dword ptr ds:[esi+4]
100C22F0 FF52 08 call dword ptr ds:[edx+8] 最终进行sha hash ,hash结果保存在[[ESI +C]+8]+c]处
再看第3处的硬件信息Hash,100C01D0 -> 100BFD70 -> 100BF590,列出 100BF590 主要处理过程
100BF609 51 push ecx
100BF60A FF15 98311010 call dword ptr ds:[<&KERNEL32.CreateF>;创建硬盘句柄
100BF69E FFD7 call edi 获取硬盘SMART_GET_VERSION的信息
100BF724 52 push edx
100BF725 55 push ebp
100BF726 E8 F5F7FFFF call 100BEF20 获取硬盘SMART_RCV_DRIVE_DATA的信息,获取其硬盘ID号
100BF7EA 52 push edx [edx + c] 为硬盘ID号的字符串
100BF7EB 50 push eax
100BF7EC E8 0FFDFFFF call 100BF500 sha hash,细节处理跟100C3140相同
第4处硬件信息Hash,100BEE30返回的结果为一固定字符串,没有读取硬件信息,细节处理跟上述的sha hash差不多。
现在我们再看100B9DD0的处理,看调用 100B9DD0 -> 100BCB10 -> 100BCD20,
100BCE14 52 push edx edx为长度
100BCE15 50 push eax eax为刚才产生的4份硬件指纹数据
100BCE16 8D4C24 64 lea ecx, dword ptr ss:[esp+64]
100BCE1A E8 2F9FF9FF call 10056D4E sha update
100BCE1F 8D4424 5C lea eax, dword ptr ss:[esp+5C]
100BCE23 50 push eax
100BCE24 8D4C24 30 lea ecx, dword ptr ss:[esp+30]
100BCE28 E8 F1ACF9FF call 10057B1E
100BCE2D 8D4C24 2C lea ecx, dword ptr ss:[esp+2C]
100BCE31 51 push ecx
100BCE32 8D4C24 60 lea ecx, dword ptr ss:[esp+60]
100BCE36 C68424 A0000000>mov byte ptr ss:[esp+A0], 5
100BCE3E E8 829EF9FF call 10056CC5 sha finiale,得到的结果为[[ecx+8]+C]
100BCE1A处要注意,除了刚才4份硬件指纹数据外,还有几个固定字符组合在一起,
取10056CC5处sha hash后的数据,取从第10位开始的5个字节,返回到10054169
10054169 6A 04 push 4 产品系列号的值的长度
1005416B 8D5424 4C lea edx, dword ptr ss:[esp+4C]
1005416F 52 push edx edx产品系列号的值,此值为固定值
10054170 8D4424 14 lea eax, dword ptr ss:[esp+14]
10054174 50 push eax 保存结果到eax + C中
10054175 8D4C24 28 lea ecx, dword ptr ss:[esp+28]
10054179 C64424 4C 01 mov byte ptr ss:[esp+4C], 1
1005417E E8 292C0000 call 10056DAC sha Hash
10054183 8B7C24 18 mov edi, dword ptr ss:[esp+18]
10054187 8A0F mov cl, byte ptr ds:[edi] 取产品系列号Sha Hash后的第一位
10054189 880B mov byte ptr ds:[ebx], cl 组成最后的硬件指纹数组5字节
1005418B 8B4C24 14 mov ecx, dword ptr ss:[esp+14]
至此,整个硬件指纹产生结束,硬件指纹值为5字节。
过程II:Activcation Code的验证
10051EF0 E8 9BFAFFFF call 10051990 验证算法,赋值到esi+8,esi+C,我称为验证I,II
10051EF5 385E 08 cmp byte ptr ds:[esi+8], bl esi+8的值要为1
10051EF8 74 0A je short 10051F04
10051EFA 397E 0C cmp dword ptr ds:[esi+C], edi esi+C 值要等于 产品系列号的值
10051EFD 0F94C0 sete al
10051F00 3AC3 cmp al, bl
10051F02 75 4C jnz short 10051F50
10051F50 -> 10051460,分析10051460的主验证过程
10051569 8A56 04 mov dl, byte ptr ds:[esi+4]
1005156C 8A46 03 mov al, byte ptr ds:[esi+3]
1005156F 8A4E 02 mov cl, byte ptr ds:[esi+2]
10051572 889424 B4000000 mov byte ptr ss:[esp+B4], dl 逆转硬件指纹数据,并储存到此地址,称Rstr
10051579 8A56 01 mov dl, byte ptr ds:[esi+1]
1005157C 888424 B5000000 mov byte ptr ss:[esp+B5], al
10051583 8A06 mov al, byte ptr ds:[esi]
100515D7 6A 03 push 3
100515D9 6A 05 push 5
100515DB 8D8C24 BC000000 lea ecx, dword ptr ss:[esp+BC]
100515E2 51 push ecx
100515E3 8D5424 6C lea edx, dword ptr ss:[esp+6C] 压入Rstr
100515E7 52 push edx
100515E8 8D8C24 98000000 lea ecx, dword ptr ss:[esp+98]
100515EF C68424 1C010000>mov byte ptr ss:[esp+11C], 5
100515F7 E8 80630000 call 1005797C 产生 init key,IV str for blowfish
在1005797C处,会产生一组8字节字符,和一组16字节字符,主要的产生函数是1005759B
100577CF 6A 01 push 1
100577D1 6A 10 push 10 长度
100577D3 53 push ebx 固定字符串
100577D4 FF75 0C push dword ptr ss:[ebp+C]
100577D7 8D45 D4 lea eax, dword ptr ss:[ebp-2C] 长度
100577DA FF75 08 push dword ptr ss:[ebp+8] Rstr
100577DD 50 push eax
100577DE E8 B8FDFFFF call 1005759B ShaEX call
列出1005759B的关键处理过程
10057604 8B4D C4 mov ecx, dword ptr ss:[ebp-3C] 此处控制循环次数2次
10057607 8D0419 lea eax, dword ptr ds:[ecx+ebx]
1005760A 3945 08 cmp dword ptr ss:[ebp+8], eax
1005760D 72 0C jb short 1005761B
1005760F 8B45 E4 mov eax, dword ptr ss:[ebp-1C]
10057612 3945 EC cmp dword ptr ss:[ebp-14], eax
10057628 FF75 DC push dword ptr ss:[ebp-24] 字符串长度
1005762B 8BCE mov ecx, esi
1005762D FF75 E0 push dword ptr ss:[ebp-20] 压入第一次sha的Hash值
10057630 E8 19F7FFFF call 10056D4E sha update
10057635 FF75 10 push dword ptr ss:[ebp+10] 字符串长度
10057638 8BCE mov ecx, esi
1005763A FF75 0C push dword ptr ss:[ebp+C] 上层传入的字符串
1005763D C645 F3 01 mov byte ptr ss:[ebp-D], 1
10057641 E8 08F7FFFF call 10056D4E sha update
10057646 837D 14 00 cmp dword ptr ss:[ebp+14], 0
1005764A 74 0D je short 10057659
1005764C FF75 18 push dword ptr ss:[ebp+18]
1005764F 8BCE mov ecx, esi
10057651 FF75 14 push dword ptr ss:[ebp+14]
10057654 E8 F5F6FFFF call 10056D4E sha update
10057659 8BCE mov ecx, esi
1005765B E8 E4F5FFFF call 10056C44 sha finalize
1005770B 51 push ecx 压入16字节
1005770C 53 push ebx ebx为hash的前16字节
1005770D 8BCF mov ecx, edi 10057E75将第一次hash结果保存到ecx+14处
1005770F E8 61070000 call 10057E75
10057714 FF75 D0 push dword ptr ss:[ebp-30] 压入8字节
10057717 8BCF mov ecx, edi
10057719 FF75 D4 push dword ptr ss:[ebp-2C] 改处为第一次sha的最后4位+第二次sha的前4位
1005771C E8 B7070000 call 10057ED8 10057ED8将第二次hash结果保存到ecx+20处
至此,BlowFish所需要的key,和IV数组便产生,回到主验证过程10051605
10051605 51 push ecx ecx + c 为IV数组 8字节
10051606 8D9424 8C000000 lea edx, dword ptr ss:[esp+8C]
1005160D 898424 B8000000 mov dword ptr ss:[esp+B8], eax
10051614 52 push edx edx + c 为要进行Blowfish Init的key
10051615 8D4C24 68 lea ecx, dword ptr ss:[esp+68]
10051619 C68424 14010000>mov byte ptr ss:[esp+114], 6
10051621 888424 C0000000 mov byte ptr ss:[esp+C0], al
10051628 E8 2E5D0000 call 1005735B blowfish Init
这里是blowfish Init处理
1005166A 50 push eax eax+8为输入的验证码
1005166B 8D4C24 64 lea ecx, dword ptr ss:[esp+64]
1005166F C68424 10010000>mov byte ptr ss:[esp+110], 7 ecx + 0x20 blowfish结构体
10051677 E8 D55A0000 call 10057151 blowfish decrypt
blowfish decrypt处理,这里不是调用ECB,CFB模式,具体流程会走到1005E280,列出主要过程
1005E3F7 50 push eax
1005E3F8 51 push ecx
1005E3F9 895424 1C mov dword ptr ss:[esp+1C], edx
1005E3FD E8 7EF4FFFF call 1005D880 blowfish的具体decrypt函数
1005E447 8A03 mov al, byte ptr ds:[ebx] 注册码
1005E449 8A0C3E mov cl, byte ptr ds:[esi+edi] IV数组
1005E44C 88043E mov byte ptr ds:[esi+edi], al 用注册码值来作为下次加密
1005E44F 32C1 xor al, cl 两个数据xor
1005E451 8B4C24 20 mov ecx, dword ptr ss:[esp+20]
1005E455 43 inc ebx
1005E456 8801 mov byte ptr ds:[ecx], al 结果保存到ecx的地址
1005E458 8B4424 24 mov eax, dword ptr ss:[esp+24]
1005E45C 41 inc ecx
1005E45D 46 inc esi
1005E45E 83E6 07 and esi, 7
1005E461 48 dec eax 递减加密字符串的长度
回到主验证过程1005167C
1005167C 8B4C24 1C mov ecx, dword ptr ss:[esp+1C]
10051680 8B01 mov eax, dword ptr ds:[ecx]
10051682 898424 BC000000 mov dword ptr ss:[esp+BC], eax
10051689 8B51 04 mov edx, dword ptr ds:[ecx+4]
1005168C 899424 C0000000 mov dword ptr ss:[esp+C0], edx
10051693 66:8B49 08 mov cx, word ptr ds:[ecx+8]
10051697 66:898C24 C4000>mov word ptr ss:[esp+C4], cx
1005169F 8B4D 0C mov ecx, dword ptr ss:[ebp+C]
100516A2 8BBC24 C1000000 mov edi, dword ptr ss:[esp+C1] 将Blowfish decrypt后的数据,第5位起的4字节赋值到edi
100516A9 6A 05 push 5
100516AB 8D55 3C lea edx, dword ptr ss:[ebp+3C]
100516AE 8902 mov dword ptr ds:[edx], eax
100516B0 8A8424 C4000000 mov al, byte ptr ss:[esp+C4]
100516B7 56 push esi 硬件指纹数组
100516B8 51 push ecx
100516B9 8BCD mov ecx, ebp
100516BB 8842 04 mov byte ptr ds:[edx+4], al
100516BE E8 4DD6FFFF call 1004ED10 sha(硬件指纹数组+固定值)
看1004ED10的重要处理过程
1004ED6B 8B5424 64 mov edx, dword ptr ss:[esp+64]
1004ED6F 51 push ecx 长度
1004ED70 52 push edx edx为硬件指纹数组
1004ED71 8D4C24 14 lea ecx, dword ptr ss:[esp+14]
1004ED75 C64424 60 01 mov byte ptr ss:[esp+60], 1
1004ED7A E8 CF7F0000 call 10056D4E sha update
1004ED7F 8A4C24 63 mov cl, byte ptr ss:[esp+63]
1004ED83 B0 53 mov al, 53
1004ED85 884424 44 mov byte ptr ss:[esp+44], al
1004ED89 884424 45 mov byte ptr ss:[esp+45], al
1004ED8D 8B4424 60 mov eax, dword ptr ss:[esp+60]
1004ED91 884424 48 mov byte ptr ss:[esp+48], al
1004ED95 8A4424 62 mov al, byte ptr ss:[esp+62]
1004ED99 6A 14 push 14 长度
1004ED9B 8D5424 3C lea edx, dword ptr ss:[esp+3C]
1004ED9F 886424 4D mov byte ptr ss:[esp+4D], ah
1004EDA3 884424 4E mov byte ptr ss:[esp+4E], al
1004EDA7 52 push edx sha update,这数据此值为固定值
1004EDA8 8D4424 30 lea eax, dword ptr ss:[esp+30]
1004EDAC 884C24 53 mov byte ptr ss:[esp+53], cl
1004EDB0 50 push eax 返回sha后的结果,在eax+C处
1004EDB1 8D4C24 18 lea ecx, dword ptr ss:[esp+18]
1004EDF6 C64424 53 02 mov byte ptr ss:[esp+53], 2
1004EDFB E8 AC7F0000 call 10056DAC sha update,并且 sha finalize
返回到100516C3,此处要求值一致
100516C3 3BC7 cmp eax, edi 返回结果到eax,取头4字节
100516C5 74 03 je short 100516CA 与100516A2处的edi对比,即与Blowfish加密后的数据对比
100516C7 |897D 0C mov dword ptr ss:[ebp+C], edi 赋值到验证处2
到了最后一步验证,将blowfish crypto后的9个字节数据进行sha hash,然后与取其第一个值与第10个字节对比
10051707 6A 09 push 9 长度为9字节
10051709 8D8C24 C0000000 lea ecx, dword ptr ss:[esp+C0]
10051710 51 push ecx blowfish decrypto后的str地址
10051711 8D5424 3C lea edx, dword ptr ss:[esp+3C]
10051715 52 push edx edx+C储存sha hash后的结果
10051716 8D4C24 50 lea ecx, dword ptr ss:[esp+50]
1005171A C68424 18010000>mov byte ptr ss:[esp+118], 9
10051722 E8 85560000 call 10056DAC 对ecx进行sha hash
10051727 8B7C24 40 mov edi, dword ptr ss:[esp+40]
1005172B 8A0F mov cl, byte ptr ds:[edi] 获取ecx第10的值
1005172D 8A8424 C5000000 mov al, byte ptr ss:[esp+C5] 获取1004ED10 hash的第一个值
10051734 3AC1 cmp al, cl 对比两个值
10051736 0F94C1 sete cl
10051739 884D 08 mov byte ptr ss:[ebp+8], cl 赋值到验证处1
至此,整个activation code验证完毕。
【加密思路】
1:读取硬件信息,产生4个sha hash数组;
2:4个sha hash数组加固定字符组合在一起,然后再进行sha hash,取从第10个字节开始的5个字节;
3:对产品系列号的值进行sha hash,取第一个字节,与第二步骤产生的5个字节合并,产生硬件指纹;
4:逆转第3步产生的字符串,然后调用1005797C,产生blowfish的IV,Key数组;
5:先调用BlowFish Init,然后对输入的activation code进行Blowfish解密处理,产生数组简称Dstr;
6:对第3步产生的硬件指纹,调用1004ED10 进行 Sha Hash,取头4字节,取Dstr第5个字节起的4个字节,两者进行比较,要求值一致;
7:取Dstr数组的头9个字节,调用sha hash,hash后得到的数组取第1个字节与Dstr数组的第10个字节,进行比较,要求值一致.
【解密思路】
1 - 3.头4个步骤与加密思路相同,先得到硬件指纹,然后模拟1005797C函数得到blowfish的IV,Key数组;
4.模拟解密后的数组,先随机产生5个字节数据;
5.与加密思路步骤6相同,模拟1004ED10,取头4字节,与步骤4产生的数据合并,组成9个字节的数组A;
6.对A数组,调用sha hash,取hash数组第1个字节,作为数组A的第10个字节
7.对A进行Blowfish 加密处理,还原出activation code.
【结语】
这篇文章,只是列出关键的处理过程,只是向大家说明一个加密思路,细致的跟踪留给感兴趣的朋友们,还有我放出的注册机
只是在xp,08系统测试过,不保证所有系统平台都可以。
【版权声明】
本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2011 年 11月 18日 by Daniel
上传的附件: