Delphi程序破解分析心得-例程[反汇编练习] 160个CrackMe之79(fireworx.11)
本帖最后由 pk8900 于 2018-1-13 22:44 编辑经过几个月的断断续续的研究 【适合破解新手的160个crackme练手】已经进行到第80个,正好是一半,现在的速度已经比开始时快了好几倍,这期间C++的语法和应用也熟练了不少,今天用这个例程来介绍一下Delphi程序快速分析定位关键代码找出算法的一点心得,也可以说是相关工具综合应用的心得。
【crackme简介】
下载地址:http://pan.baidu.com/share/link?shareid=541269&uk=4146939145
Delphi编写,有壳,是一个用户名+序列号验证方式,界面两个文本框,一个底图。
【初试】在Crackme中输入任意用户名和序列号,没有按钮,点任何地方没有反应,脱壳就不介绍了,专用工具或调试器脱都行。
分析工具:Ldr + IDA + X64dbg
【crackme截图】
【算法分析过程】
这个fireworx是一个系列的Crackme,都是Delphi语言编写,这个079,应该是系统里比较典型的一个例子。综合运用Ldr + IDA + X64dbg三大杀器,将会快速搞定他。
【步骤1:Ldr静态分析】:将程序拖入Crackme中,显示为Delphi-4语言。
Forms(f5)页面,Form选项下,程序总共有两个窗体,双击Form1,我们看到了注册窗口,Form2应该是注册成功窗口了,看起来有点恐怖,右下角有succed字样,应该是注册成功会出现这个窗口。在Form1中找到唯一的事件Unit1.TForm1.Image1Click,看来关键代码就在这里了。
还有三个标签,应该被设置了隐藏属性,运行界面上看不到。查看窗体代码方法:选Forms(f5)页面,Text选项后双击来查看窗体属性代码, object Label1: TLabel。。。Caption = 'Wrong Serial' object Label2: TLabel。。。 Caption = 'VL -3585903..46119.-208490.'object Label3: TLabel。。。 Caption = 'VL -',看来这些标签应该是作者编写时用来测试的,在发布的时修将属性Visble设为False了。VL -3585903..46119.-208490.看起来像注册码,尝试无效,'Wrong Serial'为注册错误提示,因为是标签的属性文字,在调试器里可能搜索不到。还是看一下关键事件Unit1.TForm1.Image1Click代码吧,点击CodeViewer(F6)窗口下方的“Src”按钮,SourceCode(F10)页会显示反编译的Delphi代码,将代码复制到NotePad++中,对流程进行分析:
EAX := Name;
EAX := Length(Name);
if (EAX{Length(Name)} >= 0) then
begin//2
//00455545
EAX := EAX + 1;//EAX
lvar_18 := EAX;
EDI := 0;
for lvar_18 := 0 todo
begin//3
//0045554B
ESI := EDI;
ESI := ESI Shr 14;//EDI Div 16384
ESI := ESI Xor EDI;//EDI Shr 14 Xor 0
ESI := ESI + $2F21A0{3088800};//ESI
ESI := ESI + $795CE{497102};//ESI
EAX := ESI;//ESI
lvar_8 := IntToStr(ESI);
EAX := ESI;//ESI
ECX := $49{73};
EAX := EAX Div ECX;//(ESI) Div $49{73}
EAX := EAX - $BBA{3002};//EAX
lvar_14 := EAX;
EAX := lvar_14;
lvar_C := IntToStr(lvar_14);
EAX := ESI;//ESI
ECX := $130{304};
EAX := EAX Div ECX;//(ESI) Div $130{304}
EAX := EAX Shl 2;//(ESI) Div $130{304} * 4
EAX := EAX + EAX * 4;
EAX := EAX Xor lvar_14;//EAX + EAX * 4 Xor lvar_14
EAX := EAX + $10F{271};//EAX
EAX := EAX - 0;//EAX
ESI := EAX;//EAX
EAX := ESI;//EAX
lvar_10 := IntToStr(EAX);
EAX := Edit2;
lvar_1C := Edit2.GetText{Caption};
EAX := lvar_1C;
EAX := Label3;
lvar_24 := Label3.GetText{Caption};
EDX := 8;
lvar_20 := lvar_24 + ' -' + lvar_8 + '..' + lvar_C + '.-' + lvar_10 + '.';
EDX := lvar_20;
if (lvar_1C{EAX} = lvar_20) then
begin//4
//00455604
EAX := Edit2;
lvar_1C := Edit2.GetText{Caption};
EAX := lvar_1C;
EAX := Label2;
lvar_20 := Label2.GetText{Caption};
EDX := lvar_20;
if (lvar_1C{EAX} = lvar_20) then
begin//5
//0045562F
EAX := Label1;
lvar_1C := Label1.GetText{Caption};
EAX := lvar_1C;
ShowMessage(lvar_1C);
end//5
经分析发现,Edit1(用户名)文本框未被引用,也就是说这个文本框与注册算法无关,最终注册码是 lvar_20 := lvar_24 + ' -' + lvar_8 + '..' + lvar_C + '.-' + lvar_10 + '.';这些字符连接组成最终注册码,而lvar_24 := Label3.GetText{Caption};,也就是lvar_24=“VL -”,而 lvar_8 、lvar_C 、 lvar_10是上面的算法中生成的,这里代码看来有些乱,还是看看IDA中分析的结果。
【步骤2:IDA静态分析】
在IDA中打开程序,按G转到Unit1.TForm1.Image1Click事件地址:00455504,F5分析伪代码,在这段代码中找到关键算法部分:
v4 = (v3 ^ (v3 >> 14)) + 3585902;
Sysutils::IntToStr(v4);
v18 = v4 / 73 - 3002;
Sysutils::IntToStr(v18);
Sysutils::IntToStr((v18 ^ 20 * (v4 / 304)) + 271);
TControl::GetText(*(TControl **)(v1 + 716));
v5 = v16;
TControl::GetText(*(TControl **)(v1 + 728));
System::__linkproc__ LStrCatN(&v15, 8, v6, &str___, v21, &str___, v20, &str___, v19, &str___2);
System::__linkproc__ LStrCmp(v5, v15);
根据IDA中的伪代码可以分析出:
行01:v4<即lvar_8> = (v3<循环变量> ^ (v3 >> 14)) + 3585902;
行03:v18<即lvar_C> = v4 / 73 - 3002;
行05:lvar_10=(v18 ^ 20 * (v4 / 304)) + 271;
不得不说,IDA真的很强大,通过对LDR和IDA中的代码进行分析,加上在X64DBG中的动态验证:程序的循环流程是:取TForm1的Name属性('Form1')字符串长度为循环次数,计数器从0开始循环到5,最后一个循环生成的值拼接后为真正注册码。
00455535 mov eax,dword ptr ;TForm1.Name:TComponentName
00455538 call @LStrLen
0045553D test eax,eax
0045553F> jl 00455660
00455545 inc eax
00455546 mov dword ptr ,eax
eax取TForm1.Name后@LStrLen,得到长度,inc eax:从1开始循环。
【步骤3:X64DBG动态验证】
动态验证的过程就不详写了,提供一个窍门,可以在LDR中的Tools菜单下,点击 MAP Generator生成MAP文件,然后在X64DBG中用插件导入。这样代码会一目了然。
附添加MAP数据后的对比图:
未导入MAP文件:
导入MAP文件后:
这个CRACKME的算法就分析完成了,注册机的C++代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include <string>
using namespace std;
void main()
{
string serial = "VL -";
long v4 = 0;
long v18 = 10;
long v10 = 0;
for (int x = 0; x <= 5; x++)
{
v4 = (x ^ (x >> 0xE)) + 0x36B76E;
v18 = v4 / 0x49 - 0xBBA;
v10 = (v18 ^((v4 / 304)*20)) + 0x10F;
}
serial = serial + " -" + to_string(v4) + ".." + to_string(v18) + ".-" + to_string(v10) + ".";
cout << "your serial is:" << serial << endl;
system("pause");
}
注册码为:VL - -3585907..46120.-208483.
对于这一系列CRACKME(071-080)都适用于本方法快速破解,当然也同样用于其它DELPHI(代码无加密混淆)的程序,教程未尽之处或不对的地方,还请路过的大神指正。
pk8900 发表于 2019-3-29 21:16
按第二个图的步骤
你的第二个步骤我这个软件出来是这样的 在窗体这一栏里面 没有登陆需要输入序列号、ID和KEY的界面
软件登录的时候是这样的是不是有什么地方做的不对的这个是软件的链接 请大佬指点 中猪佩奇 发表于 2019-3-31 08:52
你的第二个步骤我这个软件出来是这样的 在窗体这一栏里面 没有登陆需要输入序列号、ID和KEY的界面
软件 ...
好像不是一个软件吧 给你感觉好厉害 教程详尽明了,学习了 没办法。还是不会 学习中 谢谢 这个自我感觉新手挺有难度的 学习了,谢谢分享 很详细,学习一下 高深了,很有收获 Delphi的……大佬厉害