GIF
Movie Gear v3.0.2 破解小谈(附注册机源码)
最近在老罗的坛子里好多人的签名都换成了PL的图片。嘿嘿,偶自然也不愿落后,so便想自己DIY一个英俊潇洒玉树临风貌比潘安才比伯虎的挂上去,可是以前买的Flash
MX D版盘怎么也找不到了,于是便到天空那边儿去找做GIF动画的软件,再于是便找到了这个软件,据说是使用简单,方便快捷…
结果,呵呵(冷汗…搞了一个上午也没搞出张像样的图片来)。偷鸡不成,怎么也要抓一把米回来吧,反正今天除了没完成的事儿其它的事儿都做完了…
;)
首先当然是先要看一下人家有没有加壳,结果是另人满意的,过程是另人愉快的,答案是VC6.0的。^_^具然没加壳…
那还等什么呢?点Help菜单中的Register
Now…。接着就呼出你埋伏已久的调试器吧,我用的是TRW2000。(随便问一句哥们儿,TRW2000呼出是按Ctrl+N这事儿你知道吧,知道啊。那上海2010年办世博会,这事儿你也知道吧,哦,都知道了,那甲A前天晚上…当!…好好好,我继续就是了)呼出TRW2000后下断点bpx
hmemcpy(我用的是98嘛),然后按F5返回。接着在Name处偶输入Suunb[CCG],在Code处输入20030413(呵呵,今天的日期 ^_^)
好的,接下来就按OK吧。
结果是显而易见的,成功被我军爱国者导弹给拦截掉了。之后就一个pmodule导弹过去跳出程序的领空,之后在按F12的时候会发现只按1次就提示出错了。
好的,知道这些后,就再来一遍吧。这次在pmodule返回后就按F10来单步执行,代码如下:
0167:00431972
lea edx,[esp+c4]
<--会来到这里!
0167:00431979 push byte +64
0167:0043197b
push edx
0167:0043197c push dword 0450
0167:00431981
push esi
0167:00431982 call edi
<--看上边儿压进去的参数,这个Call应该是调用API函数GetDlgItem来得到注册码输入框的句柄。
0167:00431984
push eax
0167:00431985 call ebx
<--用先前得到的注册码输入框的句柄通过调用GetWindowTextA来得到输入的注册码
0167:00431987
lea eax,[esp+c4]
<--用d指令可以知道esp+c4处装的是用户输入的注册码,将这个地址装入eax中
0167:0043198e lea
ecx,[esp+60] <--同样用d指令可以知道esp+60处装的是用户输入的注册名,装其地址装入ecx中
0167:00431992
push eax
<--注册码地址压栈
0167:00431993 push
ecx <--注册名地址压栈
0167:00431994
call 00431590
<--嘿嘿,整个过程就由这个CALL一手操控了
0167:00431999 add esp,byte
+08 <--栈顶还原
0167:0043199c test
eax,eax
<--测试eax中装入的值
0167:0043199e jz near 00431a51
<--为0就跳到00431a51处,跳过去就Over了
0167:004319a4
lea edx,[esp+10]
<--从这里开始程序通过调用RegCreateKeyExA、RegSetvalueExA等其它一些注册表相关API来向注册表中写入用户的注册信息。也就是HKEY_CURRENT_USER\Software\gamani\GIFMovieGear\2.0主键下面的RegName3与RegCode3子键。当然这是在你输入的注册码正确的前提下,RegName3中装的是你的注册名,RegCode3中自然就是你输入的册码了…
0167:004319a8
lea eax,[esp+0c]
0167:004319ac push
edx
0167:004319ad push eax
0167:004319ae push
byte +00
0167:004319b0 push dword 000f003f
0167:004319b5
push byte +00
0167:004319b7 push dword
0044ed14
0167:004319bc push byte +00
0167:004319be push
dword 0044b3f8 <--此处可以看一下0044b3f8,得到Software\gamani\GIFMovieGear\2.0
0167:004319c3
push dword 80000001 <--这个值就是HKEY_CURRENT_USER
0167:004319c8
call `ADVAPI32!RegCreateKeyExA` <--API函数RegCreateKeyExA
0167:004319ce lea edi,[esp+60]
0167:004319d2
or ecx,byte -01
0167:004319d5 xor
eax,eax
0167:004319d7 mov edx,[esp+0c]
0167:004319db
repne scasb
0167:004319dd not ecx
0167:004319df
mov ebx,[00448018]
0167:004319e5 push
ecx
0167:004319e6 lea ecx,[esp+64]
0167:004319ea
push ecx
0167:004319eb push byte +01
0167:004319ed
push eax
0167:004319ee push dword 0044d498
<--0044d498处就是字符串RegName3
0167:004319f3
push edx
0167:004319f4 call ebx
<--RegSetvalueExA
0167:004319f6
lea edi,[esp+c4]
0167:004319fd or
ecx,byte -01
0167:00431a00 xor eax,eax
0167:00431a02
repne scasb
0167:00431a04 not ecx
0167:00431a06
lea eax,[esp+c4]
0167:00431a0d push
ecx
0167:00431a0e mov ecx,[esp+10]
0167:00431a12
push eax
0167:00431a13 push byte +01
0167:00431a15
push byte +00
0167:00431a17 push dword
0044d4a4 <--0044d4a4嘛,就是字符串RegCode3
0167:00431a1c
push ecx
0167:00431a1d call ebx
<--RegSetvalueExA
0167:00431a1f
mov edx,[esp+0c]
0167:00431a23 push
edx
0167:00431a24 call `ADVAPI32!RegCloseKey`
0167:00431a2a
push dword 0044d4b0
0167:00431a2f push
dword 80000002
0167:00431a34 call `ADVAPI32!RegDeleteKeyA`
0167:00431a3a
push byte +01
0167:00431a3c push esi
0167:00431a3d
call `USER32!EndDialog` <--用EndDialog来关掉输入注册码的这个对话框
0167:00431a43
pop edi
0167:00431a44 pop esi
0167:00431a45
xor eax,eax
0167:00431a47 pop
ebx
0167:00431a48 add esp,011c
0167:00431a4e
ret 10
<--返回
0167:00431a51 push
byte +30 <--在前边儿0043199c处如果没通过就会跳到这里,到了这里就一切都玩儿完了
;)
0167:00431a53 push dword 9d15
0167:00431a58 push
dword 9d14
0167:00431a5d push esi
0167:00431a5e
call 0040ee90
0167:00431a63 add esp,byte
+10
0167:00431a66 push dword 044f
0167:00431a6b push
esi
0167:00431a6c call edi
0167:00431a6e
push eax
0167:00431a6f call `USER32!SetFocus`
0167:00431a75
pop edi
0167:00431a76 pop esi
0167:00431a77
xor eax,eax
0167:00431a79 pop
ebx
0167:00431a7a add esp,011c
0167:00431a80
ret 10
HeHe~~很明显吧,00431994处的那个CALL就是关键的所在嘛。
也就是说如果在00431994处的那个CALL中程序确定注册码是正确的话就会将其与用户名一同输入进注册表,以后每次程序启动的时候都会进行比较。But你输入的是错误的话嘛,程序就懒得去写进注册表了。所以我们尽管可以在0043199c处的时候用r
fl z指令来欺骗程序,但一点儿用都没有 (众人:那你说它干嘛)
那接着就再来一遍,这次就可以直接用断点bpx
00431994了。断到后就按F8跟进去吧:
0167:00431590 push ebx
0167:00431591
push ebp
0167:00431592 mov ebp,[esp+10]
<--将注册码的地址装入ebp中
0167:00431596
push esi
0167:00431597 push edi
0167:00431598
cmp byte [ebp+00],6d <--ebp+00也就是注册码的第一位,用注册码的第一位与6d相比(6d即m的ASCII码)
0167:0043159c jnz near 00431642
<--第一位不是m就跳到00431642处,跳过去就玩儿完了。呵呵,我输入的是20030413,在这里就挂掉了,再来一遍,这次把前4位改成mg37,即mg3720030413
0167:004315a2
cmp byte [ebp+01],67 <--判断注册码的第2位是否为g
0167:004315a6
jnz near 00431642
0167:004315ac cmp
byte [ebp+02],33 <--同理,判断第3位是否为3
0167:004315b0
jnz near 00431642
0167:004315b6 cmp
byte [ebp+03],37 <--第4位是否为4
0167:004315ba
jnz near 00431642
0167:004315c0 mov
ebx,0044d4c4
0167:004315c5 mov
edx,[ebx]
0167:004315c7
or ecx,byte -01
0167:004315ca
mov edi,edx
0167:004315cc xor eax,eax
0167:004315ce repne scasb
0167:004315d0 not
ecx
0167:004315d2 dec ecx
0167:004315d3
mov edi,edx
0167:004315d5 mov
esi,ebp
0167:004315d7 xor eax,eax
0167:004315d9 repe cmpsb
0167:004315db jz
00431642
0167:004315dd
add ebx,byte +04
0167:004315e0 cmp
ebx,0044d4c8
0167:004315e6 jl 004315c5
0167:004315e8
cmp byte [ebp+04],73 <--比较看注册码的第5位是否为s,ebp中装的其实是注册码的地址,这点很重要,后边儿会有说明
0167:004315ec
jnz 004315ef
<--不是就跳到004315ef处
0167:004315ee inc ebp
<--是的话ebp+1
0167:004315ef
add ebp,byte +07
<--ebp加上7
0167:004315f2 push ebp
<--ebp入栈
0167:004315f3
call 0043f3c8
<--!!
0167:004315f8 mov edx,[esp+18]
0167:004315fc
add esp,byte +04
0167:004315ff mov
edi,edx
0167:00431601 xor ecx,ecx
<--ecx清0
0167:00431603 mov
dl,[edx]
<--装入注册名中的第一个字符
0167:00431605 mov esi,0bdf
<--esi中装入0bdf,即十进制数3039
0167:0043160a
test dl,dl
<--看dl中是否为0
0167:0043160c jz
00431634
0167:0043160e movsx edx,dl
<--霸占整个edx寄存器 ;)
0167:00431611
inc ecx
<--ecx加1
0167:00431612 imul
edx,ecx <--用edx中此时装入的注册名中的某一位字符乘的ASCII码乘以ecx中的值
0167:00431615
add esi,edx
<--用esi中的值加上edx中的值
0167:00431617 cmp
esi,17be <--用esi中的值与17be,即十进制数6078比较
0167:0043161d
jng 00431625
<---不大于不跳到00431625处
0167:0043161f sub
esi,17be <--大于的话就减去它
0167:00431625 cmp ecx,byte +0a
<--用A(也就是10)与ecx中的值比较
0167:00431628 jng
0043162c
<--不大于就跳到0043162c处
0167:0043162a xor ecx,ecx
<--ecx清0
0167:0043162c
mov dl,[edi+01]
<--dl中装入注册名中的下一个字符
0167:0043162f inc edi
<--edi加上1
0167:00431630
test dl,dl
<--测试dl
0167:00431632 jnz 0043160e
<--不为0就跳加0043160e处继续用下一位来进行计算
0167:00431634
cmp esi,eax
<--比较esi与eax中的值,esi中装入的就是前边儿0043160e-00431632处将注册名中各位字符进行计算后的值,而eax中的值是通过004315f3处的这个CALL装进来的,相对于我输入的这个注册名及注册码,它的值是76CD,也就是十进制数30413。
0167:00431636
jnz 00431642
<--不相等就跳到00431642处
0167:00431638 pop edi
0167:00431639
pop esi
0167:0043163a pop ebp
0167:0043163b
mov eax,01
<--相等的话就继续执行到这里,并将eax置1,我们已经知道出来后会比较看eax是否为0,是的话就Game
Over
0167:00431640 pop ebx
0167:00431641 ret
0167:00431642 pop edi
<--从前面跳过来的话就…
0167:00431643
pop esi
0167:00431644 pop ebp
0167:00431645
xor eax,eax
<--可恶吧,会将eax置0
0167:00431647 pop
ebx
0167:00431648 ret
我认为我有必要讲一下,其实这并不难理解。在004315e8处的时候我们可以通过d指令知道ebp中装的其实就是注册码的地址,在004315e8处的时候会比较注册码的第5位是否为s,是的话就将ebp加上1。而到了004315ef处的时候会将ebp加上7,之后就将这个地址压栈了。过了004315f3处的那个CALL后EAX中的值就会改变了,完全不必要追进去,猜也能猜出来了。呵呵,这个CALL的作用就是将之前004315f2处压入的ebp中的地址处开始的值装入eax中。而ebp中装的就是注册码的第7位的地址,明白过来了吗?注册码从第7位开始的值就是程序真正要用的
;)可问题是第7位以后还有几位呢?嘿嘿,这个很容易就能发现,在00431617的时候程序不是会判断esi中的值是否大于6078吗?而6078,也就是6078只有4位,所以嘛,注册码的位数就是7+4即11位!不过在004315e8和我们会发现程序会判断注册码的第5位是否为s,是的话就接着将ebp加上1,所以问题就解决了。正确的注册码位数只有两种情况:一种是11位,另一种是12位,这个12位的第5位是一个固定不变的,即s。
呵呵,我们来看一下正确的注册码的格式吧,第一种11位的是mg37XXXXXXX,另一种12位的是mg37sXXXXXXX。
现在我们知道的已经够多了,那就写注册机吧
;)
这之前再大概说一遍程序注册码的计算过过程:
首先固定不变的是程序注册码的前4位,永远是mg37,然后有一个可有可无的位,即第5位,要这一位的话,就让它为s
(注意如果注册码的第5位是s,那就应该在其后再补上3位),否则就不要它而直接在mg37后边儿随便补充3位,就比如说CCG ^_^。而接下来就是最后4位了,这个也是重要的地方所在了
;) 后4位的计算过程其实也不难,就是用你输入的注册名的首位字符的ASCII码乘以X(X每计算一位字符就加上1,如果值后来一直累加到11,就会还原为0)。再用这个乘积加上3039。并将其保存起来,这里称它为Y,之后比较Y是否大于6078,如果大于就用Y减去6078。接下来第二位字符参加运算,同样用其值乘以X,然后加上Y,再比较Y是否大于6078,再接下来第三位字符参加运算,用其乘以X,然后加上Y…直到所有字符均参加完运算…
BTW:如果字符参加完运算后得到的是一个3位有效值,比如123,就在1的前边儿补上一个0,如0123。
贴的这个是注册机源码是Delphi的,直接声明这个函数就能用了:
function
KeyGen(Name: String): String;
var
i,Cnt,vai,ASC:integer;
Serial:String;
begin
Cnt:=3039;
vai:=0;
for i:=1 to Length(Name) do
begin
inc(vai);
ASC:=Ord(Name[i]);
ASC:=ASC*vai;
Cnt:=Cnt+ASC;
if Cnt>6078 then
Cnt:=Cnt-6078;
if vai>10 then vai:=0;
end;
Serial:=inttostr(Cnt);
Case Length(Serial)
of
3:Serial:='0'+Serial;
2:Serial:='00'+Serial;
1:Serial:='000'+Serial;
end;
Serial:='mg37CCG'+Serial;
Result:=Serial;
end;
OK,就这些。