mirror of
https://github.com/ocornut/imgui.git
synced 2026-11-09 07:55:52 +01:00
Update main.cpp
This commit is contained in:
parent
69ef916fd7
commit
6a0313c6e7
147
main.cpp
147
main.cpp
@ -14,6 +14,8 @@
|
||||
#include <chrono>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
#include "dobby.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_android.h"
|
||||
@ -22,11 +24,35 @@
|
||||
#define TAG "IL2CPP_Drive"
|
||||
#define GAME_MODULE "libil2cpp.so"
|
||||
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
|
||||
// 日志缓冲区(线程安全,循环队列)
|
||||
#define MAX_LOG_LINES 200
|
||||
#define MAX_LOG_LEN 256
|
||||
|
||||
static std::mutex g_LogMutex;
|
||||
static char g_LogBuffer[MAX_LOG_LINES][MAX_LOG_LEN];
|
||||
static int g_LogHead = 0;
|
||||
static int g_LogCount = 0;
|
||||
|
||||
void AddLog(const char* fmt, ...) {
|
||||
char buf[MAX_LOG_LEN];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
std::lock_guard<std::mutex> lock(g_LogMutex);
|
||||
strncpy(g_LogBuffer[g_LogHead], buf, MAX_LOG_LEN - 1);
|
||||
g_LogBuffer[g_LogHead][MAX_LOG_LEN - 1] = '\0';
|
||||
g_LogHead = (g_LogHead + 1) % MAX_LOG_LINES;
|
||||
if (g_LogCount < MAX_LOG_LINES) g_LogCount++;
|
||||
// 同时也输出到 logcat,方便调试
|
||||
__android_log_print(ANDROID_LOG_INFO, TAG, "%s", buf);
|
||||
}
|
||||
|
||||
// 全局变量
|
||||
static bool g_Initialized = false;
|
||||
static bool g_FontLoaded = false;
|
||||
static bool g_ShowLogWindow = true; // 默认显示日志窗口
|
||||
|
||||
struct {
|
||||
float x = 0.0f;
|
||||
@ -50,22 +76,18 @@ static uintptr_t g_HookAddr_InitActor = 0;
|
||||
static uintptr_t g_HookAddr_ClearActor = 0;
|
||||
|
||||
struct DynamicOffsets {
|
||||
// 指针链偏移(根据你提供的值)
|
||||
uint32_t x0_to_addr1 = 0x20;
|
||||
uint32_t addr1_to_addr2 = 0x10;
|
||||
uint32_t item_to_addr3 = 0x18;
|
||||
uint32_t addr3_to_addr4 = 0x30;
|
||||
uint32_t addr3_to_addr5 = 0x100;
|
||||
uint32_t addr3_to_addr6 = 0x70;
|
||||
|
||||
// 属性偏移
|
||||
uint32_t prop_gold = 0x20;
|
||||
uint32_t prop_hp = 0x30;
|
||||
uint32_t prop_maxhp = 0x32; // int16
|
||||
uint32_t prop_maxhp = 0x32;
|
||||
uint32_t prop_level = 0x50;
|
||||
uint32_t prop_mana = 0x28;
|
||||
};
|
||||
|
||||
DynamicOffsets g_Offsets;
|
||||
std::mutex g_OffsetMutex;
|
||||
|
||||
@ -101,13 +123,13 @@ struct GameSnapshot {
|
||||
DebugChain debug;
|
||||
std::vector<PlayerData> players;
|
||||
};
|
||||
|
||||
std::mutex g_SnapshotMutex;
|
||||
GameSnapshot g_CurrentSnapshot;
|
||||
std::atomic<uintptr_t> g_ActorManager{0};
|
||||
|
||||
// ---------- 后台数据读取线程 ----------
|
||||
// 后台数据读取线程
|
||||
void DataWorkerThread() {
|
||||
AddLog("[DataThread] 启动数据线程");
|
||||
while (true) {
|
||||
GameSnapshot newSnap;
|
||||
DynamicOffsets currOff;
|
||||
@ -116,12 +138,10 @@ void DataWorkerThread() {
|
||||
currOff = g_Offsets;
|
||||
}
|
||||
newSnap.offsets = currOff;
|
||||
|
||||
uintptr_t baseX0 = g_ActorManager.load();
|
||||
if (baseX0 != 0) {
|
||||
newSnap.inMatch = true;
|
||||
newSnap.debug.baseX0 = baseX0;
|
||||
|
||||
uintptr_t addr1 = SafeRead<uintptr_t>(baseX0 + currOff.x0_to_addr1);
|
||||
newSnap.debug.addr1 = addr1;
|
||||
if (addr1) {
|
||||
@ -129,16 +149,13 @@ void DataWorkerThread() {
|
||||
newSnap.debug.addr2 = addr2;
|
||||
if (addr2) {
|
||||
for (int i = 0; i < 15; ++i) {
|
||||
uintptr_t item = SafeRead<uintptr_t>(addr2 + (i * 0x8));
|
||||
uintptr_t item = SafeRead<uintptr_t>(addr2 + i * 0x8);
|
||||
newSnap.debug.items[i].base = item;
|
||||
if (!item) continue;
|
||||
|
||||
uintptr_t addr3 = SafeRead<uintptr_t>(item + currOff.item_to_addr3);
|
||||
newSnap.debug.items[i].addr3 = addr3;
|
||||
if (!addr3) continue;
|
||||
|
||||
PlayerData p;
|
||||
|
||||
uintptr_t addr4 = SafeRead<uintptr_t>(addr3 + currOff.addr3_to_addr4);
|
||||
newSnap.debug.items[i].addr4 = addr4;
|
||||
if (addr4) {
|
||||
@ -147,7 +164,6 @@ void DataWorkerThread() {
|
||||
p.maxHp = SafeRead<int16_t>(addr4 + currOff.prop_maxhp);
|
||||
p.level = SafeRead<int32_t>(addr4 + currOff.prop_level);
|
||||
}
|
||||
|
||||
uintptr_t addr5 = SafeRead<uintptr_t>(addr3 + currOff.addr3_to_addr5);
|
||||
newSnap.debug.items[i].addr5 = addr5;
|
||||
if (addr5) {
|
||||
@ -156,21 +172,18 @@ void DataWorkerThread() {
|
||||
p.worldY = SafeRead<float>(addr5 + 0x8);
|
||||
p.mana = SafeRead<int32_t>(addr5 + currOff.prop_mana);
|
||||
}
|
||||
|
||||
uintptr_t addr6 = SafeRead<uintptr_t>(addr3 + currOff.addr3_to_addr6);
|
||||
newSnap.debug.items[i].addr6 = addr6;
|
||||
if (addr6) {
|
||||
p.mapX = SafeRead<float>(addr6 + 0x50);
|
||||
p.mapY = SafeRead<float>(addr6 + 0x54);
|
||||
}
|
||||
|
||||
if (p.maxHp > 0 && p.maxHp < 50000)
|
||||
newSnap.players.push_back(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_SnapshotMutex);
|
||||
g_CurrentSnapshot = newSnap;
|
||||
@ -179,7 +192,6 @@ void DataWorkerThread() {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 模块基址获取(修正版,只取 r-xp 段)----------
|
||||
uintptr_t GetModuleBase(const char* module_name) {
|
||||
FILE* fp = fopen("/proc/self/maps", "r");
|
||||
if (!fp) return 0;
|
||||
@ -195,29 +207,28 @@ uintptr_t GetModuleBase(const char* module_name) {
|
||||
return base;
|
||||
}
|
||||
|
||||
// ---------- 游戏 Hook 函数 ----------
|
||||
// Hook 函数
|
||||
void (*old_InitActorParams)(void* x0, void* x1, void* x2, void* x3);
|
||||
void hook_InitActorParams(void* x0, void* x1, void* x2, void* x3) {
|
||||
LOGI("[HOOK] InitActorParams called! x0 = %p", x0);
|
||||
AddLog("[HOOK] InitActorParams called! x0 = %p", x0);
|
||||
if (x0 != nullptr) {
|
||||
g_ActorManager.store((uintptr_t)x0);
|
||||
// 可选测试:尝试读取偏移,验证 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);
|
||||
AddLog("[HOOK] x0+0x%x = %p", g_Offsets.x0_to_addr1, (void*)test_addr);
|
||||
} else {
|
||||
LOGE("[HOOK] x0 is null!");
|
||||
AddLog("[HOOK] x0 is null!");
|
||||
}
|
||||
old_InitActorParams(x0, x1, x2, x3);
|
||||
}
|
||||
|
||||
void (*old_ClearActor)(void* x0);
|
||||
void hook_ClearActor(void* x0) {
|
||||
LOGI("[HOOK] ClearActor called! x0 = %p", x0);
|
||||
AddLog("[HOOK] ClearActor called! x0 = %p", x0);
|
||||
g_ActorManager.store(0);
|
||||
old_ClearActor(x0);
|
||||
}
|
||||
|
||||
// ---------- 辅助函数:分辨率自动获取 ----------
|
||||
// 辅助函数
|
||||
void AutoFetchDeviceResolution() {
|
||||
FILE* pipe = popen("wm size", "r");
|
||||
if (!pipe) return;
|
||||
@ -229,13 +240,12 @@ void AutoFetchDeviceResolution() {
|
||||
g_Touch.physW = (float)std::max(w, h);
|
||||
g_Touch.physH = (float)std::min(w, h);
|
||||
g_Touch.isSizeAutoDetected = true;
|
||||
LOGI("[Auto] Physical resolution: %.0fx%.0f", g_Touch.physW, g_Touch.physH);
|
||||
AddLog("[Auto] 物理分辨率: %.0fx%.0f", g_Touch.physW, g_Touch.physH);
|
||||
}
|
||||
}
|
||||
pclose(pipe);
|
||||
}
|
||||
|
||||
// ---------- 输入事件处理 ----------
|
||||
void handle_android_event(AInputEvent* event) {
|
||||
if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
|
||||
int32_t action = AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK;
|
||||
@ -250,19 +260,17 @@ void handle_android_event(AInputEvent* event) {
|
||||
|
||||
typedef int (*p_InputConsumer_consume)(void* instance, void* factory, bool consumeBatches, int64_t frameTime, uint32_t* outSeq, void** outEvent);
|
||||
static p_InputConsumer_consume old_consume = nullptr;
|
||||
|
||||
int hook_consume(void* instance, void* factory, bool consumeBatches, int64_t frameTime, uint32_t* outSeq, void** outEvent) {
|
||||
int res = old_consume(instance, factory, consumeBatches, frameTime, outSeq, outEvent);
|
||||
if (res == 0 && outEvent && *outEvent) handle_android_event((AInputEvent*)(*outEvent));
|
||||
return res;
|
||||
}
|
||||
|
||||
// ---------- eglSwapBuffers Hook(ImGui 渲染)----------
|
||||
typedef EGLBoolean (*p_eglSwapBuffers)(EGLDisplay dpy, EGLSurface surface);
|
||||
static p_eglSwapBuffers old_eglSwapBuffers = nullptr;
|
||||
|
||||
// 前向声明
|
||||
void DrawPointerDebugger(const GameSnapshot& snap, float w, float h);
|
||||
void DrawLogWindow();
|
||||
|
||||
EGLBoolean hook_eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
|
||||
EGLint w, h;
|
||||
@ -282,7 +290,6 @@ EGLBoolean hook_eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
|
||||
ImGui::CreateContext();
|
||||
ImGui_ImplOpenGL3_Init("#version 300 es");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
const char* systemFonts[] = {
|
||||
"/system/fonts/SysSans-Hans-Regular.ttf",
|
||||
"/system/fonts/NotoSansCJKjp-Regular.otc",
|
||||
@ -293,11 +300,12 @@ EGLBoolean hook_eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
|
||||
if (access(systemFonts[i], R_OK) == 0) {
|
||||
io.Fonts->AddFontFromFileTTF(systemFonts[i], 32.0f, NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
|
||||
g_FontLoaded = true;
|
||||
LOGI("[ImGui] Loaded font: %s", systemFonts[i]);
|
||||
AddLog("[ImGui] 加载字体成功: %s", systemFonts[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_Initialized = true;
|
||||
AddLog("[ImGui] 初始化完成");
|
||||
}
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
@ -347,7 +355,8 @@ EGLBoolean hook_eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
|
||||
}
|
||||
ImGui::Separator();
|
||||
ImGui::Checkbox("雷达", &show_radar); ImGui::SameLine();
|
||||
ImGui::Checkbox("调试器", &show_pointer_debugger);
|
||||
ImGui::Checkbox("调试器", &show_pointer_debugger); ImGui::SameLine();
|
||||
ImGui::Checkbox("日志窗口", &g_ShowLogWindow);
|
||||
ImGui::Separator();
|
||||
ImGui::TextColored(ImVec4(0,1,0,1), "状态: %s", snapshot.inMatch ? "局内" : "大厅");
|
||||
|
||||
@ -394,6 +403,8 @@ EGLBoolean hook_eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
if (g_ShowLogWindow) DrawLogWindow();
|
||||
|
||||
ImGui::Render();
|
||||
GLint v[4]; glGetIntegerv(GL_VIEWPORT, v);
|
||||
GLint d; glGetIntegerv(GL_DEPTH_TEST, &d);
|
||||
@ -406,12 +417,11 @@ EGLBoolean hook_eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
|
||||
return old_eglSwapBuffers(dpy, surface);
|
||||
}
|
||||
|
||||
// ---------- 指针调试器窗口 ----------
|
||||
void DrawPointerDebugger(const GameSnapshot& snap, float w, float h) {
|
||||
ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(w * 0.55f, h * 0.8f), ImGuiCond_FirstUseEver);
|
||||
if (ImGui::Begin("指针断点排错器 (IL2CPP)")) {
|
||||
if (ImGui::CollapsingHeader("动态偏移修改面板 (十进制)", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||
if (ImGui::CollapsingHeader("动态偏移修改面板", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||
std::lock_guard<std::mutex> lock(g_OffsetMutex);
|
||||
auto drawOffsetBtn = [](const char* label, uint32_t& val) {
|
||||
ImGui::PushID(&val);
|
||||
@ -467,57 +477,70 @@ void DrawPointerDebugger(const GameSnapshot& snap, float w, float h) {
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// ---------- 延迟 Hook 线程 ----------
|
||||
void DrawLogWindow() {
|
||||
ImGui::SetNextWindowPos(ImVec2(50, 200), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(500, 300), ImGuiCond_FirstUseEver);
|
||||
if (!ImGui::Begin("调试日志", &g_ShowLogWindow)) {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
ImGui::BeginChild("LogScroll", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_LogMutex);
|
||||
int start = (g_LogHead - g_LogCount + MAX_LOG_LINES) % MAX_LOG_LINES;
|
||||
for (int i = 0; i < g_LogCount; i++) {
|
||||
int idx = (start + i) % MAX_LOG_LINES;
|
||||
ImGui::TextUnformatted(g_LogBuffer[idx]);
|
||||
}
|
||||
if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
|
||||
ImGui::SetScrollHereY(1.0f);
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// 延迟初始化线程
|
||||
void* DelayedHookThread(void*) {
|
||||
// 1. 立即 Hook EGL 和 Input(保证菜单能显示)
|
||||
AddLog("[Init] 插件启动,开始 Hook 渲染与输入...");
|
||||
void* egl = DobbySymbolResolver("libEGL.so", "eglSwapBuffers");
|
||||
if (egl) {
|
||||
int ret = DobbyHook(egl, (void*)hook_eglSwapBuffers, (void**)&old_eglSwapBuffers);
|
||||
LOGI("[EGL] DobbyHook result: %d", ret);
|
||||
AddLog("[EGL] DobbyHook 结果: %d", ret);
|
||||
} else {
|
||||
LOGE("[EGL] eglSwapBuffers not found");
|
||||
AddLog("[EGL] 未找到 eglSwapBuffers");
|
||||
}
|
||||
|
||||
void* ins = DobbySymbolResolver("libinput.so", "_ZN7android13InputConsumer7consumeEPNS_26InputEventFactoryInterfaceEblPjPPNS_10InputEventE");
|
||||
if (ins) {
|
||||
int ret = DobbyHook(ins, (void*)hook_consume, (void**)&old_consume);
|
||||
LOGI("[Input] DobbyHook result: %d", ret);
|
||||
AddLog("[Input] DobbyHook 结果: %d", ret);
|
||||
} else {
|
||||
LOGE("[Input] InputConsumer::consume not found");
|
||||
AddLog("[Input] 未找到 InputConsumer::consume");
|
||||
}
|
||||
|
||||
// 2. 启动后台数据线程
|
||||
|
||||
std::thread(DataWorkerThread).detach();
|
||||
|
||||
// 3. 等待 libil2cpp.so 加载并 Hook 游戏函数
|
||||
AddLog("[Init] 等待游戏模块加载...");
|
||||
while (true) {
|
||||
uintptr_t base = GetModuleBase(GAME_MODULE);
|
||||
if (base != 0) {
|
||||
if (base) {
|
||||
g_GameBase = base;
|
||||
g_HookAddr_InitActor = base + 0x73507bc;
|
||||
g_HookAddr_ClearActor = base + 0x734bc10;
|
||||
LOGI("[Game] libil2cpp.so base = 0x%lx", base);
|
||||
LOGI("[Game] InitActor absolute addr = 0x%lx", g_HookAddr_InitActor);
|
||||
LOGI("[Game] ClearActor absolute addr = 0x%lx", g_HookAddr_ClearActor);
|
||||
|
||||
AddLog("[Game] libil2cpp.so 基址: 0x%lx", base);
|
||||
AddLog("[Game] InitActor 绝对地址: 0x%lx", g_HookAddr_InitActor);
|
||||
AddLog("[Game] ClearActor 绝对地址: 0x%lx", g_HookAddr_ClearActor);
|
||||
|
||||
int ret1 = DobbyHook((void*)g_HookAddr_InitActor, (void*)hook_InitActorParams, (void**)&old_InitActorParams);
|
||||
int ret2 = DobbyHook((void*)g_HookAddr_ClearActor, (void*)hook_ClearActor, (void**)&old_ClearActor);
|
||||
LOGI("[Game] DobbyHook InitActor result: %d (0=success)", ret1);
|
||||
LOGI("[Game] DobbyHook ClearActor result: %d", ret2);
|
||||
|
||||
if (ret1 == 0 && ret2 == 0) {
|
||||
LOGI("[Game] Hooks installed successfully");
|
||||
} else {
|
||||
LOGE("[Game] Hook installation failed");
|
||||
}
|
||||
AddLog("[Game] Hook InitActor 结果: %d, ClearActor: %d", ret1, ret2);
|
||||
break;
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
AutoFetchDeviceResolution();
|
||||
AddLog("[Init] 所有初始化完成,等待对局...");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// ---------- 入口 ----------
|
||||
__attribute__((constructor)) void init_plugin() {
|
||||
pthread_t t;
|
||||
pthread_create(&t, nullptr, DelayedHookThread, nullptr);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user