【吾爱2013CM大赛解答】--KeyGenMe-- a070458 -- 算法分析-注册机编写[〇〇木一]
本帖最后由 〇〇木一 于 2013-12-16 12:41 编辑【文章标题】: 【吾爱2013CM大赛解答】--KeyGenMe-- a070458 -- 算法分析[〇〇木一]
【文章作者】: 〇〇木一
【软件名称】: KeyGenMe-- a070458
【下载地址】: http://www.52pojie.cn/thread-228709-1-1.html
【操作平台】: win 7
第一次写的代码有点小错误现在已经改好了。
分析这个算法真是搞得我蛋蛋碎光了..
不用说,首先先找到他比较验证的的地方,这个很好找中断回溯,按钮事件,API断点随便可以找到。
00401DA0 .>push -0x1
00401DA2 .>push KeyGenMe.004025B0 ;SE 处理程序安装
00401DA7 .>mov eax,dword ptr fs:
00401DAD .>push eax
00401DAE .>mov dword ptr fs:,esp
00401DB5 .>sub esp,0x14
00401DB8 .>push ebx
00401DB9 .>push ebp
00401DBA .>mov ebp,ecx
00401DBC .>push esi
00401DBD .>push edi
00401DBE .>lea ecx,dword ptr ss:
00401DC2 .>call <jmp.&MFC42.#540>
00401DC7 .>lea ecx,dword ptr ss:
00401DCB .>mov dword ptr ss:,0x0
00401DD3 .>call <jmp.&MFC42.#540>
00401DD8 .>push KeyGenMe.0040403C ;UNICODE "5"
00401DDD .>lea ecx,dword ptr ss:
00401DE1 .>mov byte ptr ss:,0x1
00401DE6 .>call <jmp.&MFC42.#941>
00401DEB .>push KeyGenMe.00404038 ;UNICODE "2"
00401DF0 .>lea ecx,dword ptr ss:
00401DF4 .>call <jmp.&MFC42.#941>
00401DF9 .>push KeyGenMe.00404034 ;UNICODE "P"
00401DFE .>lea ecx,dword ptr ss:
00401E02 .>call <jmp.&MFC42.#941>
00401E07 .>push KeyGenMe.00404030 ;UNICODE "o"
00401E0C .>lea ecx,dword ptr ss:
00401E10 .>call <jmp.&MFC42.#941>
00401E15 .>push KeyGenMe.0040402C ;UNICODE "J"
00401E1A .>lea ecx,dword ptr ss:
00401E1E .>call <jmp.&MFC42.#941>
00401E23 .>push KeyGenMe.00404028 ;UNICODE "i"
00401E28 .>lea ecx,dword ptr ss:
00401E2C .>call <jmp.&MFC42.#941>
00401E31 .>push KeyGenMe.00404024 ;UNICODE "e"
00401E36 .>lea ecx,dword ptr ss:
00401E3A .>call <jmp.&MFC42.#941> ;组成"52PoJie"字串
00401E3F .>push 0x1
00401E41 .>mov ecx,ebp
00401E43 .>call <jmp.&MFC42.#6334> ;取文本框内容
00401E48 .>mov eax,dword ptr ss:
00401E4B .>lea esi,dword ptr ss:
00401E4E .>mov eax,dword ptr ds:
00401E51 .>cdq
00401E52 .>sub eax,edx
00401E54 .>sar eax,1
00401E56 .>push eax
00401E57 .>call <jmp.&MFC42.#823>
00401E5C .>mov ecx,dword ptr ss:
00401E5F .>add ebp,0x64
00401E62 .>mov edi,eax
00401E64 .>add esp,0x4
00401E67 .>mov eax,dword ptr ds:
00401E6A .>test eax,eax
00401E6C .>je short KeyGenMe.00401EB9 ;1 l
00401E6E .>mov edx,dword ptr ds:
00401E70 .>mov eax,dword ptr ds:
00401E73 .>test eax,eax
00401E75 .>je short KeyGenMe.00401EB9 ;2 l
00401E77 .>push ecx
00401E78 .>mov ecx,esp
00401E7A .>mov dword ptr ss:,esp
00401E7E .>push esi
00401E7F .>call <jmp.&MFC42.#535>
00401E84 .>call KeyGenMe.004012D0 ;判断注册码是否为16进制字串(要大写)
00401E89 .>add esp,0x4
00401E8C .>test al,al
00401E8E .>je short KeyGenMe.00401EB9
00401E90 .>mov eax,dword ptr ds:
00401E92 .>mov eax,dword ptr ds: ;取注册码长度
00401E95 .>mov ecx,eax
00401E97 .>and ecx,0x80000001
00401E9D .>jns short KeyGenMe.00401EA4
00401E9F .>dec ecx
00401EA0 .>or ecx,0xFFFFFFFE
00401EA3 .>inc ecx
00401EA4 >>jnz short KeyGenMe.00401EB9
00401EA6 .>mov edx,dword ptr ss:
00401EA9 .>mov ecx,dword ptr ds: ;取用户名长度
00401EAC .>cmp ecx,0x5
00401EAF .>jl short KeyGenMe.00401EB9 ;>=5
00401EB1 .>lea ecx,dword ptr ds:
00401EB5 .>cmp eax,ecx
00401EB7 .>je short KeyGenMe.00401EC4 ;注册码长度必须为[用户名长度]*2+2
00401EB9 >>call dword ptr ds: ;KeyGenMe.004019B0
00401EBF .>jmp KeyGenMe.00401FBA
00401EC4 >>push eax
00401EC5 .>push edi
00401EC6 .>push ecx
00401EC7 .>mov ecx,esp
00401EC9 .>mov dword ptr ss:,esp
00401ECD .>push esi
00401ECE .>call <jmp.&MFC42.#535>
00401ED3 .>call KeyGenMe.00401360 ;注册码转为16进制
00401ED8 .>mov edx,dword ptr ds:
00401EDA .>mov eax,dword ptr ds:
00401EDD .>cdq
00401EDE .>sub eax,edx
00401EE0 .>sar eax,1
00401EE2 .>push eax
00401EE3 .>push edi
00401EE4 .>call KeyGenMe.00401260 ;并转化为链表形式
00401EE9 .>mov bl,byte ptr ds: ;链表头(注册码前两位16进制值)
00401EEB .>mov esi,dword ptr ds: ;esi-next
00401EEE .>push eax
00401EEF .>mov byte ptr ss:,bl
00401EF3 .>call <jmp.&MFC42.#825>
00401EF8 .>mov edi,dword ptr ss:
00401EFC .>add esp,0x18
00401EFF .>lea eax,dword ptr ss:
00401F03 .>push edi
00401F04 .>push esi
00401F05 .>push ecx
00401F06 .>mov ecx,esp
00401F08 .>mov dword ptr ss:,esp
00401F0C .>push eax
00401F0D .>call <jmp.&MFC42.#535>
00401F12 .>call KeyGenMe.004013D0 ;对注册码的运算1
00401F17 .>add esp,0xC
00401F1A .>push edi
00401F1B .>push ecx
00401F1C .>mov ecx,esp
00401F1E .>mov dword ptr ss:,esp
00401F22 .>push ebp
00401F23 .>call <jmp.&MFC42.#535>
00401F28 .>push ecx
00401F29 .>lea edx,dword ptr ss:
00401F2D .>mov ecx,esp
00401F2F .>mov dword ptr ss:,esp
00401F33 .>push edx
00401F34 .>mov byte ptr ss:,0x2
00401F39 .>call <jmp.&MFC42.#535>
00401F3E .>lea eax,dword ptr ss:
00401F42 .>mov byte ptr ss:,0x1
00401F47 .>push eax
00401F48 .>call KeyGenMe.00401430 ;对用户名的运算1
00401F4D .>add esp,0x10
00401F50 .>push eax
00401F51 .>lea ecx,dword ptr ss:
00401F55 .>mov byte ptr ss:,0x3
00401F5A .>call <jmp.&MFC42.#858>
00401F5F .>lea ecx,dword ptr ss:
00401F63 .>mov byte ptr ss:,0x1
00401F68 .>call <jmp.&MFC42.#800>
00401F6D .>mov ecx,dword ptr ss:
00401F71 .>mov eax,dword ptr ds:
00401F74 .>lea ecx,dword ptr ss:
00401F78 .>push eax
00401F79 .>push 0x0
00401F7B .>call <jmp.&MFC42.#2915>
00401F80 .>push eax
00401F81 .>call KeyGenMe.00401260
00401F86 .>push eax
00401F87 .>call KeyGenMe.004011D0 ;对用户名的运算2
00401F8C .>push esi
00401F8D .>mov ebp,eax
00401F8F .>call KeyGenMe.004011D0 ;对注册码的运算2
00401F94 .>push edi
00401F95 .>push ebp
00401F96 .>mov esi,eax
00401F98 .>call KeyGenMe.004015D0 ;对用户名的运算3
00401F9D .>inc bl
00401F9F .>mov edi,eax
00401FA1 .>push ebx
00401FA2 .>push esi
00401FA3 .>call KeyGenMe.004015D0 ;对注册码的运算3
00401FA8 .>push eax
00401FA9 .>push edi
00401FAA .>call KeyGenMe.004017A0 ;判断最后操作后两字是否相等
00401FAF .>add esp,0x28 ;如果eax==1,则正确
00401FB2 .>inc eax
00401FB3 .>call dword ptr ds:
00401FBA >>lea ecx,dword ptr ss:
00401FBE .>mov byte ptr ss:,0x0
00401FC3 .>call <jmp.&MFC42.#800>
00401FC8 .>lea ecx,dword ptr ss:
00401FCC .>mov dword ptr ss:,-0x1
00401FD4 .>call <jmp.&MFC42.#800>
00401FD9 .>mov ecx,dword ptr ss:
00401FDD .>pop edi
00401FDE .>pop esi
00401FDF .>pop ebp
00401FE0 .>mov dword ptr fs:,ecx
00401FE7 .>pop ebx
00401FE8 .>add esp,0x20
00401FEB .>retn
分析可以得到,用户名和注册码都是经过3次运算得到值后比较是否相等
因为这里运算后不是以普通的每个元素相邻的字符串形式,而是链表模式
struct XXX
{
char value;
XXX *next;
}
这样就很难看到直观的数据,很难分析
但是可以发现因为next指针的地址都在value的地址+4,所以可以用个小脚本来获取直观的数据
mov mem,XXXXXXXX
mov long,0
mov tmp,eax
loop:
mov ,,1
inc long
mov tmp,
cmp tmp,0
jne loop
pause
pause
获取直观数据后就可以了解个大概
下面是测试的数据:
用户名:
11111
第一次运算后:
E1 D1 30 2D 4A
第二次运算后:
0E 01 0D 01 03 00 02 0D 04 0A
第三次运算后:
0E 0D 01 03 01 02 00 04 0D 0A
注册码:
222222222222
转化为16进制后:
22 22 22 22 22 22
第一次运算后:
F4 ED 50 2B 46
第二次运算后:
0F 04 0E 0D 05 00 02 0B 04 06
第三次运算后:
0F 0E 05 04 02 0D 04 00 06 0B
最后只要它们第3次运算后的值相等就成功了
然后可以一步步的解决:
对用户名的运算1:
00401F48 .>call KeyGenMe.00401430 ;对用户名的运算1
00401430/$ >push -0x1
00401432|. >push KeyGenMe.0040250F ;SE 处理程序安装
00401437|. >mov eax,dword ptr fs:
0040143D|. >push eax
0040143E|. >mov dword ptr fs:,esp
00401445|. >sub esp,0xC
00401448|. >push ebx
00401449|. >push esi
0040144A|. >push edi
0040144B|. >mov dword ptr ss:,0x0
00401453|. >lea ecx,dword ptr ss:
00401457|. >mov dword ptr ss:,0x2
0040145F|. >call <jmp.&MFC42.#540>
00401464|. >mov eax,dword ptr ss:
00401468|. >xor esi,esi
0040146A|. >xor edi,edi
0040146C|. >mov byte ptr ss:,0x3
00401471|. >mov ecx,dword ptr ds:
00401474|. >test ecx,ecx
00401476|. >jle short KeyGenMe.004014DC
00401478|. >mov edx,dword ptr ss:
0040147C|. >mov bl,byte ptr ss: ;传进的参数[注册码的第一个值]
00401480|> >/mov cl,byte ptr ds: ;逐个取用户名字符值
00401483|. >|mov al,byte ptr ds: ;逐个取"52PoJie"字符串
00401486|. >|xor al,cl ;异或
00401488|. >|cmp al,bl
0040148A|. >|mov byte ptr ss:,al
0040148E|. >|jb short KeyGenMe.00401494
00401490|. >|sub al,bl ;减
00401492|. >|jmp short KeyGenMe.004014AE
00401494|> >|mov eax,dword ptr ss:
00401498|. >|mov edx,dword ptr ss:
0040149C|. >|and eax,0xFF
004014A1|. >|and edx,0xFF
004014A7|. >|sub eax,edx ;减
004014A9|. >|add eax,0xFF
004014AE|> >|mov byte ptr ss:,al
004014B2|. >|mov bl,cl
004014B4|. >|mov eax,dword ptr ss:
004014B8|. >|lea ecx,dword ptr ss:
004014BC|. >|push eax
004014BD|. >|mov byte ptr ss:,bl
004014C1|. >|call <jmp.&MFC42.#940>
004014C6|. >|mov edx,dword ptr ss:
004014CA|. >|inc esi
004014CB|. >|cmp esi,dword ptr ds:
004014CE|. >|jl short KeyGenMe.004014D2 ;超过从头开始
004014D0|. >|xor esi,esi
004014D2|> >|mov eax,dword ptr ss:
004014D6|. >|inc edi
004014D7|. >|cmp edi,dword ptr ds:
004014DA|.^>\jl short KeyGenMe.00401480
004014DC|> >mov esi,dword ptr ss:
004014E0|. >lea ecx,dword ptr ss:
004014E4|. >push ecx
004014E5|. >mov ecx,esi
004014E7|. >call <jmp.&MFC42.#535>
004014EC|. >mov ebx,0x1
004014F1|. >mov dword ptr ss:,ebx
004014F5|. >lea ecx,dword ptr ss:
004014F9|. >mov byte ptr ss:,0x2
004014FE|. >call <jmp.&MFC42.#800>
00401503|. >lea ecx,dword ptr ss:
00401507|. >mov byte ptr ss:,bl
0040150B|. >call <jmp.&MFC42.#800>
00401510|. >lea ecx,dword ptr ss:
00401514|. >mov byte ptr ss:,0x0
00401519|. >call <jmp.&MFC42.#800>
0040151E|. >mov ecx,dword ptr ss:
00401522|. >mov eax,esi
00401524|. >pop edi
00401525|. >pop esi
00401526|. >pop ebx
00401527|. >mov dword ptr fs:,ecx
0040152E|. >add esp,0x18
00401531\. >retn
其中有一个参数是注册码16进制的第一个值
这样就可以写代码了
string dealT1(string t0,string t1,char t2h)//用户名第1次运算,需要注册码16进制的前两位
{
int i=0;
int i0=0;
int th=t2h;
th&=0xFF;
string rs="";
while(t1)
{
int tmp=t1;
int tmp1=t0;
tmp&=0xFF;
tmp1&=0xFF;
tmp^=tmp1;
tmp-=th;
if(tmp<0)
{
tmp&=0xFF;
tmp--;
}
char tmp3=tmp;
rs+=tmp3;
th=t1;
i0++;
if(i0==7)
i0=0;
i++;
}
return rs;
}
第二次运算只是将第一次运算结果的高位低位分离
CALL在004011D0
转化为代码为
string deal2(string s)//运算的第2次,高位低位分开
{
string str="";
int i=0;
while(i<s.length())
{
int v=s;
v&=0xFF;
char c1=v/16;
char c2=v%16;
str+=c1;
str+=c2;
i++;
}
return str;
}
用户名的第3次运算为将第2次结果重新排序
004016FF|> \8B7C24 1C mov edi,dword ptr ss: ;案例 0 --> 分支 0040160C
00401703|.57 push edi
00401704|.E8 37FEFFFF call KeyGenMe.00401540
00401709|.99 cdq
0040170A|.2BC2 sub eax,edx
0040170C|.83C4 04 add esp,0x4
0040170F|.D1F8 sar eax,1
00401711|.83F8 01 cmp eax,0x1
00401714|.7E 4F jle short KeyGenMe.00401765
00401716|.8D68 FF lea ebp,dword ptr ds:
00401719|>6A 01 /push 0x1 ;取第一个元素
0040171B|.57 |push edi
0040171C|.E8 2FFEFFFF |call KeyGenMe.00401550
00401721|.6A 08 |push 0x8
00401723|.8BFA |mov edi,edx
00401725|.8806 |mov byte ptr ds:,al
00401727|.E8 EC090000 |call <jmp.&MFC42.#823> ;删除
0040172C|.33C9 |xor ecx,ecx
0040172E|.8946 04 |mov dword ptr ds:,eax
00401731|.8908 |mov dword ptr ds:,ecx
00401733|.6A 02 |push 0x2 ;取第二个元素
00401735|.8948 04 |mov dword ptr ds:,ecx
00401738|.8B76 04 |mov esi,dword ptr ds:
0040173B|.57 |push edi
0040173C|.E8 0FFEFFFF |call KeyGenMe.00401550
00401741|.6A 08 |push 0x8
00401743|.8BD8 |mov ebx,eax
00401745|.8BFA |mov edi,edx
00401747|.E8 CC090000 |call <jmp.&MFC42.#823> ;删除
0040174C|.33D2 |xor edx,edx
0040174E|.8946 04 |mov dword ptr ds:,eax
00401751|.8910 |mov dword ptr ds:,edx
00401753|.83C4 18 |add esp,0x18
00401756|.8950 04 |mov dword ptr ds:,edx
00401759|.881E |mov byte ptr ds:,bl
0040175B|.8B76 04 |mov esi,dword ptr ds:
0040175E|.4D |dec ebp
0040175F|.^ 75 B8 \jnz short KeyGenMe.00401719 ;循环直到都取完
00401761|.8B5C24 10 mov ebx,dword ptr ss:
00401765|>6A 01 push 0x1
00401767|.57 push edi
00401768|.E8 E3FDFFFF call KeyGenMe.00401550
0040176D|.6A 08 push 0x8
0040176F|.8BFA mov edi,edx
00401771|.8806 mov byte ptr ds:,al
00401773|.E8 A0090000 call <jmp.&MFC42.#823>
00401778|.33C9 xor ecx,ecx
0040177A|.8946 04 mov dword ptr ds:,eax
0040177D|.8908 mov dword ptr ds:,ecx
0040177F|.6A 01 push 0x1
00401781|.8948 04 mov dword ptr ds:,ecx
00401784|.8B76 04 mov esi,dword ptr ds:
00401787|.57 push edi
00401788|.E8 C3FDFFFF call KeyGenMe.00401550
0040178D|.83C4 14 add esp,0x14
00401790|.895424 14 mov dword ptr ss:,edx
00401794|.8806 mov byte ptr ds:,al
00401796|>5F pop edi ;分支 0040160C 默认案例
00401797|.5E pop esi
00401798|.8BC3 mov eax,ebx
0040179A|.5D pop ebp
0040179B|.5B pop ebx
0040179C|.83C4 08 add esp,0x8
0040179F\.C3 retn
写成代码很简单:
string dealT1_1(string s)//用户名第3次运算,
{
string s0=s;
string str="";
while(s0.length()!=0)
{
str+=s0;
s0.erase(0,1);
if(s0.length()==1)
{
str+=s0;
s0.erase(0,1);
}
else
{
str+=s0;
s0.erase(1,1);
}
}
return str;
}
然后就是注册码第3次运算的逆运算了
先看看正运算:
0040161C|.8B7424 1C mov esi,dword ptr ss: ;案例 1 --> 分支 0040160C
00401620|.56 push esi
00401621|.E8 1AFFFFFF call KeyGenMe.00401540
00401626|.99 cdq
00401627|.2BC2 sub eax,edx
00401629|.6A 01 push 0x1 ;先取第1个
0040162B|.8BE8 mov ebp,eax
0040162D|.56 push esi
0040162E|.D1FD sar ebp,1
00401630|.83ED 02 sub ebp,0x2
00401633|.E8 18FFFFFF call KeyGenMe.00401550
00401638|.6A 02 push 0x2 ;再取第3个
0040163A|.52 push edx
0040163B|.8803 mov byte ptr ds:,al
0040163D|.E8 0EFFFFFF call KeyGenMe.00401550
00401642|.6A 08 push 0x8
00401644|.894424 28 mov dword ptr ss:,eax
00401648|.8BFA mov edi,edx
0040164A|.E8 C90A0000 call <jmp.&MFC42.#823> ;删除
0040164F|.33D2 xor edx,edx
00401651|.8943 04 mov dword ptr ds:,eax
00401654|.8910 mov dword ptr ds:,edx
00401656|.83C4 18 add esp,0x18
00401659|.8950 04 mov dword ptr ds:,edx
0040165C|.8B73 04 mov esi,dword ptr ds:
0040165F|.8A4424 10 mov al,byte ptr ss:
00401663|.83FD 01 cmp ebp,0x1
00401666|.8806 mov byte ptr ds:,al
00401668|.7C 46 jl short KeyGenMe.004016B0
0040166A|>6A 08 /push 0x8
0040166C|.E8 A70A0000 |call <jmp.&MFC42.#823> ;删除
00401671|.33C9 |xor ecx,ecx
00401673|.8946 04 |mov dword ptr ds:,eax
00401676|.8908 |mov dword ptr ds:,ecx
00401678|.6A 03 |push 0x3 ;取第3个
0040167A|.8948 04 |mov dword ptr ds:,ecx
0040167D|.8B76 04 |mov esi,dword ptr ds:
00401680|.57 |push edi
00401681|.E8 CAFEFFFF |call KeyGenMe.00401550
00401686|.6A 08 |push 0x8
00401688|.8BFA |mov edi,edx
0040168A|.8806 |mov byte ptr ds:,al
0040168C|.E8 870A0000 |call <jmp.&MFC42.#823> ;删除
00401691|.33D2 |xor edx,edx
00401693|.8946 04 |mov dword ptr ds:,eax
00401696|.8910 |mov dword ptr ds:,edx
00401698|.6A 01 |push 0x1 ;取第一个
0040169A|.8950 04 |mov dword ptr ds:,edx
0040169D|.8B76 04 |mov esi,dword ptr ds:
004016A0|.57 |push edi
004016A1|.E8 AAFEFFFF |call KeyGenMe.00401550
004016A6|.83C4 18 |add esp,0x18
004016A9|.4D |dec ebp
004016AA|.8806 |mov byte ptr ds:,al
004016AC|.8BFA |mov edi,edx
004016AE|.^ 75 BA \jnz short KeyGenMe.0040166A ;循环直到取完
004016B0|>6A 08 push 0x8
004016B2|.E8 610A0000 call <jmp.&MFC42.#823>
004016B7|.33C9 xor ecx,ecx
004016B9|.8946 04 mov dword ptr ds:,eax
004016BC|.8908 mov dword ptr ds:,ecx
004016BE|.6A 02 push 0x2
004016C0|.8948 04 mov dword ptr ds:,ecx
004016C3|.8B76 04 mov esi,dword ptr ds:
004016C6|.57 push edi
004016C7|.E8 84FEFFFF call KeyGenMe.00401550
004016CC|.6A 08 push 0x8
004016CE|.8BFA mov edi,edx
004016D0|.8806 mov byte ptr ds:,al
004016D2|.E8 410A0000 call <jmp.&MFC42.#823>
004016D7|.33D2 xor edx,edx
004016D9|.8946 04 mov dword ptr ds:,eax
004016DC|.8910 mov dword ptr ds:,edx
004016DE|.6A 01 push 0x1
004016E0|.8950 04 mov dword ptr ds:,edx
004016E3|.8B76 04 mov esi,dword ptr ds:
004016E6|.57 push edi
004016E7|.E8 64FEFFFF call KeyGenMe.00401550
004016EC|.83C4 18 add esp,0x18
004016EF|.8806 mov byte ptr ds:,al
004016F1|.8BC3 mov eax,ebx
004016F3|.895424 14 mov dword ptr ss:,edx
004016F7|.5F pop edi
004016F8|.5E pop esi
004016F9|.5D pop ebp
004016FA|.5B pop ebx
004016FB|.83C4 08 add esp,0x8
004016FE|.C3 retn
逆运算代码为:
string dealT2_1(string s)//注册码第3次运算的逆运算
{
string s0=s;
string str="";
int i=s0.length()-1;
str+=s0;
str+=s0;
i-=2;
while(i>1)
{
str.insert(0,s0,i,1);
i--;
str.insert(2,s0,i,1);
i--;
}
str.insert(1,s0,1,1);
str.insert(0,s0,0,1);
return str;
}
然后是第二次运算的逆运算
就是奇数变高位,偶数变低位
string deal2_1(string s)//第2次运算的逆运算
{
string str="";
int i=0;
while(i<s.length())
{
char c=s*16;
c+=s;
str+=c;
i+=2;
}
return str;
}
最后就是注册码第一次运算的逆运算了:
先看看call:
; 参数有注册码16进制的第一个,注册码第二位开始的链表,"52PoJie"
004013D0/$8B4C24 08 mov ecx,dword ptr ss:
004013D4|.8B4424 04 mov eax,dword ptr ss:
004013D8|.56 push esi
004013D9|.33F6 xor esi,esi
004013DB|>33D2 /xor edx,edx
004013DD|.8A1406 |mov dl,byte ptr ds: ;逐个取"52PoJie"字符
004013E0|.8BC2 |mov eax,edx
004013E2|.33D2 |xor edx,edx
004013E4|.8A11 |mov dl,byte ptr ds: ;逐个取注册码的16进制
004013E6|.33C2 |xor eax,edx ;异或
004013E8|.8B5424 10 |mov edx,dword ptr ss:;这个参数是注册码的前1位16进制
004013EC|.81E2 FF000000 |and edx,0xFF
004013F2|.2BC2 |sub eax,edx ;相减
004013F4|.79 05 |jns short KeyGenMe.004013FB ;符号问题
004013F6|.05 FF000000 |add eax,0xFF
004013FB|>8A11 |mov dl,byte ptr ds:
004013FD|.8801 |mov byte ptr ds:,al
004013FF|.8B4424 08 |mov eax,dword ptr ss:
00401403|.8B49 04 |mov ecx,dword ptr ds:
00401406|.885424 10 |mov byte ptr ss:,dl
0040140A|.46 |inc esi
0040140B|.3B70 F8 |cmp esi,dword ptr ds: ;超出"52PoJie"长度,从头开始
0040140E|.7C 02 |jl short KeyGenMe.00401412
00401410|.33F6 |xor esi,esi
00401412|>85C9 |test ecx,ecx
00401414|.^ 75 C5 \jnz short KeyGenMe.004013DB ;直到取完
00401416|.8D4C24 08 lea ecx,dword ptr ss:
0040141A|.E8 E10C0000 call <jmp.&MFC42.#800>
0040141F|.5E pop esi
00401420\.C3 retn
这个的逆运算是我的最蛋疼的了,因为这个符号问题
string dealT2_2(string s,string t0,char t2h)//注册码第一次运算的逆运算
{
string s0=s;
string str="";
str+=t2h;
int i=0;
int i0=0;
int tmp;
while(i<s0.length())
{
int p0=str;
tmp=s0;
tmp+=p0;
tmp^=t0;
int p1=tmp^t0;
p1=p1&0xFF;
int p2=p0&0xFF;
p1=p1-p2;
if(p1<0)
{
tmp=s0;
tmp&=0xFF;
tmp+=p0;
tmp++;
tmp^=t0;
}
str+=tmp;
i++;
i0++;
if(i0==7)
i0=0;
}
return str;
}
所以注册机就可以完成了,先输入用户名,再输入一个两位的16进制数作为注册码的前两位
一个用户名有很多个注册码。
注册机:
代码文件:
vc6工程:
厉害...膜拜算法牛.学习了. 头彻底晕了,高手啊 感谢分析。内容有待消化。膜拜算法牛 师傅 你太流弊了。。。 我是来膜拜的,感谢大牛分享精彩文章。 xjun 发表于 2013-12-16 11:54 static/image/common/back.gif
我是来膜拜的,感谢大牛分享精彩文章。
膜拜xjun大牛 !!
唉,好复杂的样子 {:1_932:}膜拜大牛 楼主辛苦了、
页:
[1]
2