mirror of
https://github.com/ocornut/imgui.git
synced 2026-11-07 23:15:52 +01:00
Update main.cpp
This commit is contained in:
parent
88336ccf4f
commit
4de907c26b
145
main.cpp
145
main.cpp
@ -9,17 +9,13 @@
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <link.h>
|
||||
#include <sys/mman.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <memory>
|
||||
#include "dobby.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_android.h"
|
||||
@ -28,9 +24,9 @@
|
||||
#define TAG "IL2CPP_Drive"
|
||||
#define GAME_MODULE "libil2cpp.so"
|
||||
|
||||
// --- 实时日志系统 ---
|
||||
// --- 实时日志系统 (优化:使用 deque 提升性能) ---
|
||||
std::atomic<int> g_InitCallCount{0};
|
||||
std::vector<std::string> g_AppLogs;
|
||||
std::deque<std::string> g_AppLogs;
|
||||
std::mutex g_LogMutex;
|
||||
|
||||
void AddLog(const char* fmt, ...) {
|
||||
@ -42,7 +38,7 @@ void AddLog(const char* fmt, ...) {
|
||||
__android_log_print(ANDROID_LOG_INFO, TAG, "%s", buf);
|
||||
|
||||
std::lock_guard<std::mutex> lock(g_LogMutex);
|
||||
if (g_AppLogs.size() > 30) g_AppLogs.erase(g_AppLogs.begin());
|
||||
if (g_AppLogs.size() > 30) g_AppLogs.pop_front();
|
||||
g_AppLogs.push_back(buf);
|
||||
}
|
||||
|
||||
@ -51,6 +47,7 @@ void AddLog(const char* fmt, ...) {
|
||||
#define LOGI(...) AddLog(__VA_ARGS__)
|
||||
#define LOGE(...) AddLog("[ERROR] " __VA_ARGS__)
|
||||
|
||||
// --- 基础状态变量 ---
|
||||
static bool g_Initialized = false;
|
||||
static bool g_FontLoaded = false;
|
||||
static bool g_IsHookInstalled = false;
|
||||
@ -88,8 +85,8 @@ static uintptr_t g_LastRootBase = 0;
|
||||
static bool g_ForceDirectRead = false;
|
||||
|
||||
struct DynamicOffsets {
|
||||
uint32_t x0_to_addr1 = 0x20; // x0 + 0x20 = HeroActors (TinyValueList)
|
||||
uint32_t addr1_to_addr2 = 0x10; // HeroActors + 0x10 = 真正的 Array
|
||||
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;
|
||||
@ -105,33 +102,29 @@ struct DynamicOffsets {
|
||||
DynamicOffsets g_Offsets;
|
||||
std::mutex g_OffsetMutex;
|
||||
|
||||
// ==========================================
|
||||
// 终极内部读取:信号捕获 + 指针暴力解引用
|
||||
// ==========================================
|
||||
static __thread sigjmp_buf g_JmpBuf;
|
||||
static void sigsegv_handler(int sig) {
|
||||
siglongjmp(g_JmpBuf, 1);
|
||||
// --- 优化点 1:安全内存校验器 (告别频繁的高开销 SIGSEGV) ---
|
||||
// 利用 /dev/random 或管道验证内存页是否可读,不抛出系统异常,极其稳定
|
||||
bool IsValidMemory(uintptr_t address) {
|
||||
if (address < 0x10000000 || address > 0x00007FFFFFFFFFFF) return false;
|
||||
static int dev_random_fd = open("/dev/random", O_WRONLY);
|
||||
if (dev_random_fd < 0) dev_random_fd = open("/dev/null", O_WRONLY);
|
||||
|
||||
// 尝试向安全区域写出 4 字节,如果返回 -1 (EFAULT) 说明指针无效
|
||||
ssize_t ret = write(dev_random_fd, (void*)address, 4);
|
||||
return ret >= 0;
|
||||
}
|
||||
|
||||
// 安全读取包装器
|
||||
template <typename T>
|
||||
T SafeRead(uintptr_t address) {
|
||||
T value{};
|
||||
if (address < 0x10000000 || address > 0x00007FFFFFFFFFFF) return value;
|
||||
if (!IsValidMemory(address)) return T{};
|
||||
return *(volatile T*)address;
|
||||
}
|
||||
|
||||
struct sigaction new_sa, old_sa;
|
||||
new_sa.sa_handler = sigsegv_handler;
|
||||
sigemptyset(&new_sa.sa_mask);
|
||||
new_sa.sa_flags = 0;
|
||||
sigaction(SIGSEGV, &new_sa, &old_sa);
|
||||
|
||||
if (sigsetjmp(g_JmpBuf, 1) == 0) {
|
||||
value = *(volatile T*)address;
|
||||
} else {
|
||||
value = {};
|
||||
}
|
||||
|
||||
sigaction(SIGSEGV, &old_sa, nullptr);
|
||||
return value;
|
||||
// 快速/激进读取 (用于确定父指针必然有效时,提取内部连续的结构体属性,性能拉满)
|
||||
template <typename T>
|
||||
inline T FastRead(uintptr_t address) {
|
||||
return *(volatile T*)address;
|
||||
}
|
||||
|
||||
struct PlayerData {
|
||||
@ -156,76 +149,79 @@ struct GameSnapshot {
|
||||
std::vector<PlayerData> players;
|
||||
};
|
||||
|
||||
// --- 优化点 2:无锁化快照渲染 (解决界面卡顿) ---
|
||||
std::mutex g_SnapshotMutex;
|
||||
GameSnapshot g_CurrentSnapshot;
|
||||
std::shared_ptr<GameSnapshot> g_CurrentSnapshot = std::make_shared<GameSnapshot>();
|
||||
std::atomic<uintptr_t> g_ActorManager{0};
|
||||
|
||||
void DataWorkerThread() {
|
||||
while (true) {
|
||||
GameSnapshot newSnap;
|
||||
// 在本地构建完整快照,期间不加锁,彻底释放 UI 线程
|
||||
auto newSnap = std::make_shared<GameSnapshot>();
|
||||
DynamicOffsets currOff;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_OffsetMutex);
|
||||
currOff = g_Offsets;
|
||||
}
|
||||
newSnap.offsets = currOff;
|
||||
newSnap->offsets = currOff;
|
||||
|
||||
uintptr_t baseX0 = g_ActorManager.load();
|
||||
if (baseX0 != 0) {
|
||||
newSnap.inMatch = true;
|
||||
newSnap.debug.baseX0 = baseX0;
|
||||
if (baseX0 != 0 && IsValidMemory(baseX0)) {
|
||||
newSnap->inMatch = true;
|
||||
newSnap->debug.baseX0 = baseX0;
|
||||
|
||||
uintptr_t addr1 = SafeRead<uintptr_t>(baseX0 + currOff.x0_to_addr1);
|
||||
newSnap.debug.addr1 = addr1;
|
||||
newSnap->debug.addr1 = addr1;
|
||||
if (addr1) {
|
||||
uintptr_t addr2 = SafeRead<uintptr_t>(addr1 + currOff.addr1_to_addr2);
|
||||
newSnap.debug.addr2 = addr2;
|
||||
newSnap->debug.addr2 = addr2;
|
||||
if (addr2) {
|
||||
for (int i = 0; i < 15; ++i) {
|
||||
// 【核心修复】:直接跳过 IL2CPP 数组的 0x20 头部字节,直接读取元素!
|
||||
// 【核心修复】:直接跳过 IL2CPP 数组的 0x20 头部字节
|
||||
uintptr_t item = SafeRead<uintptr_t>(addr2 + 0x20 + (i * 0x8));
|
||||
|
||||
newSnap.debug.items[i].base = item;
|
||||
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;
|
||||
newSnap->debug.items[i].addr3 = addr3;
|
||||
if (!addr3) continue;
|
||||
|
||||
PlayerData p;
|
||||
|
||||
// 优化:父指针有效时直接 FastRead,减少 Syscall 提高帧率
|
||||
uintptr_t addr4 = SafeRead<uintptr_t>(addr3 + currOff.addr3_to_addr4);
|
||||
newSnap.debug.items[i].addr4 = addr4;
|
||||
newSnap->debug.items[i].addr4 = addr4;
|
||||
if (addr4) {
|
||||
p.gold = SafeRead<int32_t>(addr4 + currOff.prop_gold);
|
||||
p.hp = SafeRead<int32_t>(addr4 + currOff.prop_hp);
|
||||
p.maxHp = SafeRead<int16_t>(addr4 + currOff.prop_maxhp);
|
||||
p.level = SafeRead<int32_t>(addr4 + currOff.prop_level);
|
||||
p.gold = FastRead<int32_t>(addr4 + currOff.prop_gold);
|
||||
p.hp = FastRead<int32_t>(addr4 + currOff.prop_hp);
|
||||
p.maxHp = FastRead<int16_t>(addr4 + currOff.prop_maxhp);
|
||||
p.level = FastRead<int32_t>(addr4 + currOff.prop_level);
|
||||
}
|
||||
|
||||
uintptr_t addr5 = SafeRead<uintptr_t>(addr3 + currOff.addr3_to_addr5);
|
||||
newSnap.debug.items[i].addr5 = addr5;
|
||||
newSnap->debug.items[i].addr5 = addr5;
|
||||
if (addr5) {
|
||||
p.worldX = SafeRead<float>(addr5 + 0x0);
|
||||
p.worldZ = SafeRead<float>(addr5 + 0x4);
|
||||
p.worldY = SafeRead<float>(addr5 + 0x8);
|
||||
p.mana = SafeRead<int32_t>(addr5 + currOff.prop_mana);
|
||||
p.worldX = FastRead<float>(addr5 + 0x0);
|
||||
p.worldZ = FastRead<float>(addr5 + 0x4);
|
||||
p.worldY = FastRead<float>(addr5 + 0x8);
|
||||
p.mana = FastRead<int32_t>(addr5 + currOff.prop_mana);
|
||||
}
|
||||
|
||||
uintptr_t addr6 = SafeRead<uintptr_t>(addr3 + currOff.addr3_to_addr6);
|
||||
newSnap.debug.items[i].addr6 = addr6;
|
||||
newSnap->debug.items[i].addr6 = addr6;
|
||||
if (addr6) {
|
||||
p.mapX = SafeRead<float>(addr6 + 0x50);
|
||||
p.mapY = SafeRead<float>(addr6 + 0x54);
|
||||
p.mapX = FastRead<float>(addr6 + 0x50);
|
||||
p.mapY = FastRead<float>(addr6 + 0x54);
|
||||
}
|
||||
|
||||
if (p.maxHp > 0 && p.maxHp < 50000)
|
||||
newSnap.players.push_back(p);
|
||||
newSnap->players.push_back(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 瞬间原子化替换指针,不阻塞渲染线程
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_SnapshotMutex);
|
||||
g_CurrentSnapshot = newSnap;
|
||||
@ -320,18 +316,16 @@ void InstallCoreHook() {
|
||||
}
|
||||
}
|
||||
|
||||
// 恢复完整版的排错器UI
|
||||
void DrawPointerDebugger(const GameSnapshot& snap, float w, float h) {
|
||||
ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(w * 0.65f, h * 0.85f), ImGuiCond_FirstUseEver);
|
||||
if (ImGui::Begin("指针断点排错器")) {
|
||||
|
||||
if (ImGui::CollapsingHeader("高级排错 (读不出数据时勾选)", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.4f, 0.4f, 1.0f));
|
||||
ImGui::Checkbox("⚠️ 开启暴力裸读 (无视系统拦截)", &g_ForceDirectRead);
|
||||
if (ImGui::CollapsingHeader("高级排错 (已升级为无异常读取)", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.4f, 1.0f, 0.4f, 1.0f));
|
||||
ImGui::Text("✔️ 当前已启用 /dev/random 内核级安全读取,告别由于捕获异常导致的卡顿和崩溃。");
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::TextColored(ImVec4(0.8f, 0.8f, 0.8f, 1.0f),
|
||||
"说明: 腾讯的反外挂可能会拦截系统的安全读取API。\n"
|
||||
"勾选此项强制使用指针解引用。已经加入了信号接管,不会闪退!");
|
||||
}
|
||||
ImGui::Separator();
|
||||
|
||||
@ -366,11 +360,10 @@ void DrawPointerDebugger(const GameSnapshot& snap, float w, float h) {
|
||||
|
||||
ImGui::BeginChild("MemDump", ImVec2(0, 450), true, ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
||||
|
||||
// 【核心升级】:扫描范围扩大至 0x1000
|
||||
for (uint32_t offset = 0; offset <= 0x1000; offset += 8) {
|
||||
uintptr_t val = SafeRead<uintptr_t>(g_CurrentExploreAddr + offset);
|
||||
|
||||
if (val > 0x10000000 && val < 0x00007FFFFFFFFFFF) {
|
||||
if (val > 0x10000000 && val < 0x00007FFFFFFFFFFF && IsValidMemory(val)) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0, 1, 0, 1));
|
||||
ImGui::Text("+0x%03X : 0x%lx", offset, val);
|
||||
ImGui::PopStyleColor();
|
||||
@ -499,7 +492,8 @@ EGLBoolean hook_eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
|
||||
g_Touch.renderW = (float)w;
|
||||
g_Touch.renderH = (float)h;
|
||||
|
||||
GameSnapshot snapshot;
|
||||
// 提取智能指针快照数据,实现无锁极速渲染
|
||||
std::shared_ptr<GameSnapshot> snapshot;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_SnapshotMutex);
|
||||
snapshot = g_CurrentSnapshot;
|
||||
@ -549,7 +543,8 @@ EGLBoolean hook_eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
|
||||
static bool show_pointer_debugger = true;
|
||||
static bool show_radar = true;
|
||||
|
||||
if (ImGui::Begin("IL2CPP 透视框架 (防闪退正式版)")) {
|
||||
// 恢复主控界面
|
||||
if (ImGui::Begin("IL2CPP 性能极客版透视框架")) {
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.1f, 0.1f, 0.15f, 1.0f));
|
||||
ImGui::BeginChild("HookController", ImVec2(0, 70), true);
|
||||
@ -580,13 +575,13 @@ EGLBoolean hook_eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
|
||||
ImGui::Checkbox("指针断点调试", &show_pointer_debugger);
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::TextColored(ImVec4(0, 1, 0, 1), "状态: %s", snapshot.inMatch ? "局内" : "未获取到对象");
|
||||
ImGui::TextColored(ImVec4(0, 1, 0, 1), "状态: %s", snapshot->inMatch ? "局内" : "未获取到对象");
|
||||
|
||||
if (ImGui::BeginTable("PlayersTable", 5, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||
ImGui::TableSetupColumn("等级"); ImGui::TableSetupColumn("血量");
|
||||
ImGui::TableSetupColumn("蓝量"); ImGui::TableSetupColumn("金币");
|
||||
ImGui::TableSetupColumn("雷达坐标"); ImGui::TableHeadersRow();
|
||||
for (const auto& p : snapshot.players) {
|
||||
for (const auto& p : snapshot->players) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn(); ImGui::Text("Lv.%d", p.level);
|
||||
ImGui::TableNextColumn(); ImGui::Text("%d/%d", p.hp, p.maxHp);
|
||||
@ -599,9 +594,11 @@ EGLBoolean hook_eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
if (show_pointer_debugger) DrawPointerDebugger(snapshot, w, h);
|
||||
// 将指针解引用传入以供原始函数调用
|
||||
if (show_pointer_debugger) DrawPointerDebugger(*snapshot, w, h);
|
||||
|
||||
if (show_radar && snapshot.inMatch) {
|
||||
// 恢复雷达绘制逻辑
|
||||
if (show_radar && snapshot->inMatch) {
|
||||
ImGui::SetNextWindowPos(ImVec2(w - 350, 30), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(300, 300), ImGuiCond_FirstUseEver);
|
||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0.5f));
|
||||
@ -610,7 +607,7 @@ EGLBoolean hook_eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
|
||||
ImVec2 size = ImGui::GetContentRegionAvail();
|
||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||
dl->AddRect(p0, ImVec2(p0.x + size.x, p0.y + size.y), IM_COL32(255, 255, 255, 100));
|
||||
for (const auto& p : snapshot.players) {
|
||||
for (const auto& p : snapshot->players) {
|
||||
float nX = p.mapX / 10000.0f;
|
||||
float nY = p.mapY / 10000.0f;
|
||||
float rX = p0.x + (nX * size.x);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user