首页
社区
课程
招聘
Bad Sector CrackMe1 静态分析注册算法C语言实现
2006-3-23 01:59 7853

Bad Sector CrackMe1 静态分析注册算法C语言实现

2006-3-23 01:59
7853
;===========================================分析说明====================================================

【软件名称】Bad Sector CrackMe1
【下载地址】附件(附KeyGen源码,本文和CrackMe1)
【应用平台】Win9x/NT/2000/XP
【软件大小】10K
【软件限制】没有。
【保护方式】用户名+序列号
【破 解 者】andy00
【破解难度】1/10
【破解声明】只是为了熟悉逆向工程。
【破解工具】OllyDbg,ResHacker,Windows自带计算器
【注册机下载】仅提供源代码,支持共享软件
【软件简介】My firts Crackme..ahh.This one is damn easy and I expect from anyoneto create keygen
            for it, but if you cant code one,it would be enough to understand how it calculates real serial.
            Enjoy btw. it's not packed/protected.   -Bad Sector
            
            
;======================================================================================================
【分析过程】

为了熟悉逆向工程,静态分析能力,不调试

1、 直接用OllyDbg反汇编,无壳;

2、 在ResHacker看到用户名栏ID为C8,注册码栏为C9

3、 在OllyDbg查找输入函数GetWindowText和GetDlgItemText,顺利地找到了GetDlgItemText,
    找到nIDDlgItem(要获取字符串的控件的ID)参数为03EB的那一个,这个GetDlgItemText应该就是获取输入的注册码的地方了.

00401139     6A 32           push 32                            ; nMaxCount=32;
0040113B     68 F3204000     push Crackme1.004020F3             ; lpNameBuf=004020F3;
00401140     68 C8000000     push 0C8                           ; nIDDlgItem=C8;
00401145     FF75 08         push dword ptr ss:[ebp+8]
00401148     E8 DE000000     call <jmp.&USER32.GetDlgItemTextA> ; eax=GetDlgItemTextA(hDlg,nIDDlgItem,lpNameBuf,nMaxCount);
                                                                ;取用户名到004020F3,用户名字符个数放到eax
0040114D     83F8 00         cmp eax,0
00401150     0F84 99000000   je Crackme1.004011EF               ; if(eax==0) goto 004011EF(失败消息);没有输入则失败
00401156     83F8 04         cmp eax,4
00401159     0F82 90000000   jb Crackme1.004011EF               ; if(eax<4) goto 004011EF(失败消息);字符数<4失败
0040115F     33C9            xor ecx,ecx
00401161     33DB            xor ebx,ebx
00401163     33F6            xor esi,esi                        ; ecx=ebx=esi=0;寄存器ECX,EBX,ESI清0
00401165     8945 FC         mov dword ptr ss:[ebp-4],eax       ; localVar1=eax;用局部变量localVar1保存字符个数
00401168     0FBE81 F3204000 movsx eax,byte ptr ds:[ecx+4020F3] ; eax=strUserName[ecx];取用户名第ecx+1个字符到eax
0040116F     83F8 20         cmp eax,20
00401172     74 07           je short Crackme1.0040117B         ; if(eax==空格) goto 0040117B继续循环
                                                                ;此处说明程序忽略空格
00401174     6BC0 04         imul eax,eax,4                     ; eax=eax*4;
00401177     03D8            add ebx,eax                        ; ebx==ebx+eax;
00401179     8BF3            mov esi,ebx                        ; esi=ebx;
0040117B     41              inc ecx                            ; ecx=ecx+1;计数器增加1
0040117C     3B4D FC         cmp ecx,dword ptr ss:[ebp-4]
0040117F   ^ 75 E7           jnz short Crackme1.00401168        ; if(ecx!=localVar1) goto 00401168 没取完取下个字符;
00401181     83FE 00         cmp esi,0
00401184     74 69           je short Crackme1.004011EF         ; if (esi==0) goto 004011EF(失败消息);若ESI等于0,则注册失败;
00401186     BB 89476500     mov ebx,654789                     ; ebx=654789;
0040118B     0FBE81 F2204000 movsx eax,byte ptr ds:[ecx+4020F2] ; eax=lpNameBuf[ecx-1];取第ecx个字符
                                                                ; 与后面结合可知此片循环从最后倒着取字符处理
00401192     4B              dec ebx                            ; ebx=ebx-1;
00401193     6BC3 02         imul eax,ebx,2                     ; eax=ebx*2;
00401196     03D8            add ebx,eax                        ; ebx=ebx+eax;
00401198     4B              dec ebx                            ; ebx=ebx-1;
00401199     49              dec ecx                            ; ecx=ecx-1;
0040119A   ^ 75 EF           jnz short Crackme1.0040118B        ; if(ecx!=0) goto 0040118B;若ecx==0,继续取字符;

0040119C     56              push esi                           ; arg1=esi;
0040119D     53              push ebx                           ; arg2=ebx;
0040119E     68 C7204000     push Crackme1.004020C7             ; lpFmt="BS-%lX-%lu";
004011A3     68 BB214000     push Crackme1.004021BB             ; lpOut=004021BB;
004011A8     E8 6C000000     call <jmp.&USER32.wsprintfA>       ; wsprintf(lpOut,lpFmt,arg2,arg1);
                                                                ;用esi,ebx的值和格式"BS-%lX-%lu"生成正确的注册码放到004021BB
                                                                ;此处可跟踪004021BB得到正确的注册码
004011AD     58              pop eax
004011AE     58              pop eax
004011AF     58              pop eax
004011B0     58              pop eax
004011B1     E8 01000000     call Crackme1.004011B7             ; SubFun004011B7();注册码检验函数
004011B6     C3              retn

;=================================SubFun004011B7()注册码逐位检验函数==================================

                                                                ;以下过程取注册码并逐位验证
                                                               
004011B7     33C9            xor ecx,ecx                        ; ecx=0;
004011B9     6A 32           push 32                            ; nMaxCount=32;最多取50个字符
004011BB     68 57214000     push Crackme1.00402157             ; lpKeyBuf=00402157;注册码取到00402157
004011C0     68 C9000000     push 0C9                           ; nIDDlgItem=C9;(注册码输入控件ID)
004011C5     FF75 08         push dword ptr ss:[ebp+8]          ; hDlg=[ebp+8];
004011C8     E8 5E000000     call <jmp.&USER32.GetDlgItemTextA> ; eax=GetDlgItemTextA(hDlg,nIDDlgItem,lpKeyBuf,nMaxCount);
                                                                ; 取输入的注册码到00402157
004011CD     83F8 00         cmp eax,0
004011D0     74 1D           je short Crackme1.004011EF         ; if(eax==0) goto 004011EF(失败消息);没有输入失败
004011D2     33C9            xor ecx,ecx                        ; ecx=0;
004011D4     0FBE81 57214000 movsx eax,byte ptr ds:[ecx+402157] ; eax=lpKeyBuf[ecx];取注册码第ecx+1个字符
004011DB     0FBE99 BB214000 movsx ebx,byte ptr ds:[ecx+4021BB] ; ebx=lpOut[0];取正确注册码第ecx+1个字符
004011E2     3BC3            cmp eax,ebx
004011E4     75 09           jnz short Crackme1.004011EF        ; if(ebx!=eax) goto 004011EF(失败消息)不相等就失败;
004011E6     83F8 00         cmp eax,0
004011E9     74 19           je short Crackme1.00401204         ; if(eax==0) goto 00401204(成功消息);
                                                                ; 此处可暴破
                                                                ; 此处作者用eax==0判断字符取完
004011EB     41              inc ecx                            ; ecx=ecx+1;
004011EC   ^ EB E6           jmp short Crackme1.004011D4        ; goto 004011D4(循环比较)继续下一位注册码比较;
004011EE     C3              retn

;========================================注册失败消息================================================

004011EF     6A 10           push 10
004011F1     68 E4204000     push Crackme1.004020E4             ; ASCII "Nope"
004011F6     68 E9204000     push Crackme1.004020E9             ; ASCII "Try again"
004011FB     FF75 08         push dword ptr ss:[ebp+8]
004011FE     E8 34000000     call <jmp.&USER32.MessageBoxA>
00401203     C3              retn

;========================================注册成功消息==================================================

00401204     6A 40           push 40
00401206     68 D2204000     push Crackme1.004020D2             ; ASCII "Solved"
0040120B     68 D9204000     push Crackme1.004020D9             ; ASCII "Well done."
00401210     FF75 08         push dword ptr ss:[ebp+8]
00401213     E8 1F000000     call <jmp.&USER32.MessageBoxA>
00401218     C3              retn

;======================================================================================================

4、 算法分析出来了,现在分析注册机算法写注册机
    其实从0040114D-004011A8的代码就是产生正确注册码的过程.写成C语言如下.
    用TC2.0编译通过
   
#include <stdio.h>
#include <conio.h>

int KeyGen(char* strName/*,char*strValidKey*/)
{
    long  eax=0,ebx=0,ecx=0,esi=0,iLen;
    char strValidKey[50]="";

    iLen=strlen(strName);;
    if(iLen<4)
        return 0;
   
    for(ecx=0;ecx<iLen;ecx++)
    {
        eax=strName[ecx];
        if(eax==0x20)
            continue;   
        ebx+=4*eax;
    }
    esi=ebx;
   
    if(esi==0)
        return 0;
    ebx=0x654789;
   
    while(ecx)
    {
        ebx--;
        ebx+=2*ebx-1;
        ecx--;
    }
   
    sprintf(strValidKey,"BS-%lX-%lu",ebx,esi);
    printf("The serial number is %s\n",strValidKey);
   
    return 1;
}
   
int main( int argc, char *argv[] )
{
    char strName[50]="";
    printf("input a user name which must long than 4 charactors:");
    scanf("%s",strName);
    printf("\n\n");
    KeyGen(strName);
   
    getch();   
    return 0;
}

    ====THE END=====
   
;===========================================QQ:41086722===============================================

欢迎交流


[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

上传的附件:
收藏
点赞7
打赏
分享
最新回复 (2)
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
曙光o 2014-7-29 20:23
2
0
这么好的文章没人顶.
雪    币: 49
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
妖的刀 2014-7-31 04:07
3
0
顶贴学习
游客
登录 | 注册 方可回帖
返回