#include #include #include #include #include "sol/sol.hpp" #include "xhook/xhook.h" #include "hook.hpp" #include "ui.hpp" #include "imgui/imgui.h" #include "imgui/imgui_impl_android.h" #include "imgui/imgui_impl_opengl3.h" using eglSwapBuffers_fnT = EGLBoolean(EGLDisplay dpy, EGLSurface surface); eglSwapBuffers_fnT* old_eglSwapBuffers = nullptr; EGLBoolean my_eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) { ui_eglSwapBuffers(dpy, surface); return old_eglSwapBuffers(dpy, surface); } #ifdef USE_32 using Input_fnT = int32_t(void* thiz, void* ex_ab, void* ex_ac); #endif #ifdef USE_64 using Input_fnT = int64_t(void* thiz, void* ex_ab, void* ex_ac); #endif Input_fnT* old_Input = nullptr; #ifdef USE_32 int32_t my_Input(void* thiz, void* ex_ab, void* ex_ac) #endif #ifdef USE_64 int64_t my_Input(void* thiz, void* ex_ab, void* ex_ac) #endif { auto ret = old_Input(thiz, ex_ab, ex_ac); ImGui_ImplAndroid_HandleInputEvent((AInputEvent *) thiz); return ret; } #ifdef USE_32 using Consume_fnT = int32_t(void* thiz, void* arg1, bool arg2, long arg3, uint32_t* arg4, AInputEvent** input_event); #endif #ifdef USE_64 using Consume_fnT = int64_t(void* thiz, int64_t arg1, char arg2, int64_t arg3, uint32_t* arg4, AInputEvent** input_event); #endif Consume_fnT* old_Consume = nullptr; #ifdef USE_32 int32_t my_Consume(void* thiz, void* arg1, bool arg2, long arg3, uint32_t* arg4, AInputEvent** input_event) #endif #ifdef USE_64 int64_t my_Consume(void* thiz, int64_t arg1, char arg2, int64_t arg3, uint32_t* arg4, AInputEvent** input_event) #endif { auto result = old_Consume(thiz, arg1, arg2, arg3, arg4, input_event); if(result != 0 || *input_event == nullptr) return result; ImGui_ImplAndroid_HandleInputEvent(*input_event); return result; } bool has_hooked = false; #define android_InputConsumer_initializeMotionEvent "_ZN7android13InputConsumer21initializeMotionEventEPNS_11MotionEventEPKNS_12InputMessageE" #define android_InputConsumer_consume "_ZN7android13InputConsumer7consumeEPNS_26InputEventFactoryInterfaceEblPjPPNS_10InputEventE" void do_ui_hook() { if (has_hooked) { return; } auto sym_eglSwapBuffers_status = xhook_register( "libunity", "eglSwapBuffers", reinterpret_cast(my_eglSwapBuffers), reinterpret_cast(&old_eglSwapBuffers) ); if (sym_eglSwapBuffers_status != 0) { SPDLOG_INFO("Hook eglSwapBuffers err: {}", sym_eglSwapBuffers_status); } auto sym_input_status = xhook_register( "libinput", android_InputConsumer_initializeMotionEvent, reinterpret_cast(my_Input), reinterpret_cast(&old_Input) ); if (sym_input_status != 0) { SPDLOG_INFO("Hook android_InputConsumer_initializeMotionEvent err: {}", sym_input_status); } auto sys_consume_status = xhook_register( "libinput", android_InputConsumer_consume, reinterpret_cast(my_Consume), reinterpret_cast(&old_Consume) ); if (sys_consume_status != 0) { SPDLOG_INFO("Hook android_InputConsumer_consume err: {}", sys_consume_status); } has_hooked = true; SPDLOG_INFO("Hook ingame ui done!"); } void hook_game_setting_panel(lua_State* l) { sol::state_view lua(l); SPDLOG_INFO("Get SettingsNotificationPanel.OnItemSwitch"); Lua::Function old = lua["SettingsNotificationPanel"]["OnItemSwitch"]; SPDLOG_INFO("Replace SettingsNotificationPanel.OnItemSwitch"); lua["SettingsNotificationPanel"]["OnItemSwitch"] = [old](sol::this_state L, Lua::VariadicArgs args) { Lua::Table config_into = args[1]; int config_id = config_into["id"]; if (config_id == 4) { bool is_enable_ui = args[2]; is_enable_ui = !is_enable_ui; if (is_enable_ui) { do_ui_hook(); CrackerUI::get_instance().show_ui(); } else { CrackerUI::get_instance().close_ui(); } } old(L, args); }; } bool g_is_game_loaded = false; bool g_is_panel_loaded = false; lua_State* g_target_L = nullptr; int (*old_luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, const char *name); int my_luaL_loadbuffer(lua_State *L, const char *buff, size_t sz,const char *name) { auto ret = old_luaL_loadbuffer(L, buff, sz, name); if (!g_is_panel_loaded) { if (name == nullptr) { return ret; } if (name[0] != '@') { return ret; } if (strstr(name, "SettingsNotificationPanel") != nullptr) { g_target_L = L; g_is_panel_loaded = true; } } return ret; } int (*old_lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); int my_lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { auto ret = old_lua_pcall(L, nargs, nresults, errfunc); if (g_is_panel_loaded && !g_is_game_loaded && g_target_L == L) { hook_game_setting_panel(L); g_is_game_loaded = true; } return ret; } void hook_game_lua_for_ingame_ui() { auto sym_luaL_loadbuffer_status = xhook_register( "libtolua", "luaL_loadbuffer", reinterpret_cast(my_luaL_loadbuffer), reinterpret_cast(&old_luaL_loadbuffer) ); if (sym_luaL_loadbuffer_status != 0) { SPDLOG_INFO("HOOK luaL_loadbuffer err: {}", sym_luaL_loadbuffer_status); } auto sym_lua_pcall_status = xhook_register( "libtolua", "lua_pcall", reinterpret_cast(my_lua_pcall), reinterpret_cast(&old_lua_pcall) ); if (sym_lua_pcall_status != 0) { SPDLOG_INFO("HOOK lua_pcall err: {}", sym_lua_pcall_status); } do_ui_hook(); auto commit_status = xhook_refresh(1); if (commit_status != 0) { SPDLOG_INFO("Commit hook err: {}", commit_status); } }