Closed PippleCultist closed 11 months ago
The script callbacks only work on VM games, they are never invoked on YYC due to the compiler linking and calling the functions directly.
To intercept such scripts, use the MmGetScriptData export (might not work on all GM versions, but try your luck), then use MinHook or some other hooking framework to intercept the target function.
How do I get the function address from a CScript? I tried using s_pFunc, but none of them were executable addresses. Also, I did notice that the s_code->i_pCode was showing a completely different code event from the the script I was trying to get.
Are you subtracting 100000 from the ID before calling MmGetScriptData?
Yeah. I get 107480 when I look for gml_Script_SpawnMob_gml_Object_obj_MobManager_Create_0 which I then get the script for by querying with index 7480. The s_pFunc ends up being a nullptr in this case. I also tried looking for a different script gml_Script_CalculateScore which gave me 101589, and this one had an s_pfunc. The hook was giving me non executable code error when I tried to hook the pScriptFunc/pFunc though. Both of their s_script showed the correct names for the script, but the s_code->i_pCode is showing a different code event from where the script is actually located (Eg. gml_Script_SpawnMob_gml_Object_obj_MobManager_Create_0 showing gml_Object_obj_MobManager_Other_10 instead of gml_Object_obj_MobManager_Create_0)
Curious, can you show the code you have that exhibits this issue?
int spawnMobIndex = -1;
int calculateScoreIndex = -1;
CallBuiltin(Result, "asset_get_index", nullptr, nullptr, { "gml_Script_SpawnMob_gml_Object_obj_MobManager_Create_0" });
//Ends up being 7480
spawnMobIndex = static_cast<int>(Result) - 100000;
PrintMessage(CLR_DEFAULT, "spawnMobIndex: %d", spawnMobIndex);
CallBuiltin(Result, "asset_get_index", nullptr, nullptr, { "gml_Script_CalculateScore" });
//Ends up being 1589
calculateScoreIndex = static_cast<int>(Result) - 100000;
PrintMessage(CLR_DEFAULT, "calculateScoreIndex: %d", calculateScoreIndex);
CScript* spawnMobCScript = nullptr;
CScript* calculateScoreCScript = nullptr;
MmGetScriptData(spawnMobCScript, spawnMobIndex);
//Prints out "gml_Script_SpawnMob_gml_Object_obj_MobManager_Create_0 gml_Object_obj_MobManager_Other_10 0"
PrintMessage(CLR_DEFAULT, "spawnMobCScript: %s %s %08x", spawnMobCScript->s_script, spawnMobCScript->s_code->i_pCode, spawnMobCScript->s_pFunc);
MmGetScriptData(calculateScoreCScript, calculateScoreIndex);
//Prints out "gml_Script_CalculateScore gml_GlobalScript_input_binding_get_verbs (non-zero address)"
PrintMessage(CLR_DEFAULT, "calculateScoreCScript: %s %s %08x", calculateScoreCScript->s_script, calculateScoreCScript->s_code->i_pCode, calculateScoreCScript->s_pFunc);
The code doesn't seem wrong, will have a closer look tomorrow, thanks for reporting this - might be a bug on YYTK's end.
Getting the pScriptFunc from the code event and hooking based off of that seems to work. It seems like it's an issue with MmGetScriptData/CScript.
Try replacing CScript with this struct
struct alignedTo(4) CScript
{
void** pVMT;
// CStream* s_text; // not in newer runners
CCode* s_code;
YYGMLFuncs* s_pFunc;
CInstance* s_pStaticObject;
union
{
const char* s_script;
int s_compiledIndex;
};
const char* s_name;
int s_offset;
};
Commenting s_text makes s_name match s_pFunc->pName for the script name, but trying to hook s_pFunc->pScriptFunc is still giving non executable errors. I compared that address that the CScript is giving for pScriptFunc with the CodeEvent for the same script name, and it seems like there's around a 0x2000 difference.
That's two pages of difference - mind querying the non-executable page and listing what protection it has applied, and the owner module of the page (ie. is it the game's memory)?
Sorry, I was looking at the wrong pScriptFunc for the code event. The issue was that I was trying to use a lambda function as the detour function. The hooks work after changing them to regular functions.
I put a PrintMessage at the beginning of the ScriptCallback function in the Chapter2_EnableDebug example plugin and tried running it with Holocure, but the ScriptCallback function was never called.