先声明一下,虽然代码出自cheat engine,但它不仅是用于游戏作弊,还广泛用于病毒查杀、反外挂等程序。
暴力匹配,应该没有更快更好的算法了,毕竟ceserver用的就是这个算法(
源码位于**/ceserver/native-api.h**,/ceserver/native-api.c :
1
2
3
4
5
6
7
|
#ifndef NativeAPI_H_
#define NativeAPI_H_
#define MAX_HIT_COUNT 5000000
DWORD AOBScan(HANDLE hProcess, const char* pattern, const char* mask, uint64_t start, uint64_t end, int inc, int protection, uint64_t* match_addr);
#endif
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
#include "api.h"
#include "porthelp.h"
#include "ceserver.h"
#include "threads.h"
#include "symbols.h"
#include "context.h"
#include "native-api.h"
DWORD AOBScan(HANDLE hProcess, const char* pattern, const char* mask, uint64_t start, uint64_t end, int inc, int protection,uint64_t * match_addr) {
RegionInfo rinfo;
uint64_t tmp = start;
uint64_t tmp2 = tmp;
char* MemoryBuff = (char*)malloc(4096);
int patternLength = (int)strlen(mask);
int result_count = 0;
while (tmp < end) {
VirtualQueryEx(hProcess, (void*)tmp, &rinfo, NULL);
if (rinfo.size == 0) {
return -1;
}
if((rinfo.protection & protection) != 0)
{
tmp2 = tmp;
while (tmp2 < tmp + rinfo.size)
{
if (!ReadProcessMemory(hProcess, (void*)tmp2, MemoryBuff, 4096)) {
break;
}
for (int i = 0; i < 4096; i += inc)
{
for (int k = 0; k < patternLength; k++)
{
if (!(mask[k] == '?' || pattern[k] == (MemoryBuff[k])))
{
goto label;
}
}
match_addr[result_count] = tmp2;
result_count++;
if (result_count >= MAX_HIT_COUNT)return result_count;
label:
tmp2 += inc; MemoryBuff += inc;
}
MemoryBuff -= 4096;
}
}
tmp += rinfo.size;
}
return result_count;
}
|
不知道你如何看待darkbyte的这段代码,我菜得狠,不敢乱评价,总之就是复制出来不能直接用,
于是我改了改,把关键内容提取出来了,我不是很擅长C语言,仅供参考…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
int AOBScan(void* addr, int len, const char* pattern, const char* mask, int pattern_len, int inc, long* match_addr, long base_addr) {
char* MemoryBuff = (char*)addr;
int result_count = 0;
for (int i = 0; i < len; i += inc) {
for (int k = 0; k < pattern_len; k++) {
if ( mask[k] != 0xff && pattern[k] != MemoryBuff[i + k] ) {
goto label;
}
}
match_addr[result_count] = base_addr + i;
result_count++;
if (result_count >= MAX_HIT_COUNT){
return result_count;
}
label:;
}
return result_count;
}
|
比较基础,但我还是大概解释一下:
参数一:指针,不解释了,(别问为啥不需要pid之类的…
参数二:扫描的那段内存的长度
参数三、四、五:特征码相关,例如特征码是aa bb cc ?? ?? aa bb:
1
2
|
char pattern[7] = {0xaa, 0xbb, 0xcc, 0x随便写, 0x随便写, 0xaa, 0xbb};
char mask[7] = {0x随便写, 0x随便写, 0x随便写, 0xff, 0xff, 0x随便写, 0x随便写};
|
参数六:内存对齐,通常都是1(速度慢)、2、4、8,具体用哪个,因目标程序而异,也要看你特征码找的O不OK。
参数七:用来存储结果的数组
参数八:读外部进程需要用到,因为变量i是基于参数一 addr的偏移,而参数一是自身进程内存空间的地址…..(好像有点啰嗦了?懂的自然懂)
在我的红米10x (4g版百元机,我意思是 做个 性能参考)上简单测试了一下,运行内存约2GB的某64位程序,过滤好Ca内存([anon:libc_malloc]),内存对齐8字节,特征码40字节,12个字节是通配符,大概2~3s就能扫描出来全部结果。