- 开发工具
- 逆向工程
- 桌面应用
【免费下载链接】Textractor
Extracts text from video games and visual novels. Highly extensible.
Textractor(曾用名 NextHooker)是一个运行于 Windows 7 及 Wine 之上的 x86/x64 开源游戏文本提取工具,通过向游戏进程注入 DLL、Hook 文本输出函数并借助命名管道回传数据,实现对视觉小说与各类游戏引擎文本的实时捕获。本篇以项目的俄文 README 为主线,完整覆盖其下载、功能、/H 与 /R 钩子码语法、扩展机制、编译方法与整体架构,并结合作用户指南 docs/TUTORIAL.md,帮助读者既会用工具,也理解其底层实现。
项目概述
Textractor是一个高度可扩展的开源文本 Hook 器,最初脱胎于 ITHVNR(ITH + VNR 引擎项目),用于从视频游戏与视觉小说中提取对话与 UI 文本。它同时支持 32 位与 64 位进程,并可在 Wine 环境下列为可用方案。项目提供多语言 README(含英文、简体中文、俄文等十余种语言),用户也可观看 docs/TUTORIAL.md 中记录的教学视频快速上手。
俄文 README 列出的核心特性如下(与英文版一致,可直接作为功能清单):
- 高度可扩展:所有后处理逻辑都以扩展(Extension)形式实现;
- 自动捕获:可从大量游戏引擎自动 Hook 文本,其中包括部分 VNR 并不支持的引擎;
- /H "hook" 码:通过 Hook 码拦截指定函数的参数或返回值来捕获文本,兼容大多数 AGTH(Another Game Text Hooker)代码;
- /R "read" 码:不注入 Hook,而是按地址周期性直接读取目标内存,实现"直读"式文本抽取。
获取版本
- Textractor 的正式发行版可在项目官方 Releases 中下载;
- 更早的 ITHVNR 版本在俄文 README 中给出了存档链接;
- 英文 README 还额外提到,带调试信息的实验性构建可以从持续集成平台的 Artifacts 中获取。
下载后解压即可运行Textractor.exe,无需额外安装。若要针对某款特定游戏长期捕获,项目约定游戏根目录下可放置TextractorConfig.txt配置文件(见 include/defs.h 中GAME_CONFIG_FILE的定义),用于保存该游戏的 Hook 码等设置。
钩子码语法:/H hook 码与 /R read 码
钩子码是 Textractor 的核心使用方式:一行代码即可描述"在哪里、按什么格式读多少字节、如何解码"。所有解析逻辑集中在 host/hookcode.cpp,入口函数HookCode::Parse会去掉可选的前缀/与行尾斜杠(兼容 legacy/AGTH 写法),再按首字母分发到ParseHCode或ParseRCode(参见 host/hookcode.cpp)。
/H hook 码
/H 码的一般结构(见ParseHCode实现,host/hookcode.cpp):
/H {类型标志} [F] [null_length<] [N] [codepage#] [padding+] 偏移 [*间接索引] [:分割偏移 [*分割间接索引]] @地址[:模块[:函数]]各字段的含义:
| 字段 | 取值 | 作用 |
|---|---|---|
| 类型标志 | A大端长度前置 | 按长度前缀读取定长文本 |
B小端长度前置 | 同上,小端序 | |
S | ANSI 字符串(直到结尾) | |
Q | Unicode 字符串 | |
V | UTF-8 字符串 | |
M | Unicode + 十六进制转储(HEX dump 模式) | |
F | — | 完整字符串模式:按参数实际读取整串并补换行 |
null_length< | 数字 | 文本长度位于字符串指针前null_length字节处(负偏移写法) |
N | — | 不读取调用上下文(NO_CONTEXT) |
codepage# | 数字 | 指定代码页,例如936#为 GBK、65001#为 UTF-8 |
padding+ | 十六进制 | 读取前跳过的填充字节 |
| 偏移 | 十六进制 | 目标寄存器/参数偏移(ITH 与 AGTH 的寄存器偏移相差 4,解析时会自动校正) |
*间接索引 | 十六进制 | 二级指针解引用(DATA_INDIRECT) |
:分割偏移 | 十六进制 | 从另一寄存器取长度(USING_SPLIT),可再带*表示二级解引用 |
@地址 | 十六进制 | 要 Hook 的函数地址 |
:模块 | 文件名 | 地址相对模块基址(如gdi.dll) |
:函数 | 符号名 | 地址相对函数入口(如GetTextOutA) |
源码中自带的测试用例给出了真实可解析的完整示例(host/hookcode.cpp):
/HQN936#-c*C:C*1C@4AA:gdi.dll:GetTextOutA ; Hook gdi.dll!GetTextOutA,GBK 解码,双级指针 + 双级长度 /HB4@0 ; 长度前置的 ANSI 文本 /RS65001#@44 ; UTF-8 直读码GenerateHCode还支持反向生成:给定HookParam与进程 ID,它会把绝对地址尝试折算成"模块 + 偏移"形式(通过VirtualQueryEx找到所属模块),使 Hook 码在 ASLR 下更稳定(host/hookcode.cpp)。
/R read 码
/R 码描述一次内存直读,结构为(见 host/hookcode.cpp):
/R {S|Q|V|M} [null_length<] [codepage#] @地址S:ANSI 字符串;Q:Unicode 字符串;V:UTF-8;M:Unicode + 十六进制转储;null_length<:长度前置位置;codepage#:代码页(如/RS65001#@44表示按 UTF-8 直读0x44处的字符串);- 非法前缀(如
/RW@44)会解析失败被拒绝。
/R 码与 /H 码的差异在于:/H 需要注入一小段指令到目标函数首部,把参数"转发"出来;/R 则不需要 Hook 代码,适合已知剧情文本缓冲区地址的场景。
扩展机制
俄文 README 指出:官方扩展示例项目展示了如何构建扩展,而仓库内的 extensions/ 文件夹本身就是扩展功能的"活文档"。该目录下包含十余个用 C++ 编写的扩展,覆盖了从文本清洗到功能增强:
removerepeatchar.cpp/removerepeatphrase.cpp/removerepeatsentence.cpp:去除重复字符、短语与句子(游戏引擎反复重绘对话时的常见问题);regexfilter.cpp/regexreplacer.cpp/replacer.cpp/styler.cpp:基于正则与替换规则的过滤、改写与样式化;extranewlines.cpp、exnewlines/extrawindow.cpp:换行处理与独立文本窗口;copyclipboard.cpp/threadlinker.cpp:剪贴板同步与多线程文本关联;bingtranslate.cpp/googletranslate.cpp/deepltranslate.cpp/translatewrapper.cpp:多种翻译服务的封装;lua.cpp/devtools.cpp:Lua 脚本扩展与开发者调试工具。
从源码结构看,GUI 在显示每一条文本前,会先把它连同元数据分发给所有扩展:GUI/mainwindow.cpp 中调用DispatchSentenceToExtensions(sentence, GetSentenceInfo(thread).data()),若某个扩展返回"跳过",则该句不显示。扩展与宿主之间的元数据接口定义在 extensions/extension.h:SentenceInfo以"名字 → 整型值"的数组形式向扩展暴露线程名、代码页等信息,扩展也可通过抛出自定义的SKIP异常主动丢弃文本。
编译项目
编译 Textractor 的前置条件(俄文 README "Compiling" 一节原文要求):
- 安装支持 CMake 的 Visual Studio;
- 安装 Qt 5.13。
随后直接用 Visual Studio 打开源码文件夹、选择配置并构建,产物即为Textractor.exe。从 CMakeLists.txt 可以看到这些要求在工程层面的体现:
- 项目强制 MSVC:非 MSVC 工具链会直接
FATAL_ERROR终止配置(CMakeLists.txt); - 全局编译选项为 C++17、多核编译
/MP,并按目标位数链接x64libs或x86libs(CMakeLists.txt); - 通过
cmake/QtUtils.cmake注册表搜索定位 Qt 5 的Core、Widgets、WinExtras、WebSockets模块(CMakeLists.txt); - 工程由
host、texthook、GUI、extensions、test五个子工程组成(CMakeLists.txt),分别对应宿主程序、被注入 DLL、图形界面、扩展与测试。
注意英文版 README 额外提示:从源码构建前需先克隆仓库并初始化子模块(git submodule update --init),因为texthook/minhook/等目录依赖子模块内容。
项目架构
俄文 README 的"项目架构"一节描述了完整的数据通路:**宿主(host)向目标进程注入 texthook.dll,两者通过两条命名管道通信;texthook 等待管道接通后,向文本输出函数(如TextOut、GetGlyphOutline)注入少量指令,把它们的输入参数转发到管道;宿主对收到的文本做初步处理后交回 GUI;GUI 在显示前再把文本分发给扩展。**下面结合源码逐环节拆解。
两条命名管道
管道名与同步对象集中定义在 include/defs.h:
constexpr auto HOOK_PIPE = L"\\\\.\\pipe\\TEXTRACTOR_HOOK"; // texthook → host constexpr auto HOST_PIPE = L"\\\\.\\pipe\\TEXTRACTOR_HOST"; // host → texthook- hostPipe(TEXTRACTOR_HOST):宿主写入端,向被注入的 DLL 下发命令;
- hookPipe(TEXTRACTOR_HOOK):texthook 写入端,回传捕获的文本、控制台日志与钩子事件。
两者都以PIPE_TYPE_MESSAGE(消息型管道)创建,保证每条消息边界完整。
texthook.dll 的启动与管道线程
被注入的 DLL 生命周期入口在 texthook/main.cc 的DllMain:
- 用命名互斥量
VNR_HOOKMAN_<pid>防止对同一进程重复注入; - 创建内核对象文件映射(即 README 中所说的"文件视图 / section object")
VNR_SECTION_<pid>,并把其中一段内存映射为TextHook hooks[MAX_HOOK]数组——宿主进程稍后会只读映射同一块内存,从而不经过管道即可查看当前所有 Hook 的状态(地址、参数、名称等); - 初始化 MinHook 后,创建独立的
Pipe线程(texthook/main.cc)。
Pipe线程的工作循环:
- 等待事件
TEXTRACTOR_PIPE_AVAILABLE,随后以客户端身份连接两条管道(CreateFileW打开HOST_PIPE与HOOK_PIPE,texthook/main.cc); - 先通过 hookPipe 写入自己的进程 ID,宿主据此建立进程记录;
- 调用
Engine::Hijack()(定义于 texthook/engine/match.cc)启动各引擎的自动匹配/Hook 逻辑; - 循环读取 hostPipe 命令,
switch分发四种HostCommandType:HOST_COMMAND_NEW_HOOK:按用户给定的HookParam插入新 Hook(名称形如UserHook1);HOST_COMMAND_REMOVE_HOOK:移除指定地址附近的 Hook;HOST_COMMAND_FIND_HOOK:按SearchParam搜索——给了文本则SearchForText(按已知文本反查地址),否则SearchForHooks(自动搜索候选 Hook);HOST_COMMAND_DETACH:结束循环,DLL 自清理并FreeLibraryAndExitThread。
捕获到的文本经TextOutput打包成"ThreadParam头 + 原文"写入 hookPipe(texthook/main.cc);找到的 Hook 通过NotifyHookFound上报,宿主会据此生成/H码并打印到控制台,方便用户保存为游戏配置。
宿主侧:管道管理、注入与文本整理
宿主逻辑在 host/host.cpp。CreatePipe为每对连接创建两条消息管道:hookPipe 为PIPE_ACCESS_INBOUND,hookPipe 连接成功后先读回 4 字节进程 ID 建立ProcessRecord,再递归调用自身以便支持多进程同时挂接(host/host.cpp)。每个ProcessRecord保存:该进程的 hostPipe 句柄、对VNR_SECTION_<pid>的只读映射视图(README 所说"映射到 TextHook 类引用"的对象),以及保护该视图的互斥量。
读取 hookPipe 的主循环按HostNotificationType分派:FOUND_HOOK(转换编码后回调 GUI 控制台)、RMVHOOK(清理对应线程)、TEXT(控制台输出),其余情况按默认分支视为文本数据——取出ThreadParam头,按"进程 + 地址 + 上下文"哈希定位TextThread,首次出现时触发OnCreate,然后把原始字节Push进线程缓冲(host/host.cpp)。
进程注入实现在Host::InjectProcess(host/host.cpp),是标准的 CreateRemoteThread 注入:
- 用
VNR_HOOKMAN_<pid>互斥量先占位,已存在则提示"已注入"; OpenProcess(PROCESS_ALL_ACCESS)打开目标,IsWow64Process检查 32/64 位匹配;VirtualAllocEx+WriteProcessMemory写入texthook.dll的完整路径,再CreateRemoteThread调用LoadLibraryW完成加载。
宿主还内置了两个特殊TextThread:console(系统日志输出)与clipboard(host/host.cpp),后者借助WH_GETMESSAGE钩子监听WM_CLIPBOARDUPDATE,把系统剪贴板里的文本也汇入统一管线——这解释了为何许多扩展能对"复制出来的游戏文本"同样生效。
文本缓冲的整理逻辑在 host/textthread.cpp 的TextThread::Push:
- 双字节字符集(DBCS)保护:当一次只读到 1 字节且是 DBCS 前导字节时(
IsDBCSLeadByteEx),先暂存等下一字节配对,避免 GBK 等编码在消息边界被切断; - 编码转换:按
HEX_DUMP、USING_UNICODE或codepage分支处理,Unicode 直接转换,ANSI 经StringToWideString按指定代码页(缺省为Host::defaultCodepage)转宽字符; - 重复过滤:
RemoveRepetition检测"整句被引擎连续重绘 N 遍"的情况并只保留一句(对应英文 README 提到的 issue #40); - 每 10 毫秒的定时器队列(
CreateTimerQueueTimer)负责把缓冲按时间窗口切分成句子(sentence)向上层输出。
数据流总览
综合以上源码,README 描述的链路可还原为:
游戏进程 └─ texthook.dll(LoadLibrary 注入) ├─ DllMain: 建 VNR_SECTION_<pid> 共享视图 + Pipe 线程 ├─ Pipe 线程: 连接管道 → Engine::Hijack() → 处理 /H、搜索、移除、断开 └─ 文本输出: ThreadParam + 原文 → hookPipe (\\.\pipe\TEXTRACTOR_HOOK) 宿主 host ├─ CreatePipe: 建立双向消息管道,按 PID 维护 ProcessRecord ├─ hostPipe 下发命令(插入/移除/搜索/断开) ├─ 只读映射 VNR_SECTION_<pid> 查看 Hook 状态 └─ TextThread: DBCS 拼接、代码页转换、去重、定时切句 GUI ├─ 显示文本线程 / 控制台 / 剪贴板线程 └─ DispatchSentenceToExtensions: 每句先过扩展,再显示支持与贡献
俄文 README 给出了明确的协作约定:
- 反馈渠道:任何 bug、Textractor 无法 Hook 的游戏、功能请求都欢迎提出;若某款游戏无法捕获,作者希望通过免费下载链接或 Steam 礼物获取该游戏用于实测;
- 贡献方式:关于代码库的问题可邮件联系作者;PR 遵循标准流程(fork → 建分支 → 提交改动 → 向 master 发起 PR);
- 翻译贡献:所有界面字符串集中在 text.cpp 中,按语言分组维护(俄文
HIJACK_ERROR等字符串就在其中),翻译该文件与 README 即可完成多语言贡献; - 贡献者名单见 docs/CREDITS.md。
小结
Textractor 以"宿主 + 被注入 DLL + 双管道 + 共享视图"的经典注入架构,把游戏内的文本捕获做成了可编码化(/H、/R 码)、可搜索(自动找 Hook)、可后处理(C++/Lua 扩展管线)的完整工具链。若你要为某款游戏做文本提取,实践路径是:先试自动引擎匹配 → 失败则用"按文本搜索"或手动/H码定位TextOut*/GetGlyphOutline类调用点 → 保存 Hook 码到TextractorConfig.txt→ 用 extensions/ 中的去重、正则扩展清洗输出。仓库中的 include/defs.h、texthook/main.cc、host/host.cpp 与 host/hookcode.cpp 是深入原理时最值得精读的四份文件。
- 开发工具
- 逆向工程
- 桌面应用
【免费下载链接】Textractor
Extracts text from video games and visual novels. Highly extensible.
相关推荐
Textractor 技术指南:游戏文本 Hook 工具的项目架构、Hook 代码机制与构建详解
Textractor 技术指南:游戏文本 Hook 工具的项目架构、Hook 代码机制与构建详解 本文为基于 Textractor 官方文档(README_DE
开发工具逆向工程桌面应用Textractor:强大的Windows游戏文本提取工具完全指南
Textractor:强大的Windows游戏文本提取工具完全指南 Textractor是一款专为Windows系统设计的开源游戏文本钩子工具,能够精准捕获游戏
开发工具逆向工程桌面应用Better Auth 环境变量完全指南:2 个必配项、密钥轮换与避坑速查
Better Auth 环境变量完全指南:2 个必配项、密钥轮换与避坑速查 Better Auth 是目前覆盖面最广的开源认证框架(邮箱密码、社交登录、Pass
认证鉴权后端身份认证
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考