首页
社区
课程
招聘
实例分析穷举破解法在crackme中的运用
发表于: 2009-9-7 14:17 15646

实例分析穷举破解法在crackme中的运用

2009-9-7 14:17
15646

前几天在大侠jackozoo的热身版贴里看到前辈们在讨论穷举破解法(算法比较复杂的情况下采用),感觉很有意思。为了尽快为我所用,特对此详细研究了一番,写下这篇文章放到看雪这里感觉很放心,也便于日后参考。
有两种方法,海风月影大侠采用了dll注入的方法,而ccfer是用的exe文件,在编程调试过程中深感ccfer的方法更能学到东西。
我用了delphi来实现ccfer的方法,编程工具无所谓哪种都可以只要达到目标更省事就行。下面贴出我的关键代码,并详细说明。
将jackozoo的crackme程序ZooCMa.exe与qiongju.exe放同一个文件夹,运行截图一张。

总体思路:就是将ZooCMa.exe加载到本程序的进程空间,并对其某些特殊地址处的指令和数据进行修改,完全模拟crackme运行时所需的环境,从而在穷举程序中可以调用本进程空间内的crackme的关键算法call,由其返回值判断我们假设的注册码是否正确,起到利用crackme的算法call为我所用的效果。
通过详细调试crackme我们可以知道在算法call中会跳出来访问一些特殊的地址和数据,如果我们不加以修改,穷举程序将无法运行。前面讲到的海风月影大侠的dll注入方法,就不用考虑这些,因为我们的dll是注入crackme的进程,减少了很多限制,而这里恰好相反,是crackme进入到我们的进程空间,所以要为我们所用,必须模拟其运行的环境。
主要要修改原来402BE6处的地址0040c000和0040c000地址开始长度为ec个字节的数据,都只要加上一个off:=Base-$400000即可。

procedure TForm1.FormCreate(Sender: TObject);
var
    dwOldProtect:pointer; i:byte;
    x,y:LPDWORD;
    off:DWORD;
    mbi_thunk:TMemoryBasicInformation;
begin
     dwOldProtect:=Nil;
     Base:=LoadLibraryEx ('ZooCMa.exe', 0,DONT_RESOLVE_DLL_REFERENCES);
     x:= LPDWORD(Base+$2BE6); //定位要修改的地址
     off:=Base-$400000;         //要增加的偏移量
      if Base  <> 0 then
         begin
          VirtualQuery(pointer(Base),mbi_thunk, sizeof(TMemoryBasicInformation));
          if VirtualProtect(pointer(Base),$9000,PAGE_EXECUTE_READWRITE,mbi_thunk.Protect) then
            begin  //修改内存的属性,为修改环境数据做准备
                x^:=x^+off; //
                y:=LPDWORD(x^);
                 for i := 0 to $3b do  //
                    begin
                       y^:=y^+off;
                       inc(y);
                    end;
                VirtualProtect(pointer(Base),$3000,mbi_thunk.Protect,dwOldProtect);
            end;  //恢复内存的属性
         end;

end;


function check(name,key: pchar) :dword;
var nameaddr,regaddr,rukoucs,keycalladdr:dword;
begin
      nameaddr:= Base + $227B0; //给crackme的算法call准备运行参数
      regaddr := Base + $22814;
      rukoucs:= Base + $F168;
      keycalladdr:= Base + $2B80;
      StrCopy(pchar(nameaddr), name);
      StrCopy(pchar(regaddr), key);
      Result:=0;
     asm
          xor ebx, ebx;
          mov ecx, nameaddr;
          push rukoucs;
          push offset @@jmpout;
          push keycalladdr;  //进入crackme的算法call
          ret;
     @@jmpout:         //又跳出来继续执行
          mov Result, eax;
      end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var name,key:string;
     m,n,k:char;
begin          //演示用的暴力破解算法,非常粗糙穷举较慢
     name:=trim(Edit1.Text);
     n:='z';
     for m:='z' downto 'a' do
        begin
           key:=m+'jk'+n;
           if check(pchar(name),pchar(key))=1 then begin Edit2.text:=key; exit; end;
           for n:='z' downto 'a' do
             begin
               key:=m+'jk'+n;
               if check(pchar(name),pchar(key))=1 then begin Edit2.text:=key; exit; end;
               for k:='z' downto 'a' do
                 begin
                   key:=m+'jk'+n+k;
                   if check(pchar(name),pchar(key))=1 then begin Edit2.text:=key; exit; end;
                 end;
             end;
             n:='z';
        end;
end;
总的来说穷举破解是没有办法的办法,需要在调试crackme的基础上充分了解其运行流程,熟知其运行所需的环境,尤其是第二种方法,否则很难调试成功。
在此提供源码和例子程序,如有错误,请大家批评指正。感谢文中提到的前辈,还有jackozoo的用vm保护的crackme。

                                                 天易love
                                                                         2009-9-7


[培训]科锐逆向工程师培训第53期2025年7月8日开班!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (24)
雪    币: 48
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
强占沙发!
感谢天易大侠的教程,虽然暂时还看不懂注入、劫持等方法。
2009-9-7 15:12
0
雪    币: 418
活跃值: (63)
能力值: ( LV12,RANK:260 )
在线值:
发帖
回帖
粉丝
3
膜拜啊。。学习中。。
2009-9-7 15:19
0
雪    币: 56
活跃值: (25)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
学习学习~~~
2009-9-7 15:23
0
雪    币: 418
活跃值: (63)
能力值: ( LV12,RANK:260 )
在线值:
发帖
回帖
粉丝
5
能否出一个VC++版本的,小弟惭愧,对dephi实在是一窍不通
2009-9-7 15:36
0
雪    币: 433
活跃值: (1895)
能力值: ( LV17,RANK:1820 )
在线值:
发帖
回帖
粉丝
6
不懂D语言,如果能给份汇编代码那再好不过了,相信来这里的大多学过汇编。
2009-9-7 16:01
0
雪    币: 2015
活跃值: (902)
能力值: ( LV12,RANK:1000 )
在线值:
发帖
回帖
粉丝
7
http://bbs.pediy.com/showthread.php?t=97046&page=4
这个页面有c语言代码是ccfer大侠的作品,大家一定能看懂。delphi编译之后,用od调试,在核心代码处也是很精炼的,抠出来就是汇编版本了。我只是给前辈的代码做了一下注释,相信大家都能看懂。
2009-9-7 20:52
0
雪    币: 296
活跃值: (89)
能力值: ( LV15,RANK:340 )
在线值:
发帖
回帖
粉丝
8
支持一下。穷举确实是个好方法,不过要是配合一些密码设置的习惯去猜解,速度会更快
(比如出现连续两个相同的字符概率较小,可以在for循环时先跳过等。当然标准点的注册码,准备个字典也不坏)
2009-9-8 21:10
0
雪    币: 8209
活跃值: (4559)
能力值: ( LV15,RANK:2473 )
在线值:
发帖
回帖
粉丝
9
不同意LS的说法,那不叫穷举
漏掉一个划不来,时间全浪费了
2009-9-8 21:35
0
雪    币: 296
活跃值: (89)
能力值: ( LV15,RANK:340 )
在线值:
发帖
回帖
粉丝
10
CM懂得不多,见笑了。
大部分CM里算出的注册码大都没规律,字典攻击并不可取。不过一般密码都是人设的,用社会工程学字典 比 一个小写字母表+数字的字典攻击成功的概率更大(至少用RainBow Table跑MD5是这样),另外一般从键盘左边的字母开始跑也比从a-z扫快。
2009-9-8 22:07
0
雪    币: 474
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
还好以前是OIer玩的是Pascal
看Delphi代码很轻松
谢谢楼主  收藏了
2009-9-10 12:18
0
雪    币: 119
活跃值: (10)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
12
天易大侠, "必须模拟其运行的环境。主要要修改原来402BE6处的地址0040c000和0040c000地址开始长度为ec个字节的数据,都只要加上一个off:=Base-$400000即可。" 这是基于什么原理呢?对于一般的CM如何构造这个环境呢?初学,百思不得其解,请教了。
2009-9-11 18:48
0
雪    币: 2015
活跃值: (902)
能力值: ( LV12,RANK:1000 )
在线值:
发帖
回帖
粉丝
13
这个vm保护的cm的特殊性决定的,你在借用它的call时,它并不是一直在这个call里,它还跳出来访问一些地址,而这些地址必须要重定位一下,因为是加载在你的进程里,而不是仍然是400000,要从加载后的base开始。
2009-9-11 21:22
0
雪    币: 119
活跃值: (10)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
14
首先谢谢天意Love的解疑。

    先后看了天意Love,ccfer,海风月影贴的穷举法的代码,看着不是很难,然后自己写个吧,发现还是有很多困惑的地方。终于仿照大牛们的代码写了一个,学习学习,感谢大家了。把学习成 果也贴出来,共同学习。
    myEasyCM是我写的一个简单的CM,在注册按钮单击后,先判断用户名和注册码的长度是否一致,然后调用一个函数判断注册码是否正确。注册码和用户名一样便正确,返回1。
    Exhaustive是仿照写的穷举的代码。穷举了aaaa...aaa 到 zzzz..zzz的所有数据,时间不容乐观。五位用户名针对本程序最长用时为1.515s, 六位的用时达到 38.869s,这还是只列举小写字母的情况,如果是数字加字母。。。时间就漫长的有些受不了了。。 看来穷举法也是有局限的,想要用好,必须对反编译非常的熟悉,找到技巧,不然也不是很可行。。
    海风月影的dl如何注入还没弄明白,继续学习中.. .. ..如何提高穷举的效率也在学习中 ...期待大牛们予以指导..
上传的附件:
2009-9-12 21:33
0
雪    币: 237
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
向天易love致敬
2009-9-12 22:58
0
雪    币: 129
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
看完好困。。。
high time to sleep
2009-9-16 00:06
0
雪    币: 119
活跃值: (10)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
17
有哪位大侠可以说下dll注入到crackme的进程是怎么实现的么?。。。
2009-9-18 21:53
0
雪    币: 388
活跃值: (25)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
18
向各位学习 一直摸索没有得到窍门 现在总算看到点曙光了
2009-9-23 19:52
0
雪    币: 1450
活跃值: (35)
能力值: (RANK:680 )
在线值:
发帖
回帖
粉丝
19
当将一个dll注射至目标进程空间时, dll的DllMain函数会被执行 . 在DllMain中调用穷举代码即可.
dll编写完后, 还需要编写一个将dll注射至目标进程的小程序, 一般使用远程线程的方式几十行代码就可以了.
相比于使用LoadLibraryEx加载CM exe镜像, dll穷举虽然操作麻烦点, 但是在编写dll过程中不用考虑重定位, 使得dll编写起来更方便.
2009-9-29 19:10
0
雪    币: 26
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
围观 学习一下
2009-9-29 22:03
0
雪    币: 290
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
你的crackme代码似乎这样写更好

  if( strlen(name) == strlen(serial) )
  {
    if( Register(name, serial) )
    {
      AfxMessageBox("success!");
    }
    else
    {
      AfxMessageBox("fail!");
    }
  }
  else
  AfxMessageBox("fail!");
2009-9-29 22:06
0
雪    币: 119
活跃值: (10)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
22
感谢jackozoo版主的答复,前些天改了个键盘钩子的代码,实现了,有些明白了。就是想办法让要破解的程序来执行Dll中的代码。似乎Strong OD有注入的这个功能吧?才学会用Strong OD,只是看到里面有注入一说.
2009-9-30 09:58
0
雪    币: 119
活跃值: (10)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
23
哦,谢谢芳草碧连!
开始的时候只是看着注入Dll好玩,写个超简单的CM,竟然没发现这么简单的代码写成这样了。这不判断长度就没啥用了么?呵呵!

原来的代码:

if( strlen(name) != strlen(serial) )
AfxMessageBox("fail!");

// 如果用户名和密码相等,则注册成功。
if( Register(name, serial) )
{
AfxMessageBox("success!");
}
else
{
AfxMessageBox("fail!");
}


或者 return了也成吧? 呵呵!
        if( strlen(name) != strlen(serial) )
        {
                AfxMessageBox("fail!");
                return;
        }
2009-9-30 10:03
0
雪    币: 194
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
开源吗?......
2009-9-30 12:54
0
雪    币: 81
活跃值: (40)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
天易
2011-12-10 10:28
0
游客
登录 | 注册 方可回帖
返回