
공격 보안 페이로드를 위한 다형성 바이너리 인코더입니다. LFSR 기반 피드백 루프, 가비지 명령어 삽입, 다중 반복 난독화를 통해 셸코드를 인코딩하여 정적 탐지를 우회합니다.
SGN은 정적으로 탐지되지 않는 바이너리 페이로드를 생성하는 등 공격적 보안 목적을 위한 다형성 바이너리 인코더입니다. 주어진 바이너리 명령어를 LFSR과 유사하게 인코딩하기 위해 가산 피드백 루프를 사용합니다. 이 프로젝트는 원본 Shikata ga nai를 golang으로 재구현한 것이며 많은 개선 사항을 포함합니다.
[!WARNING]
이 프로젝트는 최근 Rust로 포팅되었습니다. 이 포팅은 원래 설계와 동작을 유지하지만, keystone 텍스트 어셈블러를 순수 Rust 기반iced-x86어셈블러로 대체하므로 네이티브 라이브러리 의존성이 없습니다 — 일반적인cargo build로 빌드됩니다. 레거시 Go 버전은 sgn-go 브랜치를 확인하세요.
공격적 보안 커뮤니티에서 shikata ga nai 인코더의 원래 구현은 (지금까지) 최고의 셸코드 인코더로 간주됩니다. 그러나 수년에 걸쳐 보안 연구원들은 디코더 스텁을 정적으로 탐지하는 여러 가지 약점을 발견했습니다 (관련 연구: FireEye 기사). 이 프로젝트의 주요 동기는 주어진 바이너리를 완전한 무작위 데이터와 구별할 수 없을 정도로 인코딩하여 디코더의 존재를 탐지할 수 없게 만드는 더 나은 인코더를 만드는 것이었습니다.
마침내 제대로 인코딩된 x64 셸코드!LFSR 키가 1바이트로 축소됨디코더 스텁도 의사 난수 스키마로 인코딩됨스텁이 루프 조건을 전혀 사용하지 않고 자체 디코딩!!keystone으로 무작위 가비지 명령어 생성기 추가어떤 레지스터도 손상되지 않음 (선택적 프리앰블, 다형성이 줄어들 수 있음)각 인코딩 패스:
--plain이 아닌 경우, 스텁 자체를 실행마다 무작위인 스키마 암호(DWORD 단위 XOR/ADD/SUB/ROL/ROR/NOT)로 암호화하고 자기 위치를 찾는 스키마 디코더를 앞에 추가하므로 디코더조차 무작위 데이터처럼 보입니다;--enc 횟수만큼 새로운 시드로 반복합니다;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'
다음 이미지는 인코더의 기본 작업 흐름 다이어그램입니다. 그러나 가비지 명령어, 디코더 및 스키마 디코더의 크기, 위치 및 순서는 각 반복마다 변경된다는 점을 유의하세요.
LFSR 자체는 확률 공간 측면에서 상당히 강력합니다. 더욱 강력한 다형성을 위해 인코딩되지 않은 원시 페이로드의 시작 부분에 가비지 명령어가 추가됩니다. 아래 이미지는 LFSR 특성 다항식의 동반 행렬(companion matrix)과 시드를 열 벡터로 표기하여 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 셸코드는 실행 가능한 메모리에 매핑되어 프로세스 내에서 실행되고, x86 셸코드는
cc -m32 헬퍼 하네스를 통해 실행됩니다 (32비트 툴체인이 없으면 자동으로 건너뜀).
플레인, 스키마, 다중 레이어 및 안전 레지스터 모드 전반에 걸쳐 두 아키텍처 모두
무작위 스트레스 루프를 포함하여 테스트됩니다.
iced-x86의 타입화된 어셈블러 API를 사용합니다. 디코더 스텁은 RIP-상대 주소 지정(x64)과 call/pop 2패스 방식(x86)을 중심으로 재구성되었습니다.random_byte는 이제 전체 0..=255 범위를 포괄하며, 가비지 크기 예산(--max)은 블록당 상한으로 일관되게 적용됩니다.