零依赖的Linux内存取证,利用内核嵌入的BTF和kallsyms进行类型感知的内存分析,无需外部调试信息。
mquire,由 memory 和 inquire 组合而成,是一款受 osquery 启发而开发的内存查询工具。
mquire 可以在不需要外部调试符号的情况下分析 Linux 内核内存快照。
分析所需的一切都已嵌入内存转储本身。这意味着你可以分析:
内核版本要求:
scripts/kallsyms.c 格式的变更)mquire 通过读取现代 Linux 内核中嵌入的两种信息来分析内核内存:
/proc/kallsyms 使用的数据相同)通过结合类型信息和符号位置,mquire 可以查找和读取复杂的内核数据结构,例如:
这使得直接从内核的文件缓存中提取文件成为可能,即使这些文件已从磁盘中删除。
Kallsyms 扫描器依赖于内核源码中 scripts/kallsyms.c 的数据格式。如果未来内核版本更改了此格式,扫描器的启发式方法可能需要更新。
mquire 提供了 SQL 表来查询系统的不同方面或工具自身的状态。
mquire 不是一个数据库。 每次查询都通过扫描内存并跟随指针来重建内核数据结构。没有预计算的索引或缓存结果:每次表访问都是对内核数据的遍历。使用
AS MATERIALIZED可避免冗余扫描(请参阅查询优化),并在查询每个进程的表(如task_open_files和memory_mappings)时提供task等约束,以将扫描限制为单个进程。
设计原则:虚拟地址作为连接键。 表使用
virtual_address(底层数据结构的内核地址)作为规范的连接键,而不是pid或其他用户可见的标识符。这是有意为之,因为相同的 PID 可能在不同的发现源和根任务中出现多次,而虚拟地址唯一标识一个特定的内核对象。SQL 表和底层的LinuxOperatingSystemAPI 都围绕这一约定构建。
/proc/kallsyms 相同的数据)dmesg 命令相同的数据)task 约束进行针对性分析,或一次性查询所有任务)task 约束进行针对性分析,或一次性查询所有任务)task 约束,因此请与 tasks/processes 进行连接(例如 JOIN task_capabilities c ON c.task = p.virtual_address)。task 约束。mem 条目。需要 kernel_module 约束,因此请与 kernel_modules 进行连接(例如 JOIN kernel_module_mem_entries r ON r.kernel_module = m.virtual_address)。ftrace_ops_list 符号遍历的 struct ftrace_ops 节点列表。约束 virtual_address 以读取单个节点,或约束 start_vaddr(可选地通过 end_vaddr 限制范围)以从任意节点开始遍历。mquire 提供三个主要命令:
mquire shell - 启动交互式 SQL shell 以查询内存快照mquire query - 执行单个 SQL 查询并输出结果(支持 JSON 或表格格式)mquire command - 对内存快照执行自定义命令(例如 .task_tree、.system_version、.dump)mquire 提供了以点 (.) 为前缀的特殊命令,以区别于 SQL 查询。
这些命令可在交互式 shell 和 mquire query 中使用:
.tables - 列出所有可用表.schema - 显示所有表的模式.schema <table> - 显示特定表的模式.commands - 列出所有可用的自定义命令.exit - 退出交互式 shell(仅限 shell)这些命令可在交互式 shell 和 mquire command 中使用:
对任何命令使用 --help 可查看可用选项和用法信息。例如:.task_tree --help
.system_version显示操作系统版本信息。
这是一个便捷命令,等同于 SELECT * FROM os_version,但输出格式更美观。
.task_tree显示运行中进程和线程的层次结构树,类似于 Linux 上的 pstree 命令。
选项:
--show-threads - 除进程外还包括线程。启用时,显示每个条目的 TGID 和 TID。--use-real-parent - 使用 real_parent 字段而不是 parent 来构建树结构。real_parent 字段显示任何重新父进程之前的原始父进程(即使在父进程退出后,也对于跟踪进程创建链很有用)。注意:
[TGID TID](显示线程时)或 [TGID](隐藏线程时)。TGID(线程组 ID)通常称为 PID。对于主线程(TGID == TID),两个值相同。.carve将虚拟内存区域提取到磁盘。此命令使用给定的页表从特定的虚拟地址范围提取原始内存内容,适用于提取进程内存、堆内容或其他内存区域。
参数:
ROOT_PAGE_TABLE - 根页表的物理地址(十六进制字符串,可带有 0x 前缀)。这决定了用于地址转换的地址空间。VIRTUAL_ADDRESS - 开始提取的虚拟地址(十六进制字符串,可带有 0x 前缀)。SIZE - 要提取的字节数。DESTINATION_PATH - 输出文件路径,提取的内存将写入此路径。注意:
.dump从内核的文件缓存中提取文件,以直接从内存中恢复文件。此命令遍历所有任务及其打开的文件描述符,从页缓存中提取文件内容。
参数:
OUTPUT - 提取文件的输出目录。文件按 TGID 组织(例如 tgid_1234/path/to/file)。注意:
mquire 专为以下场景设计:
预构建包可作为 CI 运行的构件提供。您可以从 Actions 选项卡 下载,方法是选择一次成功的 workflow 运行并下载构件。支持以下包格式:
.deb 包.rpm 包.tar.gz 存档mquire 使用 Rust 编写。要构建它:```bash
git clone https://github.com/trailofbits/mquire cd mquire
cargo build --release
## 支持的快照格式
mquire 支持以下内存快照格式,通过文件扩展名检测:
| 格式 | 扩展名 | 描述 |
|--------|-----------|-------------|
| 原始 | `.raw` | 平坦物理内存转储(物理地址空间的逐字节副本) |
| LiME | `.lime` | [Linux 内存提取器](https://github.com/504ensicsLabs/LiME) 格式,带有地址范围头部 |
| ELF 内核 | `.elf` | 包含 PT_LOAD 段的 ELF 内核转储(由 `virsh dump` 或 QEMU `dump-guest-memory` 生成) |
## 获取内存快照
### 使用 AVML(推荐)
我们推荐使用 [AVML](https://github.com/microsoft/avml) 从运行中的 Linux 系统获取内存快照。之前曾推荐过 [LiME](https://github.com/504ensicsLabs/LiME),但它已不再积极维护。```bash
sudo avml output.lime
重要提示: 在获取用于 mquire 的快照时,不要使用
--compress。mquire 不支持压缩的 AVML 快照。如果您有压缩的快照,请先使用avml-convert解压缩:avml-convert compressed.lime uncompressed.lime
有关其他选项,请参阅 AVML 文档。
对于 libvirt/KVM 虚拟机,请使用 virsh dump 生成 ELF 核心转储:```bash
virsh -c qemu:///system dump output.elf --memory-only --format elf
VM 在转储期间暂停,之后恢复。添加 `--live` 可避免暂停,但会牺牲快照一致性。
## 入门
获得内存快照后,你可以使用 SQL 查询和自定义命令与之交互。mquire 提供了三种与快照交互的方式:
### 交互式 shell
启动交互式 SQL shell:```bash
mquire shell /path/to/memory.raw
这会打开一个提示符,您可以在其中交互式地运行SQL查询和命令:```bash mquire> .tables # List all available tables mquire> .schema tasks # Show schema for a specific table mquire> SELECT * FROM tasks; # Run SQL queries mquire> .task_tree --show-threads # Run custom commands mquire> .exit # Exit the shell
### 一次性SQL查询
从命令行执行单个SQL查询或内置命令:```bash
# Output as JSON (default)
mquire query /path/to/memory.raw "SELECT * FROM os_version"
# Output as table format
mquire query /path/to/memory.raw "SELECT * FROM tasks" --format table
# Built-in commands work too
mquire query /path/to/memory.raw ".tables"
mquire query /path/to/memory.raw ".schema tasks"
运行自定义命令进行专门分析:```bash
mquire command /path/to/memory.raw
mquire command /path/to/memory.raw ".system_version"
mquire command /path/to/memory.raw ".task_tree"
mquire command /path/to/memory.raw ".task_tree --show-threads"
mquire command /path/to/memory.raw ".task_tree --help"
## Autostart SQL Files
mquire 在启动时会自动加载并执行 `$HOME/.config/trailofbits/mquire/autostart/` 目录下的 SQL 文件。文件按操作系统和架构进行组织:```
autostart/
common/common/ # All platforms and architectures
common/{arch}/ # All platforms, specific architecture
{os}/common/ # Specific platform, all architectures
{os}/{arch}/ # Specific platform and architecture
每个目录内的文件按字母顺序排序。目录按上述顺序扫描。
特性:
.sql 扩展名mquire_diagnostics,但不会阻止执行mquire shell 和 mquire query 命令