我得快点了
说明
后面的一些样本都在这,来源是 B 站的“艮艮为山”,在此感谢 UP 的分享!
链接:https://pan.baidu.com/s/1BaROP5e9UbJMSN1sgOOKbA
提取码:z2i6
Keygenme
一些不能一目了然的程序,还是先分析算法,防止爆破的不彻底。
查壳

无壳
字符串查找
拖入 x32dbg,进去模块,按 shift + D 查看字符串。

字符串
第一个字符串后缀为 KEY,点击跳转过去看看。
分析

读取文件
显然是个读取 KEY 文件进行校验的 Crackme,文件名为 “CRACKME3.KEY”,而且文件内容长度一定要大于 0x12(十进制:18)个字节。创建一个文件,随便写入超过 0x12 个字节的内容进去。
继续往下看,发现了两个重点函数和结果校验的位置。

重点函数及结果校验
进入处理函数 1 看看

处理函数 1
逻辑很简单,第一个字节与 A 异或,第二字节与 B 异或循环 0xE(十进制14)次存储在原来位置,并将循环次数和每次异或结果累加保存。如异或结果为 0 ,则提前结束循环。继续往下看

处理函数 2 及校验
处理函数 1 完成后,将异或累加结果与 0x12345678 进行异或并存入原来位置。处理函数 2 的作用是获取文件内容的第 15~18 字节并赋值给 eax(函数一目了然,不写了)。然后将 eax 与异或累加结果进行比较,相等则校验通过。这里将 eax 存储了,是因为后面还有成功弹窗要检测 al。
代码
#define _CRT_SECURE_NO_WARNINGS
#include<windows.h>
#include<stdio.h>
#include<string.h>
#define MAX 100
int len = 0;
void Error()
{
printf("校验失败\n");
}
DWORD Func1(char* dwBytesRead)
{
char c = 'A';
DWORD sum = NULL;
for (int i = 0; i < 14; i++)
{
dwBytesRead[i] = dwBytesRead[i] ^ c;
if (dwBytesRead == NULL)
{
return sum;
}
c += 1;
sum += dwBytesRead[i];
len += 1;
}
return sum;
}
DWORD Func2(char* dwBytesRead)
{
DWORD next;
dwBytesRead += 14;
next = *dwBytesRead * 0x1000000 + (*(dwBytesRead + 1)) * 0x10000 + (*(dwBytesRead + 2)) * 0x100 + (*(dwBytesRead + 3));
return next;
}
int main(int argc, char* argv[])
{
char Str1[MAX];
char* pStr1 = Str1;
DWORD dwBytesRead;
DWORD prev;
DWORD next;
HANDLE hOpenFile = (HANDLE)CreateFile(L"CRACKME3.KEY", SE_GROUP_LOGON_ID, 0x00000003 , NULL, OPEN_EXISTING, 0x00000080, NULL);
if (hOpenFile == INVALID_HANDLE_VALUE)
{
Error();
}
else
{
BOOL iRet = ReadFile(hOpenFile, pStr1, 0x12, &dwBytesRead, NULL);
if (dwBytesRead < 12)
{
Error();
}
prev = Func1(pStr1);
printf("处理函数1执行后累加值:%lx\n", prev);
prev = prev ^ 0x12345678;
printf("计算出后四位:%lx\n",prev);
next = Func2(pStr1);
printf("文件中后四位%lx\n", next);
if (prev == next)
{
printf("Now try the next crackme!\n");
}
else
{
Error();
}
}
return 0;
}

执行结果
Crackme
根据前面,爆破只需要在同一目录下创建文件夹命名为“CRACKME3.KEY”,内容超过 18 个字节。然后将 0x0040109F 地址处的 je 改为 jne ,0x0040118A 处的 jne 改为 je 即可。

Crack