| 
									
										
										
										
											2024-09-22 21:36:40 +08:00
										 |  |  | #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); | 
					
						
							| 
									
										
										
										
											2024-09-23 18:36:55 +08:00
										 |  |  |     gum_interceptor_attach_listener(interceptor, GSIZE_TO_POINTER(FuncAddress), listener, GSIZE_TO_POINTER(FuncAddress)); | 
					
						
							| 
									
										
										
										
											2024-09-22 21:36:40 +08:00
										 |  |  |     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; | 
					
						
							| 
									
										
										
										
											2024-09-23 18:36:55 +08:00
										 |  |  |     gum_interceptor_detach_listener(interceptor, listener); | 
					
						
							| 
									
										
										
										
											2024-09-22 21:36:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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")); | 
					
						
							|  |  |  | } |