Auto Assembler:CCODE
CE 7.2 added {$CCODE} / {$ASM} blocks
Within these blocks you can write C code which will get executed by the target process at the spot it is located. It's also possible to debug through these blocks while viewing the original C code and you can look up the variable values
You can give the {$CCODE} block parameters so you have access to certain registers in a format you can work with. When you reach the end of the block (So no 'return') the changed variables will be applied back to the related registers.
Most of the parameters are formatted as variablename=registername seperated by spaces but there are also parameters like KERNELMODE, NODEBUG and PREFIX=something KERNELMODE will allocate the code in kernelmode, NODEBUG will skip the generation of debug code (You won't be able to see the c-code when stepping through it with the debugger) and PREFIX=something will add the text `something.` in front of the symbols, so you can distinguish in the disassembler between symbols of scripts that use the same variable names
The following register notations are allowed:
RAX/EBX, RBX/RCX, ...: Interpret as a 8/4 byte long RAXF,RBXF,RCXF, ... : Interpret value as float XMM0.0 or XMM0.0F (float) XMM0.1 or XMM0.1F (float) .... XMM1.0 ... XMM0.0D (double) ...
If you just use XMM0 to XMM15: then the variable will be of the following typedef:
typedef struct {
union{
struct{
float f0;
float f1;
float f2;
float f3;
};
struct{
double d0;
double d1;
};
float fa[4];
double da[2];
};
} xmmreg, *pxmmreg;
and to access double 0 of XMM0 you'd then do varname.d0 or varname.da[0]
example: RCX contains the classinstance of the player, RBX the new health after being hit, and you know that at offset b8 the 4 byte value is 1 when it's player:
{$CCODE playerbase=RCX newhealth=RBX}
int isplayer=*(*int)(playerbase+0xb8);
if (isplayer)
newhealth=100000;
else
newhealth=0;
{$ASM}
this will change the rbx register to 100000 when it's the player, and 0 when it's not