前几天在大侠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。