本人刚刚入门汇编逆向破解分析,本帖将记录我对160个CrackMe程序中的第007程序的分析过程。在学习的过程中,我会边学边记录。如果有不正确之处,还请各位指正。
首先查壳程序是无壳 Delphi编写,点击帮助按钮 弹出提示框 大概意思是 隐藏掉注册下面的注册按钮让logo显示出来。
Delphi编写的程序 先放到E2A看一下这些按钮的事件地址。通过下图可以看出 程序还有一个按钮是隐藏,隐藏掉按钮并显示出logo就算破解成功 那我们先输入假码然后在注册按钮事件下断点看一下。
断下开之后我们发现有一个跳转,经过下面的提示 看的出来他是检测 你输入的密码是不是整数型 如果不是就会走到这个进入到这个跳转里面 然后弹提示框 要求输入一个长整数形的密码。
我输的是一个整数型密码 所以这个跳转不成立 继续往下走。会看到还有一个跳转,如果我把这个跳转nop掉 那么程序就会把注册按钮隐藏掉 并且让之前分析出来的那个隐藏按钮显示出来。 所以这个跳转上面的CALL肯定是包含了算法的。我们进到这个CALL去看一下。
进到这个CALL内 我们就发现了一大堆计算的操作。
继续分析一下这些算法到底是怎么计算的, 首先我们看到了这个算法就是 两层循环 用户名的第一个字符 乘以最后一个字符 在乘以edi 第一次用一个字符把所有的字符乘一边 再用第二个乘....最后的结果相加起来放到ebx中(看下面的正向代码就理解了)。其中会和edi相乘,但是edi的值是0 那么最后无论怎么计算结果也是0 那这个计算的代码就没有意义了,继续往下看 到底会不会用到这个算法算出来的值,如果需要用到这个计算出来的值 那肯定要找到edi的赋值才可以。
继续往下的走代码可以看出,把刚才用户名算法计算出来的值 和 0xA2C2A做了取模运算 , 接着又把密码转成16进制除以0x59的商在加上除以0x50的余数在加0x1后的值 和 用户名的计算出来的值相等才可以。
用户名计算的算法我们已经知道了,但是edi的值是0 这样肯定是不对的,必须要找到edi的值才可以正确计算。
现在需要向上溯源找edi的值, 在这个CALL内 发现edi的是值eax ,那我们就要知道eax是哪里来的。
继续向上溯源我们发现 eax的值来源于0x445830这个地址,那现在就要找这个地址是在哪里赋值的。
我们搜索这个内存地址的常量看到 一共有8处对他进行了赋值。那我们肯定要看距离这个算法最近的地址 也就是 0x00442F86地址
可以看到这个赋值是在要输入不符合密码规范的时候才会赋值,那也就是说 我们先要输入一个纯数字以外的密码触发这个赋值才可以。
在这行代码可以看出 这个地址的值是eax,eax作为CALL的返回值 那我们肯定要进入这个CALL去看一下。
进入这个CALL 我们看到一些计算,这部分就是算法了 ,具体逻辑就是 循环密码的长度-1 第二个字节和0x11做取模运算 +1 然后在 乘以 第一个字节 依次递增循环 得出来的值累加到esi里面 (对应下面正向代码)
目前算法已经梳理清楚了 一个用户名算法 一个密码算法 一个edi算法。 首先要输入不符合规范的用户名计算出edi。然后用edi 才能计算出用户名算法的值 ,然后密码算法算出来的值和用户名算法值相等 即可隐藏注册按钮显示 again按钮。
现在已知用户名算法算出来的值, 密码的16进制/0x59的商 + 密码的16进制%0x50 +0x1 和算出来的用户名相等即可。 那我们就通过最简单的方法 给他穷举出来即可。
经过测试已经可以顺利隐藏注册按钮。
again按钮隐藏的算法和 注册按钮算法一样 还是在输入一遍刚才错误的密码在输入计算出来的密码 就隐藏掉了。
注册机:
[C++] 纯文本查看 复制代码 #include <iostream>
using namespace std;
int getUser(string user, int passEdi)
{
int len = user.length();
int eax = 0;
int ebx = 0;
int ecx = 0;
int edx = 0;
int edi = passEdi;
for (int i = 0; i < len; i++)
{
for (int j = 0; j < len; j++)
{
edx = user[i];
ecx = user[len - j - 1];
edx *= ecx;
edx *= edi;
ebx += edx;
}
}
eax = ebx;
ecx = 0xA2C2A;
edx = eax % ecx;
return edx;
}
int getPass(int userHex) {
int i = 1;
while (true)
{
if (i / 0x59 + i % 0x50 + 0x1 == userHex)
{
return i;
}
i++;
}
}
int getPassEdi(string pass)
{
int len = pass.length();
int eax = 0;
int ebx = 0;
int ecx = 0;
int edx = 0;
int edi = 0x11;
int esi = 0x37B;
for (int i = 0; i < len - 1; i++)
{
eax = pass[i + 1];
edx = eax % edi + 0x1;
eax = pass[i];
edx *= eax;
esi += edx;
}
return esi;
}
int main()
{
int passEdi = getPassEdi("a123456");
cout << "密码计算出的Edi: " << hex << passEdi << endl;
int userHex = getUser("123456",passEdi);
cout << "用户名计算出来的Hex: " << hex << userHex << endl;
int passHex = getPass(userHex);
cout << "通过用户名计算出的密码: "<< dec << passHex << endl;
return 0;
}
|