返回更新列表
新发布Sep 16, 2026

SindriKit v2.0.0

一个用于构建操作可信进攻能力的基础C语言库

分享

SindriKit

攻击性开发值得更好的架构。
一个用于构建攻击性能力的 C 库。


核心概念

大多数攻击性工具将执行机制硬编码在技术逻辑内部。一个反射加载器不仅仅是映射一个映像;它使用特定的、硬编码的 VirtualAlloc 或原生 NTAPI 调用链来映射它。当 EDR 开始监控该特定调用链时,你被迫重写整个工具。

SindriKit 通过接口抽象表强制实现关注点分离来解决这个问题:

  1. 技术逻辑:(例如加载器、注入器、补丁器)处理状态跟踪和数据编排。它不知道内存如何分配或线程如何创建。
  2. 执行机制:(例如 Win32 API、原生 NTAPI、直接系统调用)位于独立的 API 表中,并在运行时注入到技术中。

通过将执行机制转移到运行时函数指针,你可以用一行代码将整个策略从 Win32 调用切换为原始直接系统调用——而无需更改你的载荷执行逻辑。


设计架构

  • 解耦的执行配置文件: 通过独立的函数指针表(snd_memory_api_t、snd_module_api_t、snd_process_api_t、snd_thread_api_t、snd_mapping_api_t、snd_file_api_t)交换内存、模块、映射、进程、线程和文件机制,而无需触及技术逻辑。
  • 技术覆盖范围: 反射式 PE(EXE/DLL)和 COFF/BOF 加载,基于 shellcode/PE/COFF 的经典和早期鸟 APC 注入,以及架构感知的 FFI 和 Heaven's Gate——全部基于相同的可组合配置文件。
  • 级联系统调用管道: 可插拔的 SSN 解析器(snd_syscall_resolve_ssn_scan、snd_syscall_resolve_ssn_sort)具有优先级链,与调用器解耦:直接、间接(NTDLL gadget)或欺骗(动态 Fat-Frame 调用栈欺骗)。
  • 设施编码状态: 每个可能失败的调用都返回 snd_status_t——一个打包的设施/本地代码加上捕获的操作系统错误,其上下文字符串在静默层中编译时被移除。
  • 编译时混淆: 字符串和 API 哈希算法(DJB2、FNV1A)可以通过 CMake 全局交换。编译时自动随机化全局种子以改变静态签名。
  • 变异引擎: 通过 SND_MORPH 实现深度多态。每次构建时通过向 C 代码注入易变的 opaque predicates、向汇编存根注入功能等效的数学/NOP,以及打乱核心结构体的内存布局,生成唯一的二进制签名。
  • 发布构建: 静默层剥离所有诊断字符串、文件描述符和跟踪帧;SND_CRTLESS 构建更进一步,使用 /NODEFAULTLIB、无 SDK 头文件、PEB 前端和仅原生后端。

快速开始

该仓库附带一个单一的 unified CLI,可演练每个配置文件:

build.bat pocs
build64\pocs\Release\unified.exe load pe -f payload.dll -e Run --sys

unified 支持 load pe|coff、inject classic|apc|hijack(shell、PE、COFF)和 hg,每个都可通过 --win/--nt/--sys 选择。参见示例与 PoC和入门指南。


集成 SindriKit

cmake_minimum_required(VERSION 3.16)
project(MyTool C ASM_MASM)

set(SND_BUILD_PAYLOADS  OFF    CACHE BOOL   "")
set(SND_ENABLE_DEBUG    OFF    CACHE BOOL   "")
set(SND_HASH_ALGO      "DJB2"  CACHE STRING "")
set(SND_RANDOMIZE_SEED  ON     CACHE BOOL   "")
set(SND_MORPH           ON     CACHE BOOL   "")

add_subdirectory(libs/SindriKit)

add_executable(my_tool src/main.c)
target_link_libraries(my_tool PRIVATE sindri::engine)
cmake -B build && cmake --build build --config Release

只需两行代码,你的工具即可继承 SindriKit 的所有能力:PE 和 COFF 解析、反射加载、级联系统调用和注入配置文件。


引擎

API 抽象层

        ┌────────────────────────────────────────────────────────────────────────────┐
        │                          任意攻击性意图                                     │
        │    加载器 · 注入器 · 欺骗器 · 补丁器 · 绕过器 · 收集器 · ...                 │
        ├────────────────────────────────────────────────────────────────────────────┤
        │                     SINDRIKIT API 抽象层                                    │
        │      snd_memory_api_t   ->  alloc · free · protect                         │
        │      snd_module_api_t   ->  load_library · get_proc_address · ...          │
        │      snd_process_api_t  ->  open · alloc_remote · write · protect · thread │
        │      snd_mapping_api_t  ->  open · view · close   (KnownDlls 引导)          │
        │      snd_thread_api_t   ->  queue_apc · resume · suspend                   │
        │      snd_file_api_t     ->  load                                           │
        ├──────────────────┬──────────────────────┬──────────────────────────────────┤
        │   Win32 配置文件  │    原生配置文件       │    自带机制                       │
        │  VirtualAlloc    │  NtAllocateVirtual   │  驱动 · ROP · 奇异               │
        │  LoadLibraryA    │  PEB 遍历 + EAT      │  操作者定义的函数                 │
        └──────────────────┴──────────────────────┴──────────────────────────────────┘

在实践中,这意味着每个领域都遵循相同的契约:

// Reflective loader
snd_ldr_pe_ctx_t ctx = {0};
ctx.raw_source = &payload;
ctx.mem_api    = &snd_mem_win;   // or snd_mem_nt / snd_mem_sys
ctx.mod_api    = &snd_mod_win;   // or snd_mod_nt
snd_ldr_pe_prepare_image(&ctx);
snd_ldr_pe_execute_image(&ctx);

// Classic injection
snd_inj_ctx_t inj = {0};
inj.target_pid = 1337;
inj.payload    = &shellcode;
inj.proc_api   = &snd_proc_sys;  // or snd_proc_win / snd_proc_nt
snd_inj_classic_shell(&inj);
snd_inj_cleanup(&inj);

级联系统调用管道

SindriKit 将系统调用解析视为一种可注入的机制,按优先级顺序堆叠策略。引擎会依次尝试直到一个成功:

snd_ntdll_set_clean(clean_ntdll);
snd_syscall_set_resolver(snd_syscall_resolve_ssn_scan);
snd_syscall_add_resolver(snd_syscall_resolve_ssn_sort);
snd_syscall_set_invoker(snd_syscall_direct_invoke_asm);
// or for indirect syscalls:
// snd_syscall_set_invoker(snd_syscall_indirect_invoke_asm);
// snd_syscall_set_gadget_finder(snd_syscall_find_gadget_scan);
// or for spoofed syscalls:
// snd_syscall_set_invoker(snd_syscall_spoofed_invoke_asm);
// snd_syscall_set_spoof_finder(snd_syscall_find_spoof_scan);

调用器与 SSN 解析解耦——无需修改领域代码即可在直接、间接和欺骗系统调用之间切换。间接调用跳转到合法的 NTDLL gadget,使返回地址保持在 ntdll.dll 内部;欺骗调用还会在动态发现的“Fat Frame”中植入真实的调用者返回地址,使调用栈展开保持连贯。

编译时算法敏捷性

每个 API 名称和模块字符串在编译时通过单个 CMake 变量从最终二进制文件中移除:

set(SND_HASH_ALGO "FNV1A")  # or DJB2 recomputes everything automatically
set(SND_RANDOMIZE_SEED ON)  # generates a fresh 32-bit seed on next configure

每个哈希都使用随机生成的种子计算(如果 SND_RANDOMIZE_SEED=ON)。静态足迹在编译之间完全改变,而无需触及一行 C 代码。

架构感知的动态 FFI

一个自定义的 MASM 汇编桥接,用于任意运行时函数调用。x64 构建精确遵循 Microsoft x64 调用约定(影子空间、寄存器参数放置、栈对齐)。x86 构建按相反顺序压入参数,并支持 cdecl 和 stdcall 目标。

边界检查的 PE 解析器

一个统一的 PE32/PE32+ 解析器,带有 is_mapped 标志,可正确处理原始磁盘映像和内存映射视图。每个数据目录访问在解引用之前都会根据跟踪的缓冲区边界进行验证。导出解析支持深度达 4 的转发器链,并使用基于哈希的查找。

已针对以下内容测试:

  • 40+ 核心测试组合,针对 x86 和 x64 上的边缘情况 EXE、DLL、错误参数、缺失导出和 TLS 回调。
  • 100+ 由 pe_mutator 模块生成的动态 PE 变异:清零节名称、整数溢出、无效的 e_lfanew 边界、损坏的导入。
  • 完整的 Corkami 语料库:干净地加载有效样本,干净地拒绝畸形样本,在 99% 的样本中无崩溃。

COFF / BOF 加载器

第二种加载器技术处理未链接的 COFF 对象文件(Beacon Object Files):对头、节、符号和重定位进行有界解析;通过注入的 mod_api 解析 MODULE$Function 外部符号;用于超出范围调用的 x64 JMP [RIP+0] 跳板;以及执行命名入口点(默认 go)——本地或编组到远程进程。

状态跟踪的领域上下文

每个攻击性操作都通过一个离散的上下文结构进行管理,并带有阶段枚举。操作可以在阶段之间暂停以进行睡眠混淆或分阶段部署,干净地恢复,并检查确切的失败点,精确到子系统和原因。


API 设计哲学

一次性引导系统调用管道(典型模式):

PVOID clean_ntdll = NULL;
snd_om_knowndll_map(&snd_map_nt, L"ntdll.dll", &clean_ntdll);
snd_ntdll_set_clean(clean_ntdll);
snd_syscall_set_resolver(snd_syscall_resolve_ssn_scan);
snd_syscall_add_resolver(snd_syscall_resolve_ssn_sort);
snd_syscall_set_invoker(snd_syscall_direct_invoke_asm);
// or for indirect syscalls:
// snd_syscall_set_invoker(snd_syscall_indirect_invoke_asm);
// snd_syscall_set_gadget_finder(snd_syscall_find_gadget_scan);
// or for spoofed syscalls:
// snd_syscall_set_invoker(snd_syscall_spoofed_invoke_asm);
// snd_syscall_set_spoof_finder(snd_syscall_find_spoof_scan);

调用器与 SSN 解析解耦——无需修改领域代码即可在直接、间接和欺骗系统调用之间切换。间接调用跳转到合法的 NTDLL gadget,使返回地址保持在 ntdll.dll 内部;欺骗调用还会在动态发现的“Fat Frame”中植入真实的调用者返回地址,使调用栈展开保持连贯。

通过一次赋值交换执行配置文件:

ctx.mem_api = &snd_mem_win;   // diagnostic
ctx.mem_api = &snd_mem_nt;    // NT stubs via PEB + EAT
ctx.mem_api = &snd_mem_sys;   // direct syscalls (pipeline required)

模块解析遵循相同的模式(snd_mod_win 与 snd_mod_nt)。没有由系统调用支持的模块后端——即使在完整的 _sys 配置文件中,导入也使用 PEB 遍历 + EAT。


构建层级

调试层 — SND_ENABLE_DEBUG=ON

用于本地开发。snd_status_t 扩展为包含 file、line 和一个 128 字节的 context 字符串缓冲区。SND_ERR_CTX 和 SND_DEBUG_PRINT 输出状态机转换、解析的 PE 字段值和系统调用解析结果。使用 SND_USE_PRINTF=ON 将输出路由到 stdout 而不是调试控制台。

静默层 — SND_ENABLE_DEBUG=OFF

用于操作二进制文件的标准部署配置。每个诊断字符串、文件引用和行号都完全编译移除。snd_status_t 折叠为两个整数。仅此而已。SND_CRTLESS=ON 构建进一步叠加 /NODEFAULTLIB、无 Windows SDK 头文件、PEB 命令行前端和仅原生后端。

分类