PdB333/cortex

GitHub: PdB333/cortex

Cortex 是一个 Windows 运行时分析工具包,通过本地 REST API 将内存扫描、调试、自动化和 AI 集成整合到统一的 JSON 接口中。

Stars: 1 | Forks: 0

# Cortex ![平台](https://img.shields.io/badge/platform-Windows-0078D6) ![语言](https://img.shields.io/badge/language-C%2B%2B17-00599C) ![架构](https://img.shields.io/badge/architectures-x86%20%7C%20x64-555555) ![API](https://img.shields.io/badge/API-local%20REST-2EA44F) Cortex 是一个混合了外部宿主与可注入 Windows agent 的工具,它通过本地经过身份验证的 REST API 暴露正在运行的进程。它将内存扫描、运行时分析、调试、patching、输入自动化、截图和持久化项目状态整合到一个专为工具和 AI agent 设计的、机器可读的接口背后。 HTTP 服务器仅绑定到 `127.0.0.1`。受保护的路由需要一个在 DLL 旁边生成的 256 位 token。 ## 目录 - [为什么选择 Cortex?](#why-cortex) - [核心亮点](#highlights) - [渲染器支持](#renderer-support) - [环境要求](#requirements) - [构建](#build) - [外部宿主](#external-host) - [加载 Cortex](#load-cortex) - [验证连接](#verify-the-connection) - [快速入门教程](#quickstart-tutorial) - [后台捕获与输入](#background-capture-and-input) - [带有表达式捕获的调试器](#debugger-with-expression-captures) - [Model Context Protocol (MCP) endpoint](#model-context-protocol-mcp-endpoint) - [网络 hook](#network-hook) - [会话导出](#session-export) - [配置](#configuration) - [API 概览](#api-overview) - [持久化项目](#persistent-projects) - [操作日志与批处理](#action-journal-and-batches) - [架构](#architecture) - [安全模型](#security-model) - [已知限制](#known-limitations) - [依赖项](#dependencies) - [贡献](#contributing) - [致 AI agent](#for-ai-agents) - [许可证](#license) ## 为什么选择 Cortex? 传统的游戏研究往往需要在内存扫描器、调试器、反汇编器、脚本工具和笔记之间来回切换。Cortex 通过一个 JSON 接口整合了这些工作流,同时将大量扫描工作保留在目标进程外部: - agent 可以通过 `GET /tools` 或 `GET /openapi.json` 发现完整的 API; - 人类可以通过 Dear ImGui 覆盖层跟踪活动; - 命名地址、指针路径、冻结值、结构和笔记可以在不同会话间保留; - 写入和 patch 会被操作日志跟踪,并且可以回滚; - 批量操作减少了 API 往返次数,并支持事务式变更。 ``` AI agent / script / developer tool | | HTTP + JSON + X-Cortex-Token v 127.0.0.1:6970 127.0.0.1:6969 | | Cortex Host outside Cortex Agent inside scans, memory, maps hooks and live debug | | +------ one runtime workspace ------+ ``` ## 核心亮点 | 领域 | 功能 | |---|---| | 内存 | 类型化读写、批处理、填充、区域枚举、精确的 64 位整数处理 | | 扫描 | 外部精确/对比扫描、AOB 特征码、字符串、code caves、交集、持久化指针图 | | 逆向工程 | x86/x64 反汇编、CFG、xrefs、vtables、PE headers、推断结构、Ghidra bridge | | 调试 | 断点、命中时基于表达式的内存捕获、类 C 条件、触发器到 trace 的转换、StackWalk64 + 启发式回退、分页日志 | | 运行时插桩 | 跟踪的 patch、感知重定位的 trampolines、冻结值、调用、页面/分配监视、定向 rewind | | 自动化 | **后台**键盘/鼠标注入(Win32 + DirectInput 合成)、**后台**截图(任意渲染器)、输入序列、录制/回放、窗口控制 | | 网络 | 带有环形缓冲区的 ws2_32 recv/send/WSARecv/WSASend 拦截器 | | 寻址 | 每条路由上的通用 `module+RVA` 解析器(防 ASLR) | | AI 集成 | 原生 **Model Context Protocol** (JSON-RPC 2.0) endpoint、自动派生的工具目录、`/session/export` 归档 | | 持久化 | 每个进程的地址、指针路径、笔记、冻结值和命名结构 | | 安全性 | 仅本地环回服务器(v4 + v6)、token 身份验证、Host/Origin 检查、JSON 内容验证、变更日志 | ## 渲染器支持 Cortex 会在运行时选择可用的渲染器 hook。 | 后端 | 32 位 | 64 位 | |---|:---:|:---:| | Direct3D 8 | 是 | 否 | | Direct3D 9 | 是 | 是 | | Direct3D 10 | 是 | 是 | | Direct3D 11 | 是 | 是 | | Direct3D 12 | 否 | 是 | | OpenGL | 是 | 是 | | 原生 Vulkan | 否 | 否 | 32 位 D3D8 后端专为老游戏保留。其他后端使用 [kiero](https://github.com/Rebzzel/kiero)。D3D12 限于 x64,因为 ImGui 后端需要指针大小的 GPU 描述符句柄。 ## 环境要求 - Windows 7 或更高版本; - CMake 3.20 或更高版本; - Ninja; - MinGW-w64,带有与目标进程匹配的 x86 或 x64 编译器; - 仅在 Windows 访问规则要求时才需要管理员权限。 ## 构建 依赖项在 `CMakeLists.txt` 中锁定,并通过 CMake `FetchContent` 进行填充。 ### 32 位 ``` cmake -S . -B build -G Ninja ` -DCMAKE_C_COMPILER=i686-w64-mingw32-gcc ` -DCMAKE_CXX_COMPILER=i686-w64-mingw32-g++ cmake --build build --config Release ``` ### 64 位 ``` cmake -S . -B build_x64 -G Ninja ` -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc ` -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++ cmake --build build_x64 --config Release ``` 每次构建都会生成: - `cortex_core.dll` - 加载到目标进程中的 DLL; - `injector.exe` - 命令行注入器; - `cortex_host.exe` - 外部控制器和零自身污染扫描器。 在依赖项填充过一次后,可以使用 `-DCORTEX_OFFLINE=ON` 进行配置,以防止 CMake 尝试网络访问。 ### 测试 ``` ctest --test-dir build -C Release --output-on-failure ctest --test-dir build_x64 -C Release --output-on-failure ``` 回归测试套件还涵盖了自有内存排除、感知重定位的 trampolines、多实例结构推断、定向快照和 rewind。 ## 外部宿主 对于内存搜索,首选外部宿主。它的缓冲区位于独立的 进程中,因此永远不会出现在目标的扫描结果中。 ``` .\cortex_host.exe --process game.exe --port 6970 # 或 .\cortex_host.exe --pid 12344 ``` 宿主会写入 `cortex_host.token` 并暴露 `/health`、`/modules`、 `/memory/regions`、`/memory/read`、`/memory/write`、`/scan/new`、`/scan/next` 和 `/scan/results/{id}`。对于渲染器 hooks、断点、trace、原生调用、输入和截图,请使用端口 6969 上的注入 Agent。为了获得完整的地址空间覆盖,宿主和 Agent 可执行文件应与目标的位数相匹配。 ## 加载 Cortex 选择一种加载方法。 ### 选项 1:命令行注入器 启动目标进程,然后运行: ``` .\injector.exe [path-to-cortex_core.dll] ``` 示例: ``` .\injector.exe game.exe .\injector.exe 12344 .\cortex_core.dll ``` 如果省略了 DLL 路径,注入器将在 `injector.exe` 旁边查找 `cortex_core.dll`。 ### 选项 2:ASI loader 如果目标已经使用了 ASI loader: 1. 将匹配版本的 `cortex_core.dll` 重命名为 `cortex.asi`; 2. 将其复制到游戏的 ASI 或 `scripts` 目录中; 3. 正常启动游戏。 ## 验证连接 公共健康检查和发现 endpoint 不需要 token: ``` Invoke-RestMethod http://127.0.0.1:6969/health Invoke-RestMethod http://127.0.0.1:6969/tools ``` 所有其他 endpoint 都需要位于 DLL 旁边 `cortex.token` 中存储的 token: ``` $token = (Get-Content .\cortex.token -Raw).Trim() $headers = @{ "X-Cortex-Token" = $token } Invoke-RestMethod ` -Uri http://127.0.0.1:6969/modules ` -Headers $headers ``` 读取类型化值: ``` $body = @{ address = "0x400000" type = "u32" } | ConvertTo-Json Invoke-RestMethod ` -Method Post ` -Uri http://127.0.0.1:6969/memory/read ` -Headers $headers ` -ContentType "application/json" ` -Body $body ``` ## 快速入门教程 使用自带的 `test_target` 二进制文件完成首次命中的完整演练。它具有已知的 Canary 值,因此您无需游戏即可端到端验证每个子系统。 **1. 启动测试目标** ``` .\test_target_x64.exe ``` 它会打开一个小蓝色窗口,并打印其 PID 及其 Canary 值的地址(`g_cortex_u32 = 0xDEADBEEF`、`g_health = 100`、帧计数器等)。 **2. 注入 Cortex** ``` .\injector_x64.exe test_target_x64.exe ``` **3. 读取 token 并确认健康状态** ``` $token = (Get-Content .\cortex.token -Raw).Trim() $h = @{ "X-Cortex-Token" = $token } Invoke-RestMethod http://127.0.0.1:6969/health ``` **4. 通过 `module+RVA` 读取值**(在 ASLR/重启后依然有效) ``` $body = @{ address = "test_target_x64.exe+0x4000"; type = "u32" } | ConvertTo-Json Invoke-RestMethod -Method Post -Uri http://127.0.0.1:6969/memory/read ` -Headers $h -ContentType "application/json" -Body $body # -> { "value": 3735928559 } (0xDEADBEEF) ``` **5. 进行后台截图**(无需聚焦窗口) ``` Invoke-WebRequest "http://127.0.0.1:6969/screenshot?mode=auto" ` -Headers $h -OutFile shot.png ``` **6. 发送后台输入序列** ``` $seq = @{ mode = "os" steps = @( @{ type = "key_tap"; vk = 0x57; hold_ms = 50 }, # W @{ type = "delay"; ms = 200 }, @{ type = "text"; text = "hello" } ) } | ConvertTo-Json -Depth 5 Invoke-RestMethod -Method Post -Uri http://127.0.0.1:6969/input/sequence ` -Headers $h -ContentType "application/json" -Body $seq ``` **7. 设置在命中时捕获内存的断点** ``` $bp = @{ address = "test_target_x64.exe+0x1234" kind = "hw" capture = @( @{ name = "health"; expression = "[rcx+0x18]"; type = "i32" } ) } | ConvertTo-Json -Depth 5 $r = Invoke-RestMethod -Method Post -Uri http://127.0.0.1:6969/debug/breakpoint ` -Headers $h -ContentType "application/json" -Body $bp # 稍后:分页日志 Invoke-RestMethod "http://127.0.0.1:6969/debug/breakpoint/$($r.id)/log?limit=50" -Headers $h ``` **8. 导出完整的会话归档** ``` Invoke-RestMethod -Method Post http://127.0.0.1:6969/session/export -Headers $h # 写入 cortex_sessions/session_/session.json + screenshot.png ``` **9. 从 MCP 客户端驱动 Cortex** ``` $req = @{ jsonrpc="2.0"; id=1; method="tools/list" } | ConvertTo-Json Invoke-RestMethod -Method Post http://127.0.0.1:6969/mcp ` -Headers $h -ContentType "application/json" -Body $req ``` ## 后台捕获与输入 Cortex 捕获并注入输入,**无需要求目标窗口处于 聚焦状态**。这适用于任何渲染器(D3D8/9/10/11/12、OpenGL),甚至是 最小化的窗口。 **截图** — `GET /screenshot?mode=`: | 模式 | 行为 | |---|---| | `render` | 抓取被 hook 的后台缓冲区(保真度最高,需要渲染循环处于活动状态) | | `window` | `PrintWindow(PW_RENDERFULLCONTENT)` — 在后台工作,适用于任何渲染器 | | `last` | 返回最后缓存的帧(零消耗,可能已过期) | | `auto` | 依次尝试 `render` → `window` → `last`,头部信息会报告来源 | 响应包含 `X-Cortex-Capture-Source` 头部,以便调用者知道是哪个 路径提供了图像。 **输入** — 三种传输方式,请选择适合目标的一种: | 路由 | 传输方式 | 适用场景 | |---|---|---| | `POST /input/key`, `/input/mouse_*` | `PostMessage` | 后台,基于 Win32 消息驱动的游戏 | | `POST /input/sequence` 且带有 `mode:"dinput"` | `GetDeviceState` 上的 DirectInput vtable hook | 直接读取 DirectInput 的游戏(老游戏) | | `POST /input/sequence` 且带有 `mode:"game"` | `SendInput` | 前台,适用于所有情况 | **序列** 会将多步脚本(`key_tap`、`mouse_click`、`mouse_move`、 `text`、`delay`)排队。轮询 `GET /input/sequence/{id}` 获取状态;使用 `DELETE /input/sequence/{id}` 取消。 **录制与回放** — `POST /input/record/start` 会在专用的 pump 线程上安装低级键盘 + 鼠标 hook。`POST /input/record/stop` 返回 捕获的序列,可直接反馈给 `/input/sequence`。 **窗口控制** — `GET /window`,`POST /window/{focus,restore,minimize,move}`。 ## 带有表达式捕获的调试器 每个断点都可以带有一个在每次命中时进行评估的内存捕获列表。 表达式支持寄存器、整数文字、`+`/`-`,以及带有 `[]` 的指针大小的 解引用,因此复杂的布局可以内联解析: ``` { "address": "engine.dll+0x2A0F10", "kind": "hw", "capture": [ { "name": "hp", "expression": "[[ecx+0x18]+0x4]", "type": "i32" }, { "name": "name", "expression": "[ecx+0x40]", "type": "cstring", "size": 32 }, { "name": "position", "expression": "ecx+0x100", "type": "bytes", "size": 12 } ] } ``` 类型:`bytes`、`cstring`、`u8/i8/u16/i16/u32/i32/u64/i64`、`float`、`double`。 命中日志是分页且非破坏性的 — 环形缓冲区会报告 `dropped_entries` 和 `total_hits`,因此即使 消费者速度较慢,agent 也不会遗漏任何活动: ``` GET /debug/breakpoint/{id}/log?since_seq=0&limit=200 # -> { entries, returned, next_seq, dropped_entries, total_hits } ``` **触发器 → 自动 trace** — 使用 `POST /debug/breakpoint/{id}/trigger` 附加 trace 模板,调试器将在 每次命中时启动 trace,并可选择在当前函数返回时自动停止 (`stop_on_return`)。 栈回退将通过 **EBP 链 → `StackWalk64`(带 FPO) → 可执行页面 启发式扫描** 进行,因此即使是损坏/优化的序言也依然能生成调用栈。 ## Model Context Protocol (MCP) endpoint `POST /mcp` 使用 **JSON-RPC 2.0**,并将每个 Cortex 路由作为类型化的 MCP 工具公开。工具从相同的 `/tools` 清单自动派生 — 不需要 保持同步的第二个注册表。 支持的方法: - `initialize` — 返回 `protocolVersion: "2024-11-05"`、capabilities、serverInfo。 - `tools/list` — 作为带有 `inputSchema` 的 MCP 工具描述符的完整目录。 - `tools/call` — 按名称调用工具;该 endpoint 通过 相同的 服务器进行回环,因此路由处理程序依然是行为的唯一来源。 - `ping` — 存活检测。 - 支持批量(JSON 数组)请求。 参数格式: ``` { "jsonrpc": "2.0", "id": 42, "method": "tools/call", "params": { "name": "memory_read", "arguments": { "address": "test_target_x64.exe+0x4000", "type": "u32" } } } ``` 路径占位符(`/debug/breakpoint/{id}/log`)放在 `_path` 中,查询参数放在 `_query` 中: ``` { "name": "debug_breakpoint__id__log", "arguments": { "_path": { "id": "3" }, "_query": { "since_seq": "0", "limit": "50" } } } ``` MCP endpoint 仍然需要 `X-Cortex-Token`;单个 token 可同时对 REST 和 MCP 层面进行身份验证。 ## 网络 hook Cortex 拦截 `ws2_32` 上的 `recv`、`send`、`WSARecv` 和 `WSASend`,并 将最后 512 个事件保留在带有 64 字节十六进制预览的环形缓冲区中: ``` POST /network/capture { "enabled": true } GET /network/events?limit=100 ``` 对于观察与身份验证或遥测 服务通信的单人游戏,或对逆向工程本地 IPC 非常有用。 ## 会话导出 `POST /session/export` 会在 `/cortex_sessions/session_/` 下写入一个独立的归档: - `session.json` — 模块、断点(带有分页日志、捕获,以及 每个以 `module+RVA` 表示的地址)、trace 元数据、项目状态。 - `screenshot.png` — 通过 `mode=auto` 拍摄的快照。 归档可以直接重新加载并在多次运行之间进行 diff,这使得错误 报告和重现问题变得切实可行。 ## 配置 在 DLL 旁边创建可选的 `cortex.ini`: ``` port = 6969 toggle_key = 0x7B log_console = true api_token = ``` | 键 | 默认值 | 描述 | |---|---:|---| | `port` | `6969` | 本地 HTTP 端口 | | `toggle_key` | `0x7B` | 覆盖层热键;`0x7B` 即 F12 | | `log_console` | `true` | 在初始化期间打开调试控制台 | | `api_token` | 为空 | 固定的 token;为空时,Cortex 加载或创建 `cortex.token` | ## API 概览 除非返回的是截图等二进制数据,否则每条路由都使用 JSON。 权威的路由清单始终可以从正在运行的 DLL 中获取: ``` GET http://127.0.0.1:6969/tools GET http://127.0.0.1:6969/openapi.json ``` | 领域 | 主要路由 | |---|---| | 发现 | `/status`, `/health`, `/tools`, `/openapi.json`, `/modules` | | 内存 | `/memory/read`, `/memory/write`, `/memory/fill`, `/memory/regions`, `/memory/ownership` | | 扫描 | `/scan/new`, `/scan/next`, `/scan/results/{id}`, `/scan/aob`, `/scan/strings`, `/scan/pointers`, `/scan/pointer_path`, `/scan/intersect`, `/scan/code_caves` | | 反汇编与分析 | `/disasm`, `/analysis/functions`, `/analysis/cfg`, `/analysis/xrefs`, `/analysis/vtable`, `/analysis/structure`, `/analysis/pe_headers` | | 调试器 | `/debug/breakpoint`, `/debug/paused`, `/debug/registers`, `/trace/*`, `/watch/page_access` | | 监视 | `/watch`, `/watch/events`, `/watch/allocations`, `/watch/page_access` | | Patching | `/patch/write`, `/patch/assemble`, `/patch/detour`, `/patch/trampoline`, `/patch/alloc_cave` | | 持久化项目 | `/project`, `/project/address`, `/project/pointer_path`, `/project/resolve/{name}`, `/project/note` | | 自动化 | `/input/*`(键盘、鼠标、序列、文本、录制)、`/screenshot?mode=`、`/window/*`、`/prompt/*`、`/call/function`、`/freeze`、`/struct/*` | | 逆向工程 | `/pointermap/*`, `/struct/infer`, `/ghidra/*`, `/snapshot/*`, `/dissect/*` | | 网络 | `/network/capture`, `/network/events` | | 编排 | `/batch/run`, `/events`, `/actions`, `/actions/rollback`, `/session/export` | | MCP | `POST /mcp` (JSON-RPC 2.0: `initialize`, `tools/list`, `tools/call`, `ping`) | ### 扫描行为 内存扫描通过 `VirtualQuery` 枚举已提交的页面,并按 有限的 8 MiB 块进行读取。失败的大型读取会以 64 KiB 的窗口重试,并且 相邻的块会重叠,因此不会遗漏跨越块边界的 值和特征码。 注入的扫描默认排除 Cortex 的注册模块、临时缓冲区、指针 图和 code caves。仅在需要针对性诊断时设置 `exclude_cortex=false`。外部宿主 仍然是首选的扫描器。 大型的分配器内存区会被扫描,而不是被跳过。全局 AOB 扫描 覆盖已提交的可读映像、映射和私有区域;提供 `module` 会刻意将扫描限制在该可执行文件或 DLL 中。 ## 持久化项目 Cortex 在以下位置为每个目标存储一个项目: ``` cortex_projects/.json ``` 一个项目可以包含: - 命名地址; - 稳定的指针路径; - 自由格式的研究笔记; - 活动的冻结值; - 命名的结构定义。 项目文件以原子方式写入,并在 Cortex 初始化时恢复。 这使得 agent 或开发人员能够在每次会话后恢复工作,而无需重新发现每个 地址。 ## 操作日志与批处理 内存写入、patch、冻结值和其他被跟踪的变更都会记录在 操作日志中。使用: ``` GET /actions POST /actions/rollback POST /actions/clear ``` `POST /batch/run` 可以在一个请求中执行多个操作。事务性 批处理会拒绝不支持且不可逆的变更,并在 后续操作失败时回滚支持的写入。 ## 架构 ``` cortex/ |-- CMakeLists.txt |-- injector/ | `-- main.cpp standalone DLL injector |-- host/ | `-- main.cpp external controller and scanner |-- core/ | |-- dllmain.cpp initialization and shutdown | |-- config.cpp cortex.ini parser and defaults | |-- log.cpp debug console + rotating log file | |-- api/ HTTP server and route domains | |-- memory/ safe reads, writes, and scans | |-- process/ module enumeration | |-- debugger/ breakpoints and execution control | |-- disasm/ Zydis integration | |-- symbols/ DbgHelp / PDB symbol resolution | |-- analysis/ CFG, xrefs, vtables, structures | |-- dissect/ inferred structure layouts | |-- patch/ patches, assembly, detours, caves | |-- pointermap/ persisted cross-session pointer paths | |-- timeline/ targeted checkpoints and rewind | |-- ghidra/ runtime import/export bridge | |-- watch/ data, page, and allocation watches | |-- project/ persistent per-target state | |-- action/ mutation journal and rollback | |-- events/ Server-Sent Events stream | |-- hook/ renderer and input hooks | |-- overlay/ Dear ImGui UI | |-- capture/ screenshots (render hook + fallbacks) | |-- prompt/ human-in-the-loop prompt queue | |-- freeze/ periodic value enforcement | |-- struct/ named runtime structures | `-- call/ guarded native function calls |-- tests/ | `-- core_tests.cpp `-- third_party/ ``` ## 安全模型 Cortex 有意将进程内存访问视为一种特权本地 操作: - 服务器仅在 `127.0.0.1` 上监听; - 每个非公共路由都需要 `X-Cortex-Token`; - token 比较是固定时间的; - 拒绝非本地的 Host 和 Origin 值; - POST、PUT 和 PATCH 正文必须使用 `application/json`; - 响应会禁用缓存和 MIME 嗅探。 公共路由仅限于 `/status`、`/health`、`/tools` 和 `/openapi.json`。 ## 已知限制 - 仅限 Windows; - 注入器和 DLL 的位数必须与目标匹配; - 原生 Vulkan 渲染未被 hook; - 动态地址在重启后仍然需要特征码或指针路径; - trampoline 的创建会故意拒绝在被覆盖的序言中包含内部的相对分支,而不是生成不安全的网关; - 任意的内存写入、patch 和原生调用可能会导致目标崩溃; - 受保护的或启用了反作弊的进程可能会拒绝注入,这超出了 本项目的预期范围。 ## 依赖项 - [Dear ImGui](https://github.com/ocornut/imgui) - [MinHook](https://github.com/TsudaKageyu/minhook) - [cpp-httplib](https://github.com/yhirose/cpp-httplib) - [nlohmann/json](https://github.com/nlohmann/json) - [Zydis](https://github.com/zyantific/zydis) - [stb](https://github.com/nothings/stb) - [kiero](https://github.com/Rebzzel/kiero) 依赖项的版本锁定在 `CMakeLists.txt` 中,以确保可复现的 x86 和 x64 构建。 ## 贡献 添加 endpoint 时,请保持以下三个位置同步: 1. `core/api/routes_*.cpp` 中的实现; 2. `core/api/server.cpp` 中的注册; 3. `core/api/routes_status.cpp` 中的实时清单。 在提交更改之前,请构建并测试两种架构。 ## 致 AI agent 如果您正在通过 LLM 或自动化 agent 驱动 Cortex,请参阅 [`agent/agents.md`](agent/agents.md) 了解 API 所假定的连接、身份验证和 工作流约定。 ## 许可证 基于 [MIT 许可证](LICENSE) 发布。
标签:AI, Bash脚本, JARM, 云资产清单, 内存分析, 游戏安全, 网络调试, 自动化, 自动化代码审查, 逆向工程