看到好多人都在做,菜鸟跟风,有错请指正
本系列分为三部分:
一、剥离dll 二、分析自瞄思路 三、自写代码
赛题下载地址: https://gslab.qq.com/html/competition/2021/race-final.htm ,选择 PC客户端安全 下载。
1.准备工作
打开游戏,打开hack.exe,作弊功能未实现。
2.初步探索
打开IDA,拉入hack.exe,看到15E0处有对文件进行读写的操作,判断此处为验证函数。
3.找到根源
F5生成伪代码,可以看到在 CreateFileA 处有判断文件是否存在。
4.动态调试
打开x64dbg,定位到15e0处动态调试得出文件名为 hack.dat。
在根目录自己建立一个名为hack.dat的文件,在里面随便写点东西。
5.伪代码分析
回到IDA,分析伪代码。GetFileSize函数返回了hack.dat文件的长度,通过长度来分配内存地址,通过ReadFile函数将hack.dat内容读取放到开辟的地址addrContent中。
6.首尾呼应
跳过中间一大串的解密代码,直接来到最后的逻辑判断部分。
LABEL16块可以看到了openprocess,不难看出接下来是内存操作,也就是要开始执行外挂功能。注意这里的v14 = pe.th32ProcessID,再通过下面的openprocess可以得出pe.szExeFile为游戏进程名,则ProcName解密后应该为游戏的进程名。
7.回溯解密
回到中间的解密部分。
可以看到ProcName是通过v6的偶数成员组成,而v6来源sub_7FF6E61F14D0,显然它是一个解密函数,在IDA中将其重命名为decode。进入decode函数,可以看到函数分为两块,上面那块是一大段操作块,不去管他,看下面的解密块。
直接看v7 v5和v17的关系,不难看出他们都属于指向同一个空间的指针,所以看给v17赋值的最后一个操作,判断出加密操作为与0x3F异或然后减去0x13。
9.反向解码。
已知目标值为ShooterClient.exe,比较值为0x3F,直接通过C写代码。
int main() {
system("chcp 437>nul.");
char a[]="ShooterClient.exe";
int b[18];
int c[18];
for (int i = 0; i <= strlen(a); i++) {
b[i] = a[i] + 0x13;
for (int j = 0; j <= 0xff; j++) {
if ((j ^ 0x3f) == b[i]) {
c[i] = j;
break;
}
}
}
for (int i = 0; i < 18; i++) cout << hex <<c[i] << " ";
FILE *fp = fopen("hack.dat", "w");
char t = 0x38;
fwrite(&t, 1, 1, fp);
fwrite(&t, 1, 1, fp);
for (int i = 0; i <= strlen(a); i++) {
fwrite(&c[i], 1, 1, fp);
fwrite(&t, 1, 1, fp);
}
}
编译,放在根目录运行,生成hack.dat,这时候继续动态分析。
10.寻找flag。
回到IDA,继续往下分析。可以看到两块循环和一个字符串类型的数据。在IDA中定位得到有字符串的地址为18AC
在循环头下断,可以看到是edx和“2RS……”比较,可以看到[rax+r8]的值也是偶数成员拼凑成“ShooterClient.exe”,于是猜测将2RSxx加密则为hack.dat真实数据。于是重写代码得:
int main() {
system("chcp 437>nul.");
char a[]="2RSRhrofoWtLeLrJCSlTireznrtx.oeLxuehyyAwbpCOZq0tsS7MZyVdOUoE8";
int b[62];
int c[62];
for (int i = 0; i <= strlen(a); i++) {
b[i] = a[i] + 0x13;
for (int j = 0; j <= 0xff; j++) {
if ((j ^ 0x3f) == b[i]) {
c[i] = j;
break;
}
}
}
for (int i = 0; i < 62; i++) cout << hex <<c[i] << " ";
FILE *fp = fopen("hack.dat", "w");
for (int i = 0; i <= strlen(a); i++) {
fwrite(&c[i], 1, 1, fp);
}
}
打开游戏,再打开辅助可以看到功能成功开启,控制台也正确输出flag。
11.寻找作弊代码。
回到IDA向下拉,可以看到有对内存进行读写的操作。在之前还进行了开辟内存空间和申请保护页的操作,于是猜测游戏是通过注入dll的方式实现作弊功能
于是在WriteProcessMemory处下断,查看r8寄存器。看到r8寄存器中储存的是MZ开头的数据,于是猜测是通过将dll写入到内存,然后通过创建远程线程的方式运行dll。
再通过上下文得到内存大小为0xFA00
将r8处内存以0xfa00的大小dump出来,得到dumpHack.dll。利用CE将dll注入到游戏中,可以得到自瞄开启成功。