Solved Impossible to make C++ External Trainer (AssaultCube learning) works correctly

Hexui Undetected CSGO Cheats Sinkicheat PUBG Cheat

LsDevs

Dank Tier Donator
Full Member
Mar 12, 2020
18
338
0
Game Name
Assault Cube
Anticheat
N/A
Tutorial Link
https://guidedhacking.com/threads/how-to-hack-any-game-tutorial-c-trainer-1-external.10897/
How long you been coding/hacking?
I begin GH but I have some basics in C++
Coding Language
C++
Hi everyone,
First of all, sorry if my English is not quite good but I'm from France and I'm gonna do my best to be clear.
Also, sorry if this question is kind of noob question.

I spent a lot of time trying to make work correctly the external trainer presented in the C++ GH Part2 tutorial.
While writing the code I got a lot of warnings and sorts of errors messages from my IDE, so I tried with my basics in C++ to "rearrange" a little bit some lines to suit my needs.

The problem is that it looks like the program found the ProcID, the Modular base name but can't retrieve the pointer I have in Cheat Engine.
I've verified a thousands of time the addresses and I know the problem is just under my eyes, but I really can't see it.
I put some screenshots below to show you the console output of the program and what I got in Cheat Engine.

Here is the code I use from the tutorial :
GetProcID:
DWORD GetProcID(const wchar_t *procName) {

    DWORD procID = 0;
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnap != INVALID_HANDLE_VALUE) {

        PROCESSENTRY32 procEntry;

        procEntry.dwSize = sizeof(procEntry);
       
        if (Process32First(hSnap, &procEntry)) {
            do {
                if (_wcsicmp((wchar_t*)procEntry.szExeFile, procName))
                {
                    procID = procEntry.th32ProcessID;
                    break;
                }
            } while (Process32Next(hSnap, &procEntry));

        }
    }

    CloseHandle(hSnap);
    std::cout << "PROC ID = " << procID << std::endl;
    return procID;
};
GetModuleBaseAddresse:
uintptr_t GetModuleBaseAddress(DWORD procId, const wchar_t* modName)
{
    uintptr_t modBaseAddr = 0;
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId);
    if (hSnap != INVALID_HANDLE_VALUE)
    {
        MODULEENTRY32 modEntry;
        modEntry.dwSize = sizeof(modEntry);
        if (Module32First(hSnap, &modEntry))
        {
            do
            {
                if (_wcsicmp((wchar_t *)(modEntry.szModule), modName))
                {
                    modBaseAddr = (uintptr_t)modEntry.modBaseAddr;
                    break;
                }
            } while (Module32Next(hSnap, &modEntry));
        }
    }
    CloseHandle(hSnap);
    std::cout << "modBaseAddr = " << modBaseAddr << std::endl;
    return modBaseAddr;
}
FindMDAddy:
uintptr_t FindDMAAddy(HANDLE hProc, uintptr_t ptr, std::vector<unsigned int> offsets)
{
    uintptr_t addr = ptr;
    for (unsigned int i = 0; i < offsets.size(); ++i)
    {
        ReadProcessMemory(hProc, (BYTE*)addr, &addr, sizeof(addr), 0);
        addr += offsets[i];
    }
    std::cout << "addr = " << addr << std::endl;
    return addr;
}
Main:
int main() {

    DWORD procID = GetProcID(L"ac_client.exe");


    uintptr_t modularBase = GetModuleBaseAddress(procID, L"ac_client_exe");

    HANDLE hProcess = 0;
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, procID);

    uintptr_t dynamicPtrBaseAddr = modularBase + 0x10f4f4;

    std::cout << "dynamicPtrBaseAddr ==  " << std::hex << "0x" << dynamicPtrBaseAddr << std::endl;

    uintptr_t ammoAddr = FindDMAAddy(hProcess, dynamicPtrBaseAddr, {0x374, 0x14, 0x0});

    std::cout << "ammoAddr(DMAAddy) ==  " << std::hex << "0x" << ammoAddr << std::endl;

    int ammoValue{0};
    ReadProcessMemory(hProcess, (BYTE *) ammoAddr, &ammoValue, sizeof(ammoValue), nullptr);
    std::cout << "Current ammo == " << std::dec << ammoValue << std::endl;

    int newAmmo{1337};
    WriteProcessMemory(hProcess, (BYTE *) ammoAddr, &newAmmo, sizeof(newAmmo), nullptr);

    ReadProcessMemory(hProcess, (BYTE *) ammoAddr, &ammoValue, sizeof(ammoValue), nullptr);
    std::cout << "New ammo == " << std::dec << ammoValue << std::endl;


    getchar();
    return 0;
}
As you can see I changed some lines.
Here I needed to cast procEntry.szExeFile to a wchar_t to compile (same in GetModuleBaseAddresse)
C++:
 if (_wcsicmp((wchar_t*)procEntry.szExeFile, procName))
And notice for this line my IDE give me a warning "Cast from pointer to smaller type 'uintptr_t' (aka 'unsigned int') loses information"
C++:
modBaseAddr = (uintptr_t)modEntry.modBaseAddr;
Here you can see the ouput of the console :
output.PNG

And here my Cheat Engine :
ceoutput.PNG


Thanks a lot for taking the time to read.
 

XdarionX

Dying Light Hacker
Dank Tier VIP
Dank Tier Donator
Mar 30, 2018
847
23,408
114
Hi,
As I said above I word on Ubuntu and I cross-compile my application for Windows using mingw64.
It should use Unicode normally, and as you can see I use the predefined L macro to find the ac_client.exe :
C++:
DWORD procID = GetProcId(L"ac_client.exe");
I checking a lot of time the spelling of ac_client.exe and there's no typo or anything.
It don't understand why it's not working at all, I'm still searchings.


EDIT :
I had to use -municode flag for compilation and switch my main function to wmain function.
It now found the ProcID and the module base but now it can't resolve the multi level pointer.
Here's the output :
View attachment 9267

EDIT 2 :
After printing some results of FindDMAAddy function I get these output :
View attachment 9268
I found very strange the way it pass from 50f4f4 + 374 = 50f868 to 117a884+14 = 117a98.
Another output after relaunching the game :
View attachment 9269
i meantioned it because in first post you had:
uintptr_t modularBase = GetModuleBaseAddress(procID, L"ac_client_exe");
nvm now
those addresses are too large, they are ULONGLONG type i guess, make sure you compile your application for x86 because ac_client.exe is x86 and when you are RPM than specify to read 4 bytes (sizeof char* or sizeof void* is 8 bytes large on x64) all ptr data should be 4 bytes large (DWORD)

(edited)
 

timb3r

Semi-Retired
Dank Tier VIP
Jul 15, 2018
766
24,668
47
Your procid is zero meaning it doesn't have a valid handle to the process. Check your Get Procid function also _wcsicmp returns 0 if the string matches.
 
  • Like
Reactions: XdarionX

XdarionX

Dying Light Hacker
Dank Tier VIP
Dank Tier Donator
Mar 30, 2018
847
23,408
114
you broke the code when you were trying to "rearrange". Patch:
GetProcID::
13: if (!wcscmp((wchar_t*)procEntry.szExeFile, procName))
GetModuleBaseAddresse:
13: if (!wcscmp((wchar_t *)(modEntry.szModule), modName))
C++:
//also you should check after OpenProcess
if(!hProcess)
    error(...);
 

LsDevs

Dank Tier Donator
Full Member
Mar 12, 2020
18
338
0
Your procid is zero meaning it doesn't have a valid handle to the process. Check your Get Procid function also _wcsicmp returns 0 if the string matches.
Hi,
I was not sure if it return if the string match while watching the tutorial, I found that a little bit strange and decided to change it. I understand I've make a mistake here.

you broke the code when you were trying to "rearrange". Patch:
GetProcID::
13: if (!wcscmp((wchar_t*)procEntry.szExeFile, procName))
GetModuleBaseAddresse:
13: if (!wcscmp((wchar_t *)(modEntry.szModule), modName))
C++:
//also you should check after OpenProcess
if(!hProcess)
    error(...);
Hi,
I changed the code (in both functions) for
C++:
if (!wcscmp((wchar_t *)(modEntry.szModule), modName)
if (!wcscmp((wchar_t*)procEntry.szExeFile, procName))
and as you recommend I've added a verification after opening the process, like this :
C++:
 HANDLE hProcess = 0;
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, procID);

    if (!hProcess) {
        std::cout << "No process" << std::endl;
        getchar();
        exit(-1);
    }
And it's never founding it, you can see the output here :
out.PNG


Thanks for taking the time for helping, appreciate it a lot.

EDIT : Maybe it's important to say I'm working on Ubuntu and I cross-compile for windows with mingw64.
 
Last edited:

XdarionX

Dying Light Hacker
Dank Tier VIP
Dank Tier Donator
Mar 30, 2018
847
23,408
114
Hi,
I was not sure if it return if the string match while watching the tutorial, I found that a little bit strange and decided to change it. I understand I've make a mistake here.


Hi,
I changed the code (in both functions) for
C++:
if (!wcscmp((wchar_t *)(modEntry.szModule), modName)
if (!wcscmp((wchar_t*)procEntry.szExeFile, procName))
and as you recommend I've added a verification after opening the process, like this :
C++:
 HANDLE hProcess = 0;
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, procID);

    if (!hProcess) {
        std::cout << "No process" << std::endl;
        getchar();
        exit(-1);
    }
And it's never founding it, you can see the output here :
View attachment 9266

Thanks for taking the time for helping, appreciate it a lot.

EDIT : Maybe it's important to say I'm working on Ubuntu and I cross-compile for windows with mingw64.
man idk what you are doing but i have just tried this and it worked:
C++:
#include <Windows.h>
#include <TlHelp32.h>
#include <iostream>
DWORD GetProcID(const wchar_t *procName) {

    DWORD procID = 0;
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnap != INVALID_HANDLE_VALUE) {

        PROCESSENTRY32 procEntry;

        procEntry.dwSize = sizeof(procEntry);

        if (Process32First(hSnap, &procEntry)) {
            do {
                if (!_wcsicmp(procEntry.szExeFile, procName))
                {
                    procID = procEntry.th32ProcessID;
                    break;
                }
            } while (Process32Next(hSnap, &procEntry));

        }
    }

    CloseHandle(hSnap);
    std::cout << "PROC ID = " << procID << std::endl;
    return procID;
};

int main(void) {

    GetProcID(L"ac_client.exe");

    getchar();

}
maybe check you spelling of ac_client.exe ?
edit:
are you using unicode strs in project settings ?
 

LsDevs

Dank Tier Donator
Full Member
Mar 12, 2020
18
338
0
man idk what you are doing but i have just tried this and it worked:
C++:
#include <Windows.h>
#include <TlHelp32.h>
#include <iostream>
DWORD GetProcID(const wchar_t *procName) {

    DWORD procID = 0;
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnap != INVALID_HANDLE_VALUE) {

        PROCESSENTRY32 procEntry;

        procEntry.dwSize = sizeof(procEntry);

        if (Process32First(hSnap, &procEntry)) {
            do {
                if (!_wcsicmp(procEntry.szExeFile, procName))
                {
                    procID = procEntry.th32ProcessID;
                    break;
                }
            } while (Process32Next(hSnap, &procEntry));

        }
    }

    CloseHandle(hSnap);
    std::cout << "PROC ID = " << procID << std::endl;
    return procID;
};

int main(void) {

    GetProcID(L"ac_client.exe");

    getchar();

}
maybe check you spelling of ac_client.exe ?
edit:
are you using unicode strs in project settings ?
Hi,
As I said above I word on Ubuntu and I cross-compile my application for Windows using mingw64.
It should use Unicode normally, and as you can see I use the predefined L macro to find the ac_client.exe :
C++:
DWORD procID = GetProcId(L"ac_client.exe");
I checking a lot of time the spelling of ac_client.exe and there's no typo or anything.
It don't understand why it's not working at all, I'm still searchings.


EDIT :
I had to use -municode flag for compilation and switch my main function to wmain function.
It now found the ProcID and the module base but now it can't resolve the multi level pointer.
Here's the output :
out.PNG


EDIT 2 :
After printing some results of FindDMAAddy function I get these output :
Capture.PNG

I found very strange the way it pass from 50f4f4 + 374 = 50f868 to 117a884+14 = 117a98.
Another output after relaunching the game :
Capture.PNG
 
Last edited:

LsDevs

Dank Tier Donator
Full Member
Mar 12, 2020
18
338
0
i meantioned it because in first post you had:

nvm now
those addresses are too large, they are ULONGLONG type i guess, make sure you compile your application for x86 because ac_client.exe is x86 and when you are RPM than specify to read 4 bytes (sizeof char* or sizeof void* is 8 bytes large on x64) all ptr data should be 4 bytes large (DWORD)

(edited)
Hey, I really have to thank you a lot.
I was compiling for x64 version and not for x86.
I have a lot to learn about size of bytes and everything.
It's now working, I appreciate a lot the help and the time you take to explain and help me.
 
  • Like
Reactions: XdarionX
Attention! Before you post:

Read the How to Ask Questions Guide
99% of questions are answered in the Beginner's Guide, do it before asking a question.

No Hack Requests. Post in the correct section.  Search the forum first. Read the rules.

How to make a good post:

  • Fill out the form correctly
  • Tell us the game name & coding language
  • Post everything we need to know to help you
  • Ask specific questions, be descriptive
  • Post errors, line numbers & screenshots
  • Post code snippets using code tags
  • If it's a large project, zip it up and attach it

If you do not comply, your post may be deleted.  We want to help, please make a good post and we will do our best to help you.

Community Mods