
クロスプラットフォームのシステムコール駆動型インプラント&C2 — ダイレクトシステムコール(Win)、rawシステムコール(Linux)、HTTPS/DNS/ICMPチャネル。winapiレイヤーなし。
WinAPIゼロ。すべてのNTプリミティブはメモリ内のntdllから実行時に解決され、
SYSCALL命令はPlan9アセンブリスタブを介して直接発行される。インポートテーブルなし、
ntdllのユーザーモードフックに一切触れない。C2はHTTPS / DNS / ICMP経由、メッセージごとに
AES-256-GCM。Windowsネイティブ。Linuxビルド。macOSビルド。
これはsyscallラッパーライブラリではない。コードの注入からファイルの読み取り、レジストリへの
永続化まで、すべての操作が起動時に現在のntdllエクスポートテーブルから解決された生の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が設置したすべてのユーザーモードフックが消える。エージェントはインジェクション手法を自動的にローテーションする。各呼び出しは 異なる手法を使用する — フォレンジックにおいて2つのインジェクションが同じに見えることはない。
すべてのチェックを実行し、スコア付き脅威レポートを返す。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パスワイプ(ランダム → ゼロ → 1 → ゼロ)。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(アーリーレット)、または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_READを見て、PAGE_EXECUTE_READWRITEは見ない。 |
| プロセスホロー | NtCreateUserProcess(サスペンド) → NtSuspendProcess → イメージベースをゼロ化 → シェルコードをアロケート+書き込み → NtSetContextThread(RIP = シェルコード) → NtResumeProcess | プロセスはタスクマネージャで正規のsvchost.exeとして表示される。メモリ内容のみが異なる。 |
| APCキューイング | NtQuerySystemInformationでスレッドを列挙 → NtOpenThread → NtQueueApcThread | 新しいスレッドは作成されない。新しいTEBもない。新しいスタックアロケーションもない。スレッドがアラータブル待機に入ったときに発火する。 |
| モジュールスタンピング | ターゲット内にアロケート → 最小限のPEヘッダ+シェルコードを書き込み → エントリポイントでNtCreateThreadEx | モジュールリストにそれらしいDLL名が表示される。PEヘッダはモジュール列挙を欺くのに十分有効。 |
| チェック | 手法 |
|---|
| VM検出 | CPUIDリーフ0x40000000ハイパーバイザ署名スキャン(VMware、VirtualBox、Hyper-V、KVM、Xen、QEMU、Parallels)+リーフ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キャッシュに保存