#pragma once #include "frida-gum.h" #include #include #include "squirrel.h" #include "sqstdaux.h" #include "sqstdblob.h" #include "sqstdio.h" #include "sqstdmath.h" #include "sqstdstring.h" #include "sqstdsystem.h" #include #include extern HSQUIRRELVM v; extern std::recursive_mutex SqMtx; #define CONTAINS_STRING(str, substr) (str == substr) typedef struct { const SQChar* name; size_t offset; } CpuContextMember; // HookFunc struct _ExampleListener { GObject parent; guint num_calls; std::vector ArgumentCount; std::string RetType; HSQOBJECT CallBackOnEnter; HSQOBJECT CallBackOnLeave; SQUserPointer FuncAddress; }; enum _ExampleHookId { EXAMPLE_HOOK_OPEN, EXAMPLE_HOOK_CLOSE }; typedef struct _ExampleListener ExampleListener; typedef enum _ExampleHookId ExampleHookId; static void example_listener_iface_init(gpointer g_iface, gpointer iface_data); static GumInterceptor* interceptor; static std::thread::id Zhuxianc = std::this_thread::get_id(); #define EXAMPLE_TYPE_LISTENER (example_listener_get_type()) G_DECLARE_FINAL_TYPE(ExampleListener, example_listener, EXAMPLE, LISTENER, GObject) G_DEFINE_TYPE_EXTENDED(ExampleListener, example_listener, G_TYPE_OBJECT, 0, G_IMPLEMENT_INTERFACE(GUM_TYPE_INVOCATION_LISTENER, example_listener_iface_init)) // 自定义替换函数 static void replacement_function(GumInvocationContext* context) { // 在这里执行你的逻辑 // gum_print("自定义逻辑已执行!\n"); // 跳过原函数,直接返回 // 如果需要修改返回值,可以通过 context->cpu_context 修改寄存器 } static SQInteger L_HookFunc(HSQUIRRELVM v) { static bool InitFlag = false; if (!InitFlag) { InitFlag = true; gum_init_embedded(); interceptor = gum_interceptor_obtain(); } GumInvocationListener* listener = (GumInvocationListener*)g_object_new(EXAMPLE_TYPE_LISTENER, NULL); // 得到函数地址 SQUserPointer FuncAddress; sq_getuserpointer(v, 2, &FuncAddress); // 遍历参数类型数组 std::vector ParameterType; sq_pushnull(v); // null iterator while (SQ_SUCCEEDED(sq_next(v, 3))) { const SQChar* path; sq_getstring(v, -1, &path); ParameterType.push_back(path); sq_pop(v, 2); } sq_pop(v, 1); // 得到入口回调函数 HSQOBJECT CallBackOnEnter; sq_getstackobj(v, 4, &CallBackOnEnter); // 必须增加一次引用一会记得删除 不然这个函数会被释放 sq_addref(v, &CallBackOnEnter); // 得到出口回调函数 HSQOBJECT CallBackOnLeave; sq_getstackobj(v, 5, &CallBackOnLeave); // 必须增加一次引用一会记得删除 不然这个函数会被释放 sq_addref(v, &CallBackOnLeave); EXAMPLE_LISTENER(listener)->ArgumentCount = ParameterType; // EXAMPLE_LISTENER(listener)->RetType = std::string(RetBuf); EXAMPLE_LISTENER(listener)->CallBackOnEnter = CallBackOnEnter; EXAMPLE_LISTENER(listener)->CallBackOnLeave = CallBackOnLeave; EXAMPLE_LISTENER(listener)->FuncAddress = FuncAddress; gum_interceptor_begin_transaction(interceptor); gum_interceptor_attach(interceptor, GSIZE_TO_POINTER(FuncAddress), listener, GSIZE_TO_POINTER(FuncAddress)); gum_interceptor_end_transaction(interceptor); sq_pushuserpointer(v, listener); return 1; } static SQInteger L_DeHookFunc(HSQUIRRELVM v) { // 得到函数地址 SQUserPointer FuncAddress; sq_getuserpointer(v, 2, &FuncAddress); GumInvocationListener* listener = (GumInvocationListener*)FuncAddress; gum_interceptor_detach(interceptor, listener); return 0; } static void example_listener_on_enter(GumInvocationListener* listener, GumInvocationContext* ic) { gpointer ReturnAddress = gum_invocation_context_get_return_address(ic); ExampleListener* self = EXAMPLE_LISTENER(listener); // std::cout << "调用点: " << self->FuncAddress << std::endl; std::lock_guard lock(SqMtx); // 执行虚拟机Main函数 SQInteger top = sq_gettop(v); // saves the stack size before the call //传入返回地址 sq_pushroottable(v); sq_pushstring(v, _SC("_Haker_SetNextReturnAddress"), -1); if (SQ_SUCCEEDED(sq_get(v, -2))) { sq_pushroottable(v); sq_pushuserpointer(v, ReturnAddress); sq_call(v, 2, SQFalse, SQTrue); } sq_settop(v, top); //传入CPU上下文 sq_pushroottable(v); sq_pushstring(v, _SC("_Haker_SetCpuContext"), -1); if (SQ_SUCCEEDED(sq_get(v, -2))) { sq_pushroottable(v); sq_newtable(v); struct TableEntry { const SQChar* key; SQUserPointer value; } entries[] = { {_SC("eip"), (SQUserPointer)ic->cpu_context->eip}, {_SC("edi"), (SQUserPointer)ic->cpu_context->edi}, {_SC("esi"), (SQUserPointer)ic->cpu_context->esi}, {_SC("ebp"), (SQUserPointer)ic->cpu_context->ebp}, {_SC("esp"), (SQUserPointer)ic->cpu_context->esp}, {_SC("ebx"), (SQUserPointer)ic->cpu_context->ebx}, {_SC("edx"), (SQUserPointer)ic->cpu_context->edx}, {_SC("ecx"), (SQUserPointer)ic->cpu_context->ecx}, {_SC("eax"), (SQUserPointer)ic->cpu_context->eax}, }; for (const auto& entry : entries) { sq_pushstring(v, entry.key, -1); sq_pushuserpointer(v, entry.value); sq_newslot(v, -3, SQFalse); } sq_call(v, 2, SQFalse, SQTrue); } sq_settop(v, top); sq_pushobject(v, self->CallBackOnEnter); sq_pushroottable(v); sq_newarray(v, 0); for (size_t i = 0; i < self->ArgumentCount.size() - 1; i++) { void* Abuf = gum_invocation_context_get_nth_argument(ic, i); if (CONTAINS_STRING(self->ArgumentCount[i], "int")) sq_pushinteger(v, (int)Abuf); else if (CONTAINS_STRING(self->ArgumentCount[i], "float")) { SQFloat* a = reinterpret_cast(&Abuf); sq_pushfloat(v, *(SQFloat*)a); } else if (CONTAINS_STRING(self->ArgumentCount[i], "bool")) sq_pushbool(v, (bool)Abuf); else if (CONTAINS_STRING(self->ArgumentCount[i], "string")) sq_pushstring(v, (char*)Abuf, -1); else if (CONTAINS_STRING(self->ArgumentCount[i], "pointer")) sq_pushuserpointer(v, (void*)Abuf); else if (CONTAINS_STRING(self->ArgumentCount[i], "short")) sq_pushinteger(v, (int)Abuf); else if (CONTAINS_STRING(self->ArgumentCount[i], "char")) sq_pushinteger(v, (int)Abuf); else sq_pushuserpointer(v, (void*)Abuf); sq_arrayappend(v, -2); } sq_call(v, 2, SQTrue, SQTrue); // calls the function if (sq_gettype(v, -1) == OT_ARRAY) { sq_pushnull(v); // null iterator int Idx = 0; while (SQ_SUCCEEDED(sq_next(v, -2))) { if (CONTAINS_STRING(self->ArgumentCount[Idx], "int")) { SQInteger Abuf; sq_getinteger(v, -1, &Abuf); gum_invocation_context_replace_nth_argument(ic, Idx, (void*)Abuf); } else if (CONTAINS_STRING(self->ArgumentCount[Idx], "float")) { SQFloat Abuf; sq_getfloat(v, -1, &Abuf); gum_invocation_context_replace_nth_argument(ic, Idx, &Abuf); } else if (CONTAINS_STRING(self->ArgumentCount[Idx], "bool")) { SQBool Abuf; sq_getbool(v, -1, &Abuf); gum_invocation_context_replace_nth_argument(ic, Idx, (void*)Abuf); } else if (CONTAINS_STRING(self->ArgumentCount[Idx], "string")) { const SQChar* Abuf; sq_getstring(v, -1, &Abuf); gum_invocation_context_replace_nth_argument(ic, Idx, (void*)Abuf); } else if (CONTAINS_STRING(self->ArgumentCount[Idx], "pointer")) { SQUserPointer Abuf; sq_getuserpointer(v, -1, &Abuf); gum_invocation_context_replace_nth_argument(ic, Idx, (void*)Abuf); } else if (CONTAINS_STRING(self->ArgumentCount[Idx], "short")) { SQInteger Abuf; sq_getinteger(v, -1, &Abuf); gum_invocation_context_replace_nth_argument(ic, Idx, (void*)Abuf); } else if (CONTAINS_STRING(self->ArgumentCount[Idx], "char")) { SQInteger Abuf; sq_getinteger(v, -1, &Abuf); char CBUF = Abuf; gum_invocation_context_replace_nth_argument(ic, Idx, (void*)CBUF); } Idx++; sq_pop(v, 2); } sq_pop(v, 1); sq_settop(v, top); // restores the original stack size return; } sq_settop(v, top); // restores the original stack size return; } static void example_listener_on_leave(GumInvocationListener* listener, GumInvocationContext* ic) { ExampleListener* self = EXAMPLE_LISTENER(listener); std::lock_guard lock(SqMtx); // 执行虚拟机Main函数 SQInteger top = sq_gettop(v); // saves the stack size before the call sq_pushobject(v, self->CallBackOnLeave); sq_pushroottable(v); sq_newarray(v, 0); for (size_t i = 0; i < self->ArgumentCount.size(); i++) { void* Abuf; if (i == (self->ArgumentCount.size() - 1)) Abuf = gum_invocation_context_get_return_value(ic); else Abuf = gum_invocation_context_get_nth_argument(ic, i); if (CONTAINS_STRING(self->ArgumentCount[i], "int")) sq_pushinteger(v, (int)Abuf); else if (CONTAINS_STRING(self->ArgumentCount[i], "float")) { SQFloat* a = reinterpret_cast(&Abuf); sq_pushfloat(v, *(SQFloat*)a); } else if (CONTAINS_STRING(self->ArgumentCount[i], "bool")) sq_pushbool(v, (bool)Abuf); else if (CONTAINS_STRING(self->ArgumentCount[i], "string")) sq_pushstring(v, (char*)Abuf, -1); else if (CONTAINS_STRING(self->ArgumentCount[i], "pointer")) sq_pushuserpointer(v, (void*)Abuf); else if (CONTAINS_STRING(self->ArgumentCount[i], "short")) sq_pushinteger(v, (int)Abuf); else if (CONTAINS_STRING(self->ArgumentCount[i], "char")) sq_pushinteger(v, (int)Abuf); else sq_pushuserpointer(v, (void*)Abuf); sq_arrayappend(v, -2); } sq_call(v, 2, SQTrue, SQTrue); // calls the function if (sq_gettype(v, -1) != OT_NULL) { if (CONTAINS_STRING(self->ArgumentCount.back(), "int")) { SQInteger Abuf; sq_getinteger(v, -1, &Abuf); gum_invocation_context_replace_return_value(ic, (void*)Abuf); } else if (CONTAINS_STRING(self->ArgumentCount.back(), "float")) { SQFloat Abuf; sq_getfloat(v, -1, &Abuf); gum_invocation_context_replace_return_value(ic, &Abuf); } else if (CONTAINS_STRING(self->ArgumentCount.back(), "bool")) { SQBool Abuf; sq_getbool(v, -1, &Abuf); gum_invocation_context_replace_return_value(ic, (void*)Abuf); } else if (CONTAINS_STRING(self->ArgumentCount.back(), "string")) { const SQChar* Abuf; sq_getstring(v, -1, &Abuf); gum_invocation_context_replace_return_value(ic, (void*)Abuf); } else if (CONTAINS_STRING(self->ArgumentCount.back(), "pointer")) { SQUserPointer Abuf; sq_getuserpointer(v, -1, &Abuf); gum_invocation_context_replace_return_value(ic, (void*)Abuf); } else if (CONTAINS_STRING(self->ArgumentCount.back(), "short")) { SQInteger Abuf; sq_getinteger(v, -1, &Abuf); gum_invocation_context_replace_return_value(ic, (void*)Abuf); } else if (CONTAINS_STRING(self->ArgumentCount.back(), "char")) { SQInteger Abuf; sq_getinteger(v, -1, &Abuf); char CBUF = Abuf; gum_invocation_context_replace_return_value(ic, (void*)Abuf); } } sq_settop(v, top); } static void example_listener_class_init(ExampleListenerClass* klass) { (void)EXAMPLE_IS_LISTENER; (void)glib_autoptr_cleanup_ExampleListener; } static void example_listener_iface_init(gpointer g_iface, gpointer iface_data) { GumInvocationListenerInterface* iface = (GumInvocationListenerInterface*)g_iface; iface->on_enter = example_listener_on_enter; iface->on_leave = example_listener_on_leave; } static void example_listener_init(ExampleListener* self) { } static void RegisterActiveHook(HSQUIRRELVM v) { register_World_func(v, L_HookFunc, _SC("Sq_HookFunc")); register_World_func(v, L_DeHookFunc, _SC("Sq_DeHookFunc")); }