
Akebi-GC注入原理全解Manual Map手动映射是如何把DLL藏进游戏进程的【免费下载链接】Akebi-GC(Fork) The great software for some game that exploiting anime girls (and boys).项目地址: https://gitcode.com/gh_mirrors/ak/Akebi-GCAkebi-GC 是一款围绕《原神》的游戏辅助项目它的核心机制是通过 injector 注入器把功能 DLL 写进游戏进程内存。本文面向新手用尽量少的代码讲清楚它的注入原理从最简单的 LoadLibrary 注入为什么容易被检测到Manual Map 手动映射如何一步步手工加载 DLL 并擦除痕迹让 DLL 在游戏进程里隐身。一、先搞懂DLL 注入到底在做什么DLL 注入的本质是让另一个进程的代码在自己的地址空间里运行。想象游戏进程是一个房间DLL 是外人带来的工具箱。正常加载工具箱要走前台登记系统加载器而注入是绕过登记直接把工具箱搬进房间并使用。Akebi-GC 的注入器工作流程大致是先等旧的游戏进程GenshinImpact.exe或国服YuanShen.exe关闭以挂起状态启动新的游戏进程主线程暂停内存已就绪但游戏还没跑起来把CLibrary.dll塞进这个暂停中的进程恢复主线程游戏正常启动——此时 DLL 已经在内存里就位了。关键源码在这里main.cpp 中的OpenGenshinProcess使用CREATE_SUSPENDED标志启动游戏注入完成后才调用ResumeThread恢复。 为什么要在游戏启动前注入因为进程一启动反作弊就立刻开始扫描。抢在启动前完成注入是大多数注入器的共同选择。二、最老实的方式LoadLibrary 注入项目里其实内置了两种注入模式用编译开关切换入口在 injector.cpp默认模式LoadLibraryDLL—— 简单粗暴开启MANUAL_MAP宏ManualMapDLL—— 手动映射也就是本文主角。LoadLibrary 注入的原理一句话就能说清在游戏进程的内存里开一块空间写入 DLL 文件的路径字符串创建一个远程线程让它去调用系统函数LoadLibraryA参数就是刚才写好的路径系统加载器接管DLL 被正正规规地加载。实现非常短可以看看 load-library.cpp核心就是WriteProcessMemoryCreateRemoteThread两步。问题在于走系统加载器 一切行为都是标准动作。DLL 会完整出现在进程的PEB进程环境块模块链表中任何工具枚举一下就能看到所有 DLL 名字模块列表、LoadLibrary调用栈等系统记录里。只要反作弊程序扫一遍模块链表注入的 DLL 就现形了。这就是为什么要 Manual Map。三、Manual Map像手工组装一样拼装一个 DLL手动映射的思路既然系统加载器留下的痕迹太多那就不调用它——注入器自己扮演加载器把 DLL 文件里的代码一块块搬到目标内存里然后手工补上加载器本来要做的所有事情。完整实现在 manual-map.cpp下面按执行顺序拆成 4 个阶段。3.1 阶段一搬砖 —— 把 PE 文件抄写进目标内存Windows 的 DLL 本质是一个PE 格式的文件由文件头 若干段Section组成每段声明了自己该放在内存的哪个偏移处。手动映射第一步就是照着这个目录抄用VirtualAllocEx在游戏进程里申请一大块可读写的内存大小等于 DLL 的镜像尺寸SizeOfImage先写入文件头前 0x1000 字节再遍历每个段.text、.data等按文件中的偏移 → 内存中的偏移逐个WriteProcessMemory复制过去。对应代码见 manual-map.cpp。此时 DLL 的代码已经在游戏进程内存里了但它还不能运行——就像零件全摆好了但还没接线。3.2 阶段二接线 —— 重定位RelocationPE 文件编译时会声明一个理想基地址比如0x180000000。但我们申请到的内存地址几乎肯定是别的值。内存里所有写死的绝对地址都必须加上差值修正这些需要修正的位置由 PE 的重定位表记录。shellcode 在 manual-map.cpp 中遍历重定位块逐项把LocationDelta实际基址 − 理想基址加到对应地址上。3.3 阶段三查字典 —— 填充导入表IATDLL 会调用其他模块如kernel32.dll的函数PE 里只记录了函数名字符串真正可用的函数指针是加载器在运行时查表填进去的。手动映射必须自己干这件事读取导入表对每个模块调用LoadLibraryA拿到模块句柄再用GetProcAddress查出函数地址写回导入地址表IAT。见 manual-map.cpp。3.4 阶段四点火 —— 远程线程执行 DllMain前三步做完后注入器把一小段精心编写的shellcode写进游戏进程并创建远程线程执行它。这段 shellcodeShellcode 函数在目标进程内依次完成执行重定位修正解析导入表调用 TLS 回调如有在 64 位下通过RtlAddFunctionTable注册异常处理表让 C 异常和try/catch也能正常工作这是手写加载器最容易漏的一环最后调用 DLL 自己的入口函数DllMain(DLL_PROCESS_ATTACH)—— 从这一刻起注入的代码在游戏进程里真正开始运行。注入器随后轮询一块共享内存区等 shellcode 回填模块基址作为成功信号见 manual-map.cpp。四、藏起来的关键擦除痕迹如果说第三部分是把 DLL 装进去那第四部分就是 Manual Map 真正体现隐藏价值的地方——收尾打扫manual-map.cpp4.1 抹掉 PE 文件头PE 文件头MZ/PE签名是识别这里有个模块的最明显特征。手动映射完成后注入器用 20MB 的零缓冲区把文件头区域整个覆写成 0。内存扫一眼这里只是一堆普通内存看不出模块边界。4.2 删除用不上的段.rsrc资源、.reloc重定位表在加载完成后就没用了.pdata异常表在不启用 SEH 支持时也可清除——统统覆写为零减少扫描特征。4.3 收紧内存保护刚写入时整块内存是可读可写可执行的方便写入收尾时按每段原始特征改回只读、可读写或只读可执行VirtualProtectEx。既恢复安全姿态也降低一大块 RWX 内存这种可疑特征。4.4 销毁临时物shellcode 本身和参数区也一并清零、释放。 最终效果进程内存里有一块没有 PE 头、不在 PEB 模块链表、名字不出现在任何模块枚举结果中的代码区。传统扫模块表 找 MZ 头的检测方式全部扑空。五、原理小结一张表看懂两种注入对比项LoadLibrary 注入Manual Map 手动映射谁负责加载系统加载器注入器自己shellcode是否进入 PEB 模块链表是否内存中是否保留 PE 头保留擦除为零被模块枚举发现的概率高极低实现复杂度低几十行高重定位、导入表、SEH、收尾清理典型实现位置load-library.cppmanual-map.cpp一句话总结Manual Map 的本质是注入器手动复刻了系统加载器的全部工作搬段、重定位、填导入表、调 DllMain然后在最后一步把我是 DLL的证据全部销毁。这也是为什么它在各种游戏辅助/逆向工具中被广泛采用——它是功能可用和特征隐蔽之间的平衡点。当然痕迹擦除只是静态层面的对抗现代反作弊还会从行为侧异常内存写入、调用栈特征、API 监控入手这已经超出本文范围。理解 Manual Map是理解这一切对抗的第一块基石。六、想继续深入注入器主流程injector/src/main.cpp模式切换开关injector/src/injector.cpp手动映射完整实现cheat-base/src/cheat-base/inject/manual-map.cpp项目总览文档README.md【免费下载链接】Akebi-GC(Fork) The great software for some game that exploiting anime girls (and boys).项目地址: https://gitcode.com/gh_mirrors/ak/Akebi-GC创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考