【文章标题】: 闲暇时对COM Explorer 2.0进行算法分析
【文章作者】: 星晨缘
【使用工具】: OD
【写作时间】: 2013-05-31
【分析难度】: 定位于跟我一样的入门朋友们,高手.前辈们就跳过吧
【文章说明】: 如转载,请保持原文,谢谢!
【作者声明】: 今天闲暇时在看雪里逛了下,看到一位朋友发了个爆破的文章,我就去下载过来看了下,发现安装后里边是有个Key的,但是并不完美,没有对字母大小写进行处理,用大写的话就算不出注册码来,对于好奇,就拿了OD分析了下...不周到或者那里写错之类还请指正,谢谢!本人只是个菜鸟,希望能得到大侠们的指点,谢过!
发了贴子之后才知道这个软件原先已经有人发过了(论坛帖子下方所提示的相似帖子看到的),
地址:http://bbs.pediy.com/showthread.php?t=72984
但我之前并没看过原先的那位大侠的作品,这也太巧了点了吧,人家的还是(时 间: 2008-09-17,21:52:33)的呢!
1.查壳,PEiD查到的是>>Microsoft Visual C++ 6.0 [Overlay],既然没壳就好办多了
2.打开软件,跳出注册窗体,试着注册个试试,
输入用户名:星晨缘,注册码:123456,弹出个MessageBox对话框,这样可以用bp MessageBoxA来下断
3.OD载入,F9运行,下MessageBox断点会断在注册码生成(或说比较)的之后,往回找注册码的算法可能会比较远,所以我在这是下:bp GetWindowTextA断点(比较好找注册码算法),
再次输入注册信息,点一下解锁,让OD给断下来了
然后按Alt+F9,执行到程序领空:
而004328D3的JMP就是跳到返回,F8执行到返回,返回代码如下:
接着来看看跳转过来的代码吧,00408BE5的注释有点像注册码的格式,分析一下下边的代码吧,果真让找到注册码算法了,试着执行到下边代码
接下来当然是分析注册算法了00408BE5下个F2断点重新来过,...Go...
算法分析已经在上边代码里注明了,这里就不再重复同样的工作了!
算法注册机:
后语:;):
由于头段注册码一跟到算法处就已经存在的了,而且试了台其它机子还是同样的"6769-",由于所保存的注册位置是随机产生的,并不是每次都是在该地址的,跟了很久没跟到算这段代码的位置(可能是我个人的能力有限吧!),因把头段的注册码用作固定的字符串!
哎,这次分析还总算是相对轻松点,不像上次分析一个CrackMe那样费时费力!!!这可能就是经验吧,呵呵.
此文希望能对和我差不多的朋友们有点借用作用
注册过的朋友想重新再玩的话,可到注册表里把HKEY_LOCAL_MACHINE\SOFTWARE\4Developers下的项给删了就可以了
还希望高手,前辈们能指引指引,还有欢迎各位朋友们来拍砖,贴子肯定会有不周到之处,有不周到之处请见谅和建议下,谢谢!
为了方便,我会把软件的等打包一下上传的!
【文章作者】: 星晨缘
【使用工具】: OD
【写作时间】: 2013-05-31
【分析难度】: 定位于跟我一样的入门朋友们,高手.前辈们就跳过吧
【文章说明】: 如转载,请保持原文,谢谢!
【作者声明】: 今天闲暇时在看雪里逛了下,看到一位朋友发了个爆破的文章,我就去下载过来看了下,发现安装后里边是有个Key的,但是并不完美,没有对字母大小写进行处理,用大写的话就算不出注册码来,对于好奇,就拿了OD分析了下...不周到或者那里写错之类还请指正,谢谢!本人只是个菜鸟,希望能得到大侠们的指点,谢过!
发了贴子之后才知道这个软件原先已经有人发过了(论坛帖子下方所提示的相似帖子看到的),
地址:http://bbs.pediy.com/showthread.php?t=72984
但我之前并没看过原先的那位大侠的作品,这也太巧了点了吧,人家的还是(时 间: 2008-09-17,21:52:33)的呢!
1.查壳,PEiD查到的是>>Microsoft Visual C++ 6.0 [Overlay],既然没壳就好办多了
2.打开软件,跳出注册窗体,试着注册个试试,
输入用户名:星晨缘,注册码:123456,弹出个MessageBox对话框,这样可以用bp MessageBoxA来下断
3.OD载入,F9运行,下MessageBox断点会断在注册码生成(或说比较)的之后,往回找注册码的算法可能会比较远,所以我在这是下:bp GetWindowTextA断点(比较好找注册码算法),
再次输入注册信息,点一下解锁,让OD给断下来了
代码:
760670ED > 6A 08 push 8 //断在这里,注意取消一下断点哦
760670EF 68 58710676 push 76067158
760670F4 E8 07150100 call 76078600
760670F9 8B7D 0C mov edi, dword ptr [ebp+C]
760670FC 33DB xor ebx, ebx
760670FE 3BFB cmp edi, ebx
代码:
004328C2 |. FF7424 08 push dword ptr [esp+8] ; /Count
004328C6 |. FF7424 08 push dword ptr [esp+8] ; |Buffer
004328CA |. FF71 1C push dword ptr [ecx+1C] ; |hWnd
004328CD |. FF15 D0044500 call dword ptr [<&USER32.GetWindowTex>; \GetWindowTextA
004328D3 |. EB 12 jmp short 004328E7 ; //执行后返回到这里,这里可以看到堆栈里有注册用户的信息
004328D5 |> FF7424 08 push dword ptr [esp+8]
004328D9 |. 8B10 mov edx, dword ptr [eax]
004328DB |. 8BC8 mov ecx, eax
004328DD |. FF7424 08 push dword ptr [esp+8]
004328E1 |. FF92 84000000 call dword ptr [edx+84]
004328E7 \> C2 0800 retn 8
代码:
00408F07 . 68 FF000000 push 0FF
00408F0C . 68 68994600 push 00469968 ; ASCII "星晨缘"
00408F11 . 8D8E A8040000 lea ecx, dword ptr [esi+4A8]
00408F17 . E8 9F990200 call 004328BB ; 获取用户名
00408F1C . 68 FF000000 push 0FF ; //执行单步返回到这里
00408F21 . 68 689A4600 push 00469A68 ; ASCII "123456"
00408F26 . 8D8E 6C040000 lea ecx, dword ptr [esi+46C]
00408F2C . E8 8A990200 call 004328BB ; 获取注册码
00408F31 . 68 68994600 push 00469968 ; ASCII "星晨缘"
00408F36 . 8D4C24 0C lea ecx, dword ptr [esp+C]
00408F3A . E8 12600200 call 0042EF51 ; //有点可疑,F7跟进去看看,结果一场空
00408F3F . 8B00 mov eax, dword ptr [eax]
00408F41 . 68 98414600 push 00464198
00408F46 . 50 push eax
00408F47 . E8 33330100 call 0041C27F
00408F4C . 83C4 08 add esp, 8
00408F4F . 8D4C24 08 lea ecx, dword ptr [esp+8]
00408F53 . 85C0 test eax, eax
00408F55 . 0F94C3 sete bl
00408F58 . E8 865F0200 call 0042EEE3
00408F5D . 84DB test bl, bl
00408F5F . 74 0F je short 00408F70 ; //这里跳了,既然跳了就让它跳吧,前边几个CALL都没什么收获
00408F61 . 6A 01 push 1
00408F63 . 8BCE mov ecx, esi
00408F65 . E8 93A70200 call 004336FD
00408F6A . 5E pop esi
00408F6B . 5B pop ebx
00408F6C . 83C4 08 add esp, 8
00408F6F . C3 retn
00408F70 > E8 1BFCFFFF call 00408B90 ; //也跟进去看看,即上边的JE跳到这个CALL的
00408F75 . 85C0 test eax, eax
代码:
00408B90 /$ 6A FF push -1 ; //CALL所跳到的地方
00408B92 |. 68 98B64400 push 0044B698 ; SE 处理程序安装
00408B97 |. 64:A1 0000000>mov eax, dword ptr fs:[0]
00408B9D |. 50 push eax
00408B9E |. 64:8925 00000>mov dword ptr fs:[0], esp
00408BA5 |. 83EC 08 sub esp, 8
00408BA8 |. 57 push edi
00408BA9 |. BF 68994600 mov edi, 00469968 ; ASCII "星晨缘"
00408BAE |. 83C9 FF or ecx, FFFFFFFF
00408BB1 |. 33C0 xor eax, eax
00408BB3 |. F2:AE repne scas byte ptr es:[edi]
00408BB5 |. F7D1 not ecx
00408BB7 |. 49 dec ecx ; 和前两行加起来是为了取得用户名长度
00408BB8 |. 83F9 08 cmp ecx, 8 ; 比较用户名是否大于8位,我们输入的只有6位
00408BBB |. 894C24 08 mov dword ptr [esp+8], ecx
00408BBF |. 7D 10 jge short 00408BD1 ; 跳不了,重新来过,输入个用户名大于8位的,F2下断
00408BC1 |. 5F pop edi
00408BC2 |. 8B4C24 08 mov ecx, dword ptr [esp+8]
00408BC6 |. 64:890D 00000>mov dword ptr fs:[0], ecx
00408BCD |. 83C4 14 add esp, 14
00408BD0 |. C3 retn ; //让它返回就游了
00408BD1 |> 53 push ebx ; //上边的JGE跳到这里来的
00408BD2 |. 55 push ebp
00408BD3 |. 56 push esi
00408BD4 |. 68 68994600 push 00469968 ; ASCII "星晨缘"
00408BD9 |. E8 34300200 call 0042BC12
代码:
00408C85 |. 68 689A4600 push 00469A68 ; ASCII "123456"
00408C8A |. 52 push edx ; //在这里可在寄存器里看到注册码
00408C8B |. E8 EF350100 call 0041C27F ; 应该就是比较真假码的地方
代码:
00408BE5 |. 68 FC404600 push 004640FC ; ASCII "6769-"
00408BEA |. E8 62630200 call 0042EF51
00408BEF |. 33F6 xor esi, esi ; ESI清零,后边用作计数器
00408BF1 |. 897424 20 mov dword ptr [esp+20], esi ; 从下边开始就是第二,三段,四段注册码计算代码开始处,与0~9数字进行计算
00408BF5 |> 8B2D 483E4600 /mov ebp, dword ptr [463E48] ; Table码表
00408BFB |. 83C9 FF |or ecx, FFFFFFFF
00408BFE |. 8BFD |mov edi, ebp
00408C00 |. 33C0 |xor eax, eax
00408C02 |. F2:AE |repne scas byte ptr es:[edi]
00408C04 |. F7D1 |not ecx
00408C06 |. 49 |dec ecx ; 取得Table表位数,0xA,后边就用0xA代表Table位数
00408C07 |. 8BC6 |mov eax, esi ; ESI为计数器
00408C09 |. 33D2 |xor edx, edx
00408C0B |. 8BFD |mov edi, ebp
00408C0D |. F7F1 |div ecx ; EAX=EAX/0xA,EDX=EAX%0xA,余数用于后边取Table的位数
00408C0F |. 8B4C24 14 |mov ecx, dword ptr [esp+14] ; ECX=用户位数//n设为用户位数
00408C13 |. 8BC6 |mov eax, esi
00408C15 |. 0FBE1C2A |movsx ebx, byte ptr [edx+ebp] ; 从Table表取数,Table[EAX%10](是上面第三行所得的余数哦),EDX
00408C19 |. 33D2 |xor edx, edx
00408C1B |. F7F1 |div ecx ; 主要取EAX%n的余数
00408C1D |. 0FBE82 689946>|movsx eax, byte ptr [edx+469968] ; EAX=Name[EAX%n] >> 上边的余数作为取用户名位数
00408C24 |. 8D1440 |lea edx, dword ptr [eax+eax*2] ; EDX=用户名+用户名*2
00408C27 |. 8D0490 |lea eax, dword ptr [eax+edx*4] ; EAX=用户名+(用户名+用户名*2)*4
00408C2A |. 8BD6 |mov edx, esi
00408C2C |. 0FAFD6 |imul edx, esi ; EDX=EDX*ESI
00408C2F |. 0FAFD6 |imul edx, esi ; EDX=EDX*ESI
00408C32 |. 0FAFD1 |imul edx, ecx ; EDX=EDX*n
00408C35 |. 03D8 |add ebx, eax ; EBX=Table[EAX%10]+用户名+(用户名+用户名*2)*4
00408C37 |. 83C9 FF |or ecx, FFFFFFFF
00408C3A |. 33C0 |xor eax, eax
00408C3C |. 03DA |add ebx, edx ; EBX=EBX+((EDX*ESI)*(EDX*ESI))*n
00408C3E |. F2:AE |repne scas byte ptr es:[edi]
00408C40 |. F7D1 |not ecx
00408C42 |. 49 |dec ecx ; ECX=0xA
00408C43 |. 8BC3 |mov eax, ebx ; EAX=EBX
00408C45 |. 33D2 |xor edx, edx
00408C47 |. F7F1 |div ecx ; EAX=EAX/0xA,EDX=EAX%0xA
00408C49 |. 8D4C24 10 |lea ecx, dword ptr [esp+10] ; 取保存注册码位置
00408C4D |. 8A042A |mov al, byte ptr [edx+ebp] ; al=Table表[EAX/0xA],al即注册码
00408C50 |. 50 |push eax
00408C51 |. E8 44660200 |call 0042F29A ; 保存注册码
00408C56 |. 85F6 |test esi, esi
00408C58 |. 74 1D |je short 00408C77
00408C5A |. 8BC6 |mov eax, esi
00408C5C |. 33D2 |xor edx, edx
00408C5E |. B9 03000000 |mov ecx, 3
00408C63 |. F7F1 |div ecx
00408C65 |. 85D2 |test edx, edx
00408C67 |. 75 0E |jnz short 00408C77
00408C69 |. 68 F8404600 |push 004640F8
00408C6E |. 8D4C24 14 |lea ecx, dword ptr [esp+14]
00408C72 |. E8 FC650200 |call 0042F273 ; 添加'-'用的函数
00408C77 |> 46 |inc esi ; i++
00408C78 |. 83FE 09 |cmp esi, 9 ; 用于循环次数,总共循环9次
00408C7B |.^ 0F82 74FFFFFF \jb 00408BF5
00408C81 |. 8B5424 10 mov edx, dword ptr [esp+10]
00408C85 |. 68 689A4600 push 00469A68 ; ASCII "123456"
00408C8A |. 52 push edx
00408C8B |. E8 EF350100 call 0041C27F
算法注册机:
代码:
#include <stdio.h>
#include <conio.h>
#include <windows.h>
/*
COM Explorer 2.0算法注册机 v0.1
如有错误,请指正,谢谢!代码有点错乱,见笑了!
*/
int Key(unsigned char Name[],int Len,char Key[])//Key主要算法
{
char Table[] = "0123456789";
int m = 5;
for(int i=0;i<9;i++)
{
unsigned int k = 0;
unsigned int t = 0;
unsigned int n = 0;
if (Name[i%Len]>'z')
n = Name[i%Len] | 0xFFFFFF00;//为了支持中文
else
n = Name[i%Len];
k = n+(n+n*2)*4+Table[i%0xA];
t = i * i * i * Len;
k += t;
if(m == 9 || m == 13)
{
Key[m] = '-';
Key[m+1] = Table[k%0xA];
m += 2;
continue;
}
Key[m++] = Table[k%0xA];
}
return 0;
}
int main()
{
static char key[17] = "6769-";
unsigned char name[21] = {NULL};
int len = 0;
while(true)
{
printf("Name:");
scanf("%20s",name);
len = strlen((char*)name);
if(len<8)
{
printf("\n用户名不能小于8位,请重新输入!(请按任意键)");
getch();
system("cls");
}
else
break;
}
for (int n=0;name[n]!=0;n++)
{
if (name[n]>='A' && name[n]<='Z')
name[n] += 32;
}
Key(name,len,key);
printf("\nKey:%s\n",key);
getch();
return 0;
}
后语:;):
由于头段注册码一跟到算法处就已经存在的了,而且试了台其它机子还是同样的"6769-",由于所保存的注册位置是随机产生的,并不是每次都是在该地址的,跟了很久没跟到算这段代码的位置(可能是我个人的能力有限吧!),因把头段的注册码用作固定的字符串!
哎,这次分析还总算是相对轻松点,不像上次分析一个CrackMe那样费时费力!!!这可能就是经验吧,呵呵.
此文希望能对和我差不多的朋友们有点借用作用
注册过的朋友想重新再玩的话,可到注册表里把HKEY_LOCAL_MACHINE\SOFTWARE\4Developers下的项给删了就可以了
还希望高手,前辈们能指引指引,还有欢迎各位朋友们来拍砖,贴子肯定会有不周到之处,有不周到之处请见谅和建议下,谢谢!
为了方便,我会把软件的等打包一下上传的!