Skip to content

Game cheat base and clean architecture for your next cheat

License

Notifications You must be signed in to change notification settings

scx1125/CleanCheat

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CleanCheat

Game cheat base and clean architecture for your next cheat

Features

  • Clean architecture
  • Force your code to be maintainable and easy to read
  • Easy to use, initialize and unload(dll unload)
  • Easy global/shared data access
  • Logger (Basic one)
  • Hooks:
    • Un/Detour
    • Un/VMT swap
  • Memory:
    • Pattern scan
    • Value scan (TODO)

Options

Options presented by CleanCheatOptions struct that are passed when initialize CleanCheat

UseLogger option

Enable console logging by

Usage

To use CleanCheat you need to do 3 simple steps

Step1: Adding includes

At first your project need to know about CleanCheat. For that you have to:

  • Copy src/CleanCheat and src/CleanCheat.h OR download Latest Release to your project dir
  • Add #include "CleanCheat.h" into your cpp/h files (if you have precompiled headers it is a good place to add this include there)

Note:
In cpp/h files you need to include CleanCheat.h NOT CleanCheat/CleanCheat.h

Step2: Initialization

Initialize CleanCheat

You need to pick your options and pass it to CleanCheat::Init function

CleanCheatOptions options;
options.UseLogger = true;

CleanCheat::Init(options);

Initialize Features

Features used in the example (BasicFeature, TestFeature)

int initData = 1;

BasicFeature basic;
basic.Init(&initData);

TestFeature test;
test.Init();

Initialize Runners

Features must to be initialized before registers it in any runner BasicRunner

BasicRunner basicRunner;
basicRunner.RegisterFeature(&basic);
basicRunner.RegisterFeature(&test);

// Register the runner
CleanCheat::RegisterRunner(&basicRunner);

Step3: Use

You need to include CleanCheat.h where ever you want to access CleanCheat then you can access what Features it provide, for sure that's after Initialize CleanCheat

CleanCheat do all it's operation from CleanCheat::Tick so it needs to be called from any place that get called at least once per frame:

MessageHandler

while (!(GetAsyncKeyState(VK_END) & 1))
{
    CleanCheat::Tick(&initData);
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}

CleanCheat::Discard();

Frame hook:
InternalUnrealExample use PostRender hooked function to do it.
You can hook any (DirectX, OpenGL, Vulkan, etc) that called every frame

Use Shared data

You can access shared data related stuff using CleanCheat::SharedData

CleanCheat::SharedData->ANY_DATA;

Use Logger

You can log by LOG macro that's only work if UseLogger option are ture

int main(int argc, char* argv[])
{
    // Init CleanCheat
    ...
    
    // Log
    LOG("Hello '%s' users", "CleanCheat");
    return 0;
}

Output:
Under the hood it use std::printf function with format [FILE_NAME:FUNC_NAME:CODE_LINE] USER_MESSAGE

[Main.cpp:main:11] Hello 'CleanCheat' users

Use hooks

You can access hooking related stuff using CleanCheat::Hook

Hook by swap VMT method address
void* outOrignalMethodAddress = nullptr;
CleanCheat::Hook->SwapVmt(INSTANCE_ADDRESS, METHOD_INDEX, &HOOK_FUNC, &outOrignalMethodAddress);
Hook by detour function
void* functionAddress = 0x123456CD;
CleanCheat::Hook->Detour(&functionAddress, &HOOK_FUNC);

Use memory

You can access memory related stuff using CleanCheat::Memory

Memory pattern scan
// Look for "48 89 5C 24" in main module, and maximum result 2
std::vector<void*> addrs = CleanCheat::Memory->PatternScan("48 89 5C 24", 2);

Concepts

Shared data

The place where you would store global status and shared data, you could also add functions too. As every code need it's own collection of shared data you will need to make your own class.

Shared data basic setup

  1. Make a class that inherits from SharedDataBase
  2. Include its header in CleanCheat.h next to // Your SharedData class
  3. Edit SHARED_DATA_TYPE in CleanCheat/Macros.h with your shared data class name (default is SharedDataStruct)

Then you can use shared data

Runner and Feature

Let's say i have level objects loop that have like 10k object, and every type of objects have different task to do, if i have PlayerObject and WeaponObject, and i want to make ESP for players and zero recoil for weapons, then that is a different tasks but related to same task(object iterate).

Problem example (trust me, code will be (very UGLY and very hard to maintain) fast):

for (int i = 0; i < OBJECT_COUNT;   i)
{
    if (OBJECT[i] is PlayerObject) // Condetion
    {
        if (!OBJECT[i]->IsDead() && OBJECT[i]->Distance < 100.f) // Condetion
        {
            // Collect/Preper data
            ...
            
            // Draw
            ...
        }
    }
    
    if (OBJECT[i] is WeaponObject) // Condetion
    {
        if (!OBJECT[i]->IsEmpty()) // Condetion
        {
            // Collect/Preper data
            ...
            
            // Handle
            OBJECT[i]->Recoil = 0.f;
        }
    }
}

Runner

Runner concept present task that can be splited into tasks(Features) with providing input to that tasks to check and handle.

In our example runner will present the loop for (int i = 0; i < OBJECT_COUNT; i) and iterator Object as input for our Features.

bool LevelObjectsRunner::Condition()
{
    return CleanCheat::SharedData && CleanCheat::SharedData->World;
}

void LevelObjectsRunner::OnExecute()
{
    for (int32_t i = 0; i < curLevel->Objects.Count(); i  )
    {
        auto* curObject = curLevel->Objects[i];
        if (!curObject)
            continue;

        // Here we execute all registered features with 'curObject' as input
        ExecuteFeatures(curObject);
    }
}
Runner life cycle
Func Description
OnExecute Called by CleanCheat every tick
Condition Called before OnExecute by CleanCheat to determine run it or not
Discard Called by CleanCheat when CleanCheat itself get discarded

Feature

Feature concept present runner sub-task that can do one task with one input after pass a condition. So you can't pass same feature to multi runner (unexpected behavior). Feature are there to spilt runner code and make it easy to maintain easy to read.

In our example feature can be presented as a Player ESP task and Weapon no recoil task in separate isolated class like that:

bool EspFeature::Condition(Object* curObject)
{
    return curObject is PlayerObject && !curObject->IsDead() && curObject->Distance < 100.f;
}

void EspFeature::OnExecute(Object* curObject)
{
    // Collect/Preper data
    ...
            
    // Draw
    ...
}
bool WeaponZeroRecoilFeature::Condition(Object* curObject)
{
    return curObject is WeaponObject && !curObject->IsEmpty();
}

void WeaponZeroRecoilFeature::OnExecute(Object* curObject)
{
    // Collect/Preper data
    ...
            
    // Handle
    curObject->Recoil = 0.f;
}
Feature life cycle
Func Description
OnInit Called only once by user before it get registers by runner
OnExecute Called by runner during runner executive once or more depend on the runner
Condition Called before OnExecute by runner to determine whether it will call it or not
BeforeExecute Called by runner before call OnExecute always get called, doesn't care about Condition
AfterExecute Called by runner after call OnExecute always get called, doesn't care about Condition
Discard Called by runner when runner itself get discarded

Examples

There are a number of examples that demonstrate various aspects of using CleanCheat. They can be found in the examples folder:

Example Description
Simple Simple example
InternalUnrealEngine Shows how to use with CheatGear

Credits

CorrM

Third-party libraries

Detours

Change Log

0.0.2
  • Add feature settings
0.0.1
  • First release

About

Game cheat base and clean architecture for your next cheat

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C 100.0%