飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 5088|回复: 4

[转贴] CRACKME系列 难度由0--9,看你属于哪一级?

[复制链接]
  • TA的每日心情

    2015-7-19 14:12
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2010-5-30 08:47:53 | 显示全部楼层 |阅读模式
    本帖最后由 wswm 于 2010-6-2 08:02 编辑

    标 题: 本人原创CRACKME系列 难度由0--9,看你属于哪一级? (更新CRACKME 7的程序实现,附源码)
    作 者: zenghw
    时 间: 2009-07-20,17:26:52
    链 接: http://bbs.pediy.com/showthread.php?t=93936

    买回《加密与解密 第三版》已经半个多月了,每天晚上下班都会抽出3个小时来学习,用“拨开云雾”四个字来形容这半个月的感觉最恰当不过,一层一层的知识让我应接不暇,现在才发现原来用了好几年的EXE等文件竟存在着这么多的秘密!  虽然我是做嵌入式系统的,目前软件安全性应用得不多,但是能学到这么多感兴趣的东西,毕竟也是一件幸事,不敢独享,在此与众同乐!
        附件为我周末时用VC++编写的CRECKME系列,由于只有两天时间,目前只完成了前6个难度,即难度0--难度5,我后面会陆续再贴出后面的难度6---难度9,也将陆续贴出源码以及我个人的破解方法,望各位能一起参与,多多指教!!

       本来还想贴出各难度的帮助,但想想还是让大家先试着破解,等过一段时间贴出具体源代码和破解流程时再一起贴出好了!

       PS:由于本人用VC++ MFC 编译,所以如果文件打不开的话,请依照提示下载MFC71.dll等文件,如电脑中有装VC++则无需下载。

    发现CRECKME 4程序中漏了一句话,导致与我原来的想法不符,现在补上名称为"CRECKME 4修正版",有兴趣的可以从附件中下载尝试。
    CRECKME 6 已经上传! 期待分析和注册码,能爆破也行!



    结果:
    CRECKME 0:明码,无算法,有字符串可下断点,可爆破,无各项反调试措施,无加壳。    难易程度:最简单。   目的:明码典型性。
    CRECKME 1:非明码,算法简单,有字符串可下断点,可爆破,无各项反调试措施,无加壳。    难易程度:简单。    目的:非明码的实现。
    CRECKME 2:非明码,算法简单,无字符串和敏感API函数可下断点,可爆破,无各项反调试措施,无加壳。    难易程度:简单。 目的:OllyDbg消息断点或其它断点尝试。
    CRECKME 3:非明码,算法简单,无字符串和敏感API函数可下断点,有防爆破,无各项反调试措施,无加壳。    难易程度:简单。 目的:尝试防爆破。
    CRECKME 4,CRECKME 4修正版:Cyane已爆破,但尚未能得出注册码。 等待注册码后贴解析和源代码。期待中……
    CRECKME 5,6:已有爆破,但尚未有注册码。期待中……
    CRECKME 7:由于CRECKME 5,6用了别人的VM PROTECT,导致某些人的反感,我这里再次诚挚道歉,并感谢你们的关注。 CRECKME 7中不再使用VM,但有成熟算法和其它一些反调试的手段,代码里也有自己的一些思路,虽然很多是前人走过的,但毕竟也有自己的想法和创新,这个CRECKME花了我几天时间,感谢你们的继续关注!

    CRACKME 7实现流程和源码在编程模块已详细说明,有兴趣的可以看以下链接:http://bbs.pediy.com/showthread.php?p=663830#post663830, 特别感谢sessiondiy的提醒和关注!




    ----------------------------------------------------------------------------------------------------------------------------------------CRECKME 0 解析(初次解析,请多多指教):
    工具:OllyDbg,
    查壳:peid,
    1,查壳显示为Microsoft Visual C++ 7.0 Method2 [Debug],可知无加壳(当然,一些壳也能伪装这些信息,以OllyDbg入口点为准)。
    2,调试MFC程序,需先倒入MFC的LIB文件,否则MFC里面的函数将无法解析。deg--->select import libraries--->MFC42.LIB,MFC71.LIB  ,然后点击process.
    3,通过测试,我们知道有字符串提醒,因此可以用字符串下断点,用OllyDbg打开程序后,OPlugins---->Ultra String Reference -->Find AScill,找到Congratulation! Correct Serial Num,do next one,双击查看,即可找到验证代码处,我在004015A0   .  56            push    esi 行处下断点。
    4,按F9运行代码,在NAME和SERIAL中随便输入,我这里输入为NAME:zenghw,  SERIAL:5705312 (个人习惯)。点确定,程序中断。
    5,以下内容中,//后面内容即为我的注释
    004015A0   .  56            push    esi
    004015A1   .  57            push    edi
    004015A2   .  6A 01         push    1                                           ;  //UpdateDate的参数,为1,即为TRUE
    004015A4   .  8BF1          mov     esi, ecx
    004015A6   .  E8 6B030000   call    <jmp.&MFC71.#6236_CWnd::UpdateData>         ;  //UpdateDate,结合前面的参数TRUE,可知为把对话框中的内容保存起来
    004015AB   .  8D7E 74       lea     edi, dword ptr [esi+74]                     ;  //由信息窗口可知ptr[esi+74]为地址0013FEF8,再由右下角堆栈串口可知0013FEF8为我们输入的假NAME,我这里为zenghw
    004015AE   .  8BCF          mov     ecx, edi                                    ;  //把我们输入的假NAME zenghw 赋给 ecx
    004015B0   .  FF15 D0314000 call    dword ptr [<&MFC71.#2902_ATL::CSimpleString>;  MFC71.ATL::CSimpleStringT<wchar_t,1>::GetLength
    004015B6   .  83F8 06       cmp     eax, 6                                      ;  //在上面跟入可以很明显的知道eax即为返回的string长度值,即假NAME zenghw的长度值
    004015B9   .  7D 1A         jge     short 004015D5                              ;  //如果长度值>=6的话就跳,否则往下跑
    004015BB   .  817E 78 A0860>cmp     dword ptr [esi+78], 186A0
    004015C2   .  7D 11         jge     short 004015D5
    004015C4   .  6A 00         push    0
    004015C6   .  6A 00         push    0
    004015C8   .  68 8C394000   push    0040398C                                    ;  name or serial is too short!
    004015CD   .  E8 3E030000   call    <jmp.&MFC71.#1123_AfxMessageBox>
    004015D2   >  5F            pop     edi
    004015D3   .  5E            pop     esi
    004015D4   .  C3            retn
    004015D5   >  68 78394000   push    00403978                                    ;  //把字符串"indolentafternoon"推进栈
    004015DA   .  8BCF          mov     ecx, edi                                    ;  //从信息窗口和堆栈窗口可知,edi即为假NAME
    004015DC   .  FF15 C0314000 call    dword ptr [<&MFC71.#1482_ATL::CStringT<char>;  //Compare,跟进去可知为比较函数,其实看名字不跟也知道大概结果
    004015E2   .  85C0          test    eax, eax                                    ;  //eax为返回值,如果相等为0,不等为1
    004015E4   .^ 75 EC         jnz     short 004015D2
    004015E6   .  817E 78 D7C75>cmp     dword ptr [esi+78], 56C7D7                  ;  //把假SERIAL 5705312 与0X56C7D7比较,即十进制5687255
    004015ED   .^ 75 E3         jnz     short 004015D2                              ;  //如果不等的话就跳走
    004015EF   .  6A 00         push    0
    004015F1   .  6A 00         push    0
    004015F3   .  68 44394000   push    00403944                                    ;  congratulation! correct serial num,do next one? :)
    004015F8   .  E8 13030000   call    <jmp.&MFC71.#1123_AfxMessageBox>
    004015FD   .  8B06          mov     eax, dword ptr [esi]
    004015FF   .  5F            pop     edi
    00401600   .  8BCE          mov     ecx, esi
    00401602   .  5E            pop     esi


    再附上我VC里的代码:
    {
      // TODO: 在此添加控件通知处理程序代码

      UpdateData(true);

      if(m_Name.GetLength()<6 &&  m_Serial< 100000)
      {
        AfxMessageBox("Name or Serial is too short!");
        return;
      }

      if(m_Name == "IndolentAfternoon" && m_Serial == 5687255)
      {
        AfxMessageBox("Congratulation! Correct Serial Num,do next one? :)");
        OnOK();
      }
      else
        return;
    }


    CREAKME 0 内容是最简单最初步的,很多程序员也犯这样的错误:明码,不用算法,没有各种防范措施,就直接比较,相同则注册成功。

    明天继续贴CREME 1,谢谢大家关注。
    ------------------------------------------------------------------------------------------------------------------------------------
    继续贴CRECKME 1,1,还是用字符串下断点。运行后,我输入NAME为zenghw,SERIAL为5705312.
    2,分析代码:
    004013E8   .  55            push    ebp
    004013E9   .  56            push    esi
    004013EA   .  57            push    edi
    004013EB   .  33FF          xor     edi, edi
    004013ED   .  6A 01         push    1                                ;  //UpdateDate的参数,为1
    004013EF   .  8BF1          mov     esi, ecx
    004013F1   .  897C24 18     mov     dword ptr [esp+18], edi
    004013F5   .  E8 A2040000   call    <jmp.&MFC71.#6236_CWnd::UpdateDa>;  //UpdateData函数,参数为1时,表示把当前控件内容更新入变量中
    004013FA   .  8D6E 78       lea     ebp, dword ptr [esi+78]          ;  //由信息窗口可知ptr[esi+78]为地址0013FEF8,再由右下角堆栈串口可知0013FEF8为我们输入的假NAME,我这里为zenghw,在command中输入D 0013FEF8为什么不能显示?
    004013FD   .  8BCD          mov     ecx, ebp
    004013FF   .  896C24 18     mov     dword ptr [esp+18], ebp          ;  //把让ptr[esp+18]指针指向假NAME :zenghw
    00401403   .  FF15 C0214000 call    dword ptr [<&MFC71.#2902_ATL::CS>;  //获得假NAME的输入长度
    00401409   .  83F8 06       cmp     eax, 6
    0040140C   .  0F8C 71010000 jl      00401583                         ;   //如果输入长度<6,就跳向失败
    00401412   .  83C6 7C       add     esi, 7C                          ;  //做什么用?给参数分配空间吧?
    00401415   .  8BCE          mov     ecx, esi                         ;  //由信心窗口可知ESI地址为0013FEFC,由堆栈窗口可知其为假SERIAL:5705312
    00401417   .  FF15 C0214000 call    dword ptr [<&MFC71.#2902_ATL::CS>;  //获得假SERIAL的输入长度
    0040141D   .  83F8 06       cmp     eax, 6
    00401420   .  0F8C 5D010000 jl      00401583                         ;   //如果输入长度<6,就跳向失败
    00401426   .  53            push    ebx
    00401427   .  8BCE          mov     ecx, esi                         ;  //由上面分析知道ESI为假SERIAL:5705312
    00401429   .  897C24 14     mov     dword ptr [esp+14], edi
    0040142D   .  FF15 C0214000 call    dword ptr [<&MFC71.#2902_ATL::CS>;  MFC71.ATL::CSimpleStringT<wchar_t,1>::GetLength
    00401433   .  85C0          test    eax, eax
    00401435   .  7E 4E         jle     short 00401485
    00401437   >  6A 01         push    1                                ;  //由后面分析,可知其为mid函数的第二个参数,nCount
    00401439   .  8D043F        lea     eax, dword ptr [edi+edi]         ;  //相当于edi x 2
    0040143C   .  50            push    eax                              ;  //为mid第一个参数,nFirst,
    0040143D   .  8D4C24 20     lea     ecx, dword ptr [esp+20]
    00401441   .  51            push    ecx
    00401442   .  8BCE          mov     ecx, esi                         ;  //ECX为Mid函数的句柄,如string.mid(0,1)表示从string中从第0个字符开始,提取1个字符
    00401444   .  FF15 BC214000 call    dword ptr [<&MFC71.#4109_ATL::CS>;  //由注释知为mid函数,其原型大概为CString Mid( int nFirst, int nCount ),再往回看,可知1为第二个参数,eax为第一个参数
    0040144A   .  8BC8          mov     ecx, eax
    0040144C   .  FF15 B8214000 call    dword ptr [<&MFC71.#876_ATL::CSi>;  MFC71._CIP<IMoniker,&IID_IMoniker>::operator IMoniker *
    00401452   .  50            push    eax                              ; ///eax即为上面mid函数得回的返回值
    00401453   .  FF15 B0224000 call    dword ptr [<&MSVCR71.atoi>]      ; \//atoi 函数,int atoi(const char *nptr); 即把字符指针转换为整数,返回其转换后的值
    00401459   .  83C4 04       add     esp, 4
    0040145C   .  8D4C24 18     lea     ecx, dword ptr [esp+18]
    00401460   .  8BE8          mov     ebp, eax                         ;  //eax即为上面mid函数得回的返回值
    00401462   .  FF15 68204000 call    dword ptr [<&MFC71.#578_ATL::CSt>;  MFC71.ATL::CSimpleStringT<char,1>::~CSimpleStringT<char,1>
    00401468   .  8B5C24 14     mov     ebx, dword ptr [esp+14]
    0040146C   .  03DD          add     ebx, ebp                         ;  //有上面分析可知,ebp即为mid函数的返回值
    0040146E   .  8BCE          mov     ecx, esi                         ;  //ESI为假SERIAL 5705312,由后面分析可知,赋给ecx是为了得到它的长度
    00401470   .  895C24 14     mov     dword ptr [esp+14], ebx          ;  //从00401468,0040146C两行可以知道,ebx为ebx+dword ptr [esp+14]的值,在从本句,可知其为一个累加
    00401474   .  47            inc     edi                              ;  //edi加1,可以推测edi为控制累加次数
    00401475   .  FF15 C0214000 call    dword ptr [<&MFC71.#2902_ATL::CS>;  //得到假SERIAL 5705312的长度,跟进去知道其用到ecx
    0040147B   .  3BF8          cmp     edi, eax                         ;  //EDI 与 假SERIAL 570531的长度比较,如果小于假SERIAL长度,就跳
    0040147D   .^ 7C B8         jl      short 00401437                   ;  //从这个JL可推知,这是一个循环,循环以与假码长度的比较为结束,得到累加值赋给ptr [esp+14]
    0040147F   .  8B6C24 1C     mov     ebp, dword ptr [esp+1C]          ;  //由信息窗口可知ptr[esp+1c]为地址0013FEF8,再由右下角堆栈串口可知0013FEF8为我们输入的假NAME:zenghw
    00401483   .  33FF          xor     edi, edi                         ;  //edi清0
    00401485   >  6A 01         push    1
    00401487   .  57            push    edi
    00401488   .  8D5424 2C     lea     edx, dword ptr [esp+2C]
    0040148C   .  52            push    edx
    0040148D   .  8BCE          mov     ecx, esi                         ;  //有上面的分析或从堆栈窗口可知esi为假SERIAL:5705312
    0040148F   .  FF15 BC214000 call    dword ptr [<&MFC71.#4109_ATL::CS>;  //仍旧为mid函数,由参数可知为SERIAL.MID(0,1)
    00401495   .  BB 01000000   mov     ebx, 1
    0040149A   .  68 8C264000   push    0040268C                         ;  5
    0040149F   .  8BC8          mov     ecx, eax
    004014A1   .  897C24 34     mov     dword ptr [esp+34], edi
    004014A5   .  895C24 1C     mov     dword ptr [esp+1C], ebx
    004014A9   .  FF15 84204000 call    dword ptr [<&MFC71.#1482_ATL::CS>;  //跟进去看看,可知为为字符SERIAL.MID(0,1)与‘5’比较,返回值为eax.
    004014AF   .  85C0          test    eax, eax                         ;  //eax即为返回的比较是否相等的标记位,以上程序意思为取假SERAL的第一位,是否=="5"
    004014B1   .  75 64         jnz     short 00401517                   ;  //不等则跳向失败
    004014B3   .  6A 02         push    2
    004014B5   .  6A 04         push    4
    004014B7   .  8D4424 28     lea     eax, dword ptr [esp+28]
    004014BB   .  50            push    eax
    004014BC   .  8BCE          mov     ecx, esi
    004014BE   .  FF15 BC214000 call    dword ptr [<&MFC71.#4109_ATL::CS>;  MFC71.ATL::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char> > >::Mid
    004014C4   .  895C24 30     mov     dword ptr [esp+30], ebx
    004014C8   .  BB 03000000   mov     ebx, 3
    004014CD   .  68 88264000   push    00402688                         ;  31
    004014D2   .  8BC8          mov     ecx, eax
    004014D4   .  895C24 1C     mov     dword ptr [esp+1C], ebx
    004014D8   .  FF15 84204000 call    dword ptr [<&MFC71.#1482_ATL::CS>;  MFC71.ATL::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char> > >::Compare
    004014DE   .  85C0          test    eax, eax                         ;  //同样道理,以上程序意思为取假SERAL的第4,5两位,是否=="31'"
    004014E0   .  75 35         jnz     short 00401517                   ;  //不等则跳向失败
    004014E2   .  6A 01         push    1
    004014E4   .  6A 01         push    1
    004014E6   .  8D4C24 24     lea     ecx, dword ptr [esp+24]
    004014EA   .  51            push    ecx
    004014EB   .  8BCE          mov     ecx, esi
    004014ED   .  FF15 BC214000 call    dword ptr [<&MFC71.#4109_ATL::CS>;  MFC71.ATL::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char> > >::Mid
    004014F3   .  8BC8          mov     ecx, eax
    004014F5   .  BB 07000000   mov     ebx, 7
    004014FA   .  FF15 B8214000 call    dword ptr [<&MFC71.#876_ATL::CSi>;  MFC71._CIP<IMoniker,&IID_IMoniker>::operator IMoniker *
    00401500   .  50            push    eax                              ; /s
    00401501   .  FF15 B0224000 call    dword ptr [<&MSVCR71.atoi>]      ; \//同样分析,以上程序意思为:取假SERIAL:5705312的第一位(即为7),并atoi转换为整数,由此函数还可知,SERIAL中需为数字,因为如果为字母的话,经函数转换会为0
    00401507   .  8B4C24 18     mov     ecx, dword ptr [esp+18]          ;  //ptr [esp+18]即为刚刚那个循环中计算出来的累加值
    0040150B   .  83C4 04       add     esp, 4
    0040150E   .  3BC8          cmp     ecx, eax                         ;  //把其累加值和假SERIAL的第一位比较
    00401510   .  C64424 13 00  mov     byte ptr [esp+13], 0
    00401515   .  74 05         je      short 0040151C                   ;  //上面的比较中,相等则跳
    00401517   >  C64424 13 01  mov     byte ptr [esp+13], 1
    0040151C   >  F6C3 04       test    bl, 4                            ;  //为什么要test bl,4我搞不清楚,请知道的解释下下面这一小段代码!
    0040151F   .  74 0D         je      short 0040152E
    00401521   .  8D4C24 1C     lea     ecx, dword ptr [esp+1C]
    00401525   .  83E3 FB       and     ebx, FFFFFFFB
    00401528   .  FF15 68204000 call    dword ptr [<&MFC71.#578_ATL::CSt>;  MFC71.ATL::CSimpleStringT<char,1>::~CSimpleStringT<char,1>
    0040152E   >  F6C3 02       test    bl, 2
    00401531   .  74 0D         je      short 00401540
    00401533   .  8D4C24 20     lea     ecx, dword ptr [esp+20]
    00401537   .  83E3 FD       and     ebx, FFFFFFFD
    0040153A   .  FF15 68204000 call    dword ptr [<&MFC71.#578_ATL::CSt>;  MFC71.ATL::CSimpleStringT<char,1>::~CSimpleStringT<char,1>
    00401540   >  F6C3 01       test    bl, 1
    00401543   .  C74424 30 FFF>mov     dword ptr [esp+30], -1
    0040154B   .  5B            pop     ebx
    0040154C   .  74 0A         je      short 00401558
    0040154E   .  8D4C24 20     lea     ecx, dword ptr [esp+20]
    00401552   .  FF15 68204000 call    dword ptr [<&MFC71.#578_ATL::CSt>;  //以上代码为对释放字符串
    00401558   >  8A4424 0F     mov     al, byte ptr [esp+F]
    0040155C   .  84C0          test    al, al
    0040155E   .  57            push    edi
    0040155F   .  74 08         je      short 00401569
    00401561   .  57            push    edi
    00401562   >  68 60264000   push    00402660                         ;  name or serial is wrong,try again !
    00401567   .  EB 21         jmp     short 0040158A
    00401569   >  68 58264000   push    00402658                         ;  zeng
    0040156E   .  8BCD          mov     ecx, ebp
    00401570   .  FF15 B4214000 call    dword ptr [<&MFC71.#2272_ATL::CS>;  //Find函数 int Find( LPCTSTR lpszSub ) ,在某字符串中查找另一字符串,并返回在第几位找到
    00401576   .  85C0          test    eax, eax                         ;  //eax即为返回值,即在第几位找到其字符串
    00401578   .  57            push    edi
    00401579   .  57            push    edi
    0040157A   .^ 7E E6         jle     short 00401562                   ;  //没找到的话,即跳向失败
    0040157C   .  68 10264000   push    00402610                         ;  congratulation !   correct serial number,good job,do next one?   :)
    00401581   .  EB 07         jmp     short 0040158A
    00401583   >  57            push    edi
    00401584   .  57            push    edi
    00401585   .  68 F4254000   push    004025F4                         ;  name or serial is too short
    0040158A   >  E8 07030000   call    <jmp.&MFC71.#1123_AfxMessageBox>
    0040158F   .  8B4C24 24     mov     ecx, dword ptr [esp+24]
    00401593   .  5F            pop     edi
    00401594   .  5E            pop     esi
    00401595   .  5D            pop     ebp
    00401596   .  64:890D 00000>mov     dword ptr fs:[0], ecx
    0040159D   .  83C4 24       add     esp, 24
    004015A0   .  C3            retn

    再贴上程序中对应代码:
      UpdateData(true);
      if(m_sName.GetLength() < 6 || m_sSerial.GetLength() < 6)
      {
        AfxMessageBox(_T("NAME or SERIAL is too short"));
        return;
      }
      int isum=0,itemp1,itemp2,itemp3;
      for(int i=0;i<m_sSerial.GetLength();i++)
      {
        itemp1 = atoi(m_sSerial.Mid(2*i,1));
        isum += itemp1;
      }
      if(m_sSerial.Mid(0,1) != "5" || m_sSerial.Mid(4,2) != "31" || isum != atoi(m_sSerial.Mid(1,1)))
      {
        AfxMessageBox(_T("NAME or Serial is wrong,Try again !"));
        return;
      }
      if(m_sName.Find("ZENG")>0 )//&& m_sSerial.Mid(3,1) ==itemp1)
      {
        AfxMessageBox(_T("CONGRATULATION !   CORRECT SERIAL NUMBER,GOOD JOB,DO NEXT ONE?   :)"));

      }else
      {
        AfxMessageBox(_T("NAME or Serial is wrong,Try again !"));
      }
        return;


    CRECKME 1较CRECKME 0有一点不同就是代码中已经没有出现明码,但是算法仍然不强,且没有防爆破,字符串提醒无加密容易被下断等缺点。

    ------------------------------------------------------------------------------------------------------------------------------------
    继续贴CRECKME 2,
    1,用插件查看是否有敏感字符串可下断,无。  ctrl+N 查看,MFC函数太多,对用bpx getwindowitem等敏感API函数下段并无作用。
    2,消息下段。F9运行程序,出现注册对话框,切回OllyDbg,点快捷菜单中的W,出现控件窗口,选择到“确定”行--->右键--->选择message breakpoint on classproc--->messages中选择到202 WM_LBOTTONUP,确定。   在注册对话框中输入假NAME:zenghw ,假SERIAL: 5705312,点确定,此时OllyDbg被中断,按ALT+M,调出内存窗口,选择到如下一行,并按下F2,
    然后再按F9让程序运行,可见程序运行后又马上中断在CRECKME中,按F8单步走,但是否真正运行在CRECKME 2空间中,如不是,再调出内存窗口,重新下断点,按F9运行,如此反复,知道单步走时的确运行在CRECKME 2空间中,这个时候仔细查找,可以发现已到校验代码处,注意那个函数updatadate(当然了,别人程序不一定有这个函数)。
    注:用消息断点跟TRACE跟踪跟方便,请参考http://bbs.pediy.com/showthread.php?t=67866&highlight=OLLYDBG
    3,代码分析:
    00401581  |.  6A 01         push    1
    00401583  |.  8BCB          mov     ecx, ebx
    00401585  |.  AA            stos    byte ptr es:[edi]
    00401586  |.  E8 CB030000   call    <jmp.&MFC71.#6236_CWnd::Upd>
    0040158B  |.  8D4B 74       lea     ecx, dword ptr [ebx+74]     ;  //把有信息窗口可知ptr[ebx+74] = 0013FEF8,由堆栈窗口可知为假NAME:zenghw 赋给ecx
    0040158E  |.  FF15 9C314000 call    dword ptr [<&MFC71.#876_ATL>;  //把ecx里面的内容赋给eax
    00401594  |.  8D5424 10     lea     edx, dword ptr [esp+10]
    00401598  |>  8A08          /mov     cl, byte ptr [eax]         ;  //eax派上用场了
    0040159A  |.  40            |inc     eax
    0040159B  |.  880A          |mov     byte ptr [edx], cl         ;  //ptr [edx] 初地址为0013F788,注意,后面会用到
    0040159D  |.  42            |inc     edx
    0040159E  |.  84C9          |test    cl, cl                     ;  //当跳转了到字符串末尾时,为0x00,下面语句就不满足
    004015A0  |.^ 75 F6         \jnz     short 00401598             ;  //上面这个循环,为把假NAME:zenghw 字符串赋到ptr[edx]地址
    004015A2  |.  8A4424 16     mov     al, byte ptr [esp+16]       ;  //由信息窗口可以看出ptr[esp+16]为地址 0013F78E,由上面循环语句可知此为字符串里的第6个字节(从0字节算起)
    004015A6  |.  84C0          test    al, al
    004015A8  |.  75 50         jnz     short 004015FA              ;  //如果第6个字节不等于0的话,则跳向失败
    004015AA  |.  8A5424 15     mov     dl, byte ptr [esp+15]       ;  //字符串的第5个字节
    004015AE  |.  84D2          test    dl, dl
    004015B0  |.  74 48         je      short 004015FA              ;  //如果第5个字节==0的话,则跳向失败
    004015B2  |.  8B43 78       mov     eax, dword ptr [ebx+78]     ;  //由信息窗口知 此地址值为0x00570E60,即为十进制5705312,为假SERIAL
    004015B5  |.  3D A0860100   cmp     eax, 186A0                  ;  与十进制100000比较
    004015BA  |.  7C 3E         jl      short 004015FA              ;  //如果小于则跳向失败
    004015BC  |.  0FBE7424 12   movsx   esi, byte ptr [esp+12]      ;  //假NAME :zenghw 的第2位 n
    004015C1  |.  0FBE4C24 11   movsx   ecx, byte ptr [esp+11]      ;  //假NAME :zenghw 的第1位 e
    004015C6  |.  0FBE7C24 14   movsx   edi, byte ptr [esp+14]      ;  //假NAME :zenghw 的第4位 h
    004015CB  |.  03CE          add     ecx, esi                    ;  //第2位 加 上第1位,结果放在ecx中
    004015CD  |.  0FBE7424 10   movsx   esi, byte ptr [esp+10]      ;  //假NAME :zenghw 的第0位 z
    004015D2  |.  03CE          add     ecx, esi                    ;  //把上面加出的结果ecx再加上第0位
    004015D4  |.  0FBE7424 13   movsx   esi, byte ptr [esp+13]      ;  //假NAME :zenghw 的第3位 g
    004015D9  |.  0FBED2        movsx   edx, dl                     ;  //由004015AA行可知,dl即为/假NAME :zenghw 的第5位 w
    004015DC  |.  03F7          add     esi, edi                    ;  //第4位加第3位,结果放在 esi中
    004015DE  |.  03F2          add     esi, edx                    ;  //把上行相加的结果再加上第5位
    004015E0  |.  99            cdq                                 ;  //扩展,把edx扩展为eax的高位,也就是说变为64位
    004015E1  |.  BF E8030000   mov     edi, 3E8                    ;  //0X3E8即为1000
    004015E6  |.  F7FF          idiv    edi                         ;  //edx eax /edi  注意右边寄存器的变化,此时edx eax为00570E60,即为假SERIAL:5705312
    004015E8  |.  3BC8          cmp     ecx, eax                    ;  //除完的结果,商放在eax,余数放在edx,这里把除得的商与ecx比较。往回看,ecx即为假NAME第0,1,2位之和,这里显示为0X14D,即为333,把SERIAL改为333312(因为上面是/1000的商,所以333后面只跟3位),重来
    004015EA  |.  75 0E         jnz     short 004015FA
    004015EC  |.  3BF2          cmp     esi, edx                    ;  //余数与esi比较,esi即为上面假NAME 3,4,5位的和,这里显示值为 0x146,即326,因此把SERIAL改为333326,重来,测试通过
    004015EE  |.  75 0A         jnz     short 004015FA
    004015F0  |.  8B03          mov     eax, dword ptr [ebx]
    004015F2  |.  8BCB          mov     ecx, ebx
    004015F4  |.  FF90 54010000 call    dword ptr [eax+154]
    004015FA  |>  8B8C24 940000>mov     ecx, dword ptr [esp+94]
    00401601  |.  E8 43040000   call    00401A49
    00401606  |.  5F            pop     edi
    00401607  |.  5E            pop     esi
    00401608  |.  5B            pop     ebx
    00401609  |.  8BE5          mov     esp, ebp
    0040160B  |.  5D            pop     ebp
    0040160C  \.  C3            retn

    附上VC上校验的源代码:
      char cTmep[128] = {0xFF};
      int iCount1 =0,iCount2 =0;
      UpdateData(true);
      int i =0;
                  _tcscpy(cTmep, m_Name);  
                  if(cTmep[6] != 0x00 || cTmep[5] == 0x00) //用于判断长度,故意不用你API的GETLENGTH
         return;
      if(m_Serial< 100000)//用于判断长度
        return;
      for(i=0;i< 3;i++)
        iCount1 += cTmep;  
      for(i= 3;i< 6;i++)
        iCount2 += cTmep;  
      if(iCount1 == m_Serial/1000 && iCount2 == (m_Serial % 1000))//随便算法
      {
        OnOK();
      }
      else
        return;



    CRECKME 2较CRECKME 1有一点不同就是代码中不用字符串提醒,但是算法仍然偏简单,且没有防爆破,在004015E8 行等处直接用jmp语句或nop语句或更改为jz,都可以直接爆破。


    ------------------------------------------------------------------------------------------------------------------------------------
    继续贴CRECKME 3,

    CRECKME 3 较CRECKME 2只是在内存上多做了校验以防止爆破,算法依然简单,因此,在这里就不多讲解了,主要实践下ollydbg的万能断点的下法!
    1,用ollydbg加载CRECKME 3.按F9 运行,输入NAME:zenghw,SERIAL:5705312,先不点确定.
    2,切回ollydbg,按快捷键ALT+E,在NAME那列随便找到USER32行,选中,按快捷键CTRL+N;
    3,选中TranslateMessage行。如下图,按SHIFT F4,如下图设置:

    4,切至注册窗口,按“确定”,此时ollydbg中断。
    5,切回ollydbg,按快捷键ALT+M打开内存窗口,选中第一行,按CTRL+B打开搜索窗口,在ASCILL行输入NAME或SERIAL内容,我这里输入5705312,点确定,会搜索到5705312在内存中的位置,选中5705312,右键,选择break point -->memory access,按F9运行,ollydbg会马上再被中断6,此时右边寄存器窗口可看到5705312,按F8单步走,再一直按CTRL+F9知道程序跑回CHECK ME的领空,此时往上找一点点即为验证序列号的代码。

    附上源代码:
      char cTmep[128] = {0xFF};
      int iCount1 =2,iCount2 =3;
      UpdateData(true);
      int i =0;
      _tcscpy(cTmep, m_Name);  
                   for(int i=0;i<7;i++)
                  {
         if(cTmep == _T('0'))  
        return;
                    }
                    if(cTmep[6] != 0x00 || cTmep[5] == 0x00) //用于判断长度,故意不用你API的GETLENGTH
         return;
      if(m_Serial< 100000)
        return;
      for(i=0;i< 3;i++)
        iCount1 *= cTmep;  
      for(i= 3;i< 5;i++)
        iCount2 *= cTmep;  
      if(iCount1 == m_Serial/100000 && iCount2 == (m_Serial % 100000))
      {
        OnOK();
      }
      else
        return;
    关于防爆破代码的解析由于CRECKME 4也有其内容,因此放在CRECKME 4一起讲。
    CRECKME 4修正版的注册码有人解析出来了吗? 期盼中!






    运行所需的 dll在我的网盘里 不能上传 地址
    http://u.115.com/file/f3886ab9be
    运行所需的dlldll.rar

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?加入我们

    x

    评分

    参与人数 1威望 +20 收起 理由
    月之精灵 + 20 您的贴子很精彩,希望能再次分享!

    查看全部评分

    PYG19周年生日快乐!

    该用户从未签到

    发表于 2010-8-3 18:05:42 | 显示全部楼层
    只玩到CRECKME 3.rar ..5555555555555
    PYG19周年生日快乐!
  • TA的每日心情
    开心
    昨天 10:45
  • 签到天数: 353 天

    [LV.8]以坛为家I

    发表于 2010-8-7 12:46:55 | 显示全部楼层
    呵呵!!下来试试,看能到几级!
    PYG19周年生日快乐!
  • TA的每日心情
    郁闷
    2022-10-26 21:54
  • 签到天数: 5 天

    [LV.2]偶尔看看I

    发表于 2011-5-19 21:42:09 | 显示全部楼层
    加密与解密 第三版买回来N久了,有一些看不懂就没看了
    PYG19周年生日快乐!
  • TA的每日心情
    开心
    2017-5-9 01:01
  • 签到天数: 8 天

    [LV.3]偶尔看看II

    发表于 2011-6-2 07:34:49 | 显示全部楼层
    同样下载下来看看,待有时间再破。
    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表