返回更新列表
新发布Jul 29, 2026

sgn v1.0.0-rs

用于攻击性安全载荷的多态二进制编码器。利用基于LFSR的反馈回路、垃圾指令注入和多轮迭代混淆对shellcode进行编码,以规避静态检测。

分享

GitHub All Releases Build Issues Crates License: MIT

SGN 是一个用于进攻性安全目的的多态二进制编码器,例如生成静态无法检测的二进制载荷。它使用类似于 LFSR 的加法反馈循环来对给定的二进制指令进行编码。本项目是用 golang 对原始 Shikata ga nai 的重新实现,并带来了许多改进。

[!WARNING]
该项目最近已移植到 Rust。此移植保留了原始设计和行为,但使用纯 Rust 的 iced-x86 汇编器取代了 keystone 文本汇编器,因此没有任何原生库依赖——只需普通的 cargo build 即可构建。如需旧版 Go 版本,请查看 sgn-go 分支。

为什么?

对于进攻性安全社区而言,shikata ga nai 编码器的原始实现一直被认为是最好的 shellcode 编码器(直到现在)。但多年来,安全研究人员已经发现了静态检测解码器存根的几个缺陷(相关工作参见 FireEye 文章)。本项目的主要动机是创建一个更好的编码器,将给定的二进制编码到与完全随机数据无法区分的程度,并且无法检测到解码器的存在。

  • 64 位支持。终于可以正确编码 x64 shellcode 了!
  • 新的更小解码器存根。LFSR 密钥缩减为 1 字节
  • 存根采用伪随机 schema 编码。解码器存根也使用伪随机 schema 进行编码
  • 没有可见的循环条件 存根无需使用任何循环条件即可自我解码!!
  • 解码器存根混淆。新增了基于 keystone 的随机垃圾指令生成器
  • 安全寄存器选项。不会破坏任何寄存器(可选前导,可能会降低多态性)

工作原理

每次编码过程:

  1. (可选)附加一个寄存器恢复后缀(安全模式);
  2. 前置随机的、保留值的垃圾指令;
  3. 使用 ADFL(加法反馈循环)密码对载荷进行加密,并前置一个可在运行时将其还原的无循环解码器存根;
  4. 除非使用 --plain,否则使用每次运行随机生成的 schema 密码(基于 DWORD 的 XOR/ADD/SUB/ROL/ROR/NOT)对存根本身进行加密,并前置一个自定位 schema 解码器,从而使解码器本身看起来也像随机数据;
  5. 可选择使用新的随机种子重复 --enc 次;
  6. (可选)前置一个寄存器保存前缀(安全模式)。

安装

cargo install sgn

你也可以从此处获取预编译的二进制文件。

用法

-h 已经相当一目了然了,如果想看看幕后发生了什么,请使用 -v ( ͡° ͜ʖ ͡°)_/¯

       __   _ __        __                               _ 
  ___ / /  (_) /_____ _/ /____ _  ___ ____ _  ___  ___ _(_)
 (_-</ _ \/ /  '_/ _ `/ __/ _ `/ / _ `/ _ `/ / _ \/ _ `/ / 
/___/_//_/_/_/\_\\_,_/\__/\_,_/  \_, /\_,_/ /_//_/\_,_/_/  
========[Author:-Ege-Balcı-]====/___/=======v2.0.2=========  
    ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻           (ノ ゜Д゜)ノ ︵ 仕方がない

sgn [OPTIONS]

Options:
  -i, --input <INPUT>        Input binary path
  -o, --out <OUT>            Encoded output binary name (default: <input>.sgn)
  -a, --arch <ARCH>          Binary architecture (32/64) [default: 64]
  -c, --enc <ENC>            Number of times to encode the binary [default: 1]
  -M, --max <MAX>            Maximum bytes per garbage block [default: 50]
      --plain                Do not encode the decoder stub
      --ascii                Generate a fully ASCII-printable payload (slow)
  -S, --safe                 Preserve all register values (no clobber)
      --badchars <BADCHARS>  Avoid these bytes, hex format (e.g. \x00\x0a)
  -v, --verbose              Verbose mode
  -h, --help                 Print help
  -V, --version              Print version

示例:

sgn -i shellcode.bin -o encoded.bin -a 64 --badchars '\x00\x0a\x0d'

执行流程

下图是编码器的基本工作流程图。但请记住,在每次迭代中,垃圾指令、解码器和 schema 解码器的大小、位置和顺序都会发生变化。

就概率空间而言,LFSR 本身非常强大。为了进一步增强多态性,垃圾指令会被附加在未编码原始载荷的开头。下图展示了 LFSR 特征多项式的友矩阵,并将种子表示为列向量,即 Fibonacci 配置下寄存器经过 k 步后的状态。

作为库使用

use sgn::Encoder;

let shellcode = std::fs::read("payload.bin")?;
let mut encoder = sgn::Encoder::new(64)?;
let encoded = encoder.encode(&shellcode)?;
println!("encoded {} bytes", encoded.len());

参见 examples/encode_binary.rs

测试

cargo test

该套件包含密码往返单元测试以及真实执行测试:编码后的 x64 shellcode 会被映射为可执行内存并在进程内运行,x86 shellcode 则通过 cc -m32 辅助测试程序执行(如果不存在 32 位工具链,则自动跳过)。两种架构都会在 plain、schema、多层和安全寄存器等模式下接受测试,并包含一个随机化压力循环。

移植说明

  • 指令生成使用 iced-x86 的类型化汇编器 API,而非 keystone 汇编文本;解码器存根围绕 RIP 相对寻址(x64)和 call/pop 两遍方案(x86)重新构建。
  • schema 密码直接以 CPU 原生的 little-endian DWORD 视图表示,这与原始版本中混合大小端运算的方式等效,但更加清晰。
  • 原始版本中的死代码(未使用的约 3000 行指令集表,以及从未被调用的“不安全垃圾”生成器)已被移除。
  • 次要修复:random_byte 现在覆盖完整的 0..=255 范围,垃圾大小预算(--max)也一致地作为每个块的上限应用。

分类