311 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			311 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
| #pragma once
 | |
| #include "frida-gum.h"
 | |
| #include <fcntl.h>
 | |
| #include <unistd.h>
 | |
| #include "squirrel.h"
 | |
| #include "sqstdaux.h"
 | |
| #include "sqstdblob.h"
 | |
| #include "sqstdio.h"
 | |
| #include "sqstdmath.h"
 | |
| #include "sqstdstring.h"
 | |
| #include "sqstdsystem.h"
 | |
| #include <mutex>
 | |
| #include <iostream>
 | |
| 
 | |
| extern HSQUIRRELVM v;
 | |
| extern std::recursive_mutex SqMtx;
 | |
| 
 | |
| #define CONTAINS_STRING(str, substr) (str == substr)
 | |
| 
 | |
| // HookFunc
 | |
| struct _ExampleListener
 | |
| {
 | |
|     GObject parent;
 | |
|     guint num_calls;
 | |
|     std::vector<std::string> ArgumentCount;
 | |
|     std::string RetType;
 | |
|     HSQOBJECT CallBackOnEnter;
 | |
|     HSQOBJECT CallBackOnLeave;
 | |
| };
 | |
| 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;
 | |
| 
 | |
| #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 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<std::string> 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;
 | |
| 
 | |
|     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)
 | |
| {
 | |
|     ExampleListener *self = EXAMPLE_LISTENER(listener);
 | |
| 
 | |
|     std::lock_guard<std::recursive_mutex> lock(SqMtx);
 | |
|     // 执行虚拟机Main函数
 | |
|     SQInteger top = sq_gettop(v); // saves the stack size before the call
 | |
|     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<float *>(&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
 | |
| }
 | |
| static void example_listener_on_leave(GumInvocationListener *listener, GumInvocationContext *ic)
 | |
| {
 | |
|     ExampleListener *self = EXAMPLE_LISTENER(listener);
 | |
| 
 | |
|     std::lock_guard<std::recursive_mutex> 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<float *>(&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);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 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"));
 | |
| } |