内存修改作弊是指用户修改内存数据来达到修改分数,金币,生命的作弊手段,这种作弊方法最常见,门槛也最低,只需要简单地掌握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修改器,搜索分数

BIOS调整显存设置或检查显卡的物理连接_ios

 很快就搜索到了分数的地址

BIOS调整显存设置或检查显卡的物理连接_#include_02

 程序被修改

双重验证的反作弊方法

设定另一个变量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);
    }
}

BIOS调整显存设置或检查显卡的物理连接_c++_03

 改变地址来避免定位

定义指针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;
}