21 KiB
English
•
日本語 •
Portuguese •
Türkçe
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: callback 経由の library load を識別します。LoadLibraryの真の origin を call stack から隠す試みかもしれません。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: 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。Unbackedframe: known image に属さない executableMEM_PRIVATE/MEM_MAPPEDmemory。BackedModifiedframe: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 にあります。
先に言っておくと、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 の modified variant を使い、synthetic stack で network DLL を load します。Visible frame は legitimate module に見えますが、callsite validation と origin tracing が DLL load を準備した code に結び直します。
BYOUD / Unwind Metadata Spoofing
この test は 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 を捕まえます。
Threadpool Callback Chain
この sample は klezvirus/ThreadPoolExecChain の考え方に基づいています。Threadpool/proxy chain によって load が自然に見える context で発生します。StackSentry は chain context を保持し、path 上の modified frame を報告します。
Image .text Proxy
この test は LibTPLoadLib を元にした実験的な RefinedPool variant から作った PIC shellcode を使います。この technique は paranoidninja が説明した API proxying の流れや Proxy-DLL-Loads と近いものです。
PIC なので code は loader の .text に置けます。そして nvwgf2umx.dll 内の existing gadget を経由して proxy LoadLibrary flow を作れます。Final stack はきれいに見えますが、register/origin tracing は DLL load を開始した .text region に戻します。
Code Cave / Modified Image
この pattern も RefinedPool の小さな実験的 variant から来ています。Sensitive load は image-backed code cave に書き込まれた bytes を通ります。StackSentry は modified module と .tag changed-byte map を保存するため、triage でかなり役に立ちます。
SilentMoonwalk RDI Synthetic Stack
ここでは SilentMoonwalk variant を Donut/RDI payload として package しています。Bootstrap は wininet.dll や mscoree.dll を load することがありますが、重要な stage は synthetic stack での ws2_32.dll load です。2枚目の画像は hidden executable region に戻る probable origin を示します。
MassDriver 風 Dispatch
Sizeable-Bingus/MassDriver の dispatch pattern から着想を得た sample です。きれいに見える worker thread が LoadLibraryA を実行します。/dispatch-trace は、その load を dispatch structure を送った requester に結びます。
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 を使ってください。
Stack 表示モード
Detection そのものだけでなく、現在の StackSentry console は分析を少し楽にするために stack 表示も調整できます。同じ stack でも、見たい内容に応じて表示形式を変えられます:
Compact Stack
現在の default 表示です。連続して繰り返される frame は [module.dll xN] の形でまとめられます。.NET のような大きい runtime を通る payload では、これだけでかなり noise が減ります。
Offset 付き Full Stack
/full-stack を使うと、各 frame が module offset 付きで1行ずつ表示されます。どの return frame がどこに落ちたのかを細かく確認したい時に向いています。
Compression なし Inline Stack
/inline-stack を使うと、stack は1行の形式に戻り、繰り返し frame の compression も行われません。
Verbose で Clean Event も表示
Default の console は terminal が埋まらないよう alert を優先します。/verbose を使うと、score=0 の clean load も表示されます。この event は青色で出るため、DLL load が観測され記録されたことをすぐ確認できます。/verbose を使わなくても、score=0 event は events.jsonl と memory.json に保存されます。
BackedModified と Memory Audit
Return frame が本物の DLL 内に落ちても、その region の bytes が disk 上の file と一致しない場合、StackSentry はそれを clean frame として扱いません。Stack は BackedModified / captured-modified として表示され、Memory Audit は module、region、そして temporal な変更 detail を記録します。
Build
Build には build.ps1 を使います。Microsoft Visual Studio/MSVC が必要です。
.\build.ps1
Script は build\ に以下を出力します:
StackSentry64.exeCallstackMonitor.dll
Third-party code は third_party\ にあります。Credit と license note は THIRD_PARTY_NOTICES.md を確認してください。
Test Commands
Recommended commands と exact sample commands は 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 <quick|deep|max>: profile を選択します。
疑わしい loader をまず見るなら、基本は /max からでよいと思います。その後、結果に応じて /hunt、/network-use-trace、または個別 flag を追加します。
Command Groups
全オプション:
.\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 を戻そうとします:
.\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 を追います:
.\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 です:
.\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 です:
.\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 を作ります:
out\loader\loader_binary.exe - 24216\
主な artifact:
summary.json、memory.json、events.jsonlorigin_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:
.\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 にあります。















