![StackSentry](/static/StackSentry.png)
`English``日本語``Portuguese``Türkçe`       ![Release](https://img.shields.io/badge/release-v0.8-000000?style=for-the-badge)

StackSentry は、かなり単純な発想から始まりました。もし loader が `LoadLibrary` の origin を隠そうとしているなら、call stack のどこかにまだ痕跡が残っているはず、という発想です。 このプロジェクトは x64 user-mode の研究用ツールです。目的は memory triage、loader analysis、そして sensitive DLL-load detection です。対象 process を起動し、軽量な monitor DLL を inject して、重要なイベントをリアルタイムに観測します。見たいのはかなり直接的な問いです: **この DLL load、または network use を本当に起こしたのは誰か?**
> [!Important] > |**このプロジェクトは現在も開発中です**。Bug、false positive、false negative が起きる可能性があります。 | > |:--------------------------------| > | StackSentry は主に lab 環境で loader や in-memory payload の分析を楽にするために作られました。
Kernel driver はインストールせず、永続的な system change もしません。ただし、結果は必ず補助ツールと比較し、絶対的な判定ではなく triage evidence として扱ってください。 |
## アイデア StackSentry は、memory 上で実行されている code の高速 triage に焦点を当てています。考え方は実用的です。C2、RAT、fileless loader は disk 上の file を隠せます。sleep 中に自分を暗号化できます。見た目のきれいな call stack も作れます。それでも、どこかの時点で network DLL を load するか、network API を使う必要があります。 Windows では、多くの場合 `ws2_32.dll`、`wininet.dll`、`winhttp.dll`、`dnsapi.dll`、またはそれらが export する API が関係します。これらの DLL が不自然な origin から load/use されているなら、そこで止まって確認する価値があります。 この pattern は StackSentry だけの発想ではありません。Elastic の behavioral detection rule とも同じ方向を向いています: - [`defense_evasion_library_loaded_via_a_callback_function.toml`](https://github.com/elastic/protections-artifacts/blob/6e9ee22c5a7f57b85b0cb063adba9a3c72eca348/behavior/rules/windows/defense_evasion_library_loaded_via_a_callback_function.toml): callback 経由の library load を識別します。`LoadLibrary` の真の origin を call stack から隠す試みかもしれません。 - [`defense_evasion_network_module_loaded_from_suspicious_unbacked_memory.toml`](https://github.com/elastic/protections-artifacts/blob/6e9ee22c5a7f57b85b0cb063adba9a3c72eca348/behavior/rules/windows/defense_evasion_network_module_loaded_from_suspicious_unbacked_memory.toml): thread stack に known executable image 以外の frame がある状態で network module が load されるケースを検出します。 - [`defense_evasion_library_loaded_from_a_spoofed_call_stack.toml`](https://github.com/elastic/protections-artifacts/blob/6e9ee22c5a7f57b85b0cb063adba9a3c72eca348/behavior/rules/windows/defense_evasion_library_loaded_from_a_spoofed_call_stack.toml): call source を隠すために改変/spoofed された call stack からの library load を検出します。 こうした detection が存在するため、一部の loader は単純な `LoadLibrary` 呼び出しを避けます。Callback、legitimate module 内の gadget、threadpool chain、cross-thread dispatch、modified image execution、unwind metadata manipulation などを使って origin を隠そうとします。 StackSentry はその考えを lab 向けにもう少し押し進めています。単に「sensitive DLL が load された」と言うだけでなく、probable origin、memory state、stack pattern、有用な dump、そして loader が隠そうとした path を可能な範囲で表示します。 ## 何を見るか - `ws2_32`、`wininet`、`winhttp`、`dnsapi`、CLR/.NET などの sensitive DLL load。 - `Unbacked` frame: known image に属さない executable `MEM_PRIVATE` / `MEM_MAPPED` memory。 - `BackedModified` frame: `MEM_IMAGE` だが disk 上の file と live bytes が一致しない code。 - Proxy/gadget、callback、thread start、APC、VEH、threadpool、dispatch、または target `.text` から隠された origin。 - Stack spoofing: plausible callsite のない return frame、truncated stack、synthetic stack、不自然にきれいな visible caller。 - BYOUD/unwind spoofing: `.pdata`、`.xdata`、`.rdata`、`RUNTIME_FUNCTION`、dynamic unwind table の temporal change。 - `/network-use-trace` 有効時の real network API use。DLL がすでに load 済みでも観測します。 - LDR metadata inconsistency、EntryPoint hijack、module inconsistency。 - Memory audit: modified image、orphan executable mapping、private executable region、focused dump。 - `events.jsonl`、`summary.json`、`memory.json`、`network_trace.json`、`byoud_trace.json`、origin dump、module dump、hash、entropy、strings などの artifact。 ## Detection Gallery Sample の command と期待される call-stack summary は [samples/README.md](samples/README.md) にあります。
先に言っておくと、sample は local test 用のかなり疑わしい lab artifact です。きれいな showcase binary ではありません。
以下は、kernel driver なしで StackSentry が terminal に表示できる pattern の一部です。 いくつかの画像は `v0.8` 付近の output です。その後 console rendering、stack compaction、noise reduction を改善しましたが、output が少しきれいになっただけで `v0.9` と呼ぶのは正直ではないと思ったので、そのままにしています。 > [!Important] > 下の画像の多くは detection result の一部だけを切り出したものです。完全な output は sample を実行して確認してください。 ### Synthetic Stack の SilentMoonwalk この test は [klezVirus/SilentMoonwalk](https://github.com/klezVirus/SilentMoonwalk) の modified variant を使い、synthetic stack で network DLL を load します。Visible frame は legitimate module に見えますが、callsite validation と origin tracing が DLL load を準備した code に結び直します。 ![SilentMoonwalk synthetic stack detection](static/stack-03-silentmoon-synthetic.png) ### BYOUD / Unwind Metadata Spoofing この test は [klezVirus/byoud](https://github.com/klezVirus/byoud) を RDI shellcode 化したものです。Bootstrap は `wininet.dll` や `mscoree.dll` を load しますが、重要なのは BYOUD を使って `ws2_32.dll` load を隠す stage です。Return address を変える代わりに Windows unwind metadata を操作します。StackSentry は sensitive load の前に起きる temporal divergence を捕まえます。 ![BYOUD RDI detection](static/stack-05-byoud-rdi-1.png) ![BYOUD RDI detection](static/stack-05-byoud-rdi-2.png) ### Threadpool Callback Chain この sample は [klezvirus/ThreadPoolExecChain](https://github.com/klezvirus/ThreadPoolExecChain) の考え方に基づいています。Threadpool/proxy chain によって load が自然に見える context で発生します。StackSentry は chain context を保持し、path 上の modified frame を報告します。 ![Threadpool callback-chain detection](static/stack-07-threadpool-chain.png) ### Image `.text` Proxy この test は [LibTPLoadLib](https://github.com/AlmondOffSec/LibTPLoadLib) を元にした実験的な [RefinedPool](https://github.com/Vith0r/RefinedPool/tree/main/RefinedPool) variant から作った PIC shellcode を使います。この technique は [paranoidninja](https://0xdarkvortex.dev/hiding-in-plainsight/) が説明した API proxying の流れや [Proxy-DLL-Loads](https://github.com/paranoidninja/Proxy-DLL-Loads) と近いものです。 PIC なので code は loader の `.text` に置けます。そして `nvwgf2umx.dll` 内の existing gadget を経由して proxy `LoadLibrary` flow を作れます。Final stack はきれいに見えますが、register/origin tracing は DLL load を開始した `.text` region に戻します。 ![Image .text proxy detection](static/stack-01-text-section-proxy.png) ### Code Cave / Modified Image この pattern も [RefinedPool](https://github.com/Vith0r/RefinedPool/tree/main/RefinedPool) の小さな実験的 variant から来ています。Sensitive load は image-backed code cave に書き込まれた bytes を通ります。StackSentry は modified module と `.tag` changed-byte map を保存するため、triage でかなり役に立ちます。 ![Code cave modified image detection](static/stack-02-code-cave-modified-image.png) ### SilentMoonwalk RDI Synthetic Stack ここでは [SilentMoonwalk](https://github.com/klezVirus/SilentMoonwalk) variant を [Donut](https://github.com/TheWover/donut)/RDI payload として package しています。Bootstrap は `wininet.dll` や `mscoree.dll` を load することがありますが、重要な stage は synthetic stack での `ws2_32.dll` load です。2枚目の画像は hidden executable region に戻る probable origin を示します。 ![SilentMoonwalk RDI synthetic detection](static/stack-04-silentmoon-rdi-synthetic-1.png) ![SilentMoonwalk RDI synthetic detection](static/stack-04-silentmoon-rdi-synthetic-2.png) ### MassDriver 風 Dispatch [Sizeable-Bingus/MassDriver](https://github.com/Sizeable-Bingus/MassDriver) の dispatch pattern から着想を得た sample です。きれいに見える worker thread が `LoadLibraryA` を実行します。`/dispatch-trace` は、その load を dispatch structure を送った requester に結びます。 ![MassDriver-style dispatch detection](static/stack-06-massdriver-dispatch.png) ### C2 Payload の Network Use Trace この例は `/network-use-trace` を使います。Network DLL load だけでなく、payload が `connect`、`WSAConnect`、`send`、`recv`、WinHTTP/WinINet などを実際に使う場面を追います。Output には domain、IP/port、さらにこの test では `pastebin.com` のような third-party service も出ます。 画像の stack は意図的に compact しています。古い screenshot のように full stack を1行で見たい場合は `/inline-stack`、offset 付きで frame ごとに見たい場合は `/full-stack` を使ってください。 ![Network-use trace detection in C2 payload](static/stack-08-network-use-trace-c2.png) ### Stack 表示モード Detection そのものだけでなく、現在の StackSentry console は分析を少し楽にするために stack 表示も調整できます。同じ stack でも、見たい内容に応じて表示形式を変えられます: #### Compact Stack 現在の default 表示です。連続して繰り返される frame は `[module.dll xN]` の形でまとめられます。.NET のような大きい runtime を通る payload では、これだけでかなり noise が減ります。 ![Compact stack](static/stack-09-compressed-stack.png) #### Offset 付き Full Stack `/full-stack` を使うと、各 frame が module offset 付きで1行ずつ表示されます。どの return frame がどこに落ちたのかを細かく確認したい時に向いています。 ![Full stack with offsets](static/stack-10-full-stack.png) #### Compression なし Inline Stack `/inline-stack` を使うと、stack は1行の形式に戻り、繰り返し frame の compression も行われません。 ![Inline stack without compression](static/stack-11-inline-stack.png) #### Verbose で Clean Event も表示 Default の console は terminal が埋まらないよう alert を優先します。`/verbose` を使うと、`score=0` の clean load も表示されます。この event は青色で出るため、DLL load が観測され記録されたことをすぐ確認できます。`/verbose` を使わなくても、`score=0` event は `events.jsonl` と `memory.json` に保存されます。 ![Clean event in verbose mode](static/stack-12-verbose-clean-load.png) #### BackedModified と Memory Audit Return frame が本物の DLL 内に落ちても、その region の bytes が disk 上の file と一致しない場合、StackSentry はそれを clean frame として扱いません。Stack は `BackedModified` / `captured-modified` として表示され、Memory Audit は module、region、そして temporal な変更 detail を記録します。 ![BackedModified and memory audit](static/stack-13-backed-modified-memory-audit.png) ## Build Build には `build.ps1` を使います。Microsoft Visual Studio/MSVC が必要です。 ```powershell .\build.ps1 ``` Script は `build\` に以下を出力します: - `StackSentry64.exe` - `CallstackMonitor.dll` Third-party code は `third_party\` にあります。Credit と license note は [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) を確認してください。 ## Test Commands Recommended commands と exact sample commands は [samples/README.md](samples/README.md) にあります。どこから始めるか迷ったらそこから始めてください。First-pass command、strong profile、stack output mode、gallery screenshot の検証用例があります。 ## Main Profiles - `/quick`: low-noise DLL-load triage profile。 - `/deep`: callback/thread-start hooks、unwind hooks、LDR integrity、dump/correlation を有効化する hunting profile。Memory API hooks は opt-in のままです。 - `/max`: 実用上いちばん強い DLL-load profile。Deep telemetry、stack audit、LDR checks、default `/auto-enter` を含みますが、`/mem`、`/tp`、`/wait` は別途有効化します。 - `/profile `: profile を選択します。 疑わしい loader をまず見るなら、基本は `/max` からでよいと思います。その後、結果に応じて `/hunt`、`/network-use-trace`、または個別 flag を追加します。 ## Command Groups 全オプション: ```powershell .\build\StackSentry64.exe /features ``` 主要グループ: - `Output style`: `/no-target-output`、`/inline-stack`、`/full-stack`、`/quiet`、`/plain`、`/live`、`/no-color`。 - `Origin / proxy analysis`: `/regtrace`、`/dispatch-trace`、`/threadpool-chain-trace`。 - `Network use analysis`: `/network-use-trace`、`/net-use-trace`。 - `Remote / multi-process`: `/follow-remote`、`/net-reset`。 - `Extra telemetry / integrity`: `/etw`、`/ldr-integrity`、`/unwind`、`/stack-audit`、`/memory-audit`、`/byoud-trace`、`/shadow-stack`。 - `Aggressive / low-level hooks`: `/mem`、`/tp`、`/wait`、`/xhooks`。 ## 重要なモード ### Origin Tracing Proxy DLL-load technique は final stack をきれいに見せることがあります。`/regtrace` はそのような case で origin を戻そうとします: ```powershell .\build\StackSentry64.exe /run .\samples\sample_03_text_section_proxy.exe /max /regtrace /no-target-output /timeout 9000 ``` `/origin-trace` は callback/thread/APC context と correlation します。`/regtrace` はそれを広げ、gadget/proxy の裏にある real origin を追います。Artifact は `origin_regions\` に出力されます。 Technical note: 現在の `/regtrace` は、main image ではない 32 MB 超の image module に対して full register tracing を意図的に避けます。Private executable memory、thread start、dynamic executable transition、origin correlation は引き続き追跡されます。この制限は、巨大な gadget-carrier image への高コストな full instrumentation を避けるためのものです。Lab case で本当に上限を上げたい場合は、source 内の小さな constant を変更できます。 ### Network Use Trace Payload が network DLL をすでに load 済みとして使う場合、新しい `LoadLibrary` は観測できないかもしれません。`/network-use-trace` は network API use を追います: ```powershell .\build\StackSentry64.exe /run target.exe /max /network-use-trace /timeout 10000 .\build\StackSentry64.exe /run target.exe /max /hunt /network-use-trace /timeout 15000 ``` この mode は `/hunt` に default では含まれません。強力ですが verbose になる可能性があります。Findings は `== Network Use Details ==`、`network_trace.json`、`memory.json`、`summary.json` に出ます。 ### Memory Audit `/memory-audit` は Moneta-style memory artifact から着想を得た live process memory scan です: ```powershell .\build\StackSentry64.exe /run target.exe /max /memory-audit /timeout 10000 ``` Modified image、orphan executable mapping、private executable region、suspicious section permission などを報告します。弱い finding は alert ではなく JSON の hunting context に残すようにしています。 ### BYOUD と Shadow Stack Research `/byoud-trace` は return address ではなく Windows x64 unwind metadata を操作する case の lab mode です: ```powershell .\build\StackSentry64.exe /run target.exe /max /byoud-trace /regtrace /timeout 12000 ``` `/hunt` は `/byoud-trace` を含みます。`/shadow-stack` は CET/HSP research switch で、platform が user-mode shadow-stack state を公開しない場合は何も出ないことがあります。`/hunt` には含めていません。 ## Console Output Console output は alert を優先します。生の詳細は JSON artifact に残ります。 - `/no-target-output`: target の stdout/stderr を StackSentry console に混ぜません。 - `/inline-stack`: repeated-frame compression なしで full stack を1行に出します。 - `/full-stack`: 各 frame を offset 付きで1行ずつ出します。 - `/verbose`: non-alert event も表示します。 - `/quiet`: artifact を書き、console UI を減らします。 Exit code: - `0`: alert なし。 - `10`: 1つ以上の alert。 - `1`/`2`: runtime、argument、target/config error。 ## Outputs 各 run は選択した `/out` path に per-process directory を作ります: ```text out\loader\loader_binary.exe - 24216\ ``` 主な artifact: - `summary.json`、`memory.json`、`events.jsonl` - `origin_regions\` - `dumps\`、`memory_audit\`、`modified_modules\`、`modified_network_modules\` - `network_trace.json`、`byoud_trace.json`、`shadow_stack_trace.json`、`etw_timeline.json` - `/follow-remote` 時の `children\` Modified module dump の隣に出る `.tag` は重要です。Disk 上の file と比較して、どの offset/byte が変わったかを示す diff map です。 ## Rules Default rule format は `config\rules.json` を見てください。Custom config: ```powershell .\build\StackSentry64.exe /run target.exe --rules path\to\rules.json ``` 古い `watch_dlls` field は compatibility alias としてまだ受け付けます。 ## 現在の制限 - これは user-mode instrumentation です。強い target は hook を検出/削除できます。 - `/mem`、`/tp`、`/wait` は noisy または destabilizing になることがあるため、明示的に有効化します。 - `/follow-remote` は user-mode remote-execution setup の観測に依存します。 - `/net-reset` は network DLL を常に unload できるわけではありません。 - `/memory-audit` は target process がまだ生きているときに意味があります。 - `/shadow-stack` は experimental CET/HSP mode で、多くの system では output が出ない可能性があります。 - Advanced stack spoofing を ring3 で完全に不可能にするものではありません。StackSentry は callsite、origin、memory、unwind、network-use の correlation でコストを上げるための tool です。 ## License このプロジェクトは MIT License (Modify It Tonight) で配布されます。使って、変えて、lab で壊して、直して、比較して、結果を公開してください。
分析時間が少しでも節約できたなら、それだけで嬉しいです。コーヒーも歓迎です。 Third-party code の license と credit は [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) にあります。