Cheat Engine

Main

Forum

About Cheat Engine

About DBVM

Bugtracker

Downloads

Tutorials

GIT

Lua Extensions

Twitter

FAQ

Contribute

Cheat Engine Wiki



Become a Patron! Check it out



Know programming?
Looking for a job?
Try patreon!





Privacy Policy
Contact


Tutorials

Basic Packet editing with Cheat Engine


This is just an example tutorial describing how to do basic packet editing with Cheat Engine. It's main purpose is to show that you don't have to use other tools when packet editing. (Sure, it helps and is easier, but CE can do it as well)

Let's say you want to change in outgoing packet data the word "hello" with the word "idiot".
First gather all needed information and discuss some basic api calling mechanics:
Packet data is sent using ws2_32.dll's send api . To target this api's location you have to use ws2_32!send as name, else ce will pick winsock32's send export, which is not what you want
Next you have to know that the 2nd parameter contains the pointer to the buffer that is being sent.
Let's first get into windows api calling mechanics. Parameter passing is done by pushing the parameters in reverse order on the stack, followed by a call to the send api., which pushes the next instruction's address on the stack as well.
Because each push decreases esp with 4 bytes, the parameters will actually appear in the correct order, making it [esp] point to the return address, [esp+4] holds the first parameter (socket), [esp+8] holds the 2nd parameter (pointer to buffer containing data), [esp+c] holds the length of that buffer, etc...

To packet edit you'll have to hook the send api and inspect and manipulate the parameters and buffers sent.
In short, code injection at ws2_32!send, get the address of the send buffer, get the length, scan that buffer for the word hello, and if found, replace that with the word idiot

The following code snipet is an example of basic packet editing. (Nothing fancy, but does the job)
alloc(newmem,2048) //2kb should be enough
label(returnhere)
label(originalcode)
label(exit)
label(repeat)
label(repeat2)
label(nomatch)
label(nomatch2)
label(endofroutine)
alloc(texttoscan,5) //non 5.4.4
alloc(texttoreplacewith,5)

define(stringlength,5)
texttoscan:
db 'hello'

texttoreplacewith:
db 'idiot'

ws2_32!send:
jmp newmem
returnhere:

newmem: //this is allocated memory, you have read,write,execute access
//place your code here

//start off with a stackframe
push ebp
mov ebp,esp

//lets save the used registers
push eax
push ecx
push esi
push edi


mov esi,[ebp+0c] //buffer (I might have said esp+8 in the post, but due to the added stackframe(push ebp), it's all shifted 4 bytes)
mov edi,texttoscan
mov ecx,[ebp+10] //length of buffer
cmp ecx,stringlength
jl endofroutine

sub ecx,stringlength-1


repeat:
//edit: because 5.4 doesn't support cmp byte [esi],'t' I have to do it different than in 5.4.4
push ecx
mov ecx,stringlength-1
repeat2:
/*
sure, it compares from the back to front, but as long as it checks it's a match
I don't care
*/
mov al,[esi+ecx]
cmp al,[edi+ecx]
jne nomatch2
loop repeat2


//still here, so a match
push esi
push edi
mov edi,esi //I want the found buffer to be the destination, not source
mov esi,texttoreplacewith
mov ecx,stringlength
rep movsb //move the byte stored at [esi] into [edi] ecx times (so move texttoreplacewith to the found string
pop edi
pop esi

nomatch2:
pop ecx

nomatch:
inc esi
loop repeat

endofroutine:

//undo any register change
pop edi
pop esi
pop ecx
pop eax

/*
undo stackframe. Ok, in this situation the stackframe of the original function
could have been used, but I try to keep it understandable to readers.
*/
mov esp,ebp
pop ebp

originalcode:
mov edi,edi
push ebp
mov ebp,esp

exit:
jmp returnhere

Note: Instead of editing the actuall buffer you might want to create a new buffer and pass that on to the send api. That'll allow for longer texts, and won't mess up if the program actually uses readonly buffers for the send api