160-CrackMe之-Cruehead-CrackMe-3

160-CrackMe之-Cruehead-CrackMe-3

先打开程序观察程序的布局


载入PEiD,没有查到壳

载入od

可以发现一个敏感的文件名“CRACKME3.KEY”,以及使用了CreateFileA函数

下方还有个跳转,通过动调可以知道:这一部分就是调用Windows API读取该程序所在目录的“CRACKME3.KEY”文件,如果不存在,则会将CrackMe v3.0 字符串后添加- Uncracked

我就自行创建了一个“CRACKME3.KEY”文件,内容写了“1234567890abcdefghijklmnopqrst”

在od观察可以看到ReadFile函数,配合动态调试,知道这是读取“CRACKME3.KEY”文件的前18个字符

再看红线处,将读取的字符串压入栈后,进入一个call,说明这个call里面应该包含了密码匹配的算法。

还要注意橙色横线处指向的地址,很有可能就是在call Cruehead.00401311内部有结果存入该地址

下图是初始时,地址内容:

跟入Cruehead.00401311

需要详细分析这段代码:

  1. 首先是做了初始化,将ecx、eax置为0,esi指向从文件中读取的字符串1234567890abcdefgh,bl置为0x41
  2. 看红线部分以及jnz short 0040131B,可以知道是一个循环,使bl从 0x41 -> 0x4F的循环,对应ASCII码表知:这就是要bl从A 遍历到O,也是要循环改变字符串的前14个字符
  3. 再看蓝框部分,这是将al赋值为esi指向的开头字符,使其与bl进行异或运算,后将结果返回至原本内存处
  4. 对应inc xx等部分,就是使对应寄存器数值加一,esi + 1是要使其开头字符变为下一位,bl + 1既是对应数据更新,也是循环条件数的更新,cl + 1是为了记录进行了几次循环
  5. 注意add dword ptr ds:[0x4020F9],eax,这指向的地址就是上文橙线地址,可以知道:该地址数据就是累加al异或bl的结果
  6. 还有cmp al,0x0je short 00401335,此处是判断异或的结果是否为零,若为零则跳出循环

转换成C++代码,如下:

unsigned int Gnum = 0;
int countfor = 0;
unsigned char s[] = "1234567890abcdefgh";
void f(char* s){
    int c = 0;
    for(char i = 'A';i < 'O';i++){
        s[i - 'A'] ^= i;
        unsigned int a = s[i - 'A'];
        Gnum += a;
        if(s[i - 'A'] = 0){
            break;
        }
        c++;
    }
    countfor = c;
    return;
}

返回到主函数里:

可以看到内存0x4020F9处的数据与0x12345678进行异或,而后进入call 0040133C

此函数就是将字符串的后四位字符赋值给eax,注意此四个字符在前面函数中并为修改。

然后cmp eax,dword ptr ds:[0x4020F9],就是使字符串后四个字符与前14个字符异或结果累加值进行比较,sete al是使ZF标志位赋值给al,如果一样的话,al为一,后续就不会回跳至未破解的函数处理处;如果不一致,则会回跳:

所以后续逻辑,使用C++代码:

unsigned char Gnum_byte[4];	//先变成字节类型,方便比较
Gnum ^= 0x12345678;
for (int i = 3, j = 24; i >= 0; i--, j -= 8) {
    Gnum_byte[i] = Gnum >> j;
}
for(int i = 0;i < 4;i++){
    if(s[i + 14] != Gnum_byte[i])
        return -1;
}
return 1;

下列是通过C++创建“CRACKME3.KEY”文件代码:

#include<iostream>
#include<fstream>
using namespace std;

int main() {
    unsigned char s[] = "1234567890abcdefgh";
    unsigned char s2[] = "1234567890abcdefgh";
    unsigned int Gnum = 0;
    for (char i = 'A'; i < 'O'; i++) {
        s[i - 'A'] ^= i;
        unsigned int a = s[i - 'A'];
        Gnum += a;
        if (s[i - 'A'] == 0) {
            break;
        }
    }
    unsigned char Gnum_byte[4];	//先变成字节类型,方便比较
    Gnum ^= 0x12345678;
    for (int i = 3, j = 24; i >= 0; i--, j -= 8) {
        Gnum_byte[i] = Gnum >> j;
    }
    for (int i = 0; i < 4; i++) {
        s2[i + 14] = Gnum_byte[i];
    }

    ofstream ofs;
    ofs.open("CRACKME3.KEY", ios::out);
    ofs << s2 << endl;
    ofs.close();
    return 0;
}

posted @ 2025-06-22 16:29  phen  阅读(29)  评论(0)    收藏  举报