本「
IT談話館」一般公開記事は、10年以上の実務経験を持つ上級Windowsエンジニアを想定しています。
本館は、Windowsカーネル深層を解析し、クラッシュ原因をはじめとするシステム内の「異様な動き」を検出・分析する
超高度な技術と実績を保有しています。
Windowsカーネルアーキテクチャー(後編)
本「IT談話館」の「一般公開記事」は、「Active Memory Dump とカーネルメモリダンプ」の解析結果を基に起草されています。「本館」主筆の「豊田孝」はDKOM(Direct Kernel Object Manipulation)ベースの解析手法の第一人者であり、Windowsカーネル空間の解析分野では世界の先頭を走っています。
現在、セキュリティー問題を無視することはできません。Microsoft社側の負担だけではなく、同社製品の利用者側の負担も増しています。困ったことではありますが、当面避けられません。セキュリティーの視点から「Windows10ソフトウェアセンサー」を見た場合、本「IT談話館」の確認範囲では、「カーネル層保護ロジック」に加え、次のような保護メカニズム階層が考案・実装されています。下記リンクはすべて本館記事を指しています。
- Silo/Server Silo
- Job
- Session
- Protected Process
- Mandatory Integrity Control(MIC)
- Windows API(+CPU)
- CPU
本稿は「Windowsカーネルアーキテクチャー(前編)」の続編であり、上記のJobオブジェクトとWindows Siloの関係を解析します。その他のオブジェクトに関しては、本「IT談話館」の別稿「Windowsメモリダンプ解析技術開発室(応用)」や「Windowsカーネルアーキテクチャー(前編)」に目を通すとよろしいかもしれません。
Siloという用語は、Server Silo、Container、Docker、Jobオブジェクト、プロセスオブジェクト、スレッドオブジェクト、セッションオブジェクトなどの多くの用語との関係の中で使用されています。実を言いますと、本館はSiloの実装実情を知りません。また、Siloに起因するクラッシュダンプ解析やシステム異常分析などの経験もありません。ただ、次のようなカーネル内部情報を見ると、SiloとJobオブジェクトの微妙な関係を推察することはできます。
3: kd> vertarget
Windows 10 Kernel Version 14393 MP (4 procs) Free x64
Product: Server, suite: TerminalServer SingleUserTS
Built by: 14393.2068.amd64fre.rs1_release.180209-1727
Machine Name:
Kernel base = 0xfffff803`c381d000 PsLoadedModuleList = 0xfffff803`c3b251a0
Debug session time: Mon Jun 25 16:16:23.767 2018 (UTC + 9:00)
System Uptime: 2 days 20:12:55.966
3: kd> dt _ejob parent*
nt!_EJOB
+0x420 ParentJob : Ptr64 _EJOB
+0x428 ParentSilo : Ptr64 _EJOB
3: kd> dt _ejob server*
nt!_EJOB
+0x4e8 ServerSiloGlobals : Ptr64 _ESERVERSILO_GLOBALS
この内部情報は、SiloとJobオブジェクトの間に微妙な関係のあることを示唆しています。また、SiloにはServer Siloという異なる概念を持つSiloが存在していることも分かります。これらの前提は自然に導き出せるものですが、このメモリダンプが採取されたWindows 10ビルド環境よりも新しいビルド環境で採取されたメモリダンプには次のような異なる情報が記録されています。
1: kd> vertarget
Windows 10 Kernel Version 17134 MP (2 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 17134.1.amd64fre.rs4_release.180410-1804
Machine Name:
Kernel base = 0xfffff802`9ea1b000 PsLoadedModuleList = 0xfffff802`9edc9150
Debug session time: Sun Mar 10 06:57:53.854 2019 (UTC + 9:00)
System Uptime: 2 days 22:17:18.721
1: kd> dt _ejob parent*
ntdll!_EJOB
+0x430 ParentJob : Ptr64 _EJOB
+0x51c ParentLocked : Pos 0, 1 Bit
1: kd> dt _ejob server*
ntdll!_EJOB
+0x4e8 ServerSiloGlobals : Ptr64 _ESERVERSILO_GLOBALS
ご覧のように、「ParentSilo」というフィールドの姿が消えています。念のため、さらに新しいビルド環境で採取されたメモリダンプの内部を見てみます。
0: kd> vertarget
Windows 10 Kernel Version 18362 MP (2 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 18362.1.amd64fre.19h1_release.190318-1202
Machine Name:
Kernel base = 0xfffff802`6e400000 PsLoadedModuleList = 0xfffff802`6e848130
Debug session time: Thu Dec 26 15:26:37.338 2019 (UTC + 9:00)
System Uptime: 3 days 5:48:09.082
0: kd> dt _ejob parent*
nt!_EJOB
+0x430 ParentJob : Ptr64 _EJOB
+0x51c ParentLocked : Pos 0, 1 Bit
0: kd> dt _ejob server*
nt!_EJOB
+0x4e8 ServerSiloGlobals : Ptr64 _ESERVERSILO_GLOBALS
「ParentSilo」フィールドの姿はありません。この事実から、「ParentSilo」という概念は今後使用しない方針が確定したことが推察されます。ここで、次のような基本的な疑問が沸きます。
この疑問は自然に湧き出た基本的なものです。基本的な疑問への回答を見い出すのは意外と骨が折れるものですが、Windowsカーネル内部の解析に慣れると、次のようなカーネル関数の内容を覗き見る癖が身に付きます。
0: kd> vertarget
Windows 10 Kernel Version 18362 MP (2 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 18362.1.amd64fre.19h1_release.190318-1202
Machine Name:
Kernel base = 0xfffff802`6e400000 PsLoadedModuleList = 0xfffff802`6e848130
Debug session time: Thu Dec 26 15:26:37.338 2019 (UTC + 9:00)
System Uptime: 3 days 5:48:09.082
0: kd> uf nt!PsGetCurrentSilo
nt!PsGetCurrentSilo:
fffff802`6e43e610 65488b0c2588010000 mov rcx,qword ptr gs:[188h]
fffff802`6e43e619 488b81d8070000 mov rax,qword ptr [rcx+7D8h]
fffff802`6e43e620 4883f8fd cmp rax,0FFFFFFFFFFFFFFFDh
fffff802`6e43e624 7513 jne nt!PsGetCurrentSilo+0x29 (fffff802`6e43e639) Branch
nt!PsGetCurrentSilo+0x16:
fffff802`6e43e626 488b8120020000 mov rax,qword ptr [rcx+220h]
fffff802`6e43e62d 488b80b8030000 mov rax,qword ptr [rax+3B8h]
fffff802`6e43e634 4885c0 test rax,rax
fffff802`6e43e637 7507 jne nt!PsGetCurrentSilo+0x30 (fffff802`6e43e640) Branch
nt!PsGetCurrentSilo+0x29:
fffff802`6e43e639 c3 ret Branch
nt!PsGetCurrentSilo+0x30:
fffff802`6e43e640 f7801805000000000040 test dword ptr [rax+518h],40000000h
fffff802`6e43e64a 75ed jne nt!PsGetCurrentSilo+0x29 (fffff802`6e43e639) Branch
nt!PsGetCurrentSilo+0x3c:
fffff802`6e43e64c 488b8030040000 mov rax,qword ptr [rax+430h]
fffff802`6e43e653 4885c0 test rax,rax
fffff802`6e43e656 74e1 je nt!PsGetCurrentSilo+0x29 (fffff802`6e43e639) Branch
nt!PsGetCurrentSilo+0x48:
fffff802`6e43e658 ebe6 jmp nt!PsGetCurrentSilo+0x30 (fffff802`6e43e640) Branch
この関数は、次のような経路をたどりながら、目的の「CurrentSilo」を探し出しています。
0: kd> dt _ethread silo*
ntdll!_ETHREAD
+0x7d8 Silo : Ptr64 _EJOB
0: kd> dt _kthread process*
ntdll!_KTHREAD
+0x074 ProcessDetachActive : Pos 11, 1 Bit
+0x078 ProcessStackCountDecremented : Pos 20, 1 Bit
+0x220 Process : Ptr64 _KPROCESS
0: kd> dt _eprocess job*
ntdll!_EPROCESS
+0x308 JobNotReallyActive : Pos 0, 1 Bit
+0x3b8 Job : Ptr64 _EJOB
+0x470 JobLinks : _LIST_ENTRY
+0x6fc JobVadsAreTracked : Pos 3, 1 Bit
0: kd> dt _ejob parent*
ntdll!_EJOB
+0x430 ParentJob : Ptr64 _EJOB
+0x51c ParentLocked : Pos 0, 1 Bit
最終的には、Jobオブジェクトの「ParentJob」フィールド値を「CurrentSilo」として返しています。
以上の結果を見ますと、SiloとはJobオブジェクトの「ParentJob」フィールドに設定されるオブジェクトであることが分かりました。また、SiloはServer Siloとは異なるオブジェクトであることも同時に分かりました。
SiloやServer Siloに起因する障害の解析や動作異常分析を進める場合には、次のようなカーネル関数を調査しておくとよいでしょう。本「IT談話館」はすでに調査済みであり、解析依頼の到着を待っている状態です。
0: kd> x nt!*process*silo*
fffff802`6e468658 nt!PsIsProcessInSilo (void)
fffff802`6ea10450 nt!PspEstimateNewProcessServerSilo (void)
fffff802`6ecc5fd0 nt!PsIsProcessInAppSilo ()
fffff802`6e467ed0 nt!PsGetProcessServerSilo ()
fffff802`6e707820 nt!PsGetProcessSilo ()
0: kd> x nt!*thread*silo*
fffff802`6e468674 nt!PsIsThreadInSilo (void)
fffff802`6e402880 nt!PsIsCurrentThreadInServerSilo ()
fffff802`6e4024f0 nt!PsGetThreadServerSilo ()
0: kd> x nt!*job*silo*
fffff802`6ea6cc10 nt!PspValidateJobAssignmentSiloPolicy (void)
fffff802`6e595fec nt!EtwTraceJobServerSiloMonitorCallback (void)
fffff802`6e4cc990 nt!PspJobIsSilo ()
fffff802`6ecc9a00 nt!PspSetJobSiloThreadImpersonationPolicy ()
fffff802`6ecf53b0 nt!EtwTraceJobServerSiloStateChange ()
fffff802`6e708350 nt!PsGetJobSilo ()
fffff802`6e797940 nt!JobServerSiloStateChange =
fffff802`6e70744c nt!PspJobIsAppSilo ()
fffff802`6e708320 nt!PsGetJobServerSilo ()
fffff802`6e70737c nt!PspGetJobSilo ()
0: kd> x nt!*session*silo*
fffff802`6ea73134 nt!SepReferenceLogonSessionSilo (void)
fffff802`6ece25bc nt!SepDeleteUnreferencedLogonSessionsInSilo ()
fffff802`6e566b3c nt!MmIsSessionInCurrentServerSilo ()
従来はこのレベルの技術の習得には海外の資料や人材に頼る必要がありましたが、本「IT談話館」主筆の「豊田孝」はBlackHatなどのカンファレンスでプレゼンする海外の先端技術者に助言を与えています。時代が求める人材の育成と技術の習得には、「時間と予算の投資」が必要です。