Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


C# Trainer Tutorial (With Example)
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Tutorials
View previous topic :: View next topic  
Author Message
KryziK
Expert Cheater
Reputation: 3

Joined: 16 Aug 2009
Posts: 199

PostPosted: Sun Jan 16, 2011 6:59 pm    Post subject: C# Trainer Tutorial (With Example) This post has 2 review(s) Reply with quote

This code DOES work, but some of it is outdated/poorly written. I'm in the process of updating but it may never make it to the forums depending on how busy I stay. I'm quite new to C#, so I apologize for the inconvenience.

Hello!

I've recently started using C# for making trainers, and I thought I'd show others how to do it.

Before we begin, the memory functions that I am using, excluding:
    Memory: ReadPointer(), WritePointer(), PID(), BaseAddressH(), BaseAddressD()
    Addr: ToHex(), ToDec(), Make()

ARE NOT MINE. They were found HERE. In other words, I only wrote the funtions listed in bold, along with the code for the buttons. With that out of the way, let's begin!

Start a new WindowsFormsApplication. Name it whatever you'd like. I'm naming mine CET_Trainer, because we will be making a trainer for Cheat Engine's Tutorial-i386.exe (The new one).



Now, under the Solution Explorer, find Form1.cs. Rename it to 'TrainerForm.cs'.
This step is optional. I only changed it because I think Form1.cs is ugly and not very descriptive.



Next, go to your Form Builder, under properties, and change:
    Name to 'hForm'
    Text to '[Trainer] Cheat Engine Tutorial'

You can pick and Name and Text you want, but I recommend my suggestions so it's easier to follow the tutorial.
Note: You may have to adjust the size of the window a little bit so that the whole title is shown.



Now, create a button on your form, and change:
    Name to 'hButton_Step2'
    Text to 'Complete Step 2'

Again, you can change these to whatever you prefer.



Double-Click on your Button, and an Event will be created.
This event will be triggered when the button is clicked.
A code window should have opened up, and should look like this:



We will come back to this event later. First, we need to add our Memory Functions.
Add these to the top of the file, under the other using statements:
Code:
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Globalization;




These will allow us additional functionality such as getting a ProcessID from it's name.

Now, copy this code, and paste it under the Form Class, as shown:
Code:
class MemoryAPI
{
   [Flags]
   public enum ProcessAccessType
   {
      PROCESS_TERMINATE = (0x0001),
      PROCESS_CREATE_THREAD = (0x0002),
      PROCESS_SET_SESSIONID = (0x0004),
      PROCESS_VM_OPERATION = (0x0008),
      PROCESS_VM_READ = (0x0010),
      PROCESS_VM_WRITE = (0x0020),
      PROCESS_DUP_HANDLE = (0x0040),
      PROCESS_CREATE_PROCESS = (0x0080),
      PROCESS_SET_QUOTA = (0x0100),
      PROCESS_SET_INFORMATION = (0x0200),
      PROCESS_QUERY_INFORMATION = (0x0400)
   }

   [DllImport("kernel32.dll")]
   public static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, Int32 bInheritHandle, UInt32 dwProcessId);

   [DllImport("kernel32.dll")]
   public static extern Int32 CloseHandle(IntPtr hObject);

   [DllImport("kernel32.dll")]
   public static extern Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] buffer, UInt32 size, out IntPtr lpNumberOfBytesRead);

   [DllImport("kernel32.dll")]
   public static extern Int32 WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] buffer, UInt32 size, out IntPtr lpNumberOfBytesWritten);
}

public class Memory
{
   public Memory()
   {
   }

   public Process ReadProcess
   {
      get
      {
         return m_ReadProcess;
      }
      set
      {
         m_ReadProcess = value;
      }
   }
   private Process m_ReadProcess = null;
   private IntPtr m_hProcess = IntPtr.Zero;

   public void Open()
   {
      MemoryAPI.ProcessAccessType access = MemoryAPI.ProcessAccessType.PROCESS_VM_READ
      | MemoryAPI.ProcessAccessType.PROCESS_VM_WRITE
      | MemoryAPI.ProcessAccessType.PROCESS_VM_OPERATION;
      m_hProcess = MemoryAPI.OpenProcess((uint)access, 1, (uint)m_ReadProcess.Id);
   }

   public void CloseHandle()
   {
      int iRetValue;
      iRetValue = MemoryAPI.CloseHandle(m_hProcess);
      if (iRetValue == 0)
         throw new Exception("CloseHandle Failed");
   }

   public byte[] Read(IntPtr MemoryAddress, uint bytesToRead, out int bytesRead)
   {
      byte[] buffer = new byte[bytesToRead];
      IntPtr ptrBytesRead;
      MemoryAPI.ReadProcessMemory(m_hProcess, MemoryAddress, buffer, bytesToRead, out ptrBytesRead);
      bytesRead = ptrBytesRead.ToInt32();
      return buffer;
   }

   public byte[] PointerRead(IntPtr MemoryAddress, uint bytesToRead, int[] Offset, out int bytesRead)
   {
      int iPointerCount = Offset.Length - 1;
      IntPtr ptrBytesRead;
      bytesRead = 0;
      byte[] buffer = new byte[4]; //DWORD to hold an Address
      int tempAddress = 0;

      if (iPointerCount == 0)
      {
         MemoryAPI.ReadProcessMemory(m_hProcess, MemoryAddress, buffer, 4, out ptrBytesRead);
         tempAddress = Addr.ToDec(Addr.Make(buffer)) + Offset[0]; //Final Address

         buffer = new byte[bytesToRead];
         MemoryAPI.ReadProcessMemory(m_hProcess, (IntPtr)tempAddress, buffer, bytesToRead, out ptrBytesRead);

         bytesRead = ptrBytesRead.ToInt32();
         return buffer;
      }

      for (int i = 0; i <= iPointerCount; i++)
      {
         if (i == iPointerCount)
         {
            MemoryAPI.ReadProcessMemory(m_hProcess, (IntPtr)tempAddress, buffer, 4, out ptrBytesRead);
            tempAddress = Addr.ToDec(Addr.Make(buffer)) + Offset[i]; //Final Address

            buffer = new byte[bytesToRead];
            MemoryAPI.ReadProcessMemory(m_hProcess, (IntPtr)tempAddress, buffer, bytesToRead, out ptrBytesRead);

            bytesRead = ptrBytesRead.ToInt32();
            return buffer;
         }
         else if (i == 0)
         {
            MemoryAPI.ReadProcessMemory(m_hProcess, MemoryAddress, buffer, 4, out ptrBytesRead);
            tempAddress = Addr.ToDec(Addr.Make(buffer)) + Offset[1];
         }
         else
         {
            MemoryAPI.ReadProcessMemory(m_hProcess, (IntPtr)tempAddress, buffer, 4, out ptrBytesRead);
            tempAddress = Addr.ToDec(Addr.Make(buffer)) + Offset[i];
         }
      }

      return buffer;
   }

   public void Write(IntPtr MemoryAddress, byte[] bytesToWrite, out int bytesWritten)
   {
      IntPtr ptrBytesWritten;
      MemoryAPI.WriteProcessMemory(m_hProcess, MemoryAddress, bytesToWrite, (uint)bytesToWrite.Length, out ptrBytesWritten);
      bytesWritten = ptrBytesWritten.ToInt32();
   }

   public string PointerWrite(IntPtr MemoryAddress, byte[] bytesToWrite, int[] Offset, out int bytesWritten)
   {
      int iPointerCount = Offset.Length - 1;
      IntPtr ptrBytesWritten;
      bytesWritten = 0;
      byte[] buffer = new byte[4]; //DWORD to hold an Address
      int tempAddress = 0;

      if (iPointerCount == 0)
      {
         MemoryAPI.ReadProcessMemory(m_hProcess, MemoryAddress, buffer, 4, out ptrBytesWritten);
         tempAddress = Addr.ToDec(Addr.Make(buffer)) + Offset[0]; //Final Address
         MemoryAPI.WriteProcessMemory(m_hProcess, (IntPtr)tempAddress, bytesToWrite, (uint)bytesToWrite.Length, out ptrBytesWritten);

         bytesWritten = ptrBytesWritten.ToInt32();
         return Addr.ToHex(tempAddress);
      }

      for (int i = 0; i <= iPointerCount; i++)
      {
         if (i == iPointerCount)
         {
            MemoryAPI.ReadProcessMemory(m_hProcess, (IntPtr)tempAddress, buffer, 4, out ptrBytesWritten);
            tempAddress = Addr.ToDec(Addr.Make(buffer)) + Offset[i]; //Final Address
            MemoryAPI.WriteProcessMemory(m_hProcess, (IntPtr)tempAddress, bytesToWrite, (uint)bytesToWrite.Length, out ptrBytesWritten);

            bytesWritten = ptrBytesWritten.ToInt32();
            return Addr.ToHex(tempAddress);
         }
         else if (i == 0)
         {
            MemoryAPI.ReadProcessMemory(m_hProcess, MemoryAddress, buffer, 4, out ptrBytesWritten);
            tempAddress = Addr.ToDec(Addr.Make(buffer)) + Offset[i];
         }
         else
         {
            MemoryAPI.ReadProcessMemory(m_hProcess, (IntPtr)tempAddress, buffer, 4, out ptrBytesWritten);
            tempAddress = Addr.ToDec(Addr.Make(buffer)) + Offset[i];
         }
      }

      return Addr.ToHex(tempAddress);
   }

   public int PID()
   {
      return m_ReadProcess.Id;
   }

   public string BaseAddressH()
   {
      return Addr.ToHex(m_ReadProcess.MainModule.BaseAddress.ToInt32());
   }

   public int BaseAddressD()
   {
      return m_ReadProcess.MainModule.BaseAddress.ToInt32();
   }
}

public class Addr
{
   public static string Make(byte[] buffer)
   {
      string sTemp = "";

      for (int i = 0; i < buffer.Length; i++)
      {
         if (Convert.ToInt16(buffer[i]) < 10)
            sTemp = "0" + ToHex(buffer[i]) + sTemp;
         else
            sTemp = ToHex(buffer[i]) + sTemp;
      }

      return sTemp;
   }

   public static string ToHex(int Decimal)
   {
      return Decimal.ToString("X"); //Convert Decimal to Hexadecimal
   }

   public static int ToDec(string Hex)
   {
      return int.Parse(Hex, NumberStyles.HexNumber); //Convert Hexadecimal to Decimal
   }
}



Your code should now look like this (when the classes are minimized):



Alright, now that our memory functions are added to our project, it's time to make our button do something!

Add this code in the Form Class:
Code:
Memory oMemory = new Memory();




Add this code to the Event we described earlier:
Code:
Process[] aProcesses = Process.GetProcessesByName("Tutorial-i386"); //Find Tutorial-i386.exe
if (aProcesses.Length != 0) //If the process exists
{
      oMemory.ReadProcess = aProcesses[0]; //Sets the Process to Read/Write From/To
   oMemory.Open(); //Open Process

   int iStep2_Address = Addr.ToDec("57C310"); //The static address of the pointer (#1)
   int[] iStep2_Offsets = { 0x98, 0x4, 0x288, 0x24, 0x458 }; //Offsets from bottom to top (#2-#6)

   int bytesWritten; //Holds how many bytes were written by PointerWrite

   int iValue_To_Write = 1000; //Value that we want to write (Step2 requires that you change the value to 1000)
   byte[] bValue_To_Write = BitConverter.GetBytes(iValue_To_Write); //Turns 1000 into bytes

   string sWritten_Address = oMemory.PointerWrite((IntPtr)iStep2_Address, //PointerWrite starting with our Step2 Address
                     bValue_To_Write, //The value to write (as bytes)
                     iStep2_Offsets, //Our offsets
                     out bytesWritten); //Stores the # of Written Bytes

   if (bytesWritten == bValue_To_Write.Length) //If writing was successful
      MessageBox.Show("Wrote " + iValue_To_Write.ToString() + " to " + sWritten_Address + "!"); //Notify the user of success
   else
      MessageBox.Show("There was an error writing " + iValue_To_Write.ToString() + " to " + sWritten_Address + "."); //Notify the user of failure

   oMemory.CloseHandle(); //Close Memory Handle
}




If you found the pointer yourself, you will most likely have a different number of offsets as me, so change them accordingly. Otherwise, mine should work for you.

Unless I'm forgetting anything (which we will find out soon enough), Run your project, open Tutorial-i386.exe, and press Complete Step 2.
Now go to the Tutorial and see if Next is Enabled!

If not, make sure your Address and Offsets are correct. Check to see if the Address that the MessageBox shows is the same as in your Cheat Table ("P->XXXXXXXX")

This is how you determine iStep2_Address and iStep2_Offsets:


Note: These numbers (#1-#6) are referred to in the comments. #1 DOES NOT mean the first offset.

Now wait! What if you want to write somethine like a Float? Here's how:

Simply change:
Code:
byte[] bValue_To_Write = BitConverter.GetBytes(iValue_To_Write); //Turns 1000 into bytes

To:
Code:
byte[] bValue_To_Write = BitConverter.GetBytes((float)iValue_To_Write); //Turns 1000 into bytes


Here is a list of types. I can only confirm the usage of (float) and (double) as of now.

That concludes my tutorial! Please let me know if I forgot something, or if something is incorrect.
Also, feel free to ask questions, and I do take requests on trainers and possibly tutorials. It all depends!

Here is the whole project. It has a few more steps done so you can look at them!
Source Code - Steps 1,2,3,4,5,6,8


Last edited by KryziK on Wed Jan 26, 2011 7:58 pm; edited 1 time in total
Back to top
View user's profile Send private message
AhMunRa
Grandmaster Cheater Supreme
Reputation: 27

Joined: 06 Aug 2010
Posts: 1117

PostPosted: Mon Jan 17, 2011 9:15 am    Post subject: Reply with quote

Excellent, as a C# user, this will come in very handy.
_________________
<Wiccaan> Bah that was supposed to say 'not saying its dead' lol. Fixing >.>
Back to top
View user's profile Send private message
KryziK
Expert Cheater
Reputation: 3

Joined: 16 Aug 2009
Posts: 199

PostPosted: Mon Jan 17, 2011 10:54 am    Post subject: Reply with quote

Hopefully I was clear enough for people to be able to form it to their needs. I did not review static addresses without pointers, but those should be easy enough to figure out, as the functions are there.
Back to top
View user's profile Send private message
ej52
Cheater
Reputation: 0

Joined: 29 Mar 2011
Posts: 39
Location: Mother City

PostPosted: Wed Mar 30, 2011 3:01 pm    Post subject: Reply with quote

@darkjohn20 thx for this useful info Smile

I used this code as a base 4 my 1st trainer yesterday and it works great.

Had sum trouble figuring out how 2 dynamically create the byte arrays as
there does not seem 2 be alot of support 4 C# when it comes 2 ASM ...
but with abit of patience and alot of searching i managed 2 code a some
wat limited ASM class that genarates the byte arrays 4 simple instructions Smile

Anyway thx again
Ej52
Back to top
View user's profile Send private message
GH*master
Expert Cheater
Reputation: 8

Joined: 10 Jan 2008
Posts: 159

PostPosted: Wed Mar 30, 2011 4:14 pm    Post subject: Reply with quote

darkjohn20, WinAPI unmanaged code must be written in C++ language in the module "... .dll" as the exported functions for managed code. Your style of programming in C # is a bad ...
Back to top
View user's profile Send private message
atom0s
Moderator
Reputation: 198

Joined: 25 Jan 2006
Posts: 8517
Location: 127.0.0.1

PostPosted: Thu Mar 31, 2011 7:02 am    Post subject: Reply with quote

GH*master wrote:
darkjohn20, WinAPI unmanaged code must be written in C++ language in the module "... .dll" as the exported functions for managed code. Your style of programming in C # is a bad ...


Uh no? You don't have to import API through DLLs. You are just creating another layer of unneeded bullshit rather then just using DllImport, which is built into the language for a reason; using API.

The wrappers he made around the imported API could be written better, but none of this needs to be in a DLL, this isn't bad style its following the language standards.

_________________
- Retired.
Back to top
View user's profile Send private message Visit poster's website
frank_mascarado
How do I cheat?
Reputation: 0

Joined: 03 Jun 2007
Posts: 5

PostPosted: Thu Mar 31, 2011 1:15 pm    Post subject: Reply with quote

even though the pictures do not appear is a good tutorial for beginners:)
_________________
3haat eng1ne 6.0 Rev 1725

img96.imageshack.us/img96/6062/asdryz.jpg
Back to top
View user's profile Send private message
ej52
Cheater
Reputation: 0

Joined: 29 Mar 2011
Posts: 39
Location: Mother City

PostPosted: Thu Mar 31, 2011 1:26 pm    Post subject: Reply with quote

GH*master wrote:
WinAPI unmanaged code must be written in C++ language in the module

Not true, as Wiccaan said Smile

frank_mascarado wrote:
even though the pictures do not appear is a good tutorial for beginners:)

All the images show for me ...

_________________
Hitler dNt HiDe WaT mOtHa NaTurE pRoViDe ... Razz
Back to top
View user's profile Send private message
KryziK
Expert Cheater
Reputation: 3

Joined: 16 Aug 2009
Posts: 199

PostPosted: Thu Mar 31, 2011 2:53 pm    Post subject: Reply with quote

Here is the most recent version of my C# Memory Stuff. I think it is written quite a bit better. It does make a DLL, however the .cs file can be put straight into a project so that a DLL is not required.
Back to top
View user's profile Send private message
GH*master
Expert Cheater
Reputation: 8

Joined: 10 Jan 2008
Posts: 159

PostPosted: Fri Apr 01, 2011 7:27 am    Post subject: Reply with quote

ej52 wrote:
GH*master wrote:
WinAPI unmanaged code must be written in C++ language in the module

Not true, as Wiccaan said Smile


Maybe YOU or others did not understand me.
Maybe others have little experience of programming and code injection in games.

Think about "why Cheat Engine has a "dll injection "?! "
How can this be attributed to the managed and unmanaged code?
What might be useful managed code? What might be useful unmanaged code?
Think about it. The answer to these questions lies in the many features.
Back to top
View user's profile Send private message
shadi
Newbie cheater
Reputation: 0

Joined: 21 Apr 2011
Posts: 11

PostPosted: Thu Apr 21, 2011 10:58 am    Post subject: Reply with quote

thanks but the photo didnt show
Back to top
View user's profile Send private message
atom0s
Moderator
Reputation: 198

Joined: 25 Jan 2006
Posts: 8517
Location: 127.0.0.1

PostPosted: Thu Apr 21, 2011 2:34 pm    Post subject: Reply with quote

GH*master wrote:
ej52 wrote:
GH*master wrote:
WinAPI unmanaged code must be written in C++ language in the module

Not true, as Wiccaan said Smile


Maybe YOU or others did not understand me.
Maybe others have little experience of programming and code injection in games.

Think about "why Cheat Engine has a "dll injection "?! "
How can this be attributed to the managed and unmanaged code?
What might be useful managed code? What might be useful unmanaged code?
Think about it. The answer to these questions lies in the many features.


What does that have to do with what you said? API can be called in any language (managed or not) as long as it has proper access. C# in this case has full access to the system API and can call it. Which is why I said it does not need to be written in unmanaged code.

And you can also inject managed code too, not just unmanaged.

_________________
- Retired.
Back to top
View user's profile Send private message Visit poster's website
Uber
How do I cheat?
Reputation: 0

Joined: 15 Dec 2010
Posts: 4
Location: Core

PostPosted: Wed May 04, 2011 8:31 am    Post subject: Reply with quote

amazing C# tutorial. I'm not that good in C# only VB.NET but I'm pretty sure I can slowly understand it.

PS: Needs a lot of reading though Razz

EDIT:
Can you make a trainer for virtual villagers 5? I would love the source if you don't mind.

_________________
"We Are The World"
Back to top
View user's profile Send private message
Vulcanraven
Newbie cheater
Reputation: 0

Joined: 17 Feb 2008
Posts: 19
Location: Germany

PostPosted: Sat Jun 11, 2011 7:29 pm    Post subject: Reply with quote

thanks for the multipointer code thats useful Smile
_________________
Cheat Engine German translation in progress...
Back to top
View user's profile Send private message
iMockBa
How do I cheat?
Reputation: 0

Joined: 01 Sep 2011
Posts: 3

PostPosted: Thu Sep 01, 2011 6:00 am    Post subject: Reply with quote

Hi.. i want ask how can i read memory by using this script .

i tryed it for writing values & its work perfectly ...but as new on c# i cant find out how to tranceform that script for reading memory .

and other litl question .. in section

int iValue_To_Write = (1000); //Value that we want to write (Step2 requires that you change the value to 1000)

walue to write is inside of script ....& i would like to make that posible to write that value by user inside of TextBox ..... so how can i tranceform String on Int ? if change the cod on

int iValue_To_Write = (TextBox.Text);
i m getting error .

Previously Thanks for any help.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Tutorials All times are GMT - 6 Hours
Goto page 1, 2, 3  Next
Page 1 of 3

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites