OJOsoft系列软件的注册算法分析
目标软件:OJOsoft系列语言:VC
工具:OD
软件是VC写的,用PEID显示为:Microsoft Visual C++ 7.0 Method2 [调试]
二话不说,直接到OD载入,然后输入假的激活码,很快就能找到关键点:
00401D6D .C74424 1C 00000>mov dword ptr ss:,0
00401D75 .E8 96E80100 call <jmp.&MFC71.#3761>
00401D7A .51 push ecx
00401D7B .8D5424 08 lea edx,dword ptr ss:
00401D7F .8BCC mov ecx,esp
00401D81 .896424 10 mov dword ptr ss:,esp
00401D85 .52 push edx
00401D86 .FF15 E4514200 call dword ptr ds:[<&MFC71.#297>] ;MFC71.7C14E575
00401D8C .8B8E C8000000 mov ecx,dword ptr ds:
00401D92 .FF15 30504200 call dword ptr ds:[<&Control.AVProxy::Reg>;Control.AVProxy::RegisteProduct
显然是通过专用的DLL来验证注册的。
跟进后,来到这里:
003A6C49 C64424 4C 01 mov byte ptr ss:,1
003A6C4E FF15 94803B00 call dword ptr ds:[<&MFC71.#297>] ; MFC71.7C14E575
003A6C54 8D4C24 0C lea ecx,dword ptr ss:
003A6C58 E8 03DB0000 call Control.003B4760 //这里同样为关键CALL,跟进继续分析
003A6C5D 8BF0 mov esi,eax
003A6C5F 85F6 test esi,esi
003A6C61 75 76 jnz short Control.003A6CD9
003A6C63 8D4C24 10 lea ecx,dword ptr ss:
继续跟进
003B485D 8BCE mov ecx,esi
003B485F 885C24 3C mov byte ptr ss:,bl
003B4863 E8 38F5FFFF call Control.003B3DA0
003B4868 0FB6C0 movzx eax,al
003B486B 85C0 test eax,eax
003B486D 74 69 je short Control.003B48D8
继续跟进
003B3DE7 8BCE mov ecx,esi
003B3DE9 E8 12FAFFFF call Control.003B3800
003B3DEE 84C0 test al,al
003B3DF0 0F84 49010000 je Control.003B3F3F
跟进CALL后,发现这里是对激活码的格式的一段验证:
003B3837 2BC2 sub eax,edx
003B3839 83F8 18 cmp eax,18 //比较激活码的长度是否为0x18,不是则失败
…………………………
003B3850 >56 push esi
003B3851 . |8D4C24 20 lea ecx,dword ptr ss:
003B3855 . |FF15 20813B00 call dword ptr ds:[<&MFC71.#865>] ;MFC71.7C1894E7
003B385B . |0FBEC0 movsx eax,al
003B385E . |50 push eax
003B385F . |FFD3 call ebx
003B3861 . |83C4 04 add esp,4
003B3864 . |83FF 04 cmp edi,4
003B3867 . |75 08 jnz short Control.003B3871
003B3869 . |3C 2D cmp al,2D
003B386B . |75 33 jnz short Control.003B38A0
003B386D . |33FF xor edi,edi
003B386F . |EB 09 jmp short Control.003B387A
003B3871 > |3C 41 cmp al,41
003B3873 . |7C 2B jl short Control.003B38A0
003B3875 . |3C 5A cmp al,5A
003B3877 . |7F 27 jg short Control.003B38A0
003B3879 . |47 inc edi
003B387A > |46 inc esi
003B387B . |83FE 18 cmp esi,18
003B387E .^\7C D0 jl short Control.003B3850
难过上面一段,我们知道了激活的格式应该为:XXXX-XXXX-XXXX-XXXX-XXXX
而且应该是全为字母,不能为数字!
好了,我们重新输入来过,路跳过上面的分析,来到:
003B3960 |> /8D4424 14 /lea eax,dword ptr ss:
003B3964 |. |33ED |xor ebp,ebp
003B3966 |. |8D50 01 |lea edx,dword ptr ds:
003B3969 |. |8DA424 00000000 |lea esp,dword ptr ss:
003B3970 |> |8A08 |/mov cl,byte ptr ds:
003B3972 |. |40 ||inc eax
003B3973 |. |84C9 ||test cl,cl
003B3975 |.^|75 F9 |\jnz short Control.003B3970
003B3977 |. |2BC2 |sub eax,edx ;取软件名长度-EBX
003B3979 |. |8BF8 |mov edi,eax
003B397B |. |33C9 |xor ecx,ecx
003B397D |. |85FF |test edi,edi
003B397F |. |7E 18 |jle short Control.003B3999
003B3981 |> |0FBE740C 14 |/movsx esi,byte ptr ss:[esp+ecx+1>
003B3986 |. |8BC3 ||mov eax,ebx
003B3988 |. |0FAFC6 ||imul eax,esi
003B398B |. |99 ||cdq
003B398C |. |2BC2 ||sub eax,edx
003B398E |. |D1F8 ||sar eax,1
003B3990 |. |03C6 ||add eax,esi
003B3992 |. |03E8 ||add ebp,eax
003B3994 |. |41 ||inc ecx
003B3995 |. |3BCF ||cmp ecx,edi
003B3997 |.^|7C E8 |\jl short Control.003B3981
003B3999 |> |8BC5 |mov eax,ebp
003B399B |. |99 |cdq
003B399C |. |B9 1A000000 |mov ecx,1A
003B39A1 |. |F7F9 |idiv ecx
003B39A3 |. |8B4424 10 |mov eax,dword ptr ss: ;除以常量0x1A
003B39A7 |. |83C3 06 |add ebx,6 ;EB+=6
003B39AA |. |83C0 04 |add eax,4
003B39AD |. |83FB 19 |cmp ebx,19 ;与0x19比较,大于则结束循环
003B39B0 |. |894424 10 |mov dword ptr ss:,eax
003B39B4 |. |8950 FC |mov dword ptr ds:,edx ;将上面的相除所得余数保存到下来
003B39B7 |.^\7C A7 \jl short Control.003B3960
这段代码很重要,主要是针对程序名进行处理,得到4个整数,保存下来后,将参与注册验证!
这里将之记为modNum,代码的流程用C++转述如下(注:name记为软件名):
int modNum={0};
int k=0;
for(int i=1;i<0x19;i+=6){
int len=strlen(name);
int sum=0;
for(int j=0;j<len;j++){
int tmpSum=name*i;
tmpSum=(tmpSum>>1);
sum=sum+tmpSum+name;
}
modNum=sum % 0x1A;
k++;
}
好了,我们继续单步,来到这里:
003B3E02 |> /83FF 04 /cmp edi,4
003B3E05 |. |75 04 |jnz short Control.003B3E0B
003B3E07 |. |33FF |xor edi,edi
003B3E09 |. |EB 23 |jmp short Control.003B3E2E
003B3E0B |> |53 |push ebx
003B3E0C |. |8D8C24 E0000000 |lea ecx,dword ptr ss:
003B3E13 |. |FF15 20813B00 |call dword ptr ds:[<&MFC71.#865>] ;MFC71.7C1894E7
003B3E19 |. |0FBEC8 |movsx ecx,al
003B3E1C |. |51 |push ecx
003B3E1D |. |FFD5 |call ebp
003B3E1F |. |0FBED0 |movsx edx,al
003B3E22 |. |83EA 41 |sub edx,41
003B3E25 |. |83C4 04 |add esp,4
003B3E28 |. |8916 |mov dword ptr ds:,edx
003B3E2A |. |47 |inc edi
003B3E2B |. |83C6 04 |add esi,4
003B3E2E |> |43 |inc ebx
003B3E2F |. |83FB 18 |cmp ebx,18
003B3E32 |.^\7C CE \jl short Control.003B3E02
上面是对用户输入的假码进行处理,处理的方式是对激活码按位送去0x41(跳过"-")!
然后我们就来到了关键的比较点了:
003B3F01 |> /8B6C0C 18 /mov ebp,dword ptr ss: ;按位取第1组
003B3F05 |. |8B840C B8000000 |mov eax,dword ptr ss: ;按位取上面所得余数
003B3F0C |. |8B7C0C 28 |mov edi,dword ptr ss: ;按位取第2组
003B3F10 |. |8B740C 48 |mov esi,dword ptr ss: ;按位取第4组
003B3F14 |. |8B540C 38 |mov edx,dword ptr ss: ;按位取第3组
003B3F18 |. |03C5 |add eax,ebp
003B3F1A |. |03C7 |add eax,edi
003B3F1C |. |03C6 |add eax,esi
003B3F1E |. |03C2 |add eax,edx
003B3F20 |. |99 |cdq
003B3F21 |. |BE 1A000000 |mov esi,1A
003B3F26 |. |F7FE |idiv esi
003B3F28 |. |3B940C A8000000 |cmp edx,dword ptr ss: ;按位与第5组相比
003B3F2F |. |89540C 58 |mov dword ptr ss:,edx
003B3F33 |. |75 0A |jnz short Control.003B3F3F
003B3F35 |. |83C1 04 |add ecx,4
003B3F38 |. |83F9 10 |cmp ecx,10
003B3F3B |.^\7C C4 \jl short Control.003B3F01
003B3F3D |.EB 02 jmp short Control.003B3F41
003B3F3F |>32DB xor bl,bl
003B3F41 |>8D8C24 D8000000 lea ecx,dword ptr ss:
分析好了,我们开始写KeyGen了,完整的代码如下:
#include<stdio.h>
#include<time.h>
#include<iostream>
using namespace std;
int main()
{
char name={0};
cout<<"Please Enter SoftName:()\n";
cin.getline(name,31);
//cout<<name<<endl;
int modNum={0};
int k=0;
for(int i=1;i<0x19;i+=6){
int len=strlen(name);
int sum=0;
for(int j=0;j<len;j++){
int tmpSum=name*i;
tmpSum=(tmpSum>>1);
sum=sum+tmpSum+name;
}
modNum=sum % 0x1A;
k++;
}
srand(time(NULL));
char code={0};
for(int i=0;i<4;i++){
int n1,n2,n3,n4,n5;
while(1){
n1=((double)rand()/(double)RAND_MAX)*0x19+0;
n2=((double)rand()/(double)RAND_MAX)*0x19+0;
n3=((double)rand()/(double)RAND_MAX)*0x19+0;
n4=((double)rand()/(double)RAND_MAX)*0x19+0;
n5=((double)rand()/(double)RAND_MAX)*0x19+0;
int tmp=n1+n2+n3+n4+modNum;
if((tmp %0x1A)==n5)
break;
}
code=0x41+n1;
code=0x41+n2;
code=0x41+n3;
code=0x41+n4;
code=0x41+n5;
}
code='-';
code='-';
code='-';
code='-';
cout<<"Your RegCode is: ";
cout<<code<<endl;;
cout<<"Please Enter a Key to Exit…………\n";
getchar();
getchar();
return 0;
}
运行如下:
学习算法教程~ 除了膜拜老鸭外还是膜拜,我的学习目标:loveliness: 感謝分享系列軟體的破解方法
页:
[1]