-
-
[原创]彩虹精灵狗(2.0)的破解心得
-
发表于:
2005-7-13 09:44
16375
-
经过2个星期的奋斗终于搞定了彩虹精灵狗,在这个过程中对精灵狗的狗壳和常用的检测方法有了一些心得希望能与大家共享。
总的来说精灵狗的狗壳强度不高,加密算法很简单可以通过穷举算出解码的数值。而且限制使用日期的功能设计简单,给我们留下了脱壳的简单方法。
精灵狗api的版本,精灵狗api有3个版本(1.0、2.0、2.1)其中从2.0还是支持usb狗狗(本文中谈到的是2.0版本)。要确定程序适用的狗版本,可以在程序的.gdata段查找字符串”gawin32c.c”,找到这个字符串后再向下看如果后面的字符串是”zhangzh”就表示使用的是2.0版本,如果是”PeterCheng”就表示使用的是2.1版本。你也可以到http://cn.safenet-nc.com/download/dog/ga.asp 取下载精灵狗的开发套件在安装目录的Utility下有一个GetVer.exe文件运行后能检测程序使用的api版本 2.001->2.0版本 2.019->2.1版本。这两个版本的区别在于(精灵狗开发套件 V2.1 是在 V2.0 套件产品基础上进行的一次较大的升级。采用了我公司自主研发的第二代安全加密引擎,其中集成了最新的密码学理论和高强度加密算法,可以极大地提高受保护软件的防破解能力。同时增加了EncryptEx()和DecryptEx()接口函数。)
精灵狗狗壳使用的全局变量:
n .gdata+28 dowrd 程序的真实入口
n .gdata+2c dowrd 限时模式时间值1
n .gdata+3e dword 限时模式时间值2
n .gdata+7c dword 狗壳加密数据的地址
n .gdata+8c dword 运行在限时模式的标记 1:OK 0:NO
n .gdata+94 dword 限时模式下的解码key
n .gdata+98 byte[] 限时模式时的时间文件
n .gdata+2ca dword狗壳加密数据的长度(一般为1k)
n .gdata+2ce dword 解码key
我们可以利用精灵狗的限时模式快速的打掉狗狗,在限时模式下 运行的时间期限 = (限时模式时间值1 xor 限时模式时间值2)其格式为FFFF(年)FF(月)FF(日) 其中(日)的数据还作为解码key是用。打狗是把.gdata+8c=1 .gdata+3e=0 .gdata+94=0 .gdata+98=”时间数据文件名”(自己创建一个包含20个字节零的二进制文件)。下面重要的是要算出解码key作为运行时间的(日)字段。
狗壳的解码算法如下
len=0;
while (len < .gdata+2ca)
{
.gdata+7c[len] = .gdata+7c[len] ? get_key();
len++;
}
下面是狗壳里面算”解码key”的代码get_key(),看着是不是很复杂其实很简单” ((0x35 * 输入值) + 1) & 0xFF ”一行就行了够简单吧J 。现在的任务就是找到开始算解码时用的初值,.gdata+7c开始的4个字节原值都是0(不能保证每个程序都是,如果不是就只能从0-255一个的一个的去试了),那我们就知道第一个key就是.gdata+7c[0]的值,根据get_key()的算法我们很容易写一个程序去推算出那个初值。算出初值后我们就可以设置.gdata+2c的值了=270F(9999)0C(12)?(key)
.gtide:00453978 get_key proc near ; CODE XREF: call_api_func+DD5p
.gtide:00453978 ; read_last_rundate+30Ap ...
.gtide:00453978
.gtide:00453978 var_18 = dword ptr -18h
.gtide:00453978 var_14 = dword ptr -14h
.gtide:00453978 var_10 = dword ptr -10h
.gtide:00453978 var_C = dword ptr -0Ch
.gtide:00453978 var_8 = dword ptr -8
.gtide:00453978 var_4 = dword ptr -4
.gtide:00453978
.gtide:00453978 push ebp
.gtide:00453979 mov ebp, esp
.gtide:0045397B sub esp, 18h
.gtide:0045397E push ebx
.gtide:0045397F push esi
.gtide:00453980 push edi
.gtide:00453981 mov eax, ds:key_value
.gtide:00453986 shr eax, 10h
.gtide:00453989 mov [ebp+var_4], eax
.gtide:0045398C mov eax, ds:key_value
.gtide:00453991 and eax, 0FFFFh
.gtide:00453996 mov [ebp+var_8], eax
.gtide:00453999 mov [ebp+var_C], 15Ah
.gtide:004539A0 mov [ebp+var_14], 4E35h
.gtide:004539A7 mov eax, [ebp+var_C]
.gtide:004539AA imul eax, [ebp+var_8]
.gtide:004539AE and eax, 0FFFFh
.gtide:004539B3 mov [ebp+var_10], eax
.gtide:004539B6 cmp [ebp+var_4], 0
.gtide:004539BA jz short loc_0_4539CB
.gtide:004539BC mov eax, [ebp+var_14]
.gtide:004539BF imul eax, [ebp+var_4]
.gtide:004539C3 and eax, 0FFFFh
.gtide:004539C8 add [ebp+var_10], eax
.gtide:004539CB
.gtide:004539CB loc_0_4539CB: ; CODE XREF: get_key+42j
.gtide:004539CB mov eax, [ebp+var_14]
.gtide:004539CE imul eax, [ebp+var_8]
.gtide:004539D2 mov ecx, [ebp+var_10]
.gtide:004539D5 shl ecx, 10h
.gtide:004539D8 and ecx, 0FFFF0000h
.gtide:004539DE add eax, ecx
.gtide:004539E0 inc eax
.gtide:004539E1 mov [ebp+var_18], eax
.gtide:004539E4 mov eax, [ebp+var_18]
.gtide:004539E7 mov ds:key_value, eax
.gtide:004539EC shr [ebp+var_18], 10h
.gtide:004539F0 and [ebp+var_18], 7FFFh
.gtide:004539F7 mov ax, word ptr [ebp+var_18]
.gtide:004539FB jmp short $+2
.gtide:004539FD pop edi
.gtide:004539FE pop esi
.gtide:004539FF pop ebx
.gtide:00453A00 leave
.gtide:00453A01 retn
.gtide:00453A01 get_key endp
打掉狗狗后就要应付程序对狗狗的检测了,程序读狗是用了CreateFile DeviceIoControl等函数可以在那里下断点不过这些函数调用都很复杂,更好的方法是下载狗狗的开发包,根据程序的开发语言找到GAW32?.OBJ 文件,程序都是用这个去操作狗,这个就以GAW32VC.OBJ为例。
GAW32VC.obj模块中提供了6个外部函数,分别为:
unsigned long CreateRandom() 产生128位随机数
unsigned long GetCurrentNumber() 获取狗的流水号
unsigned long Encrypt() 加密函数
unsigned long Decrypt() 解密函数
unsigned long EncryptEx() 扩展加密函数(2.1版新加)
unsigned long DecryptEx() 扩展解密函数(2.1版新加)
它们要求调用者定义 4 个全局变量:
unsigned long SerialNumber; 存放精灵狗系列号
unsigned long UserKey; 存放用户密钥
void * InDogData; 存放输入数据的指针
void * OutDogData; 存放输出数据的指针
大家可以好好地看一下这些函数的实现,里面有很多的花指令看的时候注意。一般情况下这些代码都会出现在代码段的开头部分。我们来关注一下下面的几行代码,我们看到了一个重要的全局变量_OutDogData 如果 你在程序的代码段看到了这个,你就去看一下ds:_OutDogData的地址,在那里你应该还能看到其他的几个全局变量,这几个变量的位置相对比较固定一般会被定义在一起,我们找到一个就可能全部找到,有了这几个关键的变量再加上那几个函数要弄清程序检测狗狗的方式和位置就很容易了,打狗就不在话下了。
.text:00000003 push ecx
.text:00000004 push ebx
.text:00000005 xor ebx, ebx
.text:00000007 cmp dword ptr ds:_OutDogData, ebx
最后我们再来关注一下api调用加密问题,狗狗加壳后会修改程序中的api调用代码,把调用api的代码替换为自己实现的代码。调用的过程
比较复杂不好说清楚,我用一个实例来解释
call CloseHandle 原始的调用代码
call loc_0_456D4C 狗狗修改后的调用代码
.gtide:00456D4C call sub_XXXXX ; 这个就是狗狗的api调用代码,里面一通乱跳还有检测狗狗,最后用下面公式计算出来的地址去修改堆栈中的函数返回地址,来调用api
.gtide:00456D51 dd 463FA5h ; 0x463FA5 ? (0x00456D51& 0xFFFF) = api的地址
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课