Jump to content
Team Avolition
Dabato

How to develop cheats for every PC game

Recommended Posts

Dabato    2

When it comes to developing cheats for video games, there are multiple ways of doing it. We are going to be doing a trainer, as this is probally the easiest type of cheat to make. What we are doing is we are using the Windows API to hook into a process and change the values in certain data types. As we are going to be changing pointers, you don't have a huge selection of different programming languages you can use. You can choose between C, C++ and C#(However in c# you are going to need to use a DLL extension, like VAMemory.) I will be showing you how to do this in C++ and C#(C# is a lot easier, however C++ will give you a lot more control.) Before any of this we need to find the addresses and offsets(If you don't understand what that means, I suggest you learn C++ to the point were you completely understand pointers, what they do and how they work.) To do this we have two options, we can find them manually with Cheat Engine, or you can just google it. I will be showing you both ways. We are going to be doing this with the game Assault Cube(The link is here), because this is pretty much the standard game for learning to make hacks in, because it is so easy.

Cheat Engine

Download cheat engine from here, and install it. Next you need to launch it, and also launch assault cube(Just put this in windowed 800x600. Then on cheat engine click on the computer with a magnifying glass in front of it on the top left hand corner that has a colour changing square around it. Select assault cube and press ok. So we are going to find the health value, so make sure hex is unchecked, and type in the value box your hp(in this case 100). Then you are going to need to hurt yoruself. I do this by pressing escape, singleplayer, empty map, ac_aqueous, press e and noclip outside were there is some grenades. Throw the grenade and hurt yourself. My health now is 69, so I will change the value in the box to 69, and click next scan. I got two values there. Double click on one of them, so it is in the address list at the bottom, then double click on the value box. Try changing the value to 100, and if it changes in game you have the right one. If it isn't, go through the other boxes until you find what the correct one is. Now we need to find out what changes our variable, so select it at the bottom and press f5. Select yes to attatch the debugger. Now damage yourself again ingame. Now I damaged myself once, and a new instruction appeared, which runs mov [edx + 000000F8], eax. We right click on this and click on more info. If you are confused by this, look at this which explains what each x86 instruction does. Because mov copies data from one register to another, this is enough information for us to know that this is changing the value of the health. Open up notepad, and note down the 000000F8, this is the offset from the actual player class. So write health offset - F8. We also want to find out what the base address is, so write down in your notepad document The value after "The value of the pointer needed to find this address is probaly xxxxxxxx". For me it is 0106A1C0, so I will write that down. We can close the debugger now, and we we need to do is select hex, and replace the value with the value you just wrote down and click new scan twice. The value we have now will change each time the game is restarted, so we want to find the static pointer for it, so we look in the address list at the left for ones with green addresses. There is three for me, and I am going to select the first one. Now we are going to click on it, and press Cntrl + alt + enter. Select pointer, and in the box just above add offset type the address, which is the part that is in green in the address list. In my case it is 00509B74. Now what you need to do is set the offset as F8(The health offset) so we can check if it is correct. Press ok and the value at the bottom address less is 0000001C, and as my health in game is 28, I know that that is 1C in hexadecimal. So now we know we have the static address, we can set the offset as 0, press ok. Click on it in the address list, press Ctrl+B, then Ctrl+D to open up structure dissect. Press Ctrl+N, you can name it something, but it doesn't really matter so just hit enter a few times till the structre is full of values. No from this we have all the values in the player class, and we can work out things like ammo. So if we look at our offset(F8), we have our health. To find ammo, we look for our current ammo value, for example 19. We shoot a few times, and the value there should have updated to our current ammo. If so we have found the ammo offset, and we can write it down is 150 and so on.

Just google it

If you google AssaultCube offsets you get this link. These are accurate and you should use the offsets other people have found to save you time, however if the game has recently updated you will have to find them yourself. And here is a tip, if you are the first person to find the offsets and addresses, share them! Give back to the people that found them for you in the first place.

C# Code

So now I am going to teach you how to make a simple trainer in c# code. We have all the offsets we need, so we will start now. For C# memory management you need VAMemory.dll(You can get that here.) Save it somewere like your desktop. I am going to be using visual studio for C# because who really uses any other type of C# anymore. Create a new visual c# windows forms app. We are just gonna do a health hack for now, so add a background worker and a checkbox. Now we are going to add the VAMemory dll. Right click on refrences and click on add refrence. Click on browse, and select VAMemory.dll. Now we are going to setup the VAMemory. At the top of the class type

private VAMemory vam;

public int LocalPlayer;
public int address;

Then in the Form constructor underneath you need to type

vam = new VAMemory("ac_client"); //Initialise VAMemory with the name of the process that AssaultCube is.

Now go back to the form design and double click on backgroundWorker to give you backgroundWorker1_DoWork(object sender, DoWorkEventArgs e). Now back in the constructor you need to type:

backgroundWorker1.DoWork += backgroundWorker1_DoWork;
backgroundWorker1.RunWorkerAsync();

Now we are going to need to add the addresses in int form. So at the top of your class paste these(You may need to update this for later versions of assault cube with different offsets.)

private const int PLAYER_BASE = 0x00509B74;
private const int PLAYER_HEALTH = 0xF8;
private const int PLAYER_ARMOUR = 0xFC;
private const int RIFLE = 0x128;
private const int RIFLE_CLIP = 0x150;
private const int PISTOL = 0x114;
private const int PISTOL_CLIP = 0x13C;
private const int GRENADES = 0x158;
private const int PLAYER_X = 0x38;
private const int PLAYER_Y = 0x3C;
private const int PLAYER_Z = 0x08;
private const int LOOK_X = 0x40;
private const int LOOK_Y = 0x44;
private const int PRIMARY_TIMER = 0x178;
private const int SECONDARY_TIMER = 0x164;
private const int MOUSE_DOWN = 0x224;

Now we are going to make some vam read and write functions:

private int readInt(int offset)
{
	address = LocalPlayer + offset;
	return vam.ReadInt32((IntPtr)address);
}
private float readFloat(int offset)
{
	address = LocalPlayer + offset;
	return vam.ReadFloat((IntPtr)address);
}
private void writeInt(int offset, int value)
{
	address = LocalPlayer + offset;
	vam.WriteInt32((IntPtr)address, value);
}
private void writeFloat(int offset, float value)
{
	address = LocalPlayer + offset;
	vam.WriteFloat((IntPtr)address, value);
}

Now back in the constructer under the vam definition add the following line:

LocalPlayer = vam.ReadInt32((IntPtr)PLAYER_BASE);

Now in the backgroundWorker1_DoWork function, we are going to have our infinite loop. So add a while(true) loop. And then inside of it we are going to write to health value every time we update. So inside the loop add:

writeInt(PLAYER_HEALTH, 9999);

So far your code should look somewhat like this:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Trainer_For_Tutorial
{
    public partial class Form1 : Form
    {
        private const int PLAYER_BASE = 0x00509B74;
        private const int PLAYER_HEALTH = 0xF8;
        private const int PLAYER_ARMOUR = 0xFC;
        private const int RIFLE = 0x128;
        private const int RIFLE_CLIP = 0x150;
        private const int PISTOL = 0x114;
        private const int PISTOL_CLIP = 0x13C;
        private const int GRENADES = 0x158;
        private const int PLAYER_X = 0x38;
        private const int PLAYER_Y = 0x3C;
        private const int PLAYER_Z = 0x08;
        private const int LOOK_X = 0x40;
        private const int LOOK_Y = 0x44;
        private const int PRIMARY_TIMER = 0x178;
        private const int SECONDARY_TIMER = 0x164;
        private const int MOUSE_DOWN = 0x224;

        private VAMemory vam;

        public int LocalPlayer;
        public int address;

        public Form1()
        {
            InitializeComponent();

            vam = new VAMemory("ac_client");
            LocalPlayer = vam.ReadInt32((IntPtr)PLAYER_BASE);

            backgroundWorker1.DoWork += backgroundWorker1_DoWork;
            backgroundWorker1.RunWorkerAsync();
        }

        private int readInt(int offset)
        {
            address = LocalPlayer + offset;
            return vam.ReadInt32((IntPtr)address);
        }
        private float readFloat(int offset)
        {
            address = LocalPlayer + offset;
            return vam.ReadFloat((IntPtr)address);
        }
        private void writeInt(int offset, int value)
        {
            address = LocalPlayer + offset;
            vam.WriteInt32((IntPtr)address, value);
        }
        private void writeFloat(int offset, float value)
        {
            address = LocalPlayer + offset;
            vam.WriteFloat((IntPtr)address, value);
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            while(true)
            {
                writeInt(PLAYER_HEALTH, 9999);
            }
        }
    }
}

And so far you have a pretty functional trainer. However what we are going to do is let you toggle the hack. So simple put the writeInt(PLAYER_HEALTH, 9999); inside of

if(checkBox1.Checked)
{

}

Now you can probally figure out how to do the rest from here, but I will teach you how to do a keyboard hook, because we want to get keyboard input while a different window is selected. So first we are going to need to add these two usings:

using System.Runtime.InteropServices;
using System.Diagnostics;

Next we will make a struct outside of the class for the KeyHook:

[StructLayout(LayoutKind.Sequential)]
public struct KeyHook
{
	public Keys key;
	public int Code;
	public int flags;
	public int time;
	public IntPtr extra;
}

Add these new variables just before the constructor:

private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int id, LowLevelKeyboardProc callback, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool UnhookWindowsHookEx(IntPtr hook);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hook, int nCode, IntPtr wp, IntPtr lp);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string name);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern short GetAsyncKeyState(Keys key);
private IntPtr ptrHook;
private LowLevelKeyboardProc objKeyboardProcess;

Add this to the bottom of the constructor:

ProcessModule objCurrentModule = Process.GetCurrentProcess().MainModule;
objKeyboardProcess = new LowLevelKeyboardProc(captureKey);
ptrHook = SetWindowsHookEx(13, objKeyboardProcess, GetModuleHandle(objCurrentModule.ModuleName), 0);

Add this method somewhere:

private IntPtr captureKey(int nCode, IntPtr wp, IntPtr lp)
{
	if (nCode >= 0)
	{
		KeyHook objKeyInfo = (KeyHook)Marshal.PtrToStructure(lp, typeof(KeyHook));
		if(objKeyInfo.key == Keys.Delete)
		{
			Application.Exit();
		}
	}
	return CallNextHookEx(ptrHook, nCode, wp, lp);
}

Add this to Form.Designer.cs:

using System;

And finally add this to Form.Designer.cs in the dispose function:

if(ptrHook != IntPtr.Zero)
{
	UnhookWindowsHookEx(ptrHook);
	ptrHook = IntPtr.Zero;
}

All your code together should look like this:

Form1.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace Trainer_For_Tutorial
{
    [StructLayout(LayoutKind.Sequential)]
    public struct KeyHook
    {
        public Keys key;
        public int Code;
        public int flags;
        public int time;
        public IntPtr extra;
    }

    public partial class Form1 : Form
    {
        private const int PLAYER_BASE = 0x00509B74;
        private const int PLAYER_HEALTH = 0xF8;
        private const int PLAYER_ARMOUR = 0xFC;
        private const int RIFLE = 0x128;
        private const int RIFLE_CLIP = 0x150;
        private const int PISTOL = 0x114;
        private const int PISTOL_CLIP = 0x13C;
        private const int GRENADES = 0x158;
        private const int PLAYER_X = 0x38;
        private const int PLAYER_Y = 0x3C;
        private const int PLAYER_Z = 0x08;
        private const int LOOK_X = 0x40;
        private const int LOOK_Y = 0x44;
        private const int PRIMARY_TIMER = 0x178;
        private const int SECONDARY_TIMER = 0x164;
        private const int MOUSE_DOWN = 0x224;

        private VAMemory vam;

        public int LocalPlayer;
        public int address;

        private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int id, LowLevelKeyboardProc callback, IntPtr hMod, uint dwThreadId);
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool UnhookWindowsHookEx(IntPtr hook);
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hook, int nCode, IntPtr wp, IntPtr lp);
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string name);
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern short GetAsyncKeyState(Keys key);
        private IntPtr ptrHook;
        private LowLevelKeyboardProc objKeyboardProcess;

        public Form1()
        {
            InitializeComponent();

            vam = new VAMemory("ac_client");
            LocalPlayer = vam.ReadInt32((IntPtr)PLAYER_BASE);

            backgroundWorker1.DoWork += backgroundWorker1_DoWork;
            backgroundWorker1.RunWorkerAsync();

            ProcessModule objCurrentModule = Process.GetCurrentProcess().MainModule;
            objKeyboardProcess = new LowLevelKeyboardProc(captureKey);
            ptrHook = SetWindowsHookEx(13, objKeyboardProcess, GetModuleHandle(objCurrentModule.ModuleName), 0);
        }

        private int readInt(int offset)
        {
            address = LocalPlayer + offset;
            return vam.ReadInt32((IntPtr)address);
        }
        private float readFloat(int offset)
        {
            address = LocalPlayer + offset;
            return vam.ReadFloat((IntPtr)address);
        }
        private void writeInt(int offset, int value)
        {
            address = LocalPlayer + offset;
            vam.WriteInt32((IntPtr)address, value);
        }
        private void writeFloat(int offset, float value)
        {
            address = LocalPlayer + offset;
            vam.WriteFloat((IntPtr)address, value);
        }

        private IntPtr captureKey(int nCode, IntPtr wp, IntPtr lp)
        {
            if (nCode >= 0)
            {
                KeyHook objKeyInfo = (KeyHook)Marshal.PtrToStructure(lp, typeof(KeyHook));
                if (objKeyInfo.key == Keys.Delete)
                {
                    Application.Exit();
                }
            }
            return CallNextHookEx(ptrHook, nCode, wp, lp);
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            while(true)
            {
                if(Health.Checked)
                {
                    writeInt(PLAYER_HEALTH, 9999);
                }
            }
        }
    }
}

Form1.Designer.cs:

using System;

namespace Trainer_For_Tutorial
{
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            if (ptrHook != IntPtr.Zero)
            {
                UnhookWindowsHookEx(ptrHook);
                ptrHook = IntPtr.Zero;
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.Health = new System.Windows.Forms.CheckBox();
            this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
            this.SuspendLayout();
            // 
            // Health
            // 
            this.Health.AutoSize = true;
            this.Health.Location = new System.Drawing.Point(13, 13);
            this.Health.Name = "Health";
            this.Health.Size = new System.Drawing.Size(57, 17);
            this.Health.TabIndex = 0;
            this.Health.Text = "Health";
            this.Health.UseVisualStyleBackColor = true;
            // 
            // backgroundWorker1
            // 
            this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(284, 261);
            this.Controls.Add(this.Health);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.CheckBox Health;
        private System.ComponentModel.BackgroundWorker backgroundWorker1;
    }
}

And from this base, you can do pretty much any trainer type cheat. Once you completely understand this, I recomend going to DLL cheats, which I will probally do a tutorial for in the future.

C++

Coming soon

Conclusion

From all of this, you should be able to make aimbots, autoclickers and such. However this method is very easy to detect with anti-cheats, and is only reccomended for games with no anti-cheats and for learning. Eventually will do a guide on how to overlay on the screen, but until my next post, bye.

  • Like 1

Share this post


Link to post
Dabato    2
8 hours ago, ecx said:

Are you insinuating that I copied that tutorial? And I wrote the code on 2 hours of sleep, I cannot be bothered to write c++. C# is much easier at the start, because you don't have to deal with memory leaks, and getting the processID and the handle. I will probally write a c++ tutorial later. But if you are insinuating that I copied it, basic C# code that literally uses two functions is going to look simular. I have never actually seen that tutorial in my life.

Edited by Dabato
Typo
  • Like 1
  • Downvote 3

Share this post


Link to post
Narka    614
20 hours ago, ecx said:

Are we developing cheats so we can use them to have fun, or are we developing cheats so we can flex that we have written them in a certain language? C# is well supported and more than enough for manipulating a game that has absolutely no anti-cheat to speak of.

Edited by BeeJesus
  • Upvote 1

Share this post


Link to post
revan114    1186
1 hour ago, BeeJesus said:

Are we developing cheats so we can use them to have fun, or are we developing cheats so we can flex that we have written them in a certain language? C# is well supported and more than enough for manipulating a game that has absolutely no anti-cheat to speak of.

real hackers use c++

 

Share this post


Link to post
ecx    12
3 hours ago, BeeJesus said:

Are we developing cheats so we can use them to have fun, or are we developing cheats so we can flex that we have written them in a certain language? C# is well supported and more than enough for manipulating a game that has absolutely no anti-cheat to speak of.

Sure, maybe if you really like seeing

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]

and Pinvoke everywhere in your code. better just to start in the language you're going to end up writing in anyways, C++. ever try writing an internal in c#? Lol. C# is more work than c/c++ for game cheats, unless you don't understand strcmp or malloc or pointers.

Edited by ecx
  • Upvote 1
  • Downvote 1

Share this post


Link to post
revan114    1186
On 12/19/2017 at 6:03 PM, ecx said:

Sure, maybe if you really like seeing


[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]

and Pinvoke everywhere in your code. better just to start in the language you're going to end up writing in anyways, C++. ever try writing an internal in c#? Lol

this.

pinvoking shit in c# is good for small hacks, but if you want to do anything that actually requires more substance, you're going to be fucking annoyed. c# wasnt meant for this shit. just use c++ instead, and if you really need c#, just do the shit meant for c++ in c++ and then pinvoke that instead of trying it all in c#.

now that being said,

On 12/19/2017 at 3:06 PM, BeeJesus said:

Are we developing cheats so we can use them to have fun, or are we developing cheats so we can flex that we have written them in a certain language? C# is well supported and more than enough for manipulating a game that has absolutely no anti-cheat to speak of.

 

uh sir,

"Choose the right tool for the right job."

Edited by revan114

Share this post


Link to post
Sirenfal    4034

For whatever it's worth, I think C# is a much better language for any hack more complex than two dozen lines or so. The investment in abstraction pays off for rapid prototyping, updates, and clearer and more concise code.

If you were just using PInvoke directly instead of making a managed wrapper around the underlying calls you're doing it wrong. There's nothing different about abstracting away these underlying low level concepts versus abstracting away every other kind of low level concept that's done out of the box in every high level language.

If you run C# in /unsafe mode you barely even need to use PInvoke anyway since you bootstrap the CLR and access the game's memory directly (just as you would in C).

This is just preference as far as I'm concerned.

  • Like 1

Share this post


Link to post
ecx    12
23 hours ago, Sirenfal said:

For whatever it's worth, I think C# is a much better language for any hack more complex than two dozen lines or so. The investment in abstraction pays off for rapid prototyping, updates, and clearer and more concise code.

If you were just using PInvoke directly instead of making a managed wrapper around the underlying calls you're doing it wrong. There's nothing different about abstracting away these underlying low level concepts versus abstracting away every other kind of low level concept that's done out of the box in every high level language.

If you run C# in /unsafe mode you barely even need to use PInvoke anyway since you bootstrap the CLR and access the game's memory directly (just as you would in C).

This is just preference as far as I'm concerned.

C# doesn't have certain features, such as __declspec(native), __thiscall, pragma pack, or inline asm for instance. While you can generally avoid these in C/C++, they can come much in handy in certain spots. I have written code that is *definitely* not portable to C# because the hooking mechanism uses push/popad and push/popfd. Making game cheats in c# is a horrible idea, because you are interfacing with the game with little to no abstraction; C# just forces you to jump through another layer of hurdles to get your code working correctly.

Edited by ecx

Share this post


Link to post
Sirenfal    4034
8 minutes ago, ecx said:

C# doesn't have certain features, such as __declspec or inline asm for instance. While you can generally avoid these in C/C++, they can come much in handy in certain spots. I have written code that is *definitely* not portable to C# because the hooking mechanism uses push/popad and push/popfd.

Inline assembly is possible with some delegate magic-

https://stackoverflow.com/questions/3216535/x86-x64-cpuid-in-c-sharp/7964376#7964376

https://www.codeproject.com/Tips/855149/Csharp-Fast-Memory-Copy-Method-with-x-Assembly-Usa

You would need to translate the assembly instructions to their byte equivalents, but it works. You could also just write a 10 line C++ or Visual C++ DLL and call it with PInvoke if you had to do this.

I'm sure __declspec is manageable too but I'm not sure about it.

Like you said, it's handy in "certain spots". 99 out of 100 times you shouldn't need it. When you do need it you have options.

Share this post


Link to post
ecx    12

Of course, I'm aware you can write the low-level "plumbing" code (hooks, etc.) in C++ and then call it from C#, thereby abstracting away the low-level stuff, this just seems clunky and annoying to me. It's not *hard* to write C/C++ by any means and the abstraction granted by using a high level language usually is not useful. One issue that comes to mind would be a cheat gui interface, which could be annoying to write in C++ as opposed to C#, but it really isn't that bad at all if you are disciplined about it.

Edit: just read your most recent post. I already think inline asm is a huge code smell. Using pre-assembled bytes is much worse, in my opinion. Isn't the whole point of C# to have fast prototyping? Having to copypaste bytes from an assembler does not seem like fast prototyping to me. As for the 99/100 times argument: if you are doing anything interesting at all, C++ is usually just much easier to work with IMO, since the game you are targeting *typically* was written in C++ too, so the ABI's match up. This means you can just call functions after defining the prototype and assuming your compiler is up to play ball things will just werk (and assuming you understand calling conventions).

This is not to say I do not prefer c# to C++ in general. I like C# a lot as a language, it's one of my top 5 by far. I just think that C# is not the right tool for this job.

Edited by ecx

Share this post


Link to post
ecx    12

Okay, I think I misunderstood your argument. C# makes sense if you're writing something massive, like a complicated AI or bot (think WoW). You would write an underlying API to interface with the game (and setup hooks, call game funcs, etc) in C++ and call that from C#, I would NOT want to write a full AI in C++. As for simpler cheats, like in csgo or pubg, the actual cheat behavior is pretty limited, and most of the complexity lies in interfacing with the game. In that case, C++ is probably a better idea. So I think we don't disagree here.

Edited by ecx
  • Upvote 2

Share this post


Link to post
rakiru    2713

That covers what I generally do: entirely C/C++ for smaller stuff, but for larger things, use it to embed and provide some hooks for Lua/Python/C#.

Not that any of this really matters most of the time, because 90% of games are written in Unity, so not only do you get C# out of the box, but you get everything the game engine has with no effort. Now you too can be a 1337 game h4xx0r with zero effort!

Share this post


Link to post
rakiru    2713

I know you're shitposting, but DYLD_INSERT_LIBRARIES or vm_read/write() seem like promising starts. I imagine they also have ptrace() in some form.

  • Like 1

Share this post


Link to post
revan114    1186
12 hours ago, ecx said:

I would NOT want to write a full AI in C++.

once i wrote an irc bot in c

WULm84q.jpg

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×