mirror of
https://github.com/ocornut/imgui.git
synced 2026-11-06 14:35:51 +01:00
Update main.cpp
This commit is contained in:
parent
37a470314b
commit
d7cd15758c
538
main.cpp
538
main.cpp
@ -1,3 +1,6 @@
|
||||
// 注意:本代码基于你之前提供的完整功能版本,只修改了 Hook 部分
|
||||
// 所有原有功能(换肤、ESP、自动操作、牌池、装备管理等)均保持不变
|
||||
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <android/log.h>
|
||||
@ -6,152 +9,439 @@
|
||||
#include <dlfcn.h>
|
||||
#include <android/input.h>
|
||||
#include <stdio.h>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <deque>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <cmath>
|
||||
#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<bool> g_touchDown{false};
|
||||
// ======================== 全局配置变量与偏移声明(保持不变)========================
|
||||
enum ConfigType { C_BOOL, C_INT, C_FLOAT, C_STRING };
|
||||
struct ConfigEntry { const char* key; ConfigType type; void* ptr; };
|
||||
|
||||
// 安全读取
|
||||
template<typename T>
|
||||
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<int, ImVec2> g_cell_equip_offset;
|
||||
std::string g_cell_equip_offset_str = "";
|
||||
std::unordered_map<int, ImVec2> 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<SwipeVisData> g_active_swipes;
|
||||
std::mutex g_swipe_mutex;
|
||||
|
||||
std::unordered_set<int> g_auto_buy_heroes;
|
||||
std::string g_auto_buy_heroes_str = "";
|
||||
std::unordered_map<int, std::vector<int>> g_hero_equip_bindings;
|
||||
std::string g_hero_equip_bindings_str = "";
|
||||
std::unordered_map<int, int> g_hero_equip_priority;
|
||||
std::string g_hero_equip_priority_str = "";
|
||||
std::unordered_set<int> g_expanded_equip_heroes;
|
||||
std::map<int, std::vector<int>> g_local_pokedex;
|
||||
std::vector<int> g_local_equip_pokedex;
|
||||
std::atomic<bool> g_pokedex_ready{false};
|
||||
std::atomic<bool> 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<std::string> g_collected_skins;
|
||||
std::deque<std::string> 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<std::string> 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<std::mutex> lock(g_logMutex);
|
||||
static std::unordered_set<std::string> 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<std::mutex> 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<std::mutex> 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>((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<uintptr_t>(g_ActorManager + 0x20);
|
||||
if (addr1) {
|
||||
uintptr_t addr2 = Read<uintptr_t>(addr1 + 0x10);
|
||||
if (addr2) {
|
||||
uintptr_t item = Read<uintptr_t>(addr2);
|
||||
if (item) {
|
||||
uintptr_t addr3 = Read<uintptr_t>(item + 0x18);
|
||||
if (addr3) {
|
||||
uintptr_t addr4 = Read<uintptr_t>(addr3 + 0x30);
|
||||
if (addr4) hp = Read<int32_t>(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 函数部分,其余代码请原样保留。
|
||||
// 如果你需要我将整个完整代码(包括所有功能)重新贴出来,请告知,我会逐段提供。
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user