
システムコール実行時に任意のコールスタックを偽装するためのPoC実装(例:NtOpenProcessによるハンドル取得)
このリポジトリは、システムコールを行う際に任意のコールスタックを偽装する PoC 実装を示しています。完全な技術解説については、付随するブログ記事(https://labs.withsecure.com/blog/spoofing-call-stacks-to-confuse-edrs)を参照してください。
デフォルトでは、模倣する 3 つのサンプルコールスタックが含まれており、以下に示すように --wmi、--rpc、--svchost のいずれかを指定することで選択できます:

これらのコールスタックは、プロセスアクセスイベントを有効にした SysMon を実行し、ハンドル操作のターゲットが lsass であるイベントを検索して取得されました。
注記:注意点として、この PoC は以下の Windows ビルドでテストされました。
他のバージョンではテストされておらず、別の Windows ビルドではオフセットが明らかに異なる(したがって動作しなくなる)可能性があります。
問題が発生した場合、エラーをデバッグする 1 つの手法は、SysMon で OpenProcess イベントを生成しているプロセスを見つけ、そのプロセスに
WinDbg でアタッチすることです。アタッチしたら、bp ntdll!NtOpenProcess を実行し、bp がヒットしたら knf を実行します。
これにより、以下のような出力が表示されます。この出力には、完全なシンボル解決と、正しいスタック利用領域(「Memory」列で示されます)が含まれます:
0:003> knf
# Memory Child-SP RetAddr Call Site
00 00000037`f01fe300 00007ffd`221d2ea6 ntdll!NtOpenProcess+0x12
01 8 00000037`f01fe308 00007ffd`1ffee959 KERNELBASE!ProcessIdToSessionId+0x96
02 80 00000037`f01fe388 00007ffd`23b99633 lsm!RpcOpenEnum+0x129
03 430 00000037`f01fe7b8 00007ffd`23b33711 RPCRT4!Invoke+0x73
04 40 00000037`f01fe7f8 00007ffd`23bfd77b RPCRT4!Ndr64UnmarshallHandle+0xe1
05 70 00000037`f01fe868 00007ffd`23b7d2ac RPCRT4!Ndr64StubWorker+0xb0b
06 6c0 00000037`f01fef28 00007ffd`23b7a408 RPCRT4!NdrServerCallAll+0x3c
07 50 00000037`f01fef78 00007ffd`23b5a266 RPCRT4!DispatchToStubInCNoAvrf+0x18
08 50 00000037`f01fefc8 00007ffd`23b59bb8 RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x1a6
09 e0 00000037`f01ff0a8 00007ffd`23b68a0f RPCRT4!RPC_INTERFACE::DispatchToStub+0xf8
0a 70 00000037`f01ff118 00007ffd`23b67e18 RPCRT4!LRPC_SCALL::DispatchRequest+0x31f
0b d0 00000037`f01ff1e8 00007ffd`23b67401 RPCRT4!LRPC_SCALL::HandleRequest+0x7f8
0c 110 00000037`f01ff2f8 00007ffd`23b66e6e RPCRT4!LRPC_ADDRESS::HandleRequest+0x341
0d a0 00000037`f01ff398 00007ffd`23b6b542 RPCRT4!LRPC_ADDRESS::ProcessIO+0x89e
0e 140 00000037`f01ff4d8 00007ffd`24ab0330 RPCRT4!LrpcIoComplete+0xc2
0f a0 00000037`f01ff578 00007ffd`24ae2f26 ntdll!TppAlpcpExecuteCallback+0x260
10 80 00000037`f01ff5f8 00007ffd`23387034 ntdll!TppWorkerThread+0x456
11 300 00000037`f01ff8f8 00007ffd`24ae2651 KERNEL32!BaseThreadInitThunk+0x14
12 30 00000037`f01ff928 00000000`00000000 ntdll!RtlUserThreadStart+0x21
補足として、現在のコールサイトが使用する合計スタック領域は、下の行に示されています(例: ntdll!NtOpenProcess はわずか 8 バイトしか使用しません)。前述のとおり、この README の冒頭でリンクされているブログで完全な技術解説が説明されており、これ(および Child-SP などの概念)について詳しく解説されています。windbg によって生成された値は、問題が発生した場合に CalculateFunctionStackSize() が返す値と照合するために使用できます。
UNWIND_CODEs の解析におけるサンプルコードを提供してくれた unicorn_pe プロジェクト(https://github.com/hzqst/unicorn_pe)に感謝します。