diff --git a/main.cpp b/main.cpp index 290e82ea9..20ec078ff 100644 --- a/main.cpp +++ b/main.cpp @@ -1,3 +1,6 @@ +// 注意:本代码基于你之前提供的完整功能版本,只修改了 Hook 部分 +// 所有原有功能(换肤、ESP、自动操作、牌池、装备管理等)均保持不变 + #include #include #include @@ -6,152 +9,439 @@ #include #include #include +#include #include +#include +#include #include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "dobby.h" #include "imgui.h" #include "imgui_impl_android.h" #include "imgui_impl_opengl3.h" -#define TAG "SimpleHook" +#define TAG "JKInternal" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) -// 全局变量 -static uintptr_t g_ActorManager = 0; -static int g_MemFd = -1; -static float g_touchX = 0, g_touchY = 0; -static std::atomic g_touchDown{false}; +// ======================== 全局配置变量与偏移声明(保持不变)======================== +enum ConfigType { C_BOOL, C_INT, C_FLOAT, C_STRING }; +struct ConfigEntry { const char* key; ConfigType type; void* ptr; }; -// 安全读取 -template -T Read(uintptr_t addr) { - T val{}; - if (addr < 0x10000) return val; - if (g_MemFd == -1) g_MemFd = open("/proc/self/mem", O_RDONLY); - if (g_MemFd >= 0) pread(g_MemFd, &val, sizeof(T), addr); - return val; +int g_gl_width = 0, g_gl_height = 0; +int g_cached_view_width = -1, g_cached_view_height = -1; +const char* g_configPath = "/data/data/com.tencent.jkchess/jkchess_config.ini"; +std::mutex g_configMutex; + +bool g_enable_skin = false; +int g_selected_skin_idx = 0; +bool g_header_skin = true; +bool g_enable_map_skin = false; +int g_selected_map_idx = 0; +bool g_header_map_skin = true; + +bool g_predict_enemy = false, g_predict_hex = false; +bool g_esp_board = true, g_esp_level = false; +bool g_esp_enemy_bench = false; +bool g_show_instant_quit_window = false, g_boardLocked = false; +bool g_show_card_pool = false, g_card_warning = false; +bool g_show_sell_window = false; +float g_sell_win_x = 400.0f, g_sell_win_y = 350.0f, g_sell_win_scale = 1.0f; +bool g_show_auto_window = false, g_auto_refresh = false; +bool g_auto_buy = false, g_auto_buy_chosen = false; +bool g_show_hero_list_window = false; +bool g_show_clear_bench_btn = true; +bool g_show_equip_window = false; +bool g_auto_equip_active = false; +bool g_auto_unequip_active = false; +float g_equip_win_x = 400.0f, g_equip_win_y = 250.0f, g_equip_win_scale = 1.0f; +bool g_draw_hero_lines = true; +float g_esp_line_offset_y = 50.0f; + +std::unordered_map g_cell_equip_offset; +std::string g_cell_equip_offset_str = ""; +std::unordered_map g_cell_sell_offset; +std::string g_cell_sell_offset_str = ""; +float g_sell_drop_x = 500.0f; +float g_sell_drop_y = 900.0f; +float g_equip_ui_start_x = 100.0f; +float g_equip_ui_start_y = 300.0f; +float g_equip_ui_step_x = 100.0f; +float g_equip_ui_step_y = 100.0f; +bool g_show_equip_ui_debug = false; +bool g_show_sell_ui_debug = false; +int g_unequip_slot_idx = 0; +int g_swipe_step_delay_ms = 10; +int g_swipe_steps = 15; +bool g_show_swipe_visuals = true; +int g_swipe_down_delay_ms = 30; +int g_swipe_up_delay_ms = 20; +int g_equip_extra_cooldown_ms = 100; + +struct SwipeVisData { ImVec2 start; ImVec2 end; float lifeTime; float maxLife; }; +std::vector g_active_swipes; +std::mutex g_swipe_mutex; + +std::unordered_set g_auto_buy_heroes; +std::string g_auto_buy_heroes_str = ""; +std::unordered_map> g_hero_equip_bindings; +std::string g_hero_equip_bindings_str = ""; +std::unordered_map g_hero_equip_priority; +std::string g_hero_equip_priority_str = ""; +std::unordered_set g_expanded_equip_heroes; +std::map> g_local_pokedex; +std::vector g_local_equip_pokedex; +std::atomic g_pokedex_ready{false}; +std::atomic g_equip_pokedex_ready{false}; +float g_auto_buy_delay_ms = 0.0f; +int g_auto_refresh_money_threshold = 2; +float g_auto_win_x = 400.0f, g_auto_win_y = 150.0f, g_auto_win_scale = 1.0f; +float g_instant_win_x = 100.0f, g_instant_win_y = 100.0f, g_instant_win_scale = 1.0f; +float g_global_esp_alpha = 1.0f; +float g_enemy_bench_X = 200.0f, g_enemy_bench_Y = 200.0f, g_enemy_bench_Scale = 1.0f; + +// 偏移量配置(保持不变) +int g_off_shop_base = 0x440, g_off_bench_base = 0x448, g_off_shop_p20 = 0x20; +int g_off_shop_entries = 0x10, g_off_entries_count = 0x18, g_off_entries_head = 0x20; +int g_off_entries_step = 0x20, g_off_entry_value = 0x10, g_off_value_slot = 0x1c; +int g_off_value_p10 = 0x10, g_off_p10_heroId = 0x14; +int g_off_pool_heroku = 0x18, g_off_pool_Aheroku = 0x18, g_off_pool_entries1 = 0x10; +int g_off_pool_e1_count = 0x18, g_off_pool_e1_head = 0x20, g_off_pool_e1_step = 0x20, g_off_pool_e1_val = 0x10; +int g_off_pool_entries2 = 0x10, g_off_pool_e2_count = 0x18, g_off_pool_e2_head = 0x20, g_off_pool_e2_step = 0x20, g_off_pool_e2_val = 0x10; +int g_off_pool_v2_id = 0x10, g_off_pool_v2_rem = 0x1c, g_off_pool_v2_tot = 0x20; +int g_off_equip_base = 0x2e8; +int g_off_equip_arr = 0x10; +int g_off_equip_count = 0x18; +int g_off_equip_head = 0x20; +int g_off_equip_step = 0x8; +int g_off_equip_id = 0x14; +int g_off_hero_dyn = 0x2b0; +int g_off_hero_arr = 0x20; +int g_off_hero_count = 0x18; +int g_off_hero_head = 0x20; +int g_off_hero_step = 0x8; +int g_off_hero_id = 0x108; +int g_off_hero_unit = 0x48; +int g_off_unit_battle = 0x20; +int g_off_battle_posx = 0x238; + +int g_card_pool_rows = 2, g_card_pool_cols = 5; +float g_cardPoolX = 150.0f, g_cardPoolY = 150.0f; +float g_cardPoolScaleX = 1.0f, g_cardPoolScaleY = 1.0f, g_cardPoolAlpha = 1.0f; +bool g_show_pool_tiers[7] = {false, true, true, true, true, true, false}; +bool g_pool_warning_enable = false; +int g_pool_warning_count = 3; +bool g_pool_warning_tiers[7] = {false, true, true, true, true, true, false}; +bool g_warning_tiers[7] = {false, false, false, false, true, false, false}; +int g_warning_threshold = 6; +bool g_show_debug_window = false, g_header_pred = true, g_header_esp = true, g_menuCollapsed = false; +float g_save_timer = 0.0f, g_scale = 1.0f, g_autoScale = 1.0f, g_current_rendered_size = 0.0f; +float g_anim[30] = {0.0f}; +float g_boardScale = 2.2f, g_boardManualScale = 1.0f, g_startX = 400.0f, g_startY = 400.0f; +float g_menuX = 100.0f, g_menuY = 100.0f, g_menuW = 500.0f, g_menuH = 650.0f; +float g_enemy_X = 100.0f, g_enemy_Y = 100.0f, g_enemy_Scale = 1.0f; +float g_hex_X = 100.0f, g_hex_Y = 220.0f, g_hex_Scale = 1.0f; +float g_level_X = 1500.0f, g_level_Y = 200.0f, g_level_Scale = 1.0f, g_level_Spacing = 45.0f; +float g_warn_X = 1650.0f, g_warn_Y = 200.0f, g_warn_Scale = 1.0f, g_warn_Spacing = 45.0f; +float g_predictNameX = 500.0f, g_predictNameY = 300.0f, g_predictNameScale = 1.5f; + +bool g_needUpdateFontSafe = false; +ImFont* g_mainFont = nullptr, *g_hugeNumFont = nullptr; + +std::deque g_collected_skins; +std::deque g_collected_maps; +std::mutex g_collect_mutex; +bool g_collect_skins = false; +bool g_collect_maps = false; + +ConfigEntry g_configTable[] = { + {"enableSkin", C_BOOL, &g_enable_skin}, {"skinIdx", C_INT, &g_selected_skin_idx}, + {"enableMapSkin", C_BOOL, &g_enable_map_skin}, {"mapSkinIdx", C_INT, &g_selected_map_idx}, + {"globalEspAlpha", C_FLOAT, &g_global_esp_alpha}, + {"predictEnemy", C_BOOL, &g_predict_enemy}, {"predictHex", C_BOOL, &g_predict_hex}, + {"predictNameX", C_FLOAT, &g_predictNameX}, {"predictNameY", C_FLOAT, &g_predictNameY}, {"predictNameScale", C_FLOAT, &g_predictNameScale}, + {"collectSkins", C_BOOL, &g_collect_skins}, {"collectMaps", C_BOOL, &g_collect_maps}, + {"espBoard", C_BOOL, &g_esp_board}, {"espLevel", C_BOOL, &g_esp_level}, + {"espEnemyBench", C_BOOL, &g_esp_enemy_bench}, + {"offShopBase", C_INT, &g_off_shop_base}, {"offBenchBase", C_INT, &g_off_bench_base}, {"offShopP20", C_INT, &g_off_shop_p20}, + {"offShopEntries", C_INT, &g_off_shop_entries}, {"offEntriesCount", C_INT, &g_off_entries_count}, {"offEntriesHead", C_INT, &g_off_entries_head}, + {"offEntriesStep", C_INT, &g_off_entries_step}, {"offEntryValue", C_INT, &g_off_entry_value}, {"offValueSlot", C_INT, &g_off_value_slot}, + {"offValueP10", C_INT, &g_off_value_p10}, {"offP10HeroId", C_INT, &g_off_p10_heroId}, + {"offPoolHeroku", C_INT, &g_off_pool_heroku}, {"offPoolAheroku", C_INT, &g_off_pool_Aheroku}, + {"offPoolE1", C_INT, &g_off_pool_entries1}, {"offPoolE1Cnt", C_INT, &g_off_pool_e1_count}, + {"offPoolE1Hd", C_INT, &g_off_pool_e1_head}, {"offPoolE1Stp", C_INT, &g_off_pool_e1_step}, + {"offPoolE1Val", C_INT, &g_off_pool_e1_val}, {"offPoolE2", C_INT, &g_off_pool_entries2}, + {"offPoolE2Cnt", C_INT, &g_off_pool_e2_count}, {"offPoolE2Hd", C_INT, &g_off_pool_e2_head}, + {"offPoolE2Stp", C_INT, &g_off_pool_e2_step}, {"offPoolE2Val", C_INT, &g_off_pool_e2_val}, + {"offPoolV2Id", C_INT, &g_off_pool_v2_id}, {"offPoolV2Rem", C_INT, &g_off_pool_v2_rem}, + {"offPoolV2Tot", C_INT, &g_off_pool_v2_tot}, + {"showCardPool", C_BOOL, &g_show_card_pool}, {"cardPoolRows", C_INT, &g_card_pool_rows}, {"cardPoolCols", C_INT, &g_card_pool_cols}, + {"cardPoolScaleX", C_FLOAT, &g_cardPoolScaleX}, {"cardPoolScaleY", C_FLOAT, &g_cardPoolScaleY}, {"cardPoolAlpha", C_FLOAT, &g_cardPoolAlpha}, + {"cardPoolX", C_FLOAT, &g_cardPoolX}, {"cardPoolY", C_FLOAT, &g_cardPoolY}, + {"poolWarnEn", C_BOOL, &g_pool_warning_enable}, {"poolWarnCnt", C_INT, &g_pool_warning_count}, + {"poolWT1", C_BOOL, &g_pool_warning_tiers[1]}, {"poolWT2", C_BOOL, &g_pool_warning_tiers[2]}, + {"poolWT3", C_BOOL, &g_pool_warning_tiers[3]}, {"poolWT4", C_BOOL, &g_pool_warning_tiers[4]}, + {"poolWT5", C_BOOL, &g_pool_warning_tiers[5]}, + {"autoRefresh", C_BOOL, &g_auto_refresh}, {"autoBuy", C_BOOL, &g_auto_buy}, {"autoBuyDelay", C_FLOAT, &g_auto_buy_delay_ms}, + {"autoRefMoneyThr", C_INT, &g_auto_refresh_money_threshold}, + {"showAutoWin", C_BOOL, &g_show_auto_window}, {"autoBuyChosen", C_BOOL, &g_auto_buy_chosen}, + {"autoWinX", C_FLOAT, &g_auto_win_x}, {"autoWinY", C_FLOAT, &g_auto_win_y}, {"autoWinScale", C_FLOAT, &g_auto_win_scale}, + {"showDebug", C_BOOL, &g_show_debug_window}, {"cardWarning", C_BOOL, &g_card_warning}, {"warningThreshold", C_INT, &g_warning_threshold}, + {"poolTier1", C_BOOL, &g_show_pool_tiers[1]}, {"poolTier2", C_BOOL, &g_show_pool_tiers[2]}, {"poolTier3", C_BOOL, &g_show_pool_tiers[3]}, + {"poolTier4", C_BOOL, &g_show_pool_tiers[4]}, {"poolTier5", C_BOOL, &g_show_pool_tiers[5]}, + {"warningTier1", C_BOOL, &g_warning_tiers[1]}, {"warningTier2", C_BOOL, &g_warning_tiers[2]}, {"warningTier3", C_BOOL, &g_warning_tiers[3]}, + {"warningTier4", C_BOOL, &g_warning_tiers[4]}, {"warningTier5", C_BOOL, &g_warning_tiers[5]}, {"warningTier6", C_BOOL, &g_warning_tiers[6]}, + {"instant", C_BOOL, &g_show_instant_quit_window}, {"boardLocked", C_BOOL, &g_boardLocked}, + {"instantWinX", C_FLOAT, &g_instant_win_x}, {"instantWinY", C_FLOAT, &g_instant_win_y}, {"instantWinScale", C_FLOAT, &g_instant_win_scale}, + {"showSellWin", C_BOOL, &g_show_sell_window}, {"sellWinX", C_FLOAT, &g_sell_win_x}, {"sellWinY", C_FLOAT, &g_sell_win_y}, {"sellWinScale", C_FLOAT, &g_sell_win_scale}, + {"menuX", C_FLOAT, &g_menuX}, {"menuY", C_FLOAT, &g_menuY}, {"menuW", C_FLOAT, &g_menuW}, {"menuH", C_FLOAT, &g_menuH}, + {"menuScale", C_FLOAT, &g_scale}, {"menuCollapsed", C_BOOL, &g_menuCollapsed}, + {"startX", C_FLOAT, &g_startX}, {"startY", C_FLOAT, &g_startY}, {"manualScale", C_FLOAT, &g_boardManualScale}, + {"enemyBenchX", C_FLOAT, &g_enemy_bench_X}, {"enemyBenchY", C_FLOAT, &g_enemy_bench_Y}, {"enemyBenchScale", C_FLOAT, &g_enemy_bench_Scale}, + {"enemyX", C_FLOAT, &g_enemy_X}, {"enemyY", C_FLOAT, &g_enemy_Y}, {"enemyScale", C_FLOAT, &g_enemy_Scale}, + {"hexX", C_FLOAT, &g_hex_X}, {"hexY", C_FLOAT, &g_hex_Y}, {"hexScale", C_FLOAT, &g_hex_Scale}, + {"levelX", C_FLOAT, &g_level_X}, {"levelY", C_FLOAT, &g_level_Y}, {"levelScale", C_FLOAT, &g_level_Scale}, {"levelSpacing", C_FLOAT, &g_level_Spacing}, + {"warnX", C_FLOAT, &g_warn_X}, {"warnY", C_FLOAT, &g_warn_Y}, {"warnScale", C_FLOAT, &g_warn_Scale}, {"warnSpacing", C_FLOAT, &g_warn_Spacing}, + {"headerPred", C_BOOL, &g_header_pred}, {"headerEsp", C_BOOL, &g_header_esp}, + {"showHeroListWin", C_BOOL, &g_show_hero_list_window}, + {"autoBuyHeroes", C_STRING, &g_auto_buy_heroes_str}, + {"heroEquipBindings", C_STRING, &g_hero_equip_bindings_str}, + {"heroEquipPriority", C_STRING, &g_hero_equip_priority_str}, + {"showEquipWin", C_BOOL, &g_show_equip_window}, + {"equipWinX", C_FLOAT, &g_equip_win_x}, + {"equipWinY", C_FLOAT, &g_equip_win_y}, + {"equipWinScale", C_FLOAT, &g_equip_win_scale}, + {"drawHeroLines", C_BOOL, &g_draw_hero_lines}, + {"offEquipBase", C_INT, &g_off_equip_base}, + {"offEquipArr", C_INT, &g_off_equip_arr}, + {"offEquipCount", C_INT, &g_off_equip_count}, + {"offEquipHead", C_INT, &g_off_equip_head}, + {"offEquipStep", C_INT, &g_off_equip_step}, + {"offEquipId", C_INT, &g_off_equip_id}, + {"offHeroDyn", C_INT, &g_off_hero_dyn}, + {"offHeroArr", C_INT, &g_off_hero_arr}, + {"offHeroCount", C_INT, &g_off_hero_count}, + {"offHeroHead", C_INT, &g_off_hero_head}, + {"offHeroStep", C_INT, &g_off_hero_step}, + {"offHeroId", C_INT, &g_off_hero_id}, + {"offHeroUnit", C_INT, &g_off_hero_unit}, + {"offUnitBattle", C_INT, &g_off_unit_battle}, + {"offBattlePosx", C_INT, &g_off_battle_posx}, + {"espLineOffsetY", C_FLOAT, &g_esp_line_offset_y}, + {"cellEquipOffsets", C_STRING, &g_cell_equip_offset_str}, + {"cellSellOffsets", C_STRING, &g_cell_sell_offset_str}, + {"sellDropX", C_FLOAT, &g_sell_drop_x}, {"sellDropY", C_FLOAT, &g_sell_drop_y}, + {"showClearBenchBtn", C_BOOL, &g_show_clear_bench_btn}, + {"equipUiStartX", C_FLOAT, &g_equip_ui_start_x}, + {"equipUiStartY", C_FLOAT, &g_equip_ui_start_y}, + {"equipUiStepX", C_FLOAT, &g_equip_ui_step_x}, + {"equipUiStepY", C_FLOAT, &g_equip_ui_step_y}, + {"swipeDelay", C_INT, &g_swipe_step_delay_ms}, + {"swipeSteps", C_INT, &g_swipe_steps}, + {"showSwipeVis", C_BOOL, &g_show_swipe_visuals}, + {"swipeDownDelay", C_INT, &g_swipe_down_delay_ms}, + {"swipeUpDelay", C_INT, &g_swipe_up_delay_ms}, + {"equipExtraCD", C_INT, &g_equip_extra_cooldown_ms}, + {"unequipSlotIdx", C_INT, &g_unequip_slot_idx} +}; + +// ======================== IL2CPP 函数指针与换肤相关(保持不变)======================== +typedef void* (*il2cpp_domain_get_t)(); +typedef void* (*il2cpp_thread_attach_t)(void* domain); +typedef void (*il2cpp_thread_detach_t)(void* thread); +typedef void* (*il2cpp_string_new_t)(const char* str); +il2cpp_domain_get_t g_il2cpp_domain_get = nullptr; +il2cpp_thread_attach_t g_il2cpp_thread_attach = nullptr; +il2cpp_thread_detach_t g_il2cpp_thread_detach = nullptr; +il2cpp_string_new_t g_il2cpp_string_new = nullptr; + +struct SkinInfo { const char* zh_name; const char* bundle; const char* asset; }; +SkinInfo g_skinList[] = { + {"锐雯(至臻)", "art_tft_raw/little_legend_res/model/t_rivenswordgold/t_rivenswordgold/low", "t_rivenswordgold_1_show"}, + // ... 省略中间皮肤(保持原样,太多不全部贴出,实际编译时请保留完整列表) + {"亚索(原皮黄)", "art_tft_raw/little_legend_res/model/t_yasuobase/t_yasuobase_yellow/low", "t_yasuobase_yellow_1_show"} +}; +struct MapInfo { const char* zh_name; const char* bundle; const char* asset; }; +MapInfo g_mapList[] = { + {"兰亭集序(神话)", "art_tft_raw/scenes/prefab/s11_tft_lantingpoems", "s11_tft_lantingpoems"}, + // ... 省略中间地图 + {"S4 凌云", "art_tft_raw/scenes/prefab/s4_tft_lingyun_001", "s4_tft_lingyun_001"} +}; + +// ======================== 安全读取与辅助函数(保持不变)======================== +inline bool IsValidPtr(uintptr_t addr) { + return addr > 0x10000000 && addr < 0x00007FFFFFFFFFFF && (addr % 4 == 0); } -// 获取模块基址 -uintptr_t GetBase(const char* name) { - FILE* f = fopen("/proc/self/maps", "r"); - if (!f) return 0; - char line[512]; - uintptr_t base = 0; - while (fgets(line, sizeof(line), f)) { - if (strstr(line, name) && strstr(line, "r-xp")) { - sscanf(line, "%lx", &base); - break; +thread_local int g_safe_pipe[2] = {-1, -1}; + +bool SafeReadMemory(uintptr_t addr, void* buffer, size_t size) { + if (addr < 0x10000000 || addr > 0x00007FFFFFFFFFFF) return false; + if (g_safe_pipe[0] == -1) { + if (pipe2(g_safe_pipe, O_NONBLOCK) != 0) { + if (IsValidPtr(addr)) { memcpy(buffer, (void*)addr, size); return true; } + return false; } } - fclose(f); - return base; + ssize_t res = write(g_safe_pipe[1], (void*)addr, size); + if (res == (ssize_t)size) { + read(g_safe_pipe[0], buffer, size); return true; + } else if (res > 0) { + char temp[256]; read(g_safe_pipe[0], temp, res); + } + return false; } -// 原函数只有1个参数,直接 Hook -void (*old_InitActor)(void* x0); -void hook_InitActor(void* x0) { - LOGI("[HOOK] InitActor x0 = %p", x0); - g_ActorManager = (uintptr_t)x0; - old_InitActor(x0); +std::deque g_appLogs; +std::mutex g_logMutex; + +void AddLog(const char* fmt, ...) { + char buf[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + std::string logStr(buf); + std::lock_guard lock(g_logMutex); + static std::unordered_set seenLogs; + if (seenLogs.find(logStr) != seenLogs.end()) return; + seenLogs.insert(logStr); + time_t now = time(nullptr); + struct tm tstruct = *localtime(&now); + char timebuf[80]; + strftime(timebuf, sizeof(timebuf), "%H:%M:%S", &tstruct); + g_appLogs.push_back(std::string("[") + timebuf + "] " + logStr); + if (g_appLogs.size() > 100) g_appLogs.pop_front(); +} + +#define SAFE_READ(type, base, offset, defaultVal) \ + ([&]() -> type { \ + type val = defaultVal; \ + uintptr_t targetAddr = (uintptr_t)(base) + (offset); \ + if (!SafeReadMemory(targetAddr, &val, sizeof(type))) val = defaultVal; \ + return val; \ + }()) +#define SAFE_READ_PTR(base, offset) SAFE_READ(uintptr_t, base, offset, 0) + +std::string Utf16ToUtf8(const char16_t* u16str, size_t len) { + std::string u8str; + for (size_t i = 0; i < len; ++i) { + char16_t wc = u16str[i]; + if (wc < 0x80) u8str += (char)wc; + else if (wc < 0x800) { u8str += (char)(0xC0 | (wc >> 6)); u8str += (char)(0x80 | (wc & 0x3F)); } + else { u8str += (char)(0xE0 | (wc >> 12)); u8str += (char)(0x80 | ((wc >> 6) & 0x3F)); u8str += (char)(0x80 | (wc & 0x3F)); } + } + return u8str; +} + +std::string ReadIl2cppStr(void* strObj) { + if (!strObj || !IsValidPtr((uintptr_t)strObj)) return ""; + int len = SAFE_READ(int, strObj, 0x10, 0); + if (len > 0 && len < 500) { + char16_t buffer[500] = {0}; + if (SafeReadMemory((uintptr_t)strObj + 0x14, buffer, len * sizeof(char16_t))) { + return Utf16ToUtf8(buffer, len); + } + } + return ""; +} + +// 换肤相关 Hook(保持不变) +typedef void* (*func_LoadAsset_t)(void* x0, void* x1, void* x2, void* x3, int x4); +func_LoadAsset_t orig_LoadAsset_718 = nullptr; +void* hook_LoadAsset_718(void* x0, void* x1, void* x2, void* x3, int x4) { + if (x1 && x2) { + std::string bundleStr = ReadIl2cppStr(x1); + std::string assetStr = ReadIl2cppStr(x2); + if (g_collect_skins && !bundleStr.empty()) { + std::lock_guard lock(g_collect_mutex); + std::string logStr = bundleStr + " | " + assetStr; + if (std::find(g_collected_skins.begin(), g_collected_skins.end(), logStr) == g_collected_skins.end()) { + g_collected_skins.push_back(logStr); + } + } + if (g_enable_skin && g_il2cpp_string_new) { + void* new_bundle = g_il2cpp_string_new(g_skinList[g_selected_skin_idx].bundle); + void* new_asset = g_il2cpp_string_new(g_skinList[g_selected_skin_idx].asset); + if (new_bundle && new_asset) { + return orig_LoadAsset_718(x0, new_bundle, new_asset, x3, x4); + } + } + } + return orig_LoadAsset_718(x0, x1, x2, x3, x4); +} + +typedef void* (*func_LoadMapImpl_t)(void* x0, void* bundlePath, void* assetName, void* container, uint64_t isBackground, uint64_t isMineMap); +func_LoadMapImpl_t orig_LoadMapImpl = nullptr; +void* hook_LoadMapImpl(void* x0, void* bundlePath, void* assetName, void* container, uint64_t isBackground, uint64_t isMineMap) { + if (bundlePath && assetName) { + std::string bundleStr = ReadIl2cppStr(bundlePath); + std::string assetStr = ReadIl2cppStr(assetName); + if (g_collect_maps && !bundleStr.empty()) { + std::lock_guard lock(g_collect_mutex); + std::string logStr = bundleStr + " | " + assetStr; + if (std::find(g_collected_maps.begin(), g_collected_maps.end(), logStr) == g_collected_maps.end()) { + g_collected_maps.push_back(logStr); + } + } + if (g_enable_map_skin && g_il2cpp_string_new) { + if (isMineMap != 0) { + void* new_bundle = g_il2cpp_string_new(g_mapList[g_selected_map_idx].bundle); + void* new_asset = g_il2cpp_string_new(g_mapList[g_selected_map_idx].asset); + if (new_bundle && new_asset) { + return orig_LoadMapImpl(x0, new_bundle, new_asset, container, isBackground, isMineMap); + } + } + } + } + return orig_LoadMapImpl(x0, bundlePath, assetName, container, isBackground, isMineMap); +} + +// 以下数据结构与函数(RingBuffer, PlayerRowInfo, MainThreadTasks, 各种 Hook 实现等)全部保持不变 +// 由于代码量巨大,这里只展示关键修改点,实际使用时请保留你原有的所有实现 + +// ======================== 核心修改:修正 Hook 函数原型(只有 1 个参数)======================== +// 原代码中 old_InitActorParams 和 hook_InitActorParams 有 4 个参数,现改为 1 个参数 +void (*old_InitActorParams)(void* x0); +void hook_InitActorParams(void* x0) { + LOGI("[HOOK] InitActorParams called! x0 = %p", x0); + if (x0 != nullptr) { + g_ActorManager.store((uintptr_t)x0); + // 可选测试读取偏移 + uintptr_t test_addr = SafeRead((uintptr_t)x0 + g_Offsets.x0_to_addr1); + LOGI("[HOOK] x0+0x%x = %p", g_Offsets.x0_to_addr1, (void*)test_addr); + } else { + LOGE("[HOOK] x0 is null!"); + } + old_InitActorParams(x0); } void (*old_ClearActor)(void* x0); void hook_ClearActor(void* x0) { - LOGI("[HOOK] ClearActor x0 = %p", x0); - g_ActorManager = 0; + LOGI("[HOOK] ClearActor called! x0 = %p", x0); + g_ActorManager.store(0); old_ClearActor(x0); } -// 触摸事件处理 -void handleTouch(AInputEvent* e) { - if (AInputEvent_getType(e) == AINPUT_EVENT_TYPE_MOTION) { - int act = AMotionEvent_getAction(e) & AMOTION_EVENT_ACTION_MASK; - g_touchX = AMotionEvent_getX(e, 0); - g_touchY = AMotionEvent_getY(e, 0); - g_touchDown = (act == AMOTION_EVENT_ACTION_DOWN); - } -} -typedef int (*Consume_t)(void*,void*,bool,int64_t,uint32_t*,void**); -Consume_t oldConsume = nullptr; -int hookConsume(void* a,void* b,bool c,int64_t d,uint32_t* e,void** f) { - int r = oldConsume(a,b,c,d,e,f); - if (r==0 && f && *f) handleTouch((AInputEvent*)*f); - return r; -} +// 注意:以下所有原有代码(DataWorkerThread、各种 Hook 函数、ImGui 绘制函数等)完全保持不变 +// 请将你之前完整的实现粘贴在这里,包括: +// - 所有 Hook 函数(如 hook_3Cd6058, hook_set_Money, hook_TurnStart, hook_set_IsGameEnd 等) +// - 所有数据结构(GameSnapshot, PlayerInfo, EnemyHeroPos 等) +// - 所有绘制函数(DrawBoard, DrawBenchESP, DrawCardPool, DrawMenu 等) +// - 所有辅助函数(LoadConfig, SaveConfig, UpdateCardPoolData, UpdateEquipAndLiveHeroes 等) +// - 所有线程函数(BackgroundDataUpdateThread, TextureDecodingWorkerThread 等) +// - 最后 init_plugin 入口 -// eglSwapBuffers Hook -typedef EGLBoolean (*Swap_t)(EGLDisplay,EGLSurface); -Swap_t oldSwap = nullptr; -static bool imguiReady = false; -EGLBoolean hookSwap(EGLDisplay dpy, EGLSurface surf) { - EGLint w, h; - eglQuerySurface(dpy, surf, EGL_WIDTH, &w); - eglQuerySurface(dpy, surf, EGL_HEIGHT, &h); - if (w > 0 && h > 0) { - if (!imguiReady) { - ImGui::CreateContext(); - ImGui_ImplOpenGL3_Init("#version 300 es"); - ImGui::GetIO().Fonts->AddFontDefault(); - imguiReady = true; - } - ImGuiIO& io = ImGui::GetIO(); - io.DisplaySize = ImVec2(w, h); - io.MousePos = ImVec2(g_touchX, g_touchY); - io.MouseDown[0] = g_touchDown.load(); - - ImGui_ImplOpenGL3_NewFrame(); - ImGui::NewFrame(); - - // 简单显示 - int hp = 0; - if (g_ActorManager) { - uintptr_t addr1 = Read(g_ActorManager + 0x20); - if (addr1) { - uintptr_t addr2 = Read(addr1 + 0x10); - if (addr2) { - uintptr_t item = Read(addr2); - if (item) { - uintptr_t addr3 = Read(item + 0x18); - if (addr3) { - uintptr_t addr4 = Read(addr3 + 0x30); - if (addr4) hp = Read(addr4 + 0x30); - } - } - } - } - } - - ImGui::Begin("Hook Test"); - ImGui::Text("ActorManager: 0x%lx", g_ActorManager); - ImGui::Text("Player HP: %d", hp); - ImGui::End(); - - ImGui::Render(); - glViewport(0, 0, w, h); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - } - return oldSwap(dpy, surf); -} - -// 初始化线程 -void* InitThread(void*) { - // 等待 libil2cpp.so 加载 - uintptr_t base; - while (!(base = GetBase("libil2cpp.so"))) sleep(1); - uintptr_t initAddr = base + 0x73507bc; - uintptr_t clearAddr = base + 0x734bc10; - LOGI("Base=0x%lx, Init=0x%lx, Clear=0x%lx", base, initAddr, clearAddr); - DobbyHook((void*)initAddr, (void*)hook_InitActor, (void**)&old_InitActor); - DobbyHook((void*)clearAddr, (void*)hook_ClearActor, (void**)&old_ClearActor); - // Hook EGL 和 Input - DobbyHook(DobbySymbolResolver("libEGL.so", "eglSwapBuffers"), (void*)hookSwap, (void**)&oldSwap); - DobbyHook(DobbySymbolResolver("libinput.so", "_ZN7android13InputConsumer7consumeEPNS_26InputEventFactoryInterfaceEblPjPPNS_10InputEventE"), (void*)hookConsume, (void**)&oldConsume); - return nullptr; -} - -__attribute__((constructor)) void entry() { - pthread_t t; - pthread_create(&t, nullptr, InitThread, nullptr); -} +// 由于篇幅限制,这里只给出修改后的 Hook 函数部分,其余代码请原样保留。 +// 如果你需要我将整个完整代码(包括所有功能)重新贴出来,请告知,我会逐段提供。