【文章标题】: 新手的一个 CreakMe分析+注册机代码
【文章作者】: 壹只老虎
【软件名称】: vcrkme01.exe
【软件大小】: 32kb
【下载地址】:http://bbs.hackbase.com/attachment.php?aid=2600
【加壳方式】: 无壳
【保护方式】: 序列号+注册码
【编写语言】: Microsoft Visual C++ 6.0
【使用工具】: od+peid+windows计算器
【操作平台】: xp
【软件介绍】: 一个算法型的creame,算法的代码有点长,耐心点分析
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
1:PEID查壳,Microsoft Visual C++ 6.0,无壳
2:运行程序,填写注册资料:序列号:123456,注册码:11111111,注册,没反应,晕!
3:OD载入,查找ASCII字符串:嘿嘿!找到了这个-->,
00401271 push vcrkme01.00406080 GOOD JOB! - CRACKED!
00401276 push vcrkme01.00406050 Send your solution to : [email]v0id2k1@hotmail.com[/email]
嘿嘿!虽然说没有错误提示,可是这个由正确提示阿!也不错吧!嘿嘿!过去看看!
下个断点!往上面看------〉找到两个用于获取输入的api,好了,知道怎么断了八!
看看!
先看看主函数的分析结果!这个比较简单!
主函数分析如下:
004011FF > \8B4424 10 mov eax,dword ptr ss:[esp+10]
00401203 . 25 FFFF0000 and eax,0FFFF
00401208 . 2D E8030000 sub eax,3E8 ; Switch (cases 3E8..3EB)
0040120D . 74 7C je short vcrkme01.0040128B
0040120F . 83E8 03 sub eax,3
00401212 . 0F85 B60000>jnz vcrkme01.004012CE
00401218 . A1 28694000 mov eax,dword ptr ds:[406928] ; Case 3EB of switch 00401208
在这里下断点就可以了
0040121D . 8B35 C05040>mov esi,dword ptr ds:[<&USER32.GetDlg>; USER32.GetDlgItemTextA
00401223 . 68 FF000000 push 0FF ; /Count = FF (255.)
00401228 . 68 30694000 push vcrkme01.00406930 ; |Buffer = vcrkme01.00406930
0040122D . 68 E8030000 push 3E8 ; |ControlID = 3E8 (1000.)
00401232 . 50 push eax ; |hWnd => 002206C2 ('[v0!d] Crackme - v0.01',class='#32770')
00401233 . FFD6 call esi ; \GetDlgItemTextA
00401235 . 8B0D 286940>mov ecx,dword ptr ds:[406928]
0040123B . 68 FF000000 push 0FF ; /Count = FF (255.)
00401240 . 68 306A4000 push vcrkme01.00406A30 ; |Buffer = vcrkme01.00406A30
00401245 . 68 EA030000 push 3EA ; |ControlID = 3EA (1002.)
0040124A . 51 push ecx ; |hWnd => 002206C2 ('[v0!d] Crackme - v0.01',class='#32770')
0040124B . FFD6 call esi ; \GetDlgItemTextA
0040124D . 68 306A4000 push vcrkme01.00406A30 ;
00401252 . 68 30694000 push vcrkme01.00406930 ;
00401257 . E8 A4FDFFFF call vcrkme01.00401000 ; 这里跟进去,算法CALL
0040125C . 83C4 08 add esp,8
0040125F . 83F8 01 cmp eax,1 ; 关键比较
00401262 . A3 646C4000 mov dword ptr ds:[406C64],eax
00401267 . 75 65 jnz short vcrkme01.004012CE ; 关键跳
虽然没有出错信息,可是有成功信息也可以阿!
00401269 . 8B15 286940>mov edx,dword ptr ds:[406928]
0040126F . 6A 40 push 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
00401271 . 68 80604000 push vcrkme01.00406080 ; |Title = "GOOD JOB! - CRACKED!"
00401276 . 68 50604000 push vcrkme01.00406050 ; |Text = "Send your solution to : [email]v0id2k1@hotmail.com[/email] "
0040127B . 52 push edx ; |hOwner => 002206C2 ('[v0!d] Crackme - v0.01',class='#32770')
0040127C . FF15 C45040>call dword ptr ds:[<&USER32.MessageBo>; \MessageBoxA
00401282 . B8 01000000 mov eax,1
00401287 . 5E pop esi
00401288 . C2 1000 retn 10
4:看看这个
00401257 . E8 A4FDFFFF call vcrkme01.00401000 ; 这里跟进去,算法CALL
这个是算法call,要跟进去好好研究下:
下面是我的分析结果(分析了好久!没办法啊!自己太菜了!5555555555555)
有点长,慢慢分析就好了,不难得!
跟进 CALL---> 00401000 分析如下
00401000 /$ 53 push ebx
00401001 |. 8B5C24 0C mov ebx,dword ptr ss:[esp+C] ; ebx=注册码字符串
00401005 |. 55 push ebp
00401006 |. 56 push esi
00401007 |. 8B7424 10 mov esi,dword ptr ss:[esp+10] ; esi=注册名字符串
0040100B |. 8A0B mov cl,byte ptr ds:[ebx] ; cl=注册码 的第一位
0040100D |. 33ED xor ebp,ebp ; ebp=0
0040100F |. 57 push edi
00401010 |. 8A06 mov al,byte ptr ds:[esi] ; al=注册名第一位
00401012 |. 3AC1 cmp al,cl ; 比较
00401014 |. 0F85 690100>jnz vcrkme01.00401183 ; 不等就跳出
0040101A |. 8BFE mov edi,esi ; edi=注册名字符串
0040101C |. 83C9 FF or ecx,FFFFFFFF ; ecx=ffffffff
0040101F |. 33C0 xor eax,eax ; eax=0
00401021 |. F2:AE repne scas byte ptr es:[edi]
00401023 |. F7D1 not ecx ; ecx注册名长度+1
00401025 |. 49 dec ecx ; ecx-1
00401026 |. 83F9 05 cmp ecx,5 ; ecx与5比较
00401029 |. 0F82 540100>jb vcrkme01.00401183 ; <5就跳出
0040102F |. 807B 01 2D cmp byte ptr ds:[ebx+1],2D ; 注册码第2位和"-"比较
00401033 |. 0F85 4A0100>jnz vcrkme01.00401183 ; 不等就跳出
00401039 |. 8BFE mov edi,esi ; edi=注册名字符串
0040103B |. 83C9 FF or ecx,FFFFFFFF ; ECX=FFFFFFFF
0040103E |. 33C0 xor eax,eax ; EAX=0
00401040 |. 33D2 xor edx,edx ; EDX=0
00401042 |. F2:AE repne scas byte ptr es:[edi]
00401044 |. F7D1 not ecx
00401046 |. 49 dec ecx ; ECX=注册名长度
00401047 |. 74 17 je short vcrkme01.00401060 ; 长度为0就跳过
00401049 |> 0FBE0C32 /movsx ecx,byte ptr ds:[edx+esi] ; ecx=逐位取注册名ascii码
0040104D |. 03E9 |add ebp,ecx ; ebp=ebp+ecx
0040104F |. 8BFE |mov edi,esi ; edi=注册名字符串
00401051 |. 83C9 FF |or ecx,FFFFFFFF ; ecx=ffffffff
00401054 |. 33C0 |xor eax,eax ; eax=0
00401056 |. 42 |inc edx ; edx+1(循环变量)
00401057 |. F2:AE |repne scas byte ptr es:[edi]
00401059 |. F7D1 |not ecx
0040105B |. 49 |dec ecx ; ECX=注册名长度
0040105C |. 3BD1 |cmp edx,ecx ; 看看是否循环结束
0040105E |.^ 72 E9 \jb short vcrkme01.00401049 ; 循环结束时ebp=注册名各位ascii码之和
00401060 |> 81C5 646000>add ebp,6064 ; ebp=ebp+24676
00401066 |. 55 push ebp ; ebp压栈
00401067 |. 68 34604000 push vcrkme01.00406034 ; ASCII "%lu"
0040106C |. 68 306B4000 push vcrkme01.00406B30 ; ASCII "24943"
00401071 |. E8 B6030000 call vcrkme01.0040142C ; ebp的10进制字符串放00406b30
00401076 |. 8A16 mov dl,byte ptr ds:[esi] ; 注册名第一位的ascii码送dl
00401078 |. 8BFE mov edi,esi ; edi=注册名字符串
0040107A |. 83C9 FF or ecx,FFFFFFFF ; 这里说明一下:406b44地址方的是一组计算结果的注册码(不断累加的)
0040107D |. 33C0 xor eax,eax ; eax=0
0040107F |. 8815 446B40>mov byte ptr ds:[406B44],dl ; dl-->00406b44
00401085 |. C605 456B40>mov byte ptr ds:[406B45],2D ; 45("-")-->00406b45
0040108C |. F2:AE repne scas byte ptr es:[edi]
0040108E |. F7D1 not ecx
00401090 |. 49 dec ecx ; ecx=注册名长度
00401091 |. 0FBE4431 FF movsx eax,byte ptr ds:[ecx+esi-1] ; eax=注册名最后一位的ascii码
00401096 |. 50 push eax ; eax压栈
00401097 |. E8 C4020000 call vcrkme01.00401360 ; 进去看看
0040109C |. A2 466B4000 mov byte ptr ds:[406B46],al ; 注册名最后一位(大写,数字就不变)加入真码尾部
004010A1 |. BF 306B4000 mov edi,vcrkme01.00406B30 ; edi=str_10(注册名计算得到的数据的10进制字符串)
004010A6 |. 83C9 FF or ecx,FFFFFFFF ; ecx=ffffffff
004010A9 |. 33C0 xor eax,eax ; eax=0
004010AB |. F2:AE repne scas byte ptr es:[edi]
004010AD |. F7D1 not ecx ; ecx=str_10长度+1
004010AF |. 2BF9 sub edi,ecx ; edi=str_10的10进制字符串
004010B1 |. 81C5 646000>add ebp,6064 ; ebp=ebp+24676
004010B7 |. 8BF7 mov esi,edi ; edi=str_10的10进制字符串
004010B9 |. 8BD1 mov edx,ecx ; edx=str_10长度+1
004010BB |. BF 446B4000 mov edi,vcrkme01.00406B44 ; edi=现在得到的部分注册码
004010C0 |. 83C9 FF or ecx,FFFFFFFF
004010C3 |. F2:AE repne scas byte ptr es:[edi]
004010C5 |. 8BCA mov ecx,edx ; ecx=str_10长度+1
004010C7 |. 4F dec edi ; edi-1
004010C8 |. C1E9 02 shr ecx,2 ; ecx=ecx shr 2
004010CB |. F3:A5 rep movs dword ptr es:[edi],dword ptr>; 注册码继续追加
004010CD |. 8BCA mov ecx,edx ; ecx=str_10长度+1
004010CF |. 55 push ebp ; ebp压栈
004010D0 |. 83E1 03 and ecx,3 ; ecx=ecx and 3
004010D3 |. 68 34604000 push vcrkme01.00406034 ; ASCII "%lu"
004010D8 |. F3:A4 rep movs byte ptr es:[edi],byte ptr d>; 再追加str_10的最后一位
004010DA |. BF 30604000 mov edi,vcrkme01.00406030
004010DF |. 83C9 FF or ecx,FFFFFFFF
004010E2 |. F2:AE repne scas byte ptr es:[edi]
004010E4 |. F7D1 not ecx ; ecx="-"的在生成注册码中的位置
004010E6 |. 2BF9 sub edi,ecx ; edi=edi-ecx
004010E8 |. 68 306B4000 push vcrkme01.00406B30 ; ASCII "24943"
004010ED |. 8BF7 mov esi,edi
004010EF |. 8BD1 mov edx,ecx
004010F1 |. BF 446B4000 mov edi,vcrkme01.00406B44 ; ASCII "1-"
004010F6 |. 83C9 FF or ecx,FFFFFFFF
004010F9 |. F2:AE repne scas byte ptr es:[edi]
004010FB |. 8BCA mov ecx,edx
004010FD |. 4F dec edi
004010FE |. C1E9 02 shr ecx,2
00401101 |. F3:A5 rep movs dword ptr es:[edi],dword ptr>
00401103 |. 8BCA mov ecx,edx
00401105 |. 83E1 03 and ecx,3
00401108 |. F3:A4 rep movs byte ptr es:[edi],byte ptr d>; 追加-
0040110A |. E8 1D030000 call vcrkme01.0040142C ; 以下是追加ebp的是进制数据
0040110F |. BF 306B4000 mov edi,vcrkme01.00406B30 ; ASCII "24943"
00401114 |. 83C9 FF or ecx,FFFFFFFF
00401117 |. 33C0 xor eax,eax
00401119 |. 83C4 1C add esp,1C
0040111C |. F2:AE repne scas byte ptr es:[edi]
0040111E |. F7D1 not ecx
00401120 |. 2BF9 sub edi,ecx
00401122 |. 8BF7 mov esi,edi
00401124 |. 8BD1 mov edx,ecx
00401126 |. BF 446B4000 mov edi,vcrkme01.00406B44 ; ASCII "1-"
0040112B |. 83C9 FF or ecx,FFFFFFFF
0040112E |. F2:AE repne scas byte ptr es:[edi]
00401130 |. 8BCA mov ecx,edx
00401132 |. 4F dec edi
00401133 |. C1E9 02 shr ecx,2
00401136 |. F3:A5 rep movs dword ptr es:[edi],dword ptr>
00401138 |. 8BCA mov ecx,edx
0040113A |. 8BC3 mov eax,ebx
0040113C |. 83E1 03 and ecx,3
0040113F |. F3:A4 rep movs byte ptr es:[edi],byte ptr d>
00401141 |. BE 446B4000 mov esi,vcrkme01.00406B44 ; ASCII "1-"
00401146 |> 8A10 /mov dl,byte ptr ds:[eax] ; dl=假码第一位的ascii
00401148 |. 8A1E |mov bl,byte ptr ds:[esi] ; bl=真码第一位的 ascii
0040114A |. 8ACA |mov cl,dl ; cl=dl
0040114C |. 3AD3 |cmp dl,bl ; bl和dl比较
0040114E |. 75 25 |jnz short vcrkme01.00401175 ; 不等就跳转
00401150 |. 84C9 |test cl,cl ; cl为0时跳出循环(比较完了)
00401152 |. 74 16 |je short vcrkme01.0040116A
00401154 |. 8A50 01 |mov dl,byte ptr ds:[eax+1]
00401157 |. 8A5E 01 |mov bl,byte ptr ds:[esi+1]
0040115A |. 8ACA |mov cl,dl
0040115C |. 3AD3 |cmp dl,bl
0040115E |. 75 15 |jnz short vcrkme01.00401175
00401160 |. 83C0 02 |add eax,2
00401163 |. 83C6 02 |add esi,2
00401166 |. 84C9 |test cl,cl
00401168 |.^ 75 DC \jnz short vcrkme01.00401146
0040116A |> 33C0 xor eax,eax ; 来到这里就算正确了
0040116C |. 33D2 xor edx,edx
0040116E |. 85C0 test eax,eax
00401170 |. 0F94C2 sete dl ; dl标记一下
00401173 |. EB 12 jmp short vcrkme01.00401187
00401175 |> 1BC0 sbb eax,eax
00401177 |. 83D8 FF sbb eax,-1
0040117A |. 33D2 xor edx,edx
0040117C |. 85C0 test eax,eax
0040117E |. 0F94C2 sete dl ; 标记为0
00401181 |. EB 04 jmp short vcrkme01.00401187
00401183 |> 8B5424 14 mov edx,dword ptr ss:[esp+14]
00401187 |> B9 40000000 mov ecx,40 ; ecx=40
0040118C |. 33C0 xor eax,eax ; eax=0
0040118E |. BF 446B4000 mov edi,vcrkme01.00406B44 ; ASCII "1-"
00401193 |. F3:AB rep stos dword ptr es:[edi]
00401195 |. 5F pop edi
00401196 |. 5E pop esi
00401197 |. 5D pop ebp
00401198 |. 8BC2 mov eax,edx ; eax=dl的标记
0040119A |. 5B pop ebx
0040119B \. C3 retn
0040119C 90 nop
0040119D 90 nop
0040119E 90 nop
5:总结算法
1: 注册名长度必须大于5
2: 注册码分为3部分,中间用两个"-"连起来
3: 注册码第一部分是注册名的第一位,第二部分为注册名最后一位(如果是小写字母就转成大写的)+注册名各位的ascII码和+24676,第三部分为注册名各位的ascII码和+24676*2
总结完毕
6:写注册机了!嘿嘿!
代码如下:
procedure TForm1.Button1Click(Sender: TObject);
var
ebp:integer;
i:integer;
name,str:string;
begin
name:=edit1.Text;
if length(name)<5 then
begin
showmessage('注册名长度必须大于5');
exit;
end;
str:='';
str:=str+name[1]+'-';
if (ord(name[length(name)])>96)and (ord(name[length(name)])<123) then
str:=str+ chr(ord(name[length(name)])-32)
else
str:=str+name[length(name)];
ebp:=0;
for i:=1 to length(name) do
ebp:=ebp+ord( name ) ;
ebp:=ebp+24676 ;
str:=str+inttostr(ebp) + '-' ;
ebp:=ebp + 24676 ;
str:=str+inttostr(ebp) ;
edit2.Text:=str ;
end;
好了,到此结束!
--------------------------------------------------------------------------------
【经验总结】
这个东西总体来说比较简单,就是有点烦,算法代码有点多,不过还好都不是很复杂!都是些常用的指令!
--------------------------------------------------------------------------------
【版权声明】: BY:壹只老虎
2006年08月24日 5:12:46
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)