绿鹰PC万能精灵V3.92注册算法分析(同样适用V3.95)
先说点废话。^_^ 就是这个软件带我进入Cracker世界,感谢~ 当时由于中了卑鄙小人的木马,病急乱
投医,找到这个软件,结果要注册,呵呵,当时很想搞掉它,可惜功力不够。最近闲来无事,下载了个最新版V
3.92再研究研究,也算是了却我一个心愿吧~ 谁知道噩梦开始了,该软件虽没有用密码学算法(还不如用呢,还
好定位和分析),可是却层层嵌套,费尽心思隐藏代码生成过程,真是不堪回首,不过如果只是想要自己的注
册码的话就不用这么麻烦了,可以利用软件帮我们自己算,如果分析... 以下我只贴出主要代码,细了太长,
我也不想再回头看这段可怕的路了,祝大家好运~
[Cracker] : prince
[时间] : 2005.07.16
[声明] : 只做技术交流,不做商业用途,如果你手头宽裕并喜欢这个软件的话请支持正版软件。
[E-mail] : Cracker_prince@163.com
[软件信息]
[软件说明] :
功能判断,可杀未来木马。可实时查杀:各种网络游戏盗号木马(传奇、天堂等)、邮件木马、聊天软
件盗密木马(如OICQ、MSN等)、股票大盗...
[保护方式] : 序列号 + 次数限制 + 功能限制(只提示,不杀毒,并且不管有没有病毒都提示有可疑文件
) + 反调试 + 自校验
[外壳保护] : PECompact 2.x -> Jeremy Collake
[编译器/语言]: Microsoft Visual C++ 6.0 / C/C++
[下载地址] : http://www.onlinedown.net/soft/6396.htm (3.95版)
[分析过程] :
文件脱壳、自校验和反调试我前几天已经写过,这里不再赘述,可以参考这里:http://bbs.pediy.com/showth
read.php?s=&threadid=14860
软件使用SendMessage获取用户输入的注册码,下断bpx SendMessageA,将我们没有点击注册按钮之前
的所有断点,添好假码8765432133333333(格式后面分析),点确定,断下来:
------------------------------------------------------------------
004248AC >call dword ptr ds:[<&user32.SendMessageA>] ; \SendMessageA
004248B2 >test eax,eax
004248B4 >mov eax,dword ptr ds:[47B0F0]
004248B9 >jnz UN2_++自.00424AA8
004248BF >mov dword ptr ss:[esp+94],eax
004248C6 >mov dword ptr ss:[esp+1364],0
004248D1 >mov dword ptr ss:[esp+10],eax
004248D5 >mov dword ptr ss:[esp+11C],eax
004248DC >lea ecx,dword ptr ss:[esp+94]
004248E3 >mov byte ptr ss:[esp+1364],2
004248EB >push ecx
004248EC >push 456
004248F1 >mov ecx,esi
004248F3 >call UN2_++自.0044BE75 ; EAX=0012F7C0 “tDF”
004248F8 >mov ecx,eax
004248FA >call UN2_++自.0044A113 ; 取用户输入的假码送ECX,EAX=假码个数
004248FF >mov edx,dword ptr ss:[esp+94] ; 假码写入内存00130608
00424906 >cmp dword ptr ds:[edx-8],10 ; 假码个数同0x10比较
0042490A >je short UN2_++自.0042494F ; 不跳就死
0042490C >mov ecx,esi
------------------------------------------------------------------
主要判断代码:
004100A0 /$ 6A>push -1
004100A2 |. 68>push UN2_++自.004591AC ; SE 句柄安装
004100A7 |. 64>mov eax,dword ptr fs:[0]
004100AD |. 50 push eax
004100AE |. 64>mov dword ptr fs:[0],esp
004100B5 |. 81>sub esp,814
004100BB |. 53 push ebx
004100BC |. 55 push ebp
004100BD |. 56 push esi
004100BE |. 57 push edi
004100BF |. 8B>mov edi,ecx
004100C1 |. 8B>mov eax,dword ptr ss:[esp+834] ; 取假码的前8位“87654321”送EAX
004100C8 |. 8B>mov ecx,dword ptr ss:[esp+838] ; 取假码的后8位“33333333”送ECX
004100CF |. C7>mov dword ptr ss:[esp+82C],3 ; 3写入[0012DB10]
004100DA |. 8B>mov edx,dword ptr ds:[eax-8] ; EDX=8
004100DD |. 8B>mov eax,dword ptr ds:[ecx-8] ; EAX=8
004100E0 |. 3B>cmp edx,eax
004100E2 |. 0F>jnz UN2_++自.0041033E
004100E8 |. 85>test eax,eax
004100EA |. 0F>je UN2_++自.0041033E
004100F0 |. 33>xor esi,esi ; ESI清零
004100F2 |. 85>test eax,eax
004100F4 |. 7E>jle short UN2_++自.0041011E
004100F6 |> 8A>/mov cl,byte ptr ds:[esi+ecx] ; 循环取假码后8位的单个字符
004100F9 |. 88>|mov byte ptr ss:[esp+10],cl
004100FD |. 8B>|mov edx,dword ptr ss:[esp+10] ; 送EDX
00410101 |. 52 |push edx ; 压栈
00410102 |. 8B>|mov ecx,edi
00410104 |. E8>|call UN2_++自.00410620
00410109 |. 85>|test eax,eax
0041010B |. 0F>|jl UN2_++自.0041033E
00410111 |. 8B>|mov ecx,dword ptr ss:[esp+838]
00410118 |. 46 |inc esi
00410119 |. 3B>|cmp esi,dword ptr ds:[ecx-8]
0041011C |.^ 7C>\jl short UN2_++自.004100F6
0041011E |> 8B>mov eax,dword ptr ss:[esp+834] ; 取假码的前8位送EAX
00410125 |. 33>xor esi,esi ; ESI清零
00410127 |. 8B>mov ecx,dword ptr ds:[eax-8] ; ECX=8
0041012A |. 85>test ecx,ecx
0041012C |. 0F>jle UN2_++自.004101F2
00410132 |. B3>mov bl,4
00410134 |> 8B>/mov ecx,dword ptr ds:[47B0F0] ; UN2_++自.0047B104
0041013A |. 89>|mov dword ptr ss:[esp+14],ecx
0041013E |. 56 |push esi ; ESI==0
0041013F |. 56 |push esi
00410140 |. 8D>|lea ecx,dword ptr ss:[esp+83C]
00410147 |. 88>|mov byte ptr ss:[esp+834],bl
0041014E |. E8>|call UN2_++自.004103B0 ; 取假码的前8位单个字符
00410153 |. 50 |push eax ; 假码的第1位压栈
00410154 |. 51 |push ecx ; ECX==0
00410155 |. 8D>|lea edx,dword ptr ss:[esp+848]
0041015C |. 8B>|mov ecx,esp
0041015E |. 89>|mov dword ptr ss:[esp+2C],esp
00410162 |. 52 |push edx
00410163 |. E8>|call UN2_++自.0044C6BF
00410168 |. 8D>|lea eax,dword ptr ss:[esp+1C] ; |
0041016C |. 8B>|mov ecx,edi ; |
0041016E |. 50 |push eax ; |Arg1
0041016F |. E8>|call UN2_++自.004103C0 ; \关键,确定后8位字符,跟进
00410174 |. 50 |push eax
00410175 |. 8D>|lea ecx,dword ptr ss:[esp+18]
00410179 |. C6>|mov byte ptr ss:[esp+830],5
00410181 |. E8>|call UN2_++自.0044CA83
00410186 |. 8D>|lea ecx,dword ptr ss:[esp+10]
0041018A |. 88>|mov byte ptr ss:[esp+82C],bl
00410191 |. E8>|call UN2_++自.0044C94A
00410196 |. 8B>|mov ecx,dword ptr ss:[esp+14]
0041019A |. 8B>|mov eax,dword ptr ss:[esp+838] ; 取假码的后8位
004101A1 |. 8A>|mov dl,byte ptr ds:[ecx] ; 查表
004101A3 |. 8A>|mov cl,byte ptr ds:[esi+eax] ; 取假码后8位单个字符
004101A6 |. 88>|mov byte ptr ss:[esp+1C],cl
004101AA |. 88>|mov byte ptr ss:[esp+18],dl ; 查表结果写入内存
004101AE |. 8B>|mov edx,dword ptr ss:[esp+1C] ;
004101B2 |. 8B>|mov ecx,edi
004101B4 |. 52 |push edx
004101B5 |. E8>|call UN2_++自.00410620
004101BA |. 8B>|mov ebp,eax
004101BC |. 8B>|mov eax,dword ptr ss:[esp+18]
004101C0 |. 50 |push eax
004101C1 |. 8B>|mov ecx,edi
004101C3 |. E8>|call UN2_++自.00410620
004101C8 |. 3B>|cmp ebp,eax ; 判断查表结果和计算结果是否相同
004101CA |. C6>|mov byte ptr ss:[esp+82C],3
004101D2 |. 8D>|lea ecx,dword ptr ss:[esp+14]
004101D6 |. 0F>|jnz UN2_++自.00410339 ; 跳走即失败!!!
004101DC |. E8>|call UN2_++自.0044C94A
004101E1 |. 8B>|mov ecx,dword ptr ss:[esp+834] ; 取假码前8个字符准备下次循环
004101E8 |. 46 |inc esi
004101E9 |. 3B>|cmp esi,dword ptr ds:[ecx-8]
004101EC |.^ 0F>\jl UN2_++自.00410134
004101F2 |> 8B>mov eax,dword ptr ss:[esp+844]
004101F9 |. 85>test eax,eax
004101FB |. 0F>jnz UN2_++自.004102DF
00410201 |. A1>mov eax,dword ptr ds:[47E420]
00410206 |. 8D>lea edx,dword ptr ss:[esp+24]
0041020A |. 68>push 800 ; /Count = 800 (2048.)
------------------------------------------------------------------
我就只贴出这些了,剩下的所有都可以从这里跟下去,很长,很复杂,而且利用多次指针转移,不容
易跟踪,大家如果有兴趣分析,可以顺藤摸瓜,逆着往回查,可以省点工夫。
我贴出注册机源码,过程中的浮点操作我不知道如何用高级语言描述,于是大多采用了程序中的汇编
源码,大家可以对照源码查看,基本过程在我的注册机里很清楚。
另外,我是边跟踪边写注册机,所以变量使用混乱,代码繁杂,也不想再修正了,大家凑合看吧,请
勿深究变量使用及设计方面的问题。
-------------------------------------------------------------------
以下代码在VC6+2K SP3下测试通过:
/***************************************************
File name : Keygen for 绿鹰PC万能精灵3.92(3.95)
Author : prince
Date : 2005.07.06
****************************************************/
#include <stdafx.h>
#include <stdio.h>
#include <Math.h>
#include <memory.h>
#include <time.h>
#include <stdlib.h>
char number = 0;
char chNumber1 = 0;
double dNumber2 = 0;
double dNumber3 = 0;
char chString[] = "EGhost";
char chChart[5] = {'3', 'b', 'y', 't', 'p'};
char chValue1[11] = {0};
double dValue2 = 0;
__int64 nValue3 = 0x40C6248000000000;
double dValue4 = 0;
double dCount = 0;
__int64 dSaveFcw = 0;
__int64 dTemp7 = 0;
int nFlag = 0;
char GeneratePart2Key(char chPart1Key, int nIndex)
{
nFlag = 0;
__int64 dTemp1 = 0;
__int64 dTemp2 = 0;
__int64 dTemp3 = 0;
__int64 dTemp4 = 0;
__int64 dTemp5 = 0;
__int64 dTemp6 = 0;
dTemp1 = 0x43498ECDC7C69E38;
dTemp5 = 0x4314723E396BB1C4;
dTemp6 = 0xC3E8F574F517F684;
dTemp7 = 0xC0C6248000000000;
dCount = 0;
if (0 == chPart1Key)
{
printf("damn it! please try again! :(\n");
return -1;
}
number = chPart1Key;
__asm
{
pushad
xor eax, eax
xor ecx, ecx
mov eax, nIndex
mov ecx, eax
shl ecx, 5
lea eax, dword ptr ss:[ecx + eax + 0xb]
mov dword ptr ss:[nIndex], eax
popad
}
number ^= nIndex;
__asm
{
push eax
mov eax, dword ptr ss:[number]
mov dword ptr ss:[chNumber1], eax
mov dword ptr ss:[chNumber1 + 7], 0
pop eax
}
__asm
{
pushad
fild qword ptr ds: [chNumber1]
fsin
fst st(1)
fmul qword ptr ds:[dTemp1]
xor eax, eax
wait
fstcw dTemp1
wait
mov ax, word ptr ss:[dTemp1]
or ah, 0xc
mov word ptr ss:[dTemp2], ax
fldcw word ptr ss:[dTemp2]
fistp qword ptr ss:[dTemp3]
fldcw word ptr ss:[dTemp1]
mov eax, dword ptr ss:[dTemp3]
mov edx, dword ptr ss:[dTemp3 + 4]
test eax, eax
jl Lable
fmul qword ptr ds:[dTemp5]
jmp Lable0
Lable:
fmul qword ptr ss:[dTemp6]
Lable0:
fstcw word ptr ss:[dTemp2]
wait
mov ax, word ptr ss:[dTemp2]
or ah, 0xc
mov word ptr ss:[dTemp3], ax
fldcw word ptr ss:[dTemp3]
fistp qword ptr ss:[dTemp4]
fldcw word ptr ss:[dTemp2]
mov eax, dword ptr ss:[dTemp4]
xor edx, edx
add eax, 0x4fe31c6b
mov dword ptr ss:[dTemp2], eax
adc edx, 0x3733e7d0
mov dword ptr ss:[dTemp4], 0x3733e7d0
mov dword ptr ss:[dTemp3], 0x12
xor edi, edi
mov eax, edx
mov eax, 0x12
xor ebx, ebx
mov ebx, eax
xor ecx, ecx
mov ecx, 0x2442ef71
mov eax, dword ptr ss:[dTemp2]
again1:
shr ebx, 1
rcr ecx, 1
shr edx, 1
rcr eax, 1
or ebx, ebx
jnz again1
div ecx
mov ecx, eax
mul dword ptr ss:[dTemp3]
xchg eax, ecx
mov dword ptr ss:[dTemp3], 0x2442ef71
mul dword ptr ss:[dTemp3]
add edx, ecx
cmp edx, dword ptr ss:[dTemp4]
ja Lable1
jb Lable2
Lable1:
sub eax, 0x2442ef71
sbb edx, 0x12
Lable2:
sub eax, dword ptr ss:[dTemp2]
sbb edx, 0x3733e7d0
dec edi
jns Lable3
neg edx
neg eax
sbb edx, 0
mov dword ptr ss:[dNumber2], edx
Lable3:
nop
mov edi, edx
mov esi, eax
cmp edi, ebx
jg Lable5
jl Lable4
cmp esi, ebx
jnb Lable5
Lable4:
neg esi
adc edi, ebx
neg edi
Lable5:
lea ebx, chString
xor ecx, ecx
mov ebp, 6
again2:
movsx eax, byte ptr ds:[ecx + ebx]
cdq
add esi, eax
adc edi, edx
inc ecx
cmp ecx, ebp
jl again2
xor edi, edi
mov eax, dword ptr ss:[dNumber2]
mov eax, 0x12
mov ebx, eax
mov ecx, 0x2442ef71
mov edx, dword ptr ss:[dNumber2]
mov eax, esi
again3:
shr ebx, 1
rcr ecx, 1
shr edx, 1
rcr eax, 1
or ebx, ebx
jnz again3
div ecx
mov ecx, eax
mov dword ptr ss:[esp - 4], 0x12
mul dword ptr ss:[esp - 4]
xchg eax, ecx
mov dword ptr ss:[esp - 4], 0x2442ef71
mul dword ptr ss:[esp - 4]
add edx, ecx
cmp edx, dword ptr ss:[dNumber2]
ja Lable6
jb Lable7
Lable6:
sub eax, 0x2442ef71
sbb edx, 0x12
Lable7:
sub eax, esi
sbb edx, dword ptr ss:[dNumber2]
dec edi
jns Lable8
neg edx
neg eax
sbb edx, 0
mov dword ptr ds:[dNumber3], esi
xor edx, edx
cdq
cmp edx, 0
je Lable8
neg eax
mov dword ptr ds:[dNumber3], eax
mov dword ptr ds:[nFlag], 1
Lable8:
nop
// 开始计算中间字符串
xor edx, edx
xor edi, edi
mov dword ptr ss:[dNumber2], 1
again4:
mov eax, dword ptr ss:[dNumber2]
dec dword ptr ss:[dNumber2]
test eax, eax
jg Lable9
mov eax, esi
or eax, edi
je EndAgain4
Lable9:
mov eax, 0xa
cdq
// 计算余数
mov ecx, 0xa
mov eax, dword ptr ds:[dNumber3]
div ecx
mov eax, edx
xor edx, edx
mov ebx, eax
add ebx, 0x30
// 计算商
mov eax, dword ptr ds:[dNumber3]
div ecx
cmp ebx, 0x39
mov esi, eax
mov dword ptr ds:[dNumber3], eax
mov ecx, dword ptr ds:[dCount]
mov dword ptr ds:[chValue1 + ecx], ebx
inc dword ptr ds:[dCount];
jmp again4
EndAgain4:
popad
}
char chTemp = 0;
int i = 0;
int nStrCount = 0;
__asm
{
pushad
xor eax, eax
mov eax, dword ptr ds:[dCount]
mov dword ptr ss:[nStrCount], eax
popad
}
if (1 == nFlag)
{
nStrCount++;
chValue1[nStrCount - 1] = '-';
}
switch (nStrCount)
{
case 9:
{
for (i = 0; i < 4; i++)
{
chTemp = chValue1[i];
chValue1[i] = chValue1[8 - i];
chValue1[8 - i] = chTemp;
}
break;
}
case 10:
{
for (i = 0; i < 5; i++)
{
chTemp = chValue1[i];
chValue1[i] = chValue1[9 - i];
chValue1[9 - i] = chTemp;
}
break;
}
case 11:
{
for (i = 0; i < 11; i++)
{
chValue1[10 - i + 1] = chValue1[10 - i];
}
chValue1[0] = '-';
for (i = 1; i < 6; i++)
{
chTemp = chValue1[i];
chValue1[i] = chValue1[11 - i];
chValue1[11 - i] = chTemp;
}
break;
}
default:
{
break;
}
}
__asm
{
pushad
xor edx, edx
xor eax, eax
xor ecx, ecx
xor esi, esi
mov esi, dword ptr ss:[nStrCount]
xor ebp, ebp
xor ebx, ebx
lea edx, dword ptr ds:[chValue1]
mov ebp, 6
lea ebx, dword ptr ds:[chString]
again5:
test ecx, ecx
jnz Lable10
movsx eax, byte ptr ds:[edx]
xor eax, 0x16
jmp Lable11
Lable10:
movsx ebp, byte ptr ds:[ecx + edx]
xor ebp, 0x16
xor eax, ebp
Lable11:
inc ecx
cmp ecx, esi
jl again5
mov dword ptr ds:[dValue2], eax
fild qword ptr ds:[dValue2]
fsin
fld st
fmul qword ptr ss:[nValue3]
wait
fstcw word ptr ds:[dSaveFcw]
wait
mov ax, word ptr ds:[dSaveFcw]
or ah, 0xc
mov word ptr ds:[dSaveFcw + 8], ax
fldcw word ptr ds:[dSaveFcw + 8]
fistp qword ptr ss:[dValue4]
fldcw word ptr ss:[dSaveFcw]
mov eax, dword ptr ss:[dValue4]
mov ecx, eax
test ecx, ecx
jl Lable12
fmul qword ptr ss:[dTemp7]
wait
fstcw word ptr ds:[dSaveFcw]
wait
mov ax, word ptr ds:[dSaveFcw]
or ah, 0xc
mov word ptr ds:[dSaveFcw + 8], ax
fldcw word ptr ds:[dSaveFcw + 8]
fistp qword ptr ss:[dValue4]
fldcw word ptr ss:[dSaveFcw]
mov eax, dword ptr ss:[dValue4]
mov ecx, 0xcc7
sub ecx, eax
mov eax, ecx
jmp Lable13
Lable12:
mov eax, 0xcc7
fstp st
sub eax, ecx
Lable13:
cdq
mov ecx, 5
idiv ecx
mov dword ptr ds:[number], edx
popad
}
return chChart[number];
}
int main(int argc, char* argv[])
{
int i = 0;
char chPart2Key[8] = {0};
char chRandNumber[8] = {0};
srand( (unsigned)time( NULL ) );
for (i = 0; i < 8; i++)
{
int j = rand() % 3 + 1;
switch(j)
{
case 1:
{
chRandNumber[i] = (rand() % 9) + 0x30;
break;
}
case 2:
{
chRandNumber[i] = (rand() % 26) + 0x41;
break;
}
case 3:
{
chRandNumber[i] = (rand() % 26) + 0x61;
break;
}
default:
{
printf("damn it! please try again! :(\n");
return -1;
}
}
}
for (i = 0; i < 8; i++)
{
chPart2Key[i] = GeneratePart2Key(chRandNumber[i], i);
}
printf("enjoy key: %s\n", chRandNumber/*chTest, chPart2Key*/);
return 0;
}
------------------------------------------------------------------
就在我写完这篇分析的时候,最新版3.95 released,经过测试,算法没有变,仍然可以使用。
任何问题可至: Cracker_prince@163.com
菜鸟写菜文,请大侠们不吝赐教~
prince 2005.07.16