内存修改作弊是指用户修改内存数据来达到修改分数,金币,生命的作弊手段,这种作弊方法最常见,门槛也最低,只需要简单地掌握CE类修改器的使用方法即可。
源程序
#include <iostream>
#include <windows.h>
#include <conio.h>
int score = 0;
int main(){
int a,b,c,s;
while (true){
a = rand() % 10;
b = rand() % 10;
c = a + b;
system("cls");
printf("当前分数:%d\n",score);
printf("请计算:\n");
printf("%d + %d = ?\n",a,b);
scanf("%d",&s);
if(s == c){
score++;
} else if(s < 0){
break;
} else{
score--;
}
}
}
程序在屏幕上打印算式,并要求用户计算结果,计算正确加一分,否则扣一分。
作弊方法
使用CE修改器,搜索分数
很快就搜索到了分数的地址
程序被修改
双重验证的反作弊方法
设定另一个变量verify,将verify的值设定为score的10倍,如果发现score和verify对不上,则认定作弊
#include <iostream>
#include <windows.h>
#include <conio.h>
int score = 0;
int verify = 0;
void AddScore();
void MinusScore();
void CheckCheating();
int main(){
int a,b,c,s;
while (true){
a = rand() % 10;
b = rand() % 10;
c = a + b;
system("cls");
printf("当前分数:%d\n",score);
printf("请计算:\n");
printf("%d + %d = ?\n",a,b);
scanf("%d",&s);
if(s == c){
AddScore();
} else if(s < 0){
break;
} else{
MinusScore();
}
}
}
void AddScore(){
CheckCheating();
score++;
verify = score * 10;
}
void MinusScore(){
CheckCheating();
score--;
verify = score * 10;
}
void CheckCheating(){
if(score * 10 != verify){
MessageBox(NULL,"禁止作弊!","AntiCheat",MB_OK);
exit(0);
}
}
改变地址来避免定位
定义指针p指向分数,每次修改分数时都重新申请内存空间,并释放老的空间,这样会让CE类修改器无法找到分数的地址,自然就无法修改,但是可能会造成系统开销过多,大量使用指针还容易造成内存泄漏
#include <iostream>
#include <windows.h>
#include <conio.h>
int *p;
int main(){
p = (int*) malloc(sizeof(int));
*p = 0;
int a,b,c,s;
int *last;
while (true){
a = rand() % 10;
b = rand() % 10;
c = a + b;
system("cls");
printf("当前分数:%d\n",*p);
printf("请计算:\n");
printf("%d + %d = ?\n",a,b);
scanf("%d",&s);
if(s == c){
last = p;
p = (int*) malloc(sizeof(int));
*p = *last + 1;
} else if(s < 0){
break;
} else{
last = p;
p = (int*) malloc(sizeof(int));
*p = *last - 1;
}
free(last);
}
}
自定义结构
使用不寻常的方式来保存数据,加大作弊难度。
#include <iostream>
#include <windows.h>
#include <conio.h>
int score1 = 0;
int score2 = 0;
int GetScore();
void SetScore(int score);
int main(){
int a,b,c,s;
while (true){
a = rand() % 10;
b = rand() % 10;
c = a + b;
system("cls");
printf("当前分数:%d\n",GetScore());
printf("请计算:\n");
printf("%d + %d = ?\n",a,b);
scanf("%d",&s);
if(s == c){
SetScore(GetScore() + 1);
} else if(s < 0){
break;
} else{
SetScore(GetScore() - 1);
}
}
}
int GetScore(){
return score1 * 10 + score2;
}
void SetScore(int score){
score1 = score / 10;
score2 = score % 10;
}
上述代码将分数分成两部分:score1和score2,真实的分数是score1*10+score2,如果作弊者仍然搜索真实分数,就会得到错误的地址。这仅仅是一种简单的示范,实际上我们可以自定义许多复杂的结构,加大破解难度。例如
struct Num{
bool n1:1;
bool n2:1;
bool n3:1;
bool n4:1;
bool n5:1;
bool n6:1;
bool n7:1;
bool n8:1;
};
C++中的布尔变量占用一个字节,但是实际上的布尔类型仅需要一位,将8个布尔类型变量放在一个结构体里面,这个结构体占一位,此时一般的修改器会将这8个布尔变量误认为是一个数,经过测试,CE修改器成功被骗到,当八个布尔变量都为true时会将Num识别为数字255。
加密保存
将数据经过处理后保存,这样的处理可以是简单的加减乘除,也可以是复杂的加密
#include <iostream>
#include <windows.h>
#include <conio.h>
int score = 0;
int GetScore();
void SetScore(int s);
int main(){
int a,b,c,s;
while (true){
a = rand() % 10;
b = rand() % 10;
c = a + b;
system("cls");
printf("当前分数:%d\n",GetScore());
printf("请计算:\n");
printf("%d + %d = ?\n",a,b);
scanf("%d",&s);
if(s == c){
SetScore(GetScore() + 1);
} else if(s < 0){
break;
} else{
SetScore(GetScore() - 1);
}
}
}
int GetScore(){
return -score / 10;
}
void SetScore(int s){
score = -s * 10;
}