marirs/strix

GitHub: marirs/strix

一款用Rust编写的高性能二进制字符串提取工具,能从PE、ELF、Mach-O和shellcode中提取包括混淆后在内的多种类型字符串。

Stars: 0 | Forks: 0

# strix [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/f7f13dfc0d190337.svg)](https://github.com/marirs/strix/actions/workflows/ci.yml) [![Release](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/abc46d047f190338.svg)](https://github.com/marirs/strix/actions/workflows/release.yml) [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE.txt) [![Rust](https://img.shields.io/badge/rust-1.95%2B-orange.svg)](https://www.rust-lang.org) [![Platforms](https://img.shields.io/badge/platforms-linux%20%7C%20macOS%20%7C%20windows-lightgrey.svg)](#install) 从二进制文件中提取混淆字符串。库 + CLI。支持 PE、ELF、Mach-O(包括 fat binaries)和原始 shellcode。静态、栈和解码后的字符串,具有结构化 JSON 输出。 ## 零拷贝 静态字符串、Go 字符串和 Rust 字符串通过 `Cow::Borrowed(&str)` 直接借用输入字节。通过 `mmap` 传递文件,对于这些提取器不会发生分配。模拟字符串(解码/栈/紧凑)在定义上无法零拷贝——它们在模拟运行前不存在于文件中。 ## 安装 ### 预编译二进制文件 从 [Releases](https://github.com/marirs/strix/releases) 下载适合您平台的版本: | 平台 | 架构 | 归档文件 | |---------|-----------|--------------------------------------------------| | Linux | x86_64 | `strix--x86_64-unknown-linux-gnu.tar.gz` | | Linux | aarch64 | `strix--aarch64-unknown-linux-gnu.tar.gz` | | macOS | aarch64 | `strix--aarch64-apple-darwin.tar.gz` | | Windows | x86_64 | `strix--x86_64-pc-windows-msvc.zip` | 每个归档包含一个 `strix`(或 `strix.exe`)二进制文件和 SHA-256 校验和。 ### 从源码构建 ``` git clone https://github.com/marirs/strix cd strix cargo build --release --features unicorn -p strix-cli # 二进制文件: target/release/strix ``` 不启用 `--features unicorn`,您仍然可以提取静态、语言和栈字符串(x86、x86_64 和 AArch64)。`unicorn` 特性添加了用于解码字符串的暴力模拟流水线;它引入了 `unicorn-engine` C 库,并在构建时需要 `cmake` + C 工具链。 AArch64 (ARM64) 的函数发现和栈字符串模式匹配始终启用——bad64 是纯 Rust 反汇编器,因此不添加任何系统依赖。AArch64 二进制文件上的解码字符串提取仍然需要 AArch64 模拟器后端(计划中)。 ## CLI 用法 ``` # 默认:分组、人类可读输出到 stdout strix malware.exe # JSON strix --json malware.exe # 缩进 JSON,写入文件 strix --json --pretty -o malware.json malware.exe # 删除重复项(相同的值 + 类型 + 编码) strix --dedupe malware.exe # 过滤掉落在可执行段中的静态字符串 # (消除大多数汇编字节假阳性,如 AWAVAUATSH) strix --no-code malware.exe # 删除 CRT / libc / Windows-API 样板代码噪声 # (kernel32.dll, GetProcAddress, "Runtime Error!", ...) strix --no-library malware.exe # 删除低熵噪声(AAAAAA, ////////, +++++++) strix --min-quality 0.4 malware.exe # 按源函数 VA 分组模拟恢复的字符串 strix --by-function malware.exe # 组合:典型分析用法 strix --dedupe --no-code --no-library --min-quality 0.4 --by-function malware.exe # 仅运行特定提取器组 strix --only static malware.exe strix --only lang malware.exe # Go / Rust runtime strings strix --only decoded stack malware.exe # 跳过特定提取器组 strix --no decoded stack malware.exe # 提高静态字符串最小长度(默认为 4) strix --min-length 8 malware.exe # 强制文件格式(跳过自动检测) strix --format pe malware.exe strix --format elf binary strix --format macho /usr/bin/ls strix --format sc64 shellcode.bin # raw 64-bit shellcode strix --format sc32 shellcode.bin # raw 32-bit shellcode # 静默:无节标题、横幅或警告——仅字符串 strix --quiet malware.exe | sort -u ``` 运行 `strix --help` 查看完整的标志说明。 ### 输出格式 在人类可读模式下(默认),strix 按字符串种类分组: ``` strix: format=pe, size=131072 bytes arch=x86_64, bits=64 === static strings (412) === 0x0000000140001000 Microsoft Visual C++ Runtime Library 0x0000000140001028 Runtime Error! ... === decoded strings (7) === 0x0000000000000000 http://c2.example.com/beacon 0x0000000000000000 kernel32.dll ... === stack strings (12) === 0x0000000140002a30 ntdll.dll 0x0000000140002a48 LdrLoadDll ... warnings: - 3 of 14 emulated candidates failed (faulted on unmapped memory ...) ``` `--json` 输出相同数据的机器可读格式。 ## 库用法 `strix` 通过此仓库而非 crates.io 分发。 将它作为 git 依赖添加到您的 `Cargo.toml` 中: ``` [dependencies] strix = { git = "https://github.com/marirs/strix", tag = "v0.1.1", features = ["unicorn"] } serde_json = "1" ``` 使用 `branch = "master"` 代替 `tag` 来跟踪最新的未发布更改,或使用 `rev = ""` 固定到特定提交。 `unicorn` 特性是可选的——如果您只需要静态、语言和栈字符串提取,可以禁用它。禁用它后,构建时不需要 `cmake` 或 C 工具链: ``` [dependencies] strix = { git = "https://github.com/marirs/strix", tag = "v0.1.1" } ``` ### 最小示例 ``` use strix::{extract, ExtractOptions}; fn main() -> Result<(), Box> { let bytes = std::fs::read("malware.exe")?; let result = extract(&bytes, &ExtractOptions::default())?; for s in &result.strings { println!("{:?} {} {}", s.kind, s.encoding, s.value); } Ok(()) } ``` ### 配置提取 ``` use strix::{extract, ExtractOptions, FormatHint, StringKind}; let opts = ExtractOptions { min_length: 6, // skip short noise enabled: Some(vec![ // only these kinds StringKind::StaticAscii, StringKind::Decoded, StringKind::Stack, ]), format_override: Some(FormatHint::Pe), max_emulation_steps: 20_000, // cap per emulated function dedupe: true, // drop duplicate (value, kind, encoding) skip_code_sections: true, // drop static strings in .text / __TEXT,__text skip_library_strings: true, // drop CRT/libc/Windows-API noise min_quality: 0.4, // drop AAAAAA, //////, +++++ noise }; let bytes = std::fs::read("malware.exe")?; let result = strix::extract(&bytes, &opts)?; ``` ### 零拷贝读取 对于大型二进制文件,使用 mmap 映射输入,以便静态字符串切片直接借用映射中的数据,无需分配: ``` use memmap2::Mmap; let file = std::fs::File::open("malware.exe")?; let mmap = unsafe { Mmap::map(&file)? }; let result = strix::extract(&mmap, &strix::ExtractOptions::default())?; // The result borrows from `mmap`. Bind both to names that outlive // the use, or call `result.into_owned()` to detach. ``` ### JSON 输出 ``` let json = serde_json::to_string_pretty(&result)?; std::fs::write("malware.strix.json", json)?; ``` JSON 模式与 CLI 的 `--json` 输出完全匹配: ``` { "version": "0.1.1", "input": { "format": "pe", "arch": "x86_64", "bits": 64, "size": 131072 }, "strings": [ { "value": "kernel32.dll", "kind": "decoded", "encoding": "ascii", "location": { "offset": 0, "address": 4294967296, "section": "scratch" } } ], "warnings": [] } ``` ### 按种类迭代 ``` use strix::StringKind; let decoded: Vec<&str> = result.strings.iter() .filter(|s| s.kind == StringKind::Decoded) .map(|s| s.value.as_ref()) .collect(); let stack: Vec<&str> = result.strings.iter() .filter(|s| s.kind == StringKind::Stack) .map(|s| s.value.as_ref()) .collect(); ``` ### 处理来自内存的输入 库不关心字节来自何处——文件、网络、嵌入式资源都可以: ``` let bytes: Vec = fetch_sample_from_some_api()?; let result = strix::extract(&bytes, &strix::ExtractOptions::default())?; ``` ## strix 提取的内容 | 种类 | 来源 | |---------------|-----------------------------------------------------------| | `static_ascii` / `static_utf16_le` | 任何节中的可打印字节序列。 | | `go` | Go 二进制文件中的 UTF-8 字符串(存在 pclntab 时提取函数名)。 | | `rust` | Rust 二进制文件中的 UTF-8 字符串(存在 `.rustc` 时提取 crate 元数据)。 | | `stack` | 通过 mov / push / 寄存器-存储模式在栈上构建的字符串。支持 x86、x86_64 和 AArch64。 | | `decoded` | 由内存解码器例程产生的字符串,通过 Unicorn 支持的暴力模拟恢复,包括导入桩和调用点参数提取。支持 x86、x86_64 和 AArch64。 | | `tight` | 写入指令位于已发现循环体内的栈字符串。通过 CFG 回边检测与 `stack` 区分。 | ## 性能 模拟流水线(暴力解码模糊测试、调用者模拟和调用点数据流运行)通过 rayon 跨核心并行化。每个工作线程构建自己的 Unicorn 实例;每个工作线程的构建成本在其分配的所有候选者之间摊销。设置 `RAYON_NUM_THREADS=1` 进行确定性单线程运行。 在 Apple Silicon 笔记本上的指示性挂钟时间: ``` $ time target/release/strix tests/fixtures/elf-Linux-ARM64-bash > /dev/null real 0m0.265s user 0m0.910s sys 0m0.138s ``` 该次运行中用户时间与实际时间 3.4 倍的比率显示,在模拟过程中大约有三个半核心并行忙碌。 加速比随着启发式标记为高于分数阈值的解码候选者数量而扩展;仅有少量候选者的二进制文件收益很小,因为 rayon 开销占主导。 ## 工作区布局 ``` crates/ strix-core types, JSON schema, errors, traits strix-format PE / ELF / Mach-O / shellcode parsing (goblin) strix-static zero-copy ASCII + UTF-16LE scanning strix-lang Go and Rust language-specific extraction strix-emulator Unicorn-backed emulator + iced-x86 + bad64 analyzers + x86 and AArch64 stack-string pattern matchers + x86 and AArch64 call-site dataflow analyzers strix umbrella library, ties everything together strix-cli CLI binary ``` ## 许可证 Apache-2.0
标签:CPU仿真, DAST, ELF格式, Mach-O格式, PE格式, Rust语言, shellcode分析, unicorn引擎, 二进制分析, 云安全监控, 云安全运维, 云资产清单, 内存映射, 可视化界面, 字符串提取, 恶意软件分析, 混淆字符串, 结构化输出, 跨平台支持, 逆向工程, 逆向工程工具, 通知系统, 零拷贝, 静态分析