1
0
mirror of https://github.com/0O0o0oOoO00/Alas.git synced 2026-05-15 02:59:26 +08:00
Files
Alas/blcrack/cracker/ui/hook.cpp

315 lines
10 KiB
C++

#include <spdlog/spdlog.h>
#include <android/input.h>
#include <dlfcn.h>
#include <EGL/egl.h>
#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"
#include "il2cpp.hpp"
#include "dobby.h"
using eglSwapBuffers_fnT = EGLBoolean(EGLDisplay dpy, EGLSurface surface);
eglSwapBuffers_fnT* old_eglSwapBuffers = nullptr;
EGLint g_width = 0;
EGLint g_height = 0;
std::atomic<bool> g_imgui_started = false;
EGLBoolean my_eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
ui_eglSwapBuffers(dpy, surface);
if (g_width == 0 || g_height == 0) {
eglQuerySurface(dpy, surface, EGL_WIDTH, &g_width);
eglQuerySurface(dpy, surface, EGL_HEIGHT, &g_height);
}
if (!g_imgui_started.load()) {
g_imgui_started.store(true);
}
return old_eglSwapBuffers(dpy, surface);
}
std::atomic<bool> g_use_native_input = false;
#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);
if (!g_use_native_input.load()) {
g_use_native_input.store(true);
}
if (g_imgui_started.load()) {
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;
}
if (!g_use_native_input.load()) {
g_use_native_input.store(true);
}
if (g_imgui_started.load()) {
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"
#define TOUCH_PHASE_BEGAN 0
#define TOUCH_PHASE_MOVED 1
#define TOUCH_PHASE_STATIONARY 2
#define TOUCH_PHASE_ENDED 3
#define TOUCH_PHASE_CANCELED 4
void My_ImGui_ImplAndroid_HandleInputEvent(const UnityEngine_Touch_o& touch) {
auto& io = ImGui::GetIO();
// SPDLOG_INFO("Touch (RawX = {}, RawY = {}), (X = {}, Y = {}), (DeltaX = {}, DeltaY = {})",
// touch.fields.m_RawPosition.fields.x, touch.fields.m_RawPosition.fields.y,
// touch.fields.m_Position.fields.x, touch.fields.m_Position.fields.y,
// touch.fields.m_PositionDelta.fields.x, touch.fields.m_PositionDelta.fields.y
// );
auto phase = touch.fields.m_Phase;
io.AddMouseSourceEvent(ImGuiMouseSource_TouchScreen);
switch(phase) {
case TOUCH_PHASE_BEGAN:
io.AddMousePosEvent(touch.fields.m_Position.fields.x, g_height - touch.fields.m_Position.fields.y);
io.AddMouseButtonEvent(0, true);
io.AddMouseButtonEvent(1, true);
io.AddMouseButtonEvent(2, true);
break;
case TOUCH_PHASE_MOVED:
case TOUCH_PHASE_STATIONARY:
io.AddMousePosEvent(touch.fields.m_Position.fields.x, g_height - touch.fields.m_Position.fields.y);
break;
case TOUCH_PHASE_ENDED:
case TOUCH_PHASE_CANCELED:
io.AddMousePosEvent(touch.fields.m_Position.fields.x, g_height - touch.fields.m_Position.fields.y);
io.AddMouseButtonEvent(0, false);
io.AddMouseButtonEvent(1, false);
io.AddMouseButtonEvent(2, false);
break;
default:
break;
}
}
using GlobalClickEventMgr_HandlePinchOnTouch_fnT = void(void* thiz, UnityEngine_Touch_array* touches);
GlobalClickEventMgr_HandlePinchOnTouch_fnT* old_GlobalClickEventMgr_HandlePinchOnTouch = nullptr;
void my_GlobalClickEventMgr_HandlePinchOnTouch(void* thiz, UnityEngine_Touch_array* touches) {
if (touches != nullptr && !g_use_native_input.load() && g_imgui_started.load()) {
for(int i = 0; i < touches->max_length; i++) {
My_ImGui_ImplAndroid_HandleInputEvent(touches->m_Items[i]);
}
}
old_GlobalClickEventMgr_HandlePinchOnTouch(thiz, touches);
}
static GlobalClickEventMgr_HandlePinchOnTouch_fnT* get_GlobalClickEventMgr_HandlePinchOnTouch() {
static GlobalClickEventMgr_HandlePinchOnTouch_fnT* fn = []() {
Il2CppDomain* domain = il2cpp_domain_get();
size_t assembly_count = 0;
Il2CppAssembly** assemblies = il2cpp_domain_get_assemblies(domain, &assembly_count);
Il2CppClass* cls = nullptr;
for (size_t i = 0; i < assembly_count; ++i) {
Il2CppImage* image = il2cpp_assembly_get_image(assemblies[i]);
Il2CppClass* klass = il2cpp_class_from_name(image, "", "GlobalClickEventMgr");
if (klass != nullptr) {
cls = klass;
break;
}
}
if (cls != nullptr) {
MethodInfo* method_info = il2cpp_class_get_method_from_name(cls, "HandlePinchOnTouch", 1);
if (method_info != nullptr) {
auto method = reinterpret_cast<GlobalClickEventMgr_HandlePinchOnTouch_fnT*>(method_info->methodPointer);
SPDLOG_INFO("Found UnityEngine.Input.get_touches at {}", (void*)method_info->methodPointer);
return method;
}
}
SPDLOG_ERROR("Failed to get UnityEngine.Input.get_touches");
throw std::runtime_error("Failed to get UnityEngine.Input.get_touches");
}();
return fn;
}
void do_ui_hook() {
if (has_hooked) {
return;
}
int dobby_hook_status = 0;
dobby_hook_status = DobbyHook(
reinterpret_cast<void*>(get_GlobalClickEventMgr_HandlePinchOnTouch()),
reinterpret_cast<void*>(my_GlobalClickEventMgr_HandlePinchOnTouch),
reinterpret_cast<void**>(&old_GlobalClickEventMgr_HandlePinchOnTouch)
);
if (dobby_hook_status != 0) {
SPDLOG_INFO("Hook GlobalClickEventMgr.HandlePinchOnTouch failed: {}", dobby_hook_status);
}
has_hooked = true;
SPDLOG_INFO("Hook ingame ui done!");
}
void hook_game_setting_panel(lua_State* l) {
sol::state_view lua(l);
Lua::Function old = lua["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);
};
SPDLOG_INFO("SettingsNotificationPanel.OnItemSwitch hooked");
}
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() {
int xhook_status = 0;
xhook_status = xhook_register(
"libunity",
"eglSwapBuffers",
reinterpret_cast<void*>(my_eglSwapBuffers),
reinterpret_cast<void**>(&old_eglSwapBuffers)
);
if (xhook_status != 0) {
SPDLOG_INFO("Hook eglSwapBuffers failed: {}", xhook_status);
}
xhook_status = xhook_register(
"libtolua",
"luaL_loadbuffer",
reinterpret_cast<void*>(my_luaL_loadbuffer),
reinterpret_cast<void**>(&old_luaL_loadbuffer)
);
if (xhook_status != 0) {
SPDLOG_INFO("Hook luaL_loadbuffer failed: {}", xhook_status);
}
xhook_status = xhook_register(
"libtolua",
"lua_pcall",
reinterpret_cast<void*>(my_lua_pcall),
reinterpret_cast<void**>(&old_lua_pcall)
);
if (xhook_status != 0) {
SPDLOG_INFO("Hook lua_pcall failed: {}", xhook_status);
}
xhook_status = xhook_register(
"libinput",
android_InputConsumer_initializeMotionEvent,
reinterpret_cast<void*>(my_Input),
reinterpret_cast<void**>(&old_Input)
);
if (xhook_status != 0) {
SPDLOG_INFO("Hook android::InputConsumer::initializeMotionEvent failed: {}", xhook_status);
}
xhook_status = xhook_register(
"libinput",
android_InputConsumer_consume,
reinterpret_cast<void*>(my_Consume),
reinterpret_cast<void**>(&old_Consume)
);
if (xhook_status != 0) {
SPDLOG_INFO("Hook android::InputConsumer::consume failed: {}", xhook_status);
}
xhook_status = xhook_refresh(1);
if (xhook_status != 0) {
SPDLOG_INFO("XHook commit failed: {}", xhook_status);
}
}