本「
IT談話館」一般公開記事は、10年以上の実務経験を持つ上級Windowsエンジニアを想定しています。
本館は、Windowsカーネル深層を解析し、クラッシュ原因をはじめとするシステム内の「異様な動き」を検出・分析する
超高度な技術と実績を保有しています。
Windows XP/7/8/10の割り込みテーブル(IDT)解析
本「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 10環境で採取されたカーネルメモリダンプを本「IT談話館」の独自解析コードで解析し、通常、IDTと略称されている「割り込みテーブル」を解析します。IDTは割り込み記述テーブルや割り込みディスパッチテーブルなどと呼ばれることもありますが、本稿では、「割り込みテーブル」と総称します。
Windows 10の「割り込みテーブル」はWindows 8.1からWindows 10へのバージョンアップ過程におけるカーネル内部仕様の変更の影響を受けているため、XPから8.0までの解析技術は適応できません。そこで、本館は次のような視点からバージョンアップ後のカーネル仕様を解析し、Windows 10の「割り込みテーブル」解析に適応できる解析コードを独自に開発しました。この解析コードは、実は、Windows 11の「割り込みテーブル」解析にそのまま適応できます。
- Microsoft社はCPUやAPICをはじめとするICチップのメーカーではない
- 従って、同社はICチップとの接点部分を極端には変更できない
- また、同社エンジニアーのカーネル実装テクニックには特徴がある
「割り込みテーブル」を解析する場合、多くの方はWinDbgに内蔵されている「!idt」拡張コマンドを次のように実行していると思います。
1: kd> vertarget
Windows 10 Kernel Version 10240 MP (2 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 10240.16393.amd64fre.th1_st1.150717-1719
Machine Name:
Kernel base = 0xfffff802`2941a000 PsLoadedModuleList = 0xfffff802`2973f030
Debug session time: Mon Aug 3 17:16:15.086 2015 (UTC + 9:00)
System Uptime: 0 days 1:19:12.780
1: kd> !idt 35
Dumping IDT: ffffd0015cc628b0
35: fffff80229569178 hal!HalpInterruptCmciService (KINTERRUPT fffff80229cb84e0)
この実行結果は次のようなことを示しています。
- 割り込みテーブルはメモリ「 ffffd0015cc628b0」に置かれている
- 割り込みベクターは「35」である
- 割り込みオブジェクトはメモリ「fffff80229cb84e0」に置かれている
- 割り込み時には「 hal!HalpInterruptCmciService」ルーチンに制御が移る
割り込みオブジェクトがメモリ「fffff80229cb84e0」に実際に置かれているのかどうかを確認してみます。
1: kd> dt nt!_kinterrupt fffff80229cb84e0
+0x000 Type : 0n22
+0x002 Size : 0n256
+0x008 InterruptListEntry : _LIST_ENTRY [ 0x00000000`00000000 - 0x00000000`00000000 ]
+0x018 ServiceRoutine : 0xfffff802`29c953b0 unsigned char hal!HalpInterruptCmciService+0
+0x020 MessageServiceRoutine : (null)
+0x028 MessageIndex : 0
+0x030 ServiceContext : (null)
+0x038 SpinLock : 0
+0x040 TickCount : 0
+0x048 ActualLock : 0xffffffff`ffffffff -> ??
+0x050 DispatchAddress : 0xfffff802`295687f0 void nt!KiInterruptDispatchNoLock+0
+0x058 Vector : 0x35
+0x05c Irql : 0x5 ''
+0x05d SynchronizeIrql : 0x5 ''
+0x05e FloatingSave : 0 ''
+0x05f Connected : 0x1 ''
+0x060 Number : 1
+0x064 ShareVector : 0 ''
+0x065 EmulateActiveBoth : 0 ''
+0x066 ActiveCount : 0
+0x068 InternalState : 0n0
+0x06c Mode : 1 ( Latched )
+0x070 Polarity : 0 ( InterruptPolarityUnknown )
+0x074 ServiceCount : 0
+0x078 DispatchCount : 0
+0x080 PassiveEvent : (null)
+0x088 TrapFrame : (null)
+0x090 DisconnectData : (null)
+0x098 ServiceThread : (null)
+0x0a0 ConnectionData : (null)
+0x0a8 IntTrackEntry : (null)
+0x0b0 IsrDpcStats : _ISRDPCSTATS
+0x0f0 RedirectObject : (null)
+0x0f8 Padding : [8] ""
ご覧のように、このオブジェクト内には割り込みサービスルーチン名などが記録されています。Microsoft社の担当エンジニアーは、このような割り込みオブジェクトを設計し、割り込みテーブル経由で、割り込みベクターと割り込みオブジェクトをマッピングすることになります。Windows 8.1からWindows 10への遷移過程では、セキュリティーを強化し、かつ、パフォーマンスを改善する観点から、割り込みベクターと割り込みオブジェクトをマッピングするための専用の内部関数が追加実装されています。本IT談話館は追加実装背景を解析し、マッピングメカニズムの解明に成功しています。
割り込みテーブルから割り込みオブジェクトにアクセスする経路が分かれば、残っているのは割り込みオブジェクト内容そのものの解析作業です。この解析作業は、いろいろな意味で、カーネル空間解析者の最も重要な作業となります。上の割り込みオブジェクト情報には、たとえば、「Irql」フィールドがありますから、すべての割り込みオブジェクトの「Irql」フィールド値を取得してみます。
-No.00 Idt->0xFFFFF8022956EE00 nt!KiDivideErrorFault (fffff802`2956ee00)
-No.01 Idt->0xFFFFF8022956EF00 nt!KiDebugTrapOrFault (fffff802`2956ef00)
-No.02 Idt->0xFFFFF8022956F0C0 nt!KiNmiInterrupt (fffff802`2956f0c0)
-No.03 Idt->0xFFFFF8022956F440 nt!KiBreakpointTrap (fffff802`2956f440)
-No.04 Idt->0xFFFFF8022956F540 nt!KiOverflowTrap (fffff802`2956f540)
-No.05 Idt->0xFFFFF8022956F640 nt!KiBoundFault (fffff802`2956f640)
-No.06 Idt->0xFFFFF8022956F8C0 nt!KiInvalidOpcodeFault (fffff802`2956f8c0)
-No.07 Idt->0xFFFFF8022956FB00 nt!KiNpxNotAvailableFault (fffff802`2956fb00)
-No.08 Idt->0xFFFFF8022956FBC0 nt!KiDoubleFaultAbort (fffff802`2956fbc0)
-No.09 Idt->0xFFFFF8022956FC80 nt!KiNpxSegmentOverrunAbort (fffff802`2956fc80)
-No.0A Idt->0xFFFFF8022956FD40 nt!KiInvalidTssFault (fffff802`2956fd40)
-No.0B Idt->0xFFFFF8022956FE00 nt!KiSegmentNotPresentFault (fffff802`2956fe00)
-No.0C Idt->0xFFFFF8022956FF40 nt!KiStackFault (fffff802`2956ff40)
-No.0D Idt->0xFFFFF80229570080 nt!KiGeneralProtectionFault (fffff802`29570080)
-No.0E Idt->0xFFFFF80229570180 nt!KiPageFault (fffff802`29570180)
-No.10 Idt->0xFFFFF80229570540 nt!KiFloatingErrorFault (fffff802`29570540)
-No.11 Idt->0xFFFFF802295706C0 nt!KiAlignmentFault (fffff802`295706c0)
-No.12 Idt->0xFFFFF802295707C0 nt!KiMcheckAbort (fffff802`295707c0)
-No.13 Idt->0xFFFFF80229570E40 nt!KiXmmException (fffff802`29570e40)
-No.1F Idt->0xFFFFF8022956A2F0 nt!KiApcInterrupt (fffff802`2956a2f0)
-No.20 Idt->0xFFFFF8022956E4D0 nt!KiSwInterrupt (fffff802`2956e4d0)
-No.29 Idt->0xFFFFF80229571000 nt!KiRaiseSecurityCheckFailure (fffff802`29571000)
-No.2C Idt->0xFFFFF80229571100 nt!KiRaiseAssertion (fffff802`29571100)
-No.2D Idt->0xFFFFF80229571200 nt!KiDebugServiceTrap (fffff802`29571200)
-No.2F Idt->0xFFFFF8022956A5C0 nt!KiDpcInterrupt (fffff802`2956a5c0)
-No.30 Idt->0xFFFFF8022956A7F0 nt!KiHvInterrupt (fffff802`2956a7f0)
-No.31 Idt->0xFFFFF8022956AB50 nt!KiVmbusInterrupt0 (fffff802`2956ab50)
-No.32 Idt->0xFFFFF8022956AEA0 nt!KiVmbusInterrupt1 (fffff802`2956aea0)
-No.33 Idt->0xFFFFF8022956B1F0 nt!KiVmbusInterrupt2 (fffff802`2956b1f0)
-No.34 Idt->0xFFFFF8022956B540 nt!KiVmbusInterrupt3 (fffff802`2956b540)
+No.35 Idt->0xFFFFF80229569178 Vector->35 KInterrupt->0xFFFFF80229CB84E0 Irql->05
+No.50 Idt->0xFFFFF80229569250 Vector->50 KInterrupt->0xFFFFD00158544C80 Irql->05
+No.61 Idt->0xFFFFF802295692D8 Vector->61 KInterrupt->0xFFFFD00158A893C0 Irql->06
+No.70 Idt->0xFFFFF80229569350 Vector->70 KInterrupt->0xFFFFD00158A89C80 Irql->07
+No.71 Idt->0xFFFFF80229569358 Vector->71 KInterrupt->0xFFFFD00158A89A00 Irql->07
+No.80 Idt->0xFFFFF802295693D0 Vector->80 KInterrupt->0xFFFFD00158A89DC0 Irql->08
+No.81 Idt->0xFFFFF802295693D8 Vector->81 KInterrupt->0xFFFFD00158A89B40 Irql->08
+No.91 Idt->0xFFFFF80229569458 Vector->91 KInterrupt->0xFFFFD00158544140 Irql->09
+No.A1 Idt->0xFFFFF802295694D8 Vector->A1 KInterrupt->0xFFFFD0015B218A00 Irql->0A
+No.B0 Idt->0xFFFFF80229569550 Vector->B0 KInterrupt->0xFFFFD00158544DC0 Irql->0B
+No.B1 Idt->0xFFFFF80229569558 Vector->B1 KInterrupt->0xFFFFD00158544000 Irql->0B
+No.B8 Idt->0xFFFFF80229569590 Vector->B8 KInterrupt->0xFFFFD00158544B40 Irql->0B
+No.B9 Idt->0xFFFFF80229569598 Vector->B9 KInterrupt->0xFFFFD00158544A00 Irql->0B
+No.BA Idt->0xFFFFF802295695A0 Vector->BA KInterrupt->0xFFFFD001585448C0 Irql->0B
+No.BB Idt->0xFFFFF802295695A8 Vector->BB KInterrupt->0xFFFFD00158544780 Irql->0B
+No.BC Idt->0xFFFFF802295695B0 Vector->BC KInterrupt->0xFFFFD00158544640 Irql->0B
+No.BD Idt->0xFFFFF802295695B8 Vector->BD KInterrupt->0xFFFFD00158544500 Irql->0B
+No.BE Idt->0xFFFFF802295695C0 Vector->BE KInterrupt->0xFFFFD001585443C0 Irql->0B
+No.BF Idt->0xFFFFF802295695C8 Vector->BF KInterrupt->0xFFFFD00158544280 Irql->0B
+No.CE Idt->0xFFFFF80229569640 Vector->CE KInterrupt->0xFFFFE00150290100 Irql->0C
+No.D2 Idt->0xFFFFF80229569660 Vector->D2 KInterrupt->0xFFFFE00150290200 Irql->0D
+No.D7 Idt->0xFFFFF80229569688 Vector->D7 KInterrupt->0xFFFFF80229CB87E0 Irql->0F
+No.D8 Idt->0xFFFFF80229569690 Vector->D8 KInterrupt->0xFFFFF80229CB86E0 Irql->0F
+No.DF Idt->0xFFFFF802295696C8 Vector->DF KInterrupt->0xFFFFF80229CB85E0 Irql->0F
-No.E1 Idt->0xFFFFF8022956B890 nt!KiIpiInterrupt (fffff802`2956b890)
+No.E2 Idt->0xFFFFF802295696E0 Vector->E2 KInterrupt->0xFFFFF80229CB88E0 Irql->0F
+No.E3 Idt->0xFFFFF802295696E8 Vector->E3 KInterrupt->0xFFFFE00150290000 Irql->0E
+No.FE Idt->0xFFFFF802295697C0 Vector->FE KInterrupt->0xFFFFF80229CB89E0 Irql->0F
この実行結果からは、次のようなことを知ることができます。
- Irqlは割り込みベクター値を基に作られる
- 割り込みテーブルインデックスは割り込みベクターを示している
- 0から34までの割り込みテーブルインデックスはOS内部処理(トラップ)ルーチンを示している
- 0から4までのIrqlはソフトウェア(OS)割り込み処理ルーチンを示している
このような基本解析作業の終了後は、独自解析コード内に割り込みオブジェクトの詳細解析ルーチンを次々に追加し、割り込みに起因する問題を解決するための本格的な準備作業に入ります。「Irql」フィールド値はWindowsシステムの健康度を診断する上では極めて重要な情報です。