首页
社区
课程
招聘
[原创][邀请码已发]对简单CrackMe的分析
发表于: 2011-4-11 09:43 4071

[原创][邀请码已发]对简单CrackMe的分析

2011-4-11 09:43
4071

【文章标题】: 对CrackMe的简单分析
【文章作者】: Xsoda
【软件大小】: 8kb
【下载地址】: CreakMe.7z
【加壳方式】: 未加壳
【编写语言】: Win32Asm
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
1.        找关键Call,OD载入看入口点没加壳,F9 运行没有任何异常,说明没有反调试。胡乱注册了一下,有提示”wrong serial! Keep trying,you’ll get it!”.是个MessageBox函数提示。接下来方法就多了:
        1).可以用菜单”调试”---->”暂停”来暂停程序运行(不点击对话框的”确定”按钮,对应快捷键F12),然后Alt + K (查看调用堆栈)查看调用堆栈,如图:

图中00401263就是调用的MessageBox地址。双击“调用来自”栏的 CRACLME4.00401263就可以到达该地址的反汇编窗口,向上就可以找到爆破点。
        2).下断点”bpx MessageBox”,在所有调用该函数的地址下断点也可以找到(载入程序后,在命令栏输入bpx MessageBox ,然后回车,打开”查看””断点”检查是否已经成功下了断点,运行程序,注册信息随意输入,在点击CrackMe的“check”就可以断下来了)。
        3).最简单的超级字符串查找: 右键菜单”Ultra String Reference””Find ASCII”,可以找到刚刚发现的提示信息。最后通过3种方法找到的关键CALL如下图:

2.        爆破:我们找到的关键CALL为:00401236  |.  E8 BE000000   call    004012F9,下面根着cmp指令和je指令,0040123E  |.  74 15         je      short 00401255这个就是关键跳了,爆破方法很多:
        1).常规的将je指令该为2个nop
        2).je改为jne
        3).由于je指令只看ZF标志位,我们也可以改标志位:我也不知道可不可以直接修改ZF标志位,我只知道可以修改DF(方向)和CF(进位)标志位。但是我们可以通过变通的方法来修改:通过这里的代码cmp eax,0和je 00401255可以判断出如果注册失败,eax是等于0的(也就是函数004012F9的返回值)。我们找一个永远不会等于0的寄存器来代替eax,这样无论函数004012F9返回什么,都可以注册成功。这样的寄存器就只有2个了,eip和esp,eip不可以直接控制,我们选择esp。我们将cmp     eax,0修改成cmp       esp,0仍旧可以注册成功:

其他的爆破方法在00401236  |.  E8 BE000000   call    004012F9里面,我们跟进去看看。
3.        注册算法分析:
用IDA分析进入关键call:
.text:004012F9 sub_4012F9      proc near               ; CODE XREF: sub_401123+113p
.text:004012F9                 push    ebp
.text:004012FA                 mov     ebp, esp
.text:004012FC                 push    esi
.text:004012FD                 push    edi
.text:004012FE                 lea     esi, szName     ; szName 保存注册名
.text:00401304                 lea     edi, szSerial_1 ; szSerial_1保存真正的注册码
.text:0040130A                 xor     eax, eax        ; eax 清 0
.text:0040130C                 xor     ecx, ecx        ; ecx 清 0 作为下面的循环变量
.text:0040130E                 mov     bl, 1Ah         ; 是一个常量
.text:00401310
.text:00401310 loc_401310:                             ; CODE XREF: sub_4012F9+2Fj
.text:00401310                 cmp     byte ptr [esi], 0 ; 从这里开始循环处理注册名的每一位,0就是'\0'
.text:00401313                 jz      short endLoop
.text:00401315                 mov     al, [esi]       ; 注册名的每一位放入al
.text:00401317                 add     al, cl          ; cl是一个循环变量,初始为0,而后每处理一位都加 1
.text:00401319                 xor     al, cl
.text:0040131B                 div     bl              ; 除法,商在 eax 里面,余数在 edx
.text:0040131D                 shr     ax, 8           ; ax 右移 8 位实际是把 ah 赋值给 al,然后 ah 清0
.text:00401321                 add     al, 'A'
.text:00401323                 mov     [edi], al       ; edi 就是指向计算的真注册码了
.text:00401325                 inc     edi             ; edi 加 1,以便存放下一位真正的注册码
.text:00401326                 inc     esi             ; esi 加 1,处理szName的下一位
.text:00401327                 inc     ecx             ; 循环变量加 1
.text:00401328                 jmp     short loc_401310
.text:0040132A ; ---------------------------------------------------------------------------
.text:0040132A
.text:0040132A endLoop:                                ; CODE XREF: sub_4012F9+1Aj
.text:0040132A                 mov     byte ptr [edi], 0 ; edi 指向的是真正的注册码,这里就是构建一个以 ‘\0’结尾的字符串
.text:0040132D                 xor     eax, eax
.text:0040132F                 cmp     ecx, 0          ; ecx 只有在注册码为空时等于 0
.text:00401332                 jz      short Fail      ; 注册码位空直接跳到失败
.text:00401334                 push    offset szSerial_1 ; lpString2
.text:00401339                 push    offset szSerial ; lpString1  szSerial是我们输入的注册码
.text:0040133E                 call    lstrcmpA
.text:00401343                 cmp     eax, 0
.text:00401346                 jz      short Success   ; 两个字符串相等
.text:00401348                 xor     eax, eax
.text:0040134A                 jmp     short Fail      ; 字符串不相等,失败
.text:0040134C ; ---------------------------------------------------------------------------
.text:0040134C
.text:0040134C Success:                                ; CODE XREF: sub_4012F9+4Dj
.text:0040134C                 mov     eax, ecx
.text:0040134E
.text:0040134E Fail:                                   ; CODE XREF: sub_4012F9+39j
.text:0040134E                                         ; sub_4012F9+51j
.text:0040134E                 pop     edi
.text:0040134F                 pop     esi
.text:00401350                 leave
.text:00401351                 retn    4
.text:00401351 sub_4012F9      endp
.text:00401351
到此注册算法已经很明了了,下面给出C语言代码:

#include <stdio.h> //以下代码在VC++6.0下编译通过。
#include <stdlib.h>
char szName[20];
char szKey[20];
void keygen(void)
{
int i;
int temp;
for(i = 0; szName != '\0';i ++)
{
temp = szName + i;
temp ^= i; // C语言学的不好,我也想不到C语言中有64位的类型,就用了内嵌汇编
__asm{
mov edx,0x140608
mov eax,temp
mov bl,0x1A
div bl
mov temp,eax
}
temp >>= 8;
temp += 'A';

szKey = temp;
}
szKey = '\0';
return;
}
void main(void)
{
printf("%s","please enter your name:");
scanf("%s",szName);
keygen();
printf("the key is:%s\n",szKey);
system("pause");
return;
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
支持
分享
最新回复 (1)
雪    币: 63
活跃值: (40)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
这样的明码比较也可以得到精华啊,那我也去写几个玩玩
2011-4-20 20:50
0
游客
登录 | 注册 方可回帖
返回
//