news 2026/4/26 23:51:54

从注入到调用:一个完整的Unity il2cpp运行时Hook实战指南(附C++代码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从注入到调用:一个完整的Unity il2cpp运行时Hook实战指南(附C++代码)

从注入到调用:一个完整的Unity il2cpp运行时Hook实战指南(附C++代码)

在游戏开发与逆向工程领域,Unity引擎的il2cpp后端因其性能优势被广泛采用,但也带来了动态分析的独特挑战。本文将深入探讨如何通过运行时注入技术,实现对il2cpp编译后应用的精准控制——从定位内存结构到重定向关键函数调用,整个过程就像在黑暗森林中搭建一座可控制的桥梁。

1. 理解il2cpp运行时架构

il2cpp并非简单的C#到C++的转译器,而是一个完整的AOT(Ahead-Of-Time)编译系统。当选择il2cpp后端时,Unity会执行以下转换流程:

C#源码 → IL中间码 → C++代码 → 原生机器码

关键组件构成:

  • GameAssembly.dll/libil2cpp.so:核心运行时库,包含转换后的游戏逻辑
  • global-metadata.dat:保存类型系统映射关系的元数据仓库
  • 导出函数表:提供运行时反射能力的API接口

典型内存布局特征:

内存区域内容描述访问方式
代码段编译后的机器指令函数指针调用
元数据段类型系统结构体API查询+指针解析
动态内存区实例对象与运行时数据指针追踪+偏移计算

注意:不同Unity版本中,il2cpp内部结构体可能存在字段偏移差异,实战中需结合具体版本验证。

2. 注入环境的精密准备

2.1 动态链接库注入方案

Windows平台推荐采用经典的DLL注入技术:

// 基础注入器示例(需管理员权限) HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetPID); LPVOID pMem = VirtualAllocEx(hProcess, NULL, dllPath.size(), MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(hProcess, pMem, dllPath.c_str(), dllPath.size(), NULL); HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("kernel32"), "LoadLibraryA"), pMem, 0, NULL);

Android平台则需要结合ptraceLD_PRELOAD技术,这里展示一个dlopen的替代方案:

# 在注入器中执行 adb push injector /data/local/tmp adb push libhook.so /data/local/tmp adb shell chmod +x /data/local/tmp/injector adb shell /data/local/tmp/injector com.game.package

2.2 运行时API定位策略

il2cpp的导出函数通常包含版本特征,可通过模式匹配动态定位:

// 动态获取API函数指针示例 auto il2cpp_resolve_export(const char* pattern) { HMODULE base = GetModuleHandle("GameAssembly"); IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)((BYTE*)base + ((IMAGE_DOS_HEADER*)base)->e_lfanew); IMAGE_EXPORT_DIRECTORY* exports = (IMAGE_EXPORT_DIRECTORY*)((BYTE*)base + nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); DWORD* names = (DWORD*)((BYTE*)base + exports->AddressOfNames); for(DWORD i = 0; i < exports->NumberOfNames; ++i) { const char* name = (const char*)base + names[i]; if(strstr(name, pattern)) { return (void*)((BYTE*)base + ((DWORD*)((BYTE*)base + exports->AddressOfFunctions))[i]); } } return nullptr; }

3. 元数据导航与类型定位

3.1 程序集加载与类查询

通过三级跳转完成类方法定位:

// 典型查询路径示例 auto domain = il2cpp_domain_get(); auto assembly = il2cpp_domain_assembly_open(domain, "Assembly-CSharp"); auto image = il2cpp_assembly_get_image(assembly); auto targetClass = il2cpp_class_from_name(image, "", "PlayerController");

关键结构体关系图:

Il2CppDomain → Il2CppAssembly → Il2CppImage → Il2CppClass → MethodInfo

3.2 方法签名处理技巧

il2cpp方法调用存在隐式this指针参数,需要特殊处理:

// 方法Hook前后对比 Original: int Player_GetHealth(Player* this) { return this->health; } il2cpp转换后: int Player_GetHealth(Player* this, void* unused) { return this->health; } // 因此调用时需: typedef int (*Player_GetHealth_t)(Player*, void*); auto original = (Player_GetHealth_t)method->methodPointer; int health = original(playerInstance, nullptr);

4. 实战Hook实现方案

4.1 虚函数表替换技术

对于虚方法可采用直接修改vtable的方案:

void hook_virtual_method(Il2CppClass* klass, const char* name, void* newFunc) { for(uint16_t i = 0; i < klass->vtable_count; ++i) { if(strcmp(klass->vtable[i].method->name, name) == 0) { DWORD oldProtect; VirtualProtect(&klass->vtable[i].methodPtr, sizeof(void*), PAGE_READWRITE, &oldProtect); klass->vtable[i].methodPtr = newFunc; VirtualProtect(&klass->vtable[i].methodPtr, sizeof(void*), oldProtect, &oldProtect); break; } } }

4.2 机器码级Hook方案

更通用的指令跳转方案(x64平台示例):

#pragma pack(push, 1) struct JmpCode { uint8_t opcode = 0xE9; uint32_t offset; }; #pragma pack(pop) void install_detour(void* original, void* hook) { JmpCode jmp; jmp.offset = (uint32_t)((BYTE*)hook - (BYTE*)original - sizeof(JmpCode)); DWORD oldProtect; VirtualProtect(original, sizeof(JmpCode), PAGE_EXECUTE_READWRITE, &oldProtect); memcpy(original, &jmp, sizeof(JmpCode)); VirtualProtect(original, sizeof(JmpCode), oldProtect, &oldProtect); }

4.3 上下文保存与恢复

安全的Hook实现应保存原始上下文:

// 典型Hook代理函数 __declspec(naked) void HookProxy() { __asm { pushad pushfd // 自定义处理逻辑 call [g_customHandler] popfd popad // 跳回原函数或替代逻辑 jmp [g_originalFunc] } }

5. 高级调试技巧与异常处理

5.1 元数据校验绕过

当遇到元数据加密时,可采用动态重建策略:

Il2CppClass* safe_get_class(const char* name) { static std::unordered_map<std::string, Il2CppClass*> cache; if(auto it = cache.find(name); it != cache.end()) return it->second; auto klass = il2cpp_class_from_name(/*...*/); if(!klass) { // 尝试通过特征码扫描定位类实例 uintptr_t classPtr = scan_memory_for_class(name); if(classPtr) { klass = reinterpret_cast<Il2CppClass*>(classPtr); // 手动填充必要字段 klass->name = strdup(name); } } cache[name] = klass; return klass; }

5.2 线程安全防护措施

多线程环境下的Hook操作需要同步机制:

std::recursive_mutex g_hookMutex; void thread_safe_hook() { std::lock_guard<std::recursive_mutex> lock(g_hookMutex); suspend_all_threads(); // 执行Hook操作 resume_all_threads(); }

6. 实战案例:属性修改器实现

完整工作流程示例:

// 1. 注入初始化 void on_attach() { auto playerClass = il2cpp_class_from_name(/*...*/, "Player"); auto healthProp = il2cpp_class_get_property_from_name(playerClass, "Health"); // 2. 获取原始存取器 auto getter = il2cpp_property_get_get_method(healthProp); auto setter = il2cpp_property_get_set_method(healthProp); // 3. 安装Hook g_originalGet = getter->methodPointer; install_detour(g_originalGet, &hooked_getter); // 4. 持久化监控 create_mod_thread(); }

典型问题排查表:

现象可能原因解决方案
注入后立即崩溃版本不匹配验证Unity版本和偏移量
调用时参数错乱this指针处理错误检查调用约定和参数数量
部分功能失效元数据混淆采用动态特征码定位
多线程环境下崩溃竞态条件添加线程同步机制

在实际项目中,我发现最有效的调试方式是结合Cheat Engine的内存扫描与IL2CPP Dumper的输出交叉验证。例如当Hook一个玩家移动方法时,可以先用CE定位速度变量的内存地址,再通过反推访问路径来确定需要拦截的类方法。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/26 23:50:26

基于AgentChat的智能对话系统:从RAG原理到生产部署全解析

1. 项目概述最近在折腾AI应用开发&#xff0c;发现很多开源项目要么功能太单一&#xff0c;要么部署起来太复杂。直到我遇到了AgentChat&#xff0c;一个基于大语言模型的现代化智能对话系统&#xff0c;它几乎把我想要的功能都打包好了。AgentChat不仅仅是一个聊天界面&#x…

作者头像 李华
网站建设 2026/4/26 23:36:07

2026最新华为OD新系统机试解析 + 最新题库 + 备考策略

华为OD在2026年4月1号迎来了新系统升级&#xff0c;华为OD新系统机试相比之前的机考模式&#xff0c;产生了几个重大变化。下面重点给小伙伴说明一下华为OD新系统机考重大变化以及在华为OD机试新机考模式下如何快速备考。 华为OD机试新系统变化介绍 机试时间固定 华为OD新系…

作者头像 李华
网站建设 2026/4/26 23:24:00

如何用WebToEpub一键将网页小说转为EPUB电子书永久保存

如何用WebToEpub一键将网页小说转为EPUB电子书永久保存 【免费下载链接】WebToEpub A simple Chrome (and Firefox) Extension that converts Web Novels (and other web pages) into an EPUB. 项目地址: https://gitcode.com/gh_mirrors/we/WebToEpub 还在为网络小说网…

作者头像 李华
网站建设 2026/4/26 23:21:46

PostgreSQL 视图

PostgreSQL 视图 引言 PostgreSQL 视图是一种虚拟表,它基于一个或多个基本表的数据构建而成。视图可以简化复杂的查询,提供数据的安全性,以及增强数据的可用性。本文将详细介绍 PostgreSQL 视图的概念、创建方法、使用场景以及注意事项。 视图的概念 在 PostgreSQL 中,…

作者头像 李华
网站建设 2026/4/26 23:21:16

自动化工作流开发:OCR识别致PDF信息提取、数学计算与Word计算书生成

自动化工作流开发:OCR识别致PDF信息提取、数学计算与Word计算书生成 一、项目概要与应用场景分析 在当下数字化转型全面加速的进程中,各类工程计算、财务核算、学术分析等工作场景中,存在大量从文档中提取结构化信息、执行数学计算并生成标准化报告的需求。以工程领域为例…

作者头像 李华
网站建设 2026/4/26 23:14:35

突破性音乐解锁方案:一站式解决加密音频格式兼容性难题

突破性音乐解锁方案&#xff1a;一站式解决加密音频格式兼容性难题 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库&#xff1a; 1. https://github.com/unlock-music/unlock-music &#xff1b;2. https://git.unlock-music.dev/um/web 项目地址: http…

作者头像 李华