逆向分析挑战
一. 行为分析
打开程序,无输入界面,菜单可选,内容只有file->exit,以及help->about,排除传统序列号验证方式,猜测是文件认证或者是网络认证方式。
图1-1
使用行为检测软件ProcessMonitor,观察行为,发现程序尝试开启运行目录下的CRAKEME3.KEY文件,应该是采取文件验证的方法进行验证;
图1-2
注意在寻找程序特殊行为时,应该掠过正常的dll加载等正常的程序文件行为,主要关注有特点的行为,例如路径是用户路径(桌面,文档等),文件名字具有明显特征(crack,注册等),结果为失败(没有注册文件,文件读取会以失败结束,这里我已经完成了初步工作,所以是成功);
利用010 16进制文件编辑器在桌面创建同名文件,进入反汇编工作。
二. 反汇编调试
首先利用peid确认程序无壳,使用onlydbg反汇编程序。一般我推荐先使用IDA Pro去了解程序框架,了解它基本结构后再使用动态调试工具,但是这里该程序是直接由汇编代码编译而成,程序结构在IDA Pro中并不明显,所以其基本结构可以使用onlydbg运行一遍的方法来掌握。
我们初步执行并使用动态调试方法确认程序逻辑,初步判断程序模块功能,如图2-1,2-2所示:
图2-1
图2-2
然后我们细读每一模块的汇编代码,搞清楚所有模块的关系和其具体功能,分析结果如图2-3所示:
图2-3 程序流程图
(图中所有选择是则顺序执行,不然就跳转到错误逻辑)
分析核心模块401037函数,其汇编代码如下:
图2-4 401037函数汇编代码
代码并不复杂,很容易分析逻辑并做还原:
由前面Readfile参数可以得到0x402008是存放我们文件内容的缓冲区,我们给它取名为input[],而0x4020f9则是该函数运行结果储存位置,我们取名为result,则该段汇编代码用c++逻辑实现为:
unsigned result = 0;
for(int i=0;i<14;i++)
{
input[i]=input[i]^(0x41+i);
result=result+input[i\];
}
三. 给出注册算法
首先我们确定注册文件位置和文件名分别是程序执行路径下以及”CRACKME3.KEY”
然后我们确定注册文件大小,它应该由18个字节的数据组成,前14个字节可以自由生成,而后4个字节则由我们上面恢复的算法产生,即可通过验证;
后面粘上注册机源码:
#include <iostream>
using namespace std;
int main()
{ unsigned input[14];
unsigned result = 0;
cout << "Hello !This is m6 hacked! Please create a hex file named CRACKME3.KEY in The execution directory! \n please enter the first fourteies bytes data: " << endl;
for(int i=0;i<14;i++)
{
scanf("%X",&input[i]);
}
//401037函数还原
for(int i=0;i<14;i++)
{
input[i]=input[i]^(0x41+i);
result=result+input[i];
}
result=result^0x12345678;
cout<<"your last four bytes data is :"<<endl;
//逆序输出 高位在高字节
for(int i=0;i<4;i++)
{
printf("%X",result%256);
result = result/256;
}
return 0;
}
四. 参考资料
[1] https://www.cnblogs.com/oBYBo/p/13028964.html
[2] https://www.cnblogs.com/codeV-warehouse/articles/3732218.html
最后当然要感谢该crakme作者的劳动成果和无私分享~