 |
Cheat Engine The Official Site of Cheat Engine
|
| View previous topic :: View next topic |
| Author |
Message |
Dark Byte Site Admin
Reputation: 472
Joined: 09 May 2003 Posts: 25871 Location: The netherlands
|
Posted: Thu Aug 26, 2021 1:47 pm Post subject: {$ccode} function call example |
|
|
In this example for the 64-bit tutorial of Cheat Engine 7.3 step 2, I'll show how to call the function MessageBoxA and react on it based on the result the user clicks
It also shows how to modify a single register, and how to access memory pointed at by a pointer
| Code: |
alloc(newmem,2048,"Tutorial-x86_64.exe"+2B42C)
label(returnhere)
label(originalcode)
label(exit)
newmem: //this is allocated memory, you have read,write,execute access
//place your code here
{$ccode step2form=rbx decreaseby=eax}
#define MB_YESNO 0x4
#define IDYES 6
if (MessageBoxA(0,"Change Health to 1000 ?","Cheat Engine C",MB_YESNO)==IDYES)
{
int *health=(int*)(step2form+0x7f8);
*health=1000;
//*health=*health * 3.14159265359f; //in case you wish to multiply by pi instead (which works as well)
decreaseby=0; //don't decrease
}
//else leave everything unmodified
{$asm}
originalcode:
sub [rbx+000007F8],eax
exit:
jmp returnhere
"Tutorial-x86_64.exe"+2B42C:
jmp newmem
nop
returnhere:
|
Because the C compiler can figure out the parameters for the call for MessageBoxA you don't have to define it, but in cases where it's ambiguous you'll have to declare it.
example code you should then add at the top:
| Code: |
{$c}
extern int MessageBoxA(int, char *, char *, int);
{$asm}
|
Note that not ALL targets support calling MessageBoxA as it depends on if the target process can handle message loops at that point
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
| Back to top |
|
 |
ragnaroks Newbie cheater
Reputation: 1
Joined: 30 Aug 2021 Posts: 13
|
Posted: Mon Aug 30, 2021 12:35 pm Post subject: |
|
|
sorry for disturb you,does it have some way to use "label(tag)" or "registersymbol(tag)" in $CCODE?
what i'm think:
| Code: |
alloc(newmem,128)
label(inject)
label(return)
label(default)
label(case1)
label(exit)
inject:
jmp newmem
return:
newmem:
{$CCODE refEAX=EAX}
(int *)gameLoaded=(int *)refEAX+0x04;
if(*gameLoaded!=1){
goto exit;
}
(int *)gunType=(int *)refEAX+0x20;
if(*gunType==1 || *gunType==3 || *gunType==5){
goto case1;
}else{
goto default;
}
{$ASM}
case1:
mov [ammo],(int)30
mov [hp],(float)100
mov [ap],(float)100
jmp return
default:
mov [ammo],(int)10
mov [hp],(float)500
mov [ap],(float)500
jmp return
exit:
mov [ammo],(int)0
mov [hp],(float)0
mov [ap],(float)0
jmp return
|
i had tried this but game crash immediately:
| Code: |
alloc(newmem,128)
label(inject)
label(return)
label(default)
label(case1)
registersymbol(default)
registersymbol(case1)
inject:
jmp newmem
return:
newmem:
{$CCODE refEAX=EAX refDefault=default refCase1=case1}
(int *)gunType=(int *)refEAX+0x20;
if(*gunType==1 || *gunType==3 || *gunType==5){
goto refCase1;
}else{
goto refDefault;
}
{$ASM}
case1:
mov [ammo],(int)30
mov [hp],(float)100
mov [ap],(float)100
jmp return
default:
mov [ammo],(int)10
mov [hp],(float)500
mov [ap],(float)500
jmp return
|
|
|
| Back to top |
|
 |
Dark Byte Site Admin
Reputation: 472
Joined: 09 May 2003 Posts: 25871 Location: The netherlands
|
Posted: Mon Aug 30, 2021 3:50 pm Post subject: |
|
|
ok, there was another issue with that where local symbols didn't get recognized properly, seems a lot got changed after implementing C compiling. (it's fixed on patreon already)
Anyhow, goto is not going to work, as it's in a completely different stackframe, so the jmp that goto would do would mess up the stack.
It's better to use labels inside the c blocks instead and do the editing there, or use a register as a jump destination based on the result
example (step 2 of the tutorial)
I place an infinite loop after the ccode block, but the rcx register gets the address after that infinite loop (originalcode)
| Code: |
alloc(newmem,2048,"Tutorial-x86_64.exe"+2B42C)
label(returnhere)
label(originalcode)
label(exit)
newmem: //this is allocated memory, you have read,write,execute access
//place your code here
push rcx //save rcx as it's going to be changed
{$ccode jmpaddress=rcx}
extern void originalcode();
jmpaddress=originalcode;
{$asm}
jmp rcx //jump to where rcx points
db eb fe //inf loop
originalcode:
pop rcx //restore rcx
sub [rbx+000007F8],eax
exit:
jmp returnhere
"Tutorial-x86_64.exe"+2B42C:
jmp newmem
nop
returnhere:
|
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
| Back to top |
|
 |
ragnaroks Newbie cheater
Reputation: 1
Joined: 30 Aug 2021 Posts: 13
|
Posted: Mon Aug 30, 2021 8:24 pm Post subject: |
|
|
"extern void originalcode();" it's new syntax in $CCODE or both in $C?
thanks for your help,my test cheat logic was done,i learned so much.
|
|
| Back to top |
|
 |
Dark Byte Site Admin
Reputation: 472
Joined: 09 May 2003 Posts: 25871 Location: The netherlands
|
Posted: Tue Aug 31, 2021 12:18 am Post subject: |
|
|
can also be in {$c}
basically a {$ccode} section is a {$c} section but with a function prologue and epilog
once CE assembles the script all {$c} blocks get combined into one c-file internally and compiled like that, so {$ccode} blocks have access to what is in {$c} blocks above it. (order of the blocks matter)
in the example i posted the "extern void originalcode();" would be local to the function it's in , but if you'd put it in the {$c} blocks it'd be accessible to all the c-blocks under it.
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
| Back to top |
|
 |
MMM-304 Expert Cheater
Reputation: 0
Joined: 17 Aug 2020 Posts: 170 Location: Milkey Way
|
Posted: Tue Aug 31, 2021 12:48 am Post subject: |
|
|
| Dark Byte wrote: | can also be in {$c}
|
wait so we can call asm functions in c? thats cool, also is this feature available for lua?
|
|
| Back to top |
|
 |
Dark Byte Site Admin
Reputation: 472
Joined: 09 May 2003 Posts: 25871 Location: The netherlands
|
Posted: Wed Sep 15, 2021 6:48 am Post subject: |
|
|
yes.
Also, here's another script example for flying around in kings bounty 2 (v1.3)
it makes use of the GetKeyState() function
I could likely clean it up by making a single isKeydown() function in {$c}
| Code: |
[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
alloc(newmem,2048,"KingsBounty2.exe"+1E4AAC4)
label(returnhere)
label(originalcode)
label(exit)
newmem: //this is allocated memory, you have read,write,execute access
//place your code here
{$c}
float lockedHeight=0;
int lockHeight=0;
{$asm}
{$ccode player=RAX}
#define VK_SHIFT 0x10
#define VK_UP 0x26
#define VK_NUMPAD0 0x60
#define VK_NUMPAD2 0x62
#define VK_NUMPAD4 0x64
#define VK_NUMPAD6 0x66
#define VK_NUMPAD8 0x68
#define VK_ADD 0x6B
#define VK_SUBTRACT 0x6D
#define VK_DECIMAL 0x6E
#define SPEED 40
#define FASTSPEED 150
int speed=SPEED;
if (GetKeyState(VK_SHIFT) & (1<<15))
{
speed=FASTSPEED;
}
if (GetKeyState(VK_NUMPAD8) & (1<<15)) //up
{
*(float *)(player+0x10)+=speed;
}
if (GetKeyState(VK_NUMPAD2) & (1<<15)) //down
{
*(float *)(player+0x10)-=speed;
}
if (GetKeyState(VK_NUMPAD4) & (1<<15)) //left
{
*(float *)(player+0x14)-=speed;
}
if (GetKeyState(VK_NUMPAD6) & (1<<15)) //right
{
*(float *)(player+0x14)+=speed;
}
if (GetKeyState(VK_ADD) & (1<<15)) //numpad +
{
if (lockHeight)
lockedHeight+=speed;
*(float *)(player+0x18)+=speed;
}
if (GetKeyState(VK_SUBTRACT) & (1<<15)) //numpad -
{
if (lockHeight)
lockedHeight-=speed;
*(float *)(player+0x18)-=speed;
}
if (GetKeyState(VK_NUMPAD0) & (1<<15)) //0
{
lockedHeight=*(float *)(player+0x18);
lockHeight=1;
}
if (GetKeyState(VK_DECIMAL) & (1<<15)) //.
{
lockHeight=0;
lockedHeight=0;
}
if (lockHeight)
{
*(float *)(player+0x18)=lockedHeight;
}
{$asm}
originalcode:
movups xmm0,[rax]
movups [r13+000000B0],xmm0
exit:
jmp returnhere
"KingsBounty2.exe"+1E4AAC4:
jmp newmem
nop 6
returnhere:
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
dealloc(newmem)
"KingsBounty2.exe"+1E4AAC4:
movups xmm0,[rax]
movups [r13+000000B0],xmm0
//Alt: db 0F 10 00 41 0F 11 85 B0 00 00 00
|
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
| Back to top |
|
 |
Csimbi I post too much
Reputation: 98
Joined: 14 Jul 2007 Posts: 3356
|
Posted: Fri Feb 14, 2025 2:09 pm Post subject: |
|
|
How do you return value from a call in C code?
I could not find it in the wiki so I figured I would ask.
Is this correct?
I get a crash in the call below (I never get to test rax,rax), I assume I must be doing something wrong.
| Code: | ...
{$ccode sResult=RAX sStr=R10 sSubStr=R11}
sResult=strstr(sStr, sSubStr);
{$asm}
test rax,rax
... |
Thank you!
|
|
| Back to top |
|
 |
Dark Byte Site Admin
Reputation: 472
Joined: 09 May 2003 Posts: 25871 Location: The netherlands
|
Posted: Sat Feb 15, 2025 2:17 am Post subject: |
|
|
don't forget to add
| Code: |
char* strstr( const char* str, const char* substr );
|
else str and substr will be handled as integer values (it's a standard c thing for undefined functions), and seeing you're using 64-bit registers, there is a big chance of this going bad
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
| Back to top |
|
 |
Frouk Grandmaster Cheater
Reputation: 5
Joined: 22 Jun 2021 Posts: 511
|
Posted: Wed Jul 23, 2025 9:05 am Post subject: |
|
|
Just leaving here a method to call a function by virtual method table or by an address, AOB, whatever
| Code: |
// MACRO VERSION
{$c}
#define GET_FNC_DCL(ret, callconv, target, ...) ((ret(callconv *)(__VA_ARGS__))(target))
#define GET_VMT(object, index) ((*(void***)object)[index])
{$asm}
...
{$ccode pThis=ECX}
GET_FNC_DCL(void, __cdecl, 0x12345678, float, int)(5.0f, 0);
// OR
((void(__cdecl *)(float, int))0x12345678)(5.0f, 0);
GET_FNC_DCL(void, __fastcall /* __fastcall for 32-bit ECX register, but you need also to make EDX as dummy typename*/, GET_VMT(pThis, 7), void * /*ECX*/, void * /*EDX*/, int)(pThis, 0, 1);
// OR
((void(_fastcall *)(void *, void *, int))GET_VMT(pThis, 7))(pThis, 0, 1);
{$asm}
// Though the __fastcall might not work for 32-bit, I've tried to call a function with this calling convention, but it didn't even compiled the function call itself, just parameter preparation before calling and that's all
// for 64-bit, you need to use __stdcall
|
|
|
| Back to top |
|
 |
tuxlu Newbie cheater
Reputation: 0
Joined: 24 Sep 2023 Posts: 11
|
Posted: Tue Feb 03, 2026 1:12 pm Post subject: |
|
|
Hi, completely necroposting this thread as one question inside was left unanswered:
is there a method to call LUA methods in {$ccode} blocks?
I'm espacially interested in registerSymbol and getAddressSafe
I tried declaring the methods , but the compiler does not find them
| Code: |
extern __cdecl int registerSymbol(char *, int);
extern __cdecl int getAddressSafe(char *);
// tcc: error: undefined symbol 'registerSymbol' ...
|
are they available in C? did I get their declaration wrong?
also, I tried coding my cheat in {$LUACODE} at first, but it kept crashing, even with a simple example :/
I guess it is normal that the LUACODE functionality is not performant/unstable?
plus minor nitpick/noob rant:
I feel that you should say somewhere in documentation, that the {$CCODE} line cannot start with a space or tab.
Everytime I forget about it , indent my block, and get a "this instruction cannot be compiled" error, and take 5 minutes remembering to remove that space.
Or maybe improve the AA parser, if possible, but document it would already help.
|
|
| Back to top |
|
 |
Dark Byte Site Admin
Reputation: 472
Joined: 09 May 2003 Posts: 25871 Location: The netherlands
|
Posted: Tue Feb 03, 2026 2:43 pm Post subject: |
|
|
you can mix C and autoassembler, so in a way: yes, using luacode
now the question is, why would luacode crash for you? Sure it's not performant but i'm not sure about the crash as {$ccode} uses the same trampoline as luacode
| Code: |
alloc(lua_registerSymbol,32)
lua_registerSymbol:
//rcx=symbolname
//rdx=address
{$luacode strptr=rcx address=rdx}
print("Calling registersymbol")
local str=readString(strptr,100)
printf("str=%s address=%x",str,address)
registerSymbol(str,rdx)
print("done")
{$asm}
ret
lua_print:
{$luacode strptr=rcx}
local str=readString(strptr,100)
print(str)
{$asm}
ret
{$c}
void lua_registerSymbol(char *str, unsigned long long address);
void lua_print(char *str);
int ran=0; //global var to check what happened
void mycode()
{
ran=1; //mycode got executed
lua_print("hello!");
lua_registerSymbol("test123",0x123456789abcde);
ran=2; //mycode got all the way to the end
}
{$asm}
createThread(mycode)
|
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
| Back to top |
|
 |
tuxlu Newbie cheater
Reputation: 0
Joined: 24 Sep 2023 Posts: 11
|
Posted: Tue Feb 03, 2026 5:48 pm Post subject: |
|
|
thanks again for your quick and insightful answer Dark Byte
Elegant answer, even if it still resorts to creating LUA code
But for now it seemed to work, it crashes mainly when I do too many "print" calls.
I'm giving a complete random guess, but as I was patching the character position set method, maybe the game expected a certain timing to this method, and adding the LUA delay messed with the rest of the game? not sure.
I still have some issues, like sometimes when I enable/disable my script, I get "not all instruction could be injected", even if I alloc/dealloc the autoassembler functions I alloc. So maybe I'm doing some funky stuff, I'll have to check a bit more, see in the memory viewer how the cheat is cleaned. but the sole code I have is:
| Code: |
alloc(newmem,$2000,address)
alloc(lua_registerSymbol,64)
alloc(lua_getAddressSafe,64)
alloc(lua_print,64)
...
{$CCODE regis=RBX}
void lua_registerSymbol(char *, unsigned long long);
unsigned long long lua_getAddressSafe(char *);
void lua_print(char *str);
int original=(regis+0x42);
lua_registerSymbol("test", original);
|
Anyway, I found another way of doing what I wanted to do, without any code, asm, C or LUA:
I originally wanted to do a loop to register symbols for the 3D position of my character, with 12 values contiguous in memory (offsets are static).
Instead, I created directly from the GUI pointer records with an offset to a single registered symbol (the "x" position of the character), and it works great.
If I need to access the address from LUA, instead of getAddressSafe("player_x") I do
addrList.getMemoryRecordByDescription("x").CurrentAddress and it works very well.
|
|
| 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
|
|