程序没有加壳,用PEid查显示为:Microsoft Visual Basic 5.0 / 6.0
由于是来分析算法,所以我还用PEid的插件来分析了一下程序所用的算法是:
CRC32 [poly] :: 0013D96F :: 0053D96F
The reference is above.
心里有个数了,其他的也就不多说了,直接用OD载入吧,F9运行起来,然后找到注册位置,随意输入注册码,不急着确定,先下:bp rtcMsgBox,然后确定,断在:
ALt+F9返回:
73502096 MSVBVM> 55 push ebp
73502097 8BEC mov ebp,esp
73502099 83EC 4C sub esp,4C
7350209C 8B4D 14 mov ecx,dword ptr ss:[ebp+14]
004B8DBD . /0F84 BD000000 je wincnt.004B8E80
004B8DC3 . |8B45 08 mov eax,dword ptr ss:[ebp+8]
004B8DC6 . |8D95 FCFEFFFF lea edx,dword ptr ss:[ebp-104]
004B8DCC . |52 push edx
004B8DCD . |8B55 E8 mov edx,dword ptr ss:[ebp-18]
004B8DD0 . |8B08 mov ecx,dword ptr ds:[eax]
004B8DD2 . |52 push edx
004B8DD3 . |50 push eax
004B8DD4 . |FF91 38090000 call dword ptr ds:[ecx+938] ; 这里就是第一个关键CALL了,F7跟进
004B8DDA . |8B45 E8 mov eax,dword ptr ss:[ebp-18]
004B8DDD . |50 push eax
004B8DDE . |FFD6 call esi ; <&MSVBVM60.__vbaLenBstr>
004B8DE0 . |33C9 xor ecx,ecx
004B8DE2 . |83F8 0D cmp eax,0D
004B8DE5 . |0F9DC1 setge cl
004B8DE8 . |33D2 xor edx,edx
004B8DEA . |66:3995 FCFEFFFF cmp word ptr ss:[ebp-104],dx
004B8DF1 . |0F95C2 setne dl
004B8DF4 . |85CA test edx,ecx
004B8DF6 . |0F85 3D010000 jnz wincnt.004B8F39
004B8DFC . |BE 04000280 mov esi,80020004
004B8E01 . |8D95 50FFFFFF lea edx,dword ptr ss:[ebp-B0]
004B8E07 . |8D4D B0 lea ecx,dword ptr ss:[ebp-50]
004B8E0A . |8975 98 mov dword ptr ss:[ebp-68],esi
004B8E0D . |895D 90 mov dword ptr ss:[ebp-70],ebx
004B8E10 . |8975 A8 mov dword ptr ss:[ebp-58],esi
004B8E13 . |895D A0 mov dword ptr ss:[ebp-60],ebx
004B8E16 . |C785 58FFFFFF 4050>mov dword ptr ss:[ebp-A8],wincnt.00415040 ; UNICODE "Registration failed!"
004B8E20 . |C785 50FFFFFF 0800>mov dword ptr ss:[ebp-B0],8
004B8E2A . |FFD7 call edi ; <&MSVBVM60.__vbaVarDup>
004B8E2C . |8D95 60FFFFFF lea edx,dword ptr ss:[ebp-A0]
004B8E32 . |8D4D C0 lea ecx,dword ptr ss:[ebp-40]
004B8E35 . |C785 68FFFFFF 2450>mov dword ptr ss:[ebp-98],wincnt.00415024 ; UNICODE "Invalid Key"
004B8E3F . |C785 60FFFFFF 0800>mov dword ptr ss:[ebp-A0],8
004B8E49 . |FFD7 call edi ; <&MSVBVM60.__vbaVarDup>
004B8E4B . |8D45 90 lea eax,dword ptr ss:[ebp-70]
004B8E4E . |8D4D A0 lea ecx,dword ptr ss:[ebp-60]
004B8E51 . |50 push eax
004B8E52 . |8D55 B0 lea edx,dword ptr ss:[ebp-50]
004B8E55 . |51 push ecx
004B8E56 . |52 push edx
004B8E57 . |8D45 C0 lea eax,dword ptr ss:[ebp-40]
004B8E5A . |6A 30 push 30
004B8E5C . |50 push eax
004B8E5D . |FF15 B8114000 call dword ptr ds:[<&MSVBVM60.#595>] ; MSVBVM60.rtcMsgBox
004B8E63 . |8D4D 90 lea ecx,dword ptr ss:[ebp-70]
跟进上面的那个关键,很快就来到这里:
004CBEC9 . 52 push edx
004CBECA . 894D C4 mov dword ptr ss:[ebp-3C],ecx
004CBECD . C745 BC 08400000 mov dword ptr ss:[ebp-44],4008
004CBED4 . FFD7 call edi ; <&MSVBVM60.__vbaLenBstr>
004CBED6 . 83E8 09 sub eax,9 ; 取用户输入的注册长度,与9比较
004CBED9 . 8D4D CC lea ecx,dword ptr ss:[ebp-34]
004CBEDC . 0F80 C5000000 jo wincnt.004CBFA7 ; 小于9则出错返回
//0012F7F8 001DAA84 UNICODE "AAA-_12345678"
继续单步,来到这里:
004CBEE6 . 50 push eax
004CBEE7 . 51 push ecx
004CBEE8 . FF15 F8134000 call dword ptr ds:[<&MSVBVM60.#617>] ; MSVBVM60.rtcLeftCharVar
004CBEEE . 8D55 CC lea edx,dword ptr ss:[ebp-34] ; 取出左边4个字符
//0012F7E8 0021B104 UNICODE "AAA-"
一路单步吧:
004CBF14 . 52 push edx
004CBF15 . 8D55 EC lea edx,dword ptr ss:[ebp-14]
004CBF18 . 8B08 mov ecx,dword ptr ds:[eax]
004CBF1A . 52 push edx
004CBF1B . 50 push eax
004CBF1C . FF91 34090000 call dword ptr ds:[ecx+934] ; 关键CALL,F7跟进
//=========================================================
004CBBED . 52 push edx ; /Arg2
004CBBEE . 50 push eax ; |Arg1
004CBBEF . C785 5CFFFFFF A74D>mov dword ptr ss:[ebp-A4],4DA7 ; |
004CBBF9 . C785 54FFFFFF 0200>mov dword ptr ss:[ebp-AC],2 ; |
004CBC03 . FF15 E0114000 call dword ptr ds:[<&MSVBVM60.#520>] ; \将4DA7转换为10格式字符串,即:19879
由此可见,这里的19879是固定的,我们在做注册机时,就可以直接写上了,不用管他的转换!
004CBC3A . 8D95 44FFFFFF lea edx,dword ptr ss:[ebp-BC]
004CBC40 . 8D85 34FFFFFF lea eax,dword ptr ss:[ebp-CC]
004CBC46 . 52 push edx
004CBC47 . 50 push eax
004CBC48 . FFD7 call edi ; 将^LTB与上面得到字符串连接; <&MSVBVM60.__vbaVarCat>
004CBC4A . 50 push eax ; /得到:UNICODE "^LTB19879"
上面是一连串的字符串连接操作,这里不一一作说明了,其实都是固定下来的,得到的结果就是:^LTB19879
004CBD23 . 52 push edx
004CBD24 . 50 push eax
004CBD25 . 8975 E0 mov dword ptr ss:[ebp-20],esi
004CBD28 . C745 C4 08000000 mov dword ptr ss:[ebp-3C],8 ; 将主程序名转成小写
004CBD2F . FF15 44114000 call dword ptr ds:[<&MSVBVM60.#518>] ; MSVBVM60.rtcLowerCaseVar
004CBD35 . 8B4D E4 mov ecx,dword ptr ss:[ebp-1C] ; //UNICODE "wincnt"
……………………
004CBD4B . 50 push eax
004CBD4C . 51 push ecx
004CBD4D . C785 24FFFFFF 0800>mov dword ptr ss:[ebp-DC],8
004CBD57 . FFD7 call edi ; 接上上面的字符串得:"wincnt^LTB19879"
004CBD59 . 50 push eax ; /Arg1 = 0012F74C
……………………
004CBD6D . 51 push ecx
004CBD6E . 8D4D DC lea ecx,dword ptr ss:[ebp-24]
004CBD71 . 8B10 mov edx,dword ptr ds:[eax]
004CBD73 . 51 push ecx
004CBD74 . 8B4D 0C mov ecx,dword ptr ss:[ebp+C]
004CBD77 . 51 push ecx
004CBD78 . 50 push eax
004CBD79 . FF92 44090000 call dword ptr ds:[edx+944] ; 关键CALL,继续F7跟进
上面大部分都是字符串的连接操作,我们跟过就明白了,我们继续跟入下面的一个关键CALL吧
//=======================================
004CC8D5 . C745 C0 65F95900 mov dword ptr ss:[ebp-40],59F965 ; |
004CC8DC . C745 B8 03000000 mov dword ptr ss:[ebp-48],3 ; |
004CC8E3 . FF15 E0114000 call dword ptr ds:[<&MSVBVM60.#520>] ; \rtcTrimVar
004CC8E9 . 8B5D 0C mov ebx,dword ptr ss:[ebp+C] ; 又得一字符串:5896549
……………………
004CC923 . 51 push ecx
004CC924 . 52 push edx
004CC925 . FFD7 call edi ; 继续连接字符串; <&MSVBVM60.__vbaVarCat>
004CC927 . 50 push eax ; 得:"5896549AAA-"
004CC928 . 8D85 54FFFFFF lea eax,dword ptr ss:[ebp-AC]
004CC92E . 8D4D 88 lea ecx,dword ptr ss:[ebp-78]
004CC931 . 50 push eax
004CC932 . 51 push ecx
004CC933 . FFD7 call edi ; <&MSVBVM60.__vbaVarCat>
004CC935 . 8BD0 mov edx,eax ; 得:"5896549AAA-wincnt^LTB19879"
……………………
004CC995 . 52 push edx
004CC996 . 50 push eax
004CC997 . 8BF8 mov edi,eax
004CC999 . FF51 28 call dword ptr ds:[ecx+28] ; 关键CALL,继续F7跟进
继续跟进:
//===============================================================
0053DCB1 > /8B4D E8 mov ecx,dword ptr ss:[ebp-18]
0053DCB4 . |8B45 A4 mov eax,dword ptr ss:[ebp-5C]
0053DCB7 . |3BC8 cmp ecx,eax
0053DCB9 . |0F8F B1000000 jg wincnt.0053DD70
0053DCBF . |8B55 0C mov edx,dword ptr ss:[ebp+C]
0053DCC2 . |8B02 mov eax,dword ptr ds:[edx]
0053DCC4 . |3BC7 cmp eax,edi
0053DCC6 . |74 20 je short wincnt.0053DCE8
0053DCC8 . |66:8338 01 cmp word ptr ds:[eax],1
0053DCCC . |75 1A jnz short wincnt.0053DCE8
0053DCCE . |8B50 14 mov edx,dword ptr ds:[eax+14]
0053DCD1 . |8BF9 mov edi,ecx
0053DCD3 . |8B48 10 mov ecx,dword ptr ds:[eax+10]
0053DCD6 . |2BFA sub edi,edx
0053DCD8 . |3BF9 cmp edi,ecx
0053DCDA . |72 06 jb short wincnt.0053DCE2
0053DCDC . |FF15 38124000 call dword ptr ds:[<&MSVBVM60.__vbaGenerateBou>; MSVBVM60.__vbaGenerateBoundsError
0053DCE2 > |8BC7 mov eax,edi
0053DCE4 . |33FF xor edi,edi
0053DCE6 . |EB 06 jmp short wincnt.0053DCEE
0053DCE8 > |FF15 38124000 call dword ptr ds:[<&MSVBVM60.__vbaGenerateBou>; MSVBVM60.__vbaGenerateBoundsError
0053DCEE > |8B4D 0C mov ecx,dword ptr ss:[ebp+C]
0053DCF1 . |8B11 mov edx,dword ptr ds:[ecx]
0053DCF3 . |8B4A 0C mov ecx,dword ptr ds:[edx+C]
0053DCF6 . |33D2 xor edx,edx
0053DCF8 . |8A1401 mov dl,byte ptr ds:[ecx+eax]
0053DCFB . |8BC6 mov eax,esi
0053DCFD . |8BCA mov ecx,edx
0053DCFF . |25 FF000000 and eax,0FF
0053DD04 . |33C8 xor ecx,eax
0053DD06 . |8BC6 mov eax,esi
0053DD08 . |24 00 and al,0
0053DD0A . |99 cdq
0053DD0B . |81E2 FF000000 and edx,0FF
0053DD11 . |03C2 add eax,edx
0053DD13 . |C1F8 08 sar eax,8
0053DD16 . |25 FFFFFF00 and eax,0FFFFFF
0053DD1B . |8BF0 mov esi,eax
0053DD1D . |8B43 34 mov eax,dword ptr ds:[ebx+34]
0053DD20 . |3BC7 cmp eax,edi
0053DD22 . |74 23 je short wincnt.0053DD47
0053DD24 . |66:8338 01 cmp word ptr ds:[eax],1
0053DD28 . |75 1D jnz short wincnt.0053DD47
0053DD2A . |2B48 14 sub ecx,dword ptr ds:[eax+14]
0053DD2D . |8BF9 mov edi,ecx
0053DD2F . |8B48 10 mov ecx,dword ptr ds:[eax+10]
0053DD32 . |3BF9 cmp edi,ecx
0053DD34 . |72 06 jb short wincnt.0053DD3C
0053DD36 . |FF15 38124000 call dword ptr ds:[<&MSVBVM60.__vbaGenerateBou>; MSVBVM60.__vbaGenerateBoundsError
0053DD3C > |8D04BD 00000000 lea eax,dword ptr ds:[edi*4]
0053DD43 . |33FF xor edi,edi
0053DD45 . |EB 06 jmp short wincnt.0053DD4D
0053DD47 > |FF15 38124000 call dword ptr ds:[<&MSVBVM60.__vbaGenerateBou>; MSVBVM60.__vbaGenerateBoundsError
0053DD4D > |8B4B 34 mov ecx,dword ptr ds:[ebx+34]
0053DD50 . |8B51 0C mov edx,dword ptr ds:[ecx+C]
0053DD53 . |8B0C02 mov ecx,dword ptr ds:[edx+eax]
0053DD56 . |B8 01000000 mov eax,1
0053DD5B . |33F1 xor esi,ecx
0053DD5D . |8B4D E8 mov ecx,dword ptr ss:[ebp-18]
0053DD60 . |03C1 add eax,ecx
0053DD62 . |0F80 CC000000 jo wincnt.0053DE34
0053DD68 . |8945 E8 mov dword ptr ss:[ebp-18],eax
0053DD6B .^\E9 41FFFFFF jmp wincnt.0053DCB1
//上面的一个大循环就是CRC32计算了
对UNICODE格式的字符串"5896549AAA-wincnt^LTB19879"进行CRC32计算:
0053DD70 > \F7D6 not esi ; 对取得CRC32值取反得10进制数:"795102726"
0053DD72 . 68 B4434200 push wincnt.004243B4 ; UNICODE "00000000"
0053DD77 . 56 push esi
0053DD78 . FF15 EC104000 call dword ptr ds:[<&MSVBVM60.__vbaStrI4>] ; MSVBVM60.__vbaStrI4
0053DD7E . 8B35 08144000 mov esi,dword ptr ds:[<&MSVBVM60.__vbaStrMove>>; MSVBVM60.__vbaStrMove
0053DD84 . 8BD0 mov edx,eax
0053DD86 . 8D4D D0 lea ecx,dword ptr ss:[ebp-30]
0053DD89 . FFD6 call esi ; <&MSVBVM60.__vbaStrMove>
0053DD8B . 50 push eax
0053DD8C . FF15 58114000 call dword ptr ds:[<&MSVBVM60.__vbaStrCat>] ; 将结果与00000000相连
0053DD92 . 8945 C8 mov dword ptr ss:[ebp-38],eax ; 得:"00000000795102726"
0053DD95 . 8D45 C0 lea eax,dword ptr ss:[ebp-40]
0053DD98 . 6A 08 push 8
0053DD9A . 8D4D B0 lea ecx,dword ptr ss:[ebp-50]
0053DD9D . 50 push eax
0053DD9E . 51 push ecx
0053DD9F . C745 C0 08000000 mov dword ptr ss:[ebp-40],8
0053DDA6 . FF15 18144000 call dword ptr ds:[<&MSVBVM60.#619>] ; 取得到的字符串右8位:"95102726"
从这个CALL返回后,我就没做记录了,后面只是简单的将我们输入的假码前4位当做用户名,与我们上面一路过来所得到的值,用“_”相连!
这里的结果是“AAA-_95102726”
下面是我用C++写的KeyGen:
#include
using namespace std;
unsigned long Crc32Table[256];
void GetCRC32Table(){
int i,j;
unsigned long Crc;
for (i = 0; i < 256; i++){
Crc = i;
for (j = 0; j < 8; j++){
if (Crc & 1)
Crc = (Crc >> 1) ^ 0xEDB88320;
else
Crc >>= 1;
}
Crc32Table[i] = Crc;
}
}
//获取字符串CRC32校验值
unsigned int GetCrc32(char* InStr,int len){
GetCRC32Table();
unsigned int crc=0xffffffff;
for(int i=0; iunsigned int tmp=InStr[i];
crc = (crc >> 8) ^ Crc32Table[(crc & 0xFF) ^ tmp];
}
return crc;
}
int main(){
cout<<"请输入你的用户名(4位长字符):\t";
char name[5];
cin>>name;
char str[64]={0};
sprintf(str,"5896549%swincnt^LTB19879",name);
//下面是手工将ASCII转成UNICODE的,呵呵
char ch[128]={0};
int len=strlen(str);
int j=0;
for(int i=0;ich[j]=str[i];
j++;
ch[j]=0;
j++;
}
unsigned int crc32=GetCrc32(ch,j);//得到上面字符串的CRC32值
crc32 = crc32 ^ 0xFFFFFFFF; //对取得的CRC32值取反
char tmp[10]={0};
sprintf(tmp,"%d",crc32);//格式化成字符串
char regCode[32]={0};
sprintf(regCode,"%s_%s",name,&tmp[1]); //生成并打印出来
cout<<"Your RegCode Is: "<return 0;
}
编译并运行: