 |
Cheat Engine The Official Site of Cheat Engine
|
| View previous topic :: View next topic |
| Author |
Message |
ej52 Cheater
Reputation: 0
Joined: 29 Mar 2011 Posts: 39 Location: Mother City
|
Posted: Wed Mar 30, 2011 8:31 pm Post subject: [C#]Trainer Code Injection (Example) |
|
|
Hey all
I only started coding game trainers yesterday so please feel free to tell me
if i am doing something wrong or if there is a better way of doing it
This is just a quick example on how to create a "code cave" and inject code, using C#.
I am using the memory functions from Darkjohn20's thread called "C# Trainer Tutorial (With Example)"
which is located in the "Cheat Engine Tutorials" Section, i just added a few functions to create the "code cave".
Here is the code i added ...
MemoryAPI Class:
| Code: |
[Flags]
public enum AllocType
{
Commit = 0x1000,
Reserve = 0x2000,
Decommit = 0x4000,
}
[Flags]
public enum Protect
{
Execute = 0x10,
ExecuteRead = 0x20,
ExecuteReadWrite = 0x40,
}
[Flags]
public enum FreeType
{
Decommit = 0x4000,
Release = 0x8000,
}
|
| Code: |
[DllImport("kernel32.dll")]
public static extern Int32 VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, AllocType flAllocationType, Protect flProtect);
[DllImport("kernel32.dll")]
public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, FreeType dwFreeType);
|
Memory Class:
| Code: |
public void Alloc(out int Addr, int Size)
{
Addr = MemoryAPI.VirtualAllocEx(m_hProcess, IntPtr.Zero, Size, MemoryAPI.AllocType.Commit, MemoryAPI.Protect.ExecuteReadWrite);
}
public bool Dealloc(int Addr)
{
return MemoryAPI.VirtualFreeEx(m_hProcess, (IntPtr)Addr, 0, MemoryAPI.FreeType.Release);
}
|
As you can see iv'e created two public functions Alloc() and Dealloc() which act exactly the same as the equivalent functions in AA.
Here is a AA script i did for instant build with FarmFrenzy 3 IceAge ...
| Code: |
[ENABLE]
alloc(newmem,2048)
label(returnhere)
label(originalcode)
label(exit)
newmem:
originalcode:
fst dword ptr [esi+00000354]
mov dword ptr [esi+00000354],(float)20
exit:
jmp returnhere
00545943:
jmp newmem
nop
returnhere:
[DISABLE]
dealloc(newmem)
00545943:
fst dword ptr [esi+00000354]
|
Here is the exact same AA script in C#
Note this example does not have any error checking ...
| Code: |
int newmem = 0;
private void EnableHack()
{
Process[] process = Process.GetProcessesByName("FarmFrenzy3_Arctica.wrp"); //Find FarmFrenzy3_Arctica.wrp.exe
oMemory.ReadProcess = process[0]; //Sets the Process to Read/Write From/To
oMemory.Open(); //Open Process
oMemory.Alloc(out newmem, 0x800); //New memory allocation "code cave"
int ad1 = Addr.ToDec("00545943"); //Static address
int ad2 = newmem; //newmem
int ad3 = ad2 + 0x06; //newmem + 6 bytes (see bv2 below)
int ad4 = ad2 + 0x10; //newmem + 10 bytes (see bv3 below)
byte[] bv1 = Jmp(Addr.ToHex(ad2), Addr.ToHex(ad1), true); //jmp newmem nop (jmp newmem = 5 bytes, so add a nop)
byte[] bv2 = { 0xD9, 0x96, 0x54, 0x03, 0x00, 0x00 }; //fst dword ptr [esi+00000354]
byte[] bv3 = { 0xC7, 0x86, 0x54, 0x03, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x41 }; //mov [esi+00000354],41A00000
byte[] bv4 = Jmp(Addr.ToHex(ad1 + 0x06), Addr.ToHex(ad4), false); //jmp 00545949 (ad1 + 6 bytes)
int bytes; //Holds how many bytes were written by Write()
oMemory.Write((IntPtr)ad1, bv1, out bytes);
oMemory.Write((IntPtr)ad2, bv2, out bytes);
oMemory.Write((IntPtr)ad3, bv3, out bytes);
oMemory.Write((IntPtr)ad4, bv4, out bytes);
oMemory.CloseHandle(); //Close Memory Handle
}
private void DisableHack()
{
Process[] process = Process.GetProcessesByName("FarmFrenzy3_Arctica.wrp"); //Find FarmFrenzy3_Arctica.wrp.exe
oMemory.ReadProcess = process[0]; //Sets the Process to Read/Write From/To
oMemory.Open(); //Open Process
oMemory.Dealloc(newmem); //Release newmem "code cave"
int ad1 = Addr.ToDec("00545943"); //Static address
byte[] bv1 = { 0xD9, 0x96, 0x54, 0x03, 0x00, 0x00 }; //fst dword ptr [esi+00000354]
int bytes; //Holds how many bytes were written by Write()
oMemory.Write((IntPtr)ad1, bv1, out bytes);
oMemory.CloseHandle(); //Close Memory Handle
}
private byte[] Jmp(string to, string from, bool nop)
{
return Jmp(Convert.ToInt32("0x" + to, 16), Convert.ToInt32("0x" + from, 16), nop);
}
private byte[] Jmp(int to, int from, bool nop)
{
string dump = (to - from - 5).ToString("X"); //Get original bytes
if (dump.Length == 7) //Make sure we have 4 bytes
dump = "0" + dump;
dump = dump + "E9"; //Add JMP
if (nop)
dump = "90" + dump; //Add NOP if needed
byte[] hex = new byte[dump.Length / 2];
for (int i = 0; i < hex.Length; i++)
{
hex[i] = Convert.ToByte(dump.Substring(i * 2, 2), 16); //Set each byte to 2 chars
}
Array.Reverse(hex); //Reverse byte array for use with Write()
return hex;
}
|
The byte arrays for bv2 and bv3 in EnableHack(), and bv1 in DisableHack() i got from running the AA script and checking the bytes in Memory View.
Hope this can help a few of you C# coders, if any1 needs me to explain anything further jst ask
Regards
Ej52
Last edited by ej52 on Thu Mar 31, 2011 1:44 pm; edited 4 times in total |
|
| Back to top |
|
 |
Krähne Expert Cheater
Reputation: 0
Joined: 06 Jun 2010 Posts: 108 Location: Inside of my Kernel
|
Posted: Wed Mar 30, 2011 9:12 pm Post subject: |
|
|
Nice code, Very useful. btw is also valid use the String.Format for show to hex format.
Something like:
| Code: | byte[] Buffer = new byte[4] { 0xAA, 0xBB, 0xCC, 0xDD };
string HexResult = String.Empty;
HexResult = String.Format("{0:X4}", BitConverter.ToInt32(Buffer, 0)); |
_________________
Excuse me if you don't understand what I just said, but "english" isn't my native language. |
|
| Back to top |
|
 |
ej52 Cheater
Reputation: 0
Joined: 29 Mar 2011 Posts: 39 Location: Mother City
|
Posted: Sun Apr 10, 2011 6:46 am Post subject: |
|
|
@DaasCook thx 4 the comment, i have used String.Format in the opcde library
_________________
Hitler dNt HiDe WaT mOtHa NaTurE pRoViDe ...  |
|
| Back to top |
|
 |
Pingo Grandmaster Cheater
Reputation: 8
Joined: 12 Jul 2007 Posts: 571
|
Posted: Sun Apr 10, 2011 6:01 pm Post subject: |
|
|
You should make some functions for this. So you wont be using as much code.
That same injection could be as small as this
Inject(Jump_From, Next_Instruction, "Injection");
and to deallocate
DeAllocate(Jump_From);
Another thing you might want to look into is codeshifting. That code would only work for static addresses like 00545943
_________________
|
|
| Back to top |
|
 |
ej52 Cheater
Reputation: 0
Joined: 29 Mar 2011 Posts: 39 Location: Mother City
|
Posted: Sun Apr 10, 2011 6:24 pm Post subject: |
|
|
Hey Pingo
Sorry i can't reply 2 ur PM yet
This code was jst a quick example b4 i started coding the library.
The library has a method 4 nearly ever opcode instruction and
it automatically works out all the offsets by itself.
Simple example ...
| Code: |
int cave = mem.Alloc(0x400); //Create code cave of 1kb
mem.Mark(0x012E1850); //Start writing at this address
mem.Call(cave); //call "cave"
mem.Nop(); //nop
mem.Mark(cave); //Start writing to the code cave
mem.Fst(new mAddr(mReg.ESI, 0x354)); //fst [esi+00000354]
mem.Mov(new mAddr(mReg.ESI, 0x354), 20f); //mov [esi+00000354],(float)20
mem.Ret(); //ret
mem.Write(); //Write all the above instructions
|
This library makes it easy 2 convert AA scripts into .Net game trainers.
I am still workin on a few methods but hope 2 release the library soon
_________________
Hitler dNt HiDe WaT mOtHa NaTurE pRoViDe ...  |
|
| Back to top |
|
 |
Pingo Grandmaster Cheater
Reputation: 8
Joined: 12 Jul 2007 Posts: 571
|
Posted: Sun Apr 10, 2011 7:20 pm Post subject: |
|
|
Looking better. I dont think you'l need to specify the byte size when allocating. It'l get rounded up to a next page i think.
How are you storing these instruction in the mem class? Then using mem.Write();
Are you adding them to a byte array?
_________________
|
|
| Back to top |
|
 |
ej52 Cheater
Reputation: 0
Joined: 29 Mar 2011 Posts: 39 Location: Mother City
|
Posted: Mon Apr 11, 2011 12:00 am Post subject: |
|
|
Yea you are right about the byte size when allocating, did'nt read the docs properly
Yes this library has 1 main class which has methods 2 handle everything
Process, Memory and Opcodes
Ever instruction gets added 2 a List<AOB> (Which can be retrieved 4 debugging )
and writes them all when u call mem.Write().
AOB struct only has 2 properties Addr and Aob which should be self explanatory
_________________
Hitler dNt HiDe WaT mOtHa NaTurE pRoViDe ...  |
|
| Back to top |
|
 |
Pingo Grandmaster Cheater
Reputation: 8
Joined: 12 Jul 2007 Posts: 571
|
Posted: Mon Apr 11, 2011 4:36 am Post subject: |
|
|
Remember jump bytes written from one address isnt the same for another.
from 012E1850 to 1F000000 wont be the same as
from 013E1850 to 1F000000
to jump its Cave - Address - 5
to jump back its Next_Instruction - Cave - 5
You probably already know this but just incase you didnt.
_________________
|
|
| Back to top |
|
 |
ej52 Cheater
Reputation: 0
Joined: 29 Mar 2011 Posts: 39 Location: Mother City
|
Posted: Mon Apr 11, 2011 5:26 am Post subject: |
|
|
Yip i am aware of who 2 calculate the AOB for jumps
and the library calculates all the offsets automatically
thts why you dnt have 2 include the address in every
function, you just hav to mark the address where you
want 2 start writing ... mem.Mark(0x012E1850);
_________________
Hitler dNt HiDe WaT mOtHa NaTurE pRoViDe ...  |
|
| Back to top |
|
 |
Pingo Grandmaster Cheater
Reputation: 8
Joined: 12 Jul 2007 Posts: 571
|
Posted: Mon Apr 11, 2011 6:13 am Post subject: |
|
|
ah ic. How did you calculate the next instruction address? I couldnt figure that out.
Cause the jump requires 5 bytes but the next instruction might be 3 bytes away. So you'd need to go to the instruction after that to avoid a crash.
Thats why i use Jump_From, Next_Instruction.
Got any suggestions?
_________________
|
|
| Back to top |
|
 |
ej52 Cheater
Reputation: 0
Joined: 29 Mar 2011 Posts: 39 Location: Mother City
|
Posted: Mon Apr 11, 2011 6:52 am Post subject: |
|
|
If you look at my prev example i used "call" and "ret" instead of jumps
as the "ret" instruction automatically returns 2 the original code.
| Code: |
int cave = mem.Alloc(0x400); //Create code cave of 1kb
mem.Mark(0x012E1850); //Start writing at this address
mem.Call(cave); //call "cave"
mem.Nop(); //nop
mem.Mark(cave); //Start writing to the code cave
mem.Fst(new mAddr(mReg.ESI, 0x354)); //fst [esi+00000354]
mem.Mov(new mAddr(mReg.ESI, 0x354), 20f); //mov [esi+00000354],(float)20
mem.Ret(); //ret
mem.Write(); //Write all the above instructions
|
I used to use it like this with jumps ...
| Code: |
int start = 0x012E1850;
int cave = mem.Alloc(0x400); //Create code cave of 1kb
mem.Mark(start); //Start writing at this address
mem.Jmp(cave); //call "cave"
mem.Nop(); //nop
mem.Mark(cave); //Start writing to the code cave
mem.Fst(new mAddr(mReg.ESI, 0x354)); //fst [esi+00000354]
mem.Mov(new mAddr(mReg.ESI, 0x354), 20f); //mov [esi+00000354],(float)20
mem.Jmp(start + 6); //jump to start address + 6bytes (jmp + nop = 6)
mem.Write(); //Write all the above instructions
|
As you can see you would still have to manually set the address to
return to the original code with jumps, but i am workin on automating
the offsets for that aswell
_________________
Hitler dNt HiDe WaT mOtHa NaTurE pRoViDe ... 
Last edited by ej52 on Mon Apr 11, 2011 2:25 pm; edited 1 time in total |
|
| Back to top |
|
 |
Pingo Grandmaster Cheater
Reputation: 8
Joined: 12 Jul 2007 Posts: 571
|
Posted: Mon Apr 11, 2011 9:35 am Post subject: |
|
|
I might go try again. Could your class convert something like this.
| Code: | [Enable]
alloc(Cave,128)
Cave:
mov ecx,[esi+4c]
mov [Cave-8],ecx
mov ecx,[Cave-4]
mov [ecx+Cave+40],esi
cmp ecx,50
je Cave+1f
add ecx,04
jmp Cave+24
mov ecx,0
mov [Cave-4],ecx
mov ecx,[Cave-8]
mov ecx,[esi+4c]
fld dword ptr [esi+5c]
jmp game.exe+Next_Offset
game.exe+Start_Offset:
jmp Cave
[Disable]
dealloc(Cave)
game.exe+Start_Offset:
db 8b 4e 4c d9 46 5c |
moving values in and out of the cave
_________________
|
|
| Back to top |
|
 |
ej52 Cheater
Reputation: 0
Joined: 29 Mar 2011 Posts: 39 Location: Mother City
|
Posted: Mon Apr 11, 2011 10:33 am Post subject: |
|
|
Yip it can, heres what it will look like in C#
| Code: |
int cave = mem.Alloc(128);
mem.Mark(Start_Offset);
mem.Jmp(cave);
mem.Mark(cave);
mem.Mov(mReg.ECX, new mAddr(mReg.ESI, 0x4C));
mem.Mov(new mAddr(cave - 8), mReg.ECX);
mem.Mov(mReg.ECX, new mAddr(cave-4));
mem.Mov(new mAddr(mReg.ECX, cave + 0x40), mReg.ESI);
mem.Cmp(mReg.ECX, (byte)0x50);
mem.Jmp(mCond.Equal, cave + 0x1F); //jumps to ( mov ecx,0 )
mem.Add(mReg.ECX, (byte)4);
mem.Jmp(cave + 0x24); //jumps to ( mov [cave-4],ecx )
mem.Mov(mReg.ECX, 0);
mem.Mov(new mAddr(cave - 4), mReg.ECX);
mem.Mov(mReg.ECX, new mAddr(cave - 8));
mem.Mov(mReg.ECX, new mAddr(mReg.ESI, 0x4C));
mem.Fld(new mAddr(mReg.ESI, 0x5C));
mem.Jmp(Start_Offset + 5); //jumps to original instruction code
|
As you can see the last offset you will have 2 calculate yourself
or just get it from the memory view in CE.
As i said b4 this library just makes it easier to convert AA into .Net
its upto the user 2 set the correct addresses and offsets.
As for deallocating the code cave there is a method for tht 2
_________________
Hitler dNt HiDe WaT mOtHa NaTurE pRoViDe ...  |
|
| Back to top |
|
 |
Pingo Grandmaster Cheater
Reputation: 8
Joined: 12 Jul 2007 Posts: 571
|
Posted: Tue Apr 12, 2011 8:54 am Post subject: |
|
|
Pure sweetness! Let me know when you're at the testing stage. I'll try it.
_________________
|
|
| Back to top |
|
 |
atom0s Moderator
Reputation: 205
Joined: 25 Jan 2006 Posts: 8587 Location: 127.0.0.1
|
|
| Back to top |
|
 |
|
|
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
|
|