【文章标题】: Pj一个超简单的Crackme,适合像我一样的新手~_~
【文章作者】: 易leww/今朝/Perforce
【下载地址】: http://rapidshare.com/files/2627049/crackme.rar.html
【使用工具】: Peid,Ollydbg
【作者声明】: 新手入门ing,将自己刚取得的一点成就拿出来与大家分享,不足之处大虾们多多指教(哦,由于文章太初级,老鸟不看也罢 )。 也就Crackmes.de上最简单级别的一个Crackme,建议最好不要先看本文,自己去调试一下到不会的地方再来参考;这也是我的体会,总觉得不少时候自己去分析还好,越是看别人的分析还就越迷,看着看着就头大了……(唉,没办法,人太笨了 ) 好了,废话少说,开始::)
**********************************************************************
*>>>PART 1<<<* 用PEID查下,“MASM32 / TASM32”好,没壳,有壳的话就不会有这篇废话了,俺这可是第一次耶也。。
“那你还查什么壳哪你,浪费感情!”
“例行公事呗,前辈们这样教的~~~~~~~~”
先运行程序看一下,,,,怎么?竟然有个烦人的东西(Nag)!还说什么“Patch me if you can ”,这不挑衅吗这。。
啊?你还从来没见过这东西呢?嘿嘿,来,握握手~~~,俺也是第一次上路就碰到它了
确定之后界面出来了,界面看起来还挺大方的嘛。点Check,没反应!随便输入点什么东西再点,还是没反应!!唉,真命苦呀,第一次就碰上了这么个东西~~~~ 得,不管!硬着头皮上吧 用OD加载后,先别动!四处找找~~~~~~哦,发现反汇编窗口的注释里面有 Title="Nag" 和 Text="Patch me if you can" 下面还有个红色的MessageBoxA,看名字就知道是弹出消息框!这下知道那个NAG怎么出来的了。 00401037 E8 3B040000 call 00401477
0040103C 6A 10 push 10
0040103E 68 35304000 push 00403035 ; ASCII "Nag"
00401043 68 21304000 push 00403021 ; ASCII "Patch Me if you can"
00401048 6A 00 push 0
0040104A E8 33060000 call <jmp.&user32.MessageBoxA> 左边的汇编语句是几个Push然后后面一个Call,看来就是这个CALL把那个NAG给CALL了出来,得,干掉它!
怎么干?
Nop!! (选中那行之后,按空格键,弹出的框里填Nop)
既然那几个Push是给CALL送东西(参数)的,也同时Nop掉 。
好,现在我们已经把从0010103C到0040104A的四个PUSH和一个CALL都NOP掉了;按一下OD中有两个向左箭头的按钮(或Ctrl+F12)重新加载程序,F9运行。。。
"What???"
"Patch me if you can"!!!!
明明NOP掉了呀
怎么办?再看看喽~~~~~
注:NOP掉之后,再CTRL+F12重新加载程序的话,原来NOP掉的东西会又出现,但是将以灰颜色显示。
我们先不要CTRL+F12,看一下原来NOP掉的地方~~~~~发现什么了? 哪里NOP了,分明都还在嘛!但是,,,我们的的确确NOP过呀!
怎么回事?
好,在NOP过的地方下断,我们看看到底怎么一回事。为了保险我们断点稍微靠前下些,我就在00401031处的PUSH处按F2(下断点)。
CTRL+F12重新加载程序,将刚才的NOP(0040103C-0040104A)过程重复一遍,然后F9运行,程序断在我们所设的断点处,好,看好了:
现在0010103C至0040104A显示的还是NOP,我们按F8步过这几个汇编指令:PUSH-->MOV-->ADD(F8到这里时看下下面是不是NOP,好,没有变)-->CALL(到这里时再看下下面是不是NOP,还好,还是没变),打住!
等下再F8,怎么?你偏打不住?那好,你再F8,注意到下面没~~~~~什么?代码一下子又回来了!!!
怎么回事??
哦,原来那个CALL又把我们NOP掉的代码给CALL了回来!!! 嘿!好哇,谁怕谁呀,以为我不敢我把你这个CALL也给NOP掉!!
再CTRL+F12,将00401037-0040104A全给NOP掉,F9运行,哈,哈哈,NAG没了!!!
--------不要忘了保存哦,不然又要NOP半天(右键--复制到可执行文件--所有修改/全部复制>在弹出的窗口里单击右键,选保存文件,覆盖原文件)
注:1.其实在00401037处也可以直接JMP到0040104F,省得NOP半天。
2.仅仅如此的话,程序按下Check退出时会报错。(00401449处的CALL crackme.004015B3引起,要把这个CALL也给NOP掉才行,至于具体原因我也没搞太清楚 ,还望高手指点迷津)
**********************************************************************
*>>>PART 2<<<*
大多是文字,代码就那么点,今天的主角倒好像是那个Nag了?所以我不担心你被一大篇满满的代码吓着了 或者,,,,是我废话太多?讲究一下喽~~~~ 改掉上面几个地方之后,我们分析它的算法:
输入用户名和密码,这里我输入的是:Perforce/123456;
Check!
没反应~~~~~
由于按CHECK没反应,我们下函数断点(断点详细信息请参考CCDebuger的 OllyDBG入门教程):我们在反汇编窗口击右键-->查找-->当前模块中的名称(标签),我们找到GetWindowTextA(此函数用来取我们输入文本框里的用户名和密码),双击进入反汇编窗口,前后看看,哦,下面还有一个长像差不多的GetWindowTextLengthA,从名字猜一下它的用途?
对,它用来计算我们所输入内容的长度,两个函数中间的是此看不懂的东西不用去管了,我们就在GetWindowTextLengthA函数的00401290处按F2切换断点。
好了,CTRL+F12,F9运行,输入Perforce/123456,Check!
程序断在了我们设断的00401290,F8一下,注意EAX的值(为什么是8??还记不记得GetWindowTextLengthA是干什么用的?) 00401290 . FF15 683C4000 call [403C68] ; <jmp.&user32.GetWindowTextLengthA>
00401296 . 83F8 05 cmp eax, 5 ;将用户名长度与5比较
00401299 . 0F8C 43010000 jl 004013E2 ;小于5跳走
0040129F . 83F8 08 cmp eax, 8 ;大于等于8跳走
004012A2 . 0F8D 3A010000 jge 004013E2 ;我第一次输入的Perforce是8位,从这儿跳走了,导致失败
004012A8 . 8BC8 mov ecx, eax ;用户名长度赋给计数器
004012AA . 890D 543C4000 mov [403C54], ecx
004012B0 . 33DB xor ebx, ebx
004012B2 . 8D35 54304000 lea esi, [403054] ;Perforc的地址给ESI
004012B8 . 8D3D 54324000 lea edi, [403254] ;一个内存地址@1给EDI
004012BE > 8A4431 FF mov al, [ecx+esi-1] ;取esi处的数据(逆向,即依次为:c-r-o-f-r-e-P)
004012C2 . 80F9 04 cmp cl, 4
004012C5 . 74 13 je short 004012DA ;循环到CL==4时,将对应位赋值为-后,直接进入下次循环
004012C7 . 3C 4D cmp al, 4D
004012C9 . 7C 04 jl short 004012CF ;所输入字符ASCII码值小于4D时,跳到加15处
004012CB . 2C 11 sub al, 11 ;不小于4D就减11
004012CD . EB 02 jmp short 004012D1
004012CF > 04 15 add al, 15
004012D1 > 32C1 xor al, cl ;al与cl异或后,所得值放入al
004012D3 . 34 02 xor al, 2 ;将上述al值与2异或后,放入al
004012D5 . 88043B mov [ebx+edi], al ;al送至另一内存地址@1(所送数据为WeY-'T<)
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
004012D8 . /EB 04 jmp short 004012DE
004012DA > |C6043B 2D mov byte ptr [ebx+edi], 2>
004012DE > \43 inc ebx
004012DF .^ E0 DD loopdne short 004012BE ;循环ecx次
004012E1 . 8D35 54324000 lea esi, [403254] ;将地址@1送esi
004012E7 . 8D3D 54344000 lea edi, [403454] ;将另一地址@2送edi
004012ED . 8B0D 543C4000 mov ecx, [403C54] ;循环次数送入ecx
004012F3 . 33DB xor ebx, ebx
…
…
00401328 > 80F9 04 cmp cl, 4 ;同上
0040132B . 74 17 je short 00401344
0040132D . 8A4431 FF mov al, [ecx+esi-1] ;将@1处得到的新数据逆向分别送入al(依次为<T'-YeW)
00401331 . 3C 4D cmp al, 4D ;以下重复上面操作
00401333 . 7C 04 jl short 00401339
00401335 . 2C 11 sub al, 11
00401337 . EB 02 jmp short 0040133B
00401339 > 04 15 add al, 15
0040133B > 32C1 xor al, cl
0040133D . 34 02 xor al, 2
0040133F . 88043B mov [ebx+edi], al ;将得到的新数据送入@2(所送数据为TGH-ITE)
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
00401342 . /EB 04 jmp short 00401348
00401344 > |C6043B 2D mov byte ptr [ebx+edi], 2D
00401348 > \43 inc ebx
00401349 .^ E0 DD loopdne short 00401328
0040134B . C705 603C4000 >mov dword ptr [403C60], <jmp.&user>
00401355 . 832D 603C4000 >sub dword ptr [403C60], 7
***********************************
0040135C . 68 54324000 push 00403254 ; ASCII "WeY-`T<"---第一次循环得到的数据
00401361 . 68 54344000 push 00403454 ; ASCII "TGH-ITE"---第二次循环得到的数据
00401366 . 8305 5C3C4000 >add dword ptr [403C5C], 2
0040136D . FF15 5C3C4000 call [403C5C] ; <jmp.&kernel32.lstrcatA>---连接字符串,得到注册码。
*********************************************************************
第一次我输入的Perforce是8位,从0040129F处跳走了;
既然用户名长度应是5-7位,我只好把名字给割了尾巴:Perforc,密码还是123456。
上面已经写得很清楚,大体上就是
A:先将所输入的5至7位的用户名(按逆向)各位所对应的ASCII值进行:若小于4D则加15,否则减去11-->与ecx异或(ecx的值由7至1递减)-->与2异或-->将循环得到的字符串(WeY-`T<)送入地址@1。
B:然后将@1处得到的新字串代替上步中的用户名,执行相同操作后,将新字串(TGH-ITE)送入@2处。
C:将A、B所得字串连接(@2字串在@1字串前面),即为注册码 **********************************************************************
注册机:
C学得很烂,可能显得冗余混乱:) main()
{
int i,j,b=1;char a,user[100]={0};
input:printf("Please input username:");
scanf("%s",user);
/* scanf("%c",&a);*/
i=strlen(user);
if(i<5||i>=8)
{ printf("The len of username must between 5 and 8!\n");
goto input;}
printf("The username is:%s\n",user); for(j=0;j<i/2;j++)
{ a=user[j];
user[j]=user[i-j-1];
user[i-j-1]=a;
}
/*printf("user=%s",user);*/
loop: for(j=0;j<=i-1;j++)
if (user[j]<77) user[j]=user[j]+21;
else user[j]=user[j]-17;
for(j=0;j<i;j++)
{if(j!=i-4){user[j]=user[j]^(i-j);
user[j]=user[j]^2;
}
else user[j]=45;
}
/* printf("nnnn:%s\t",user);*/
for(j=0;j<i;j++)
user[j+i*(b+1)]=user[j];
if(b==1)
{for(j=0;j<i/2;j++)
{ a=user[j];
user[j]=user[i-j-1];
user[i-j-1]=a;
}b=b-1;goto loop;
}
if(b==0)
printf("The serial is:%s\n",user+i);
/* printf("Press ENTER to quit...");
scanf("%c",&a);*/ ***到这里我总算懂得了以前前辈们写专门供给我们这些菜鸟看的破文时有多辛苦了***
另:连接之后生成的可执行文件输入用户名之后看不清注册码的就马上退出了,有什么办法让它停下吗?我不是学计算机专业的,才刚开始自学,所以可能许多比较基础的知识都不懂
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
上传的附件: