【ハードウェア仮想化】カーネルの理想郷からは程遠い

【ハードウェア仮想化】カーネルの理想郷からは程遠い

導入

このストーリーでは、ハードウェア仮想化 (HVM) を使用して、独自のフック コードの一部をカーネルから遠ざけ、他のカーネル フックの影響を受けにくくし、検出を困難にする方法について説明します。この記事のアイデアは、学校の動的な Linux カーネル アップデートから生まれたもので、多くのコードは bluepill からコピーされています。

[[251619]]

第1章(アヴァロン)アヴァロンの夜明け

システムのコントロールをめぐる駆動力間の競争が激化するにつれ、カーネル内にクリーンなスペースはほとんどなくなります。インライン フック、ssdt フックなどのさまざまなフックが若いカーネルを埋め尽くします。複雑な構造を持つもの、相互接続されたもの、検出と監視機能を備えたものなどがあります。これらのコントロール ポイントの制御を取り戻したい場合は、それらのフックを研究するためにいくらかの労力を費やす必要があり、元々単純なフックがドミノ効果を引き起こすことになります。

今では、ハードウェア仮想化テクノロジーにより、考え方を変えてこれらの問題を解決できるようになりました...

1. (アバロン) アバロンの構成

(アバロン) アバロン本体は以下の部分で構成されています。

1. Avlboot.sys (初期化されたばかりでフックによって汚染されていないシステム カーネルを後で使用するために保存するために使用されます)

2. Avalon.sys (擬似カーネル情報の読み取り、ハードウェア仮想化の有効化、擬似カーネルのロードに使用)

3. XXX.sys (ユーザーが Avlboot.sys で提供される情報を使用して特定のフック操作を実行するプログラム)

2. (アバロン) アバロンの真実

この記事で紹介するAvalon(アバロン)は、仮想化をベースにしたカーネルローディングフレームワークです。ハードウェア仮想化 (HVM) とフックによって汚染されないカーネル メモリを使用して、PC 内で 2 つのカーネルを同時に実行できるようにします。そして、Avalon は、sysenter_eip と idt 内の疑似カーネルを指す対応するアドレスを制御することによって制御を獲得します。

つまり、(Avalon) Avalon はハードウェア仮想化 (HVM) を使用して独自のカーネルをロードし、元のカーネルを上書きすることで、検出されない環境でカーネルを制御できるようになります。

実装原理を下図に示します。


擬似カーネルのベース アドレスを取得したら、独自のフック プログラムで hookport を介して ssdt と shadow ssdt を処理できます (strongod はフックした ssdt をバックアップする必要があるため、少し面倒です。AGP はアドレスをオフセットするだけで使用できます)。

3. アバロンの応用

実際、Avalon は sysenter フック + idt フックを偽装したものと見なすことができます。

(Avalon) Avalon はハードウェア仮想化 (HVM) に基づいているため、カーネル全体をオーバーライドし、実行時にカーネルをリアルタイムで置き換え可能にすることができます。

擬似カーネルが配置されているメモリ範囲はメモリ監視の対象ではなく、他のプログラムが直接アクセスできないため、擬似カーネルは他の干渉問題を心配することなく自由にフックできる安全なユートピアになります。

このタイプのフックには、従来のフックに比べて次のような利点があります。

1. 従来のメモリ監視の範囲外であり、検出が困難です。

2. システム内のオリジナルフックコードに干渉せず、高い互換性を備えています。

しかし、いくつかの欠点もあります。

1. オブジェクトフック、irpフック、およびカーネルメモリに依存しないその他のフックコードに直接干渉できない

2. システム全体はハードウェア仮想化 (HVM) に依存しており、ハードウェア デバイスに対して特定の要件があります。

第2章: ビジョンは現実になる

1. 純粋な初期化

まず、Avalonの初期化を実装しましょう。初期化は、カーネル情報の取得、疑似カーネルの構築、IDT 情報の保存、元の SYSENTER_EIP の取得という 4 つの部分で構成されます。

実装コードは次のとおりです。

  1. NTSTATUS DriverEntry ( IN PDRIVER_OBJECT DriverObject、 IN PUNICODE_STRING RegistryPath)
  2. {
  3.  
  4. ...
  5.  
  6. KrnlCopy();
  7. IDTコピー();
  8. ReadMsrSysenter();
  9.  
  10. ...
  11.  
  12. }
  13.  
  14. /*
  15.  
  16. カーネルコピー
  17.  
  18. */
  19.  
  20. VOID KrnlCopy()
  21. {
  22. PVOID バッファ;
  23. ULONGサイズ;
  24. ULONG RetSize;
  25. PSYSTEM_MODULE_INFORMATION インフォバッファ;
  26. NTSTATUS ステータス;
  27. PVOID モジュールベース;
  28. ULONG モジュールサイズ;
  29.  
  30. サイズ= 0x1000;
  31.  
  32.  
  33. する {
  34. バッファ=ExAllocatePool(NonPagedPool,サイズ);
  35. ステータス=ZwQuerySystemInformation(SystemModuleInformation、バッファ、サイズ、&RetSize);
  36. (ステータス == STATUS_INFO_LENGTH_MISMATCH)の場合
  37. {
  38. ExFreePool(バッファ);
  39. サイズ= RetSize;
  40. }
  41. }while(ステータス == STATUS_INFO_LENGTH_MISMATCH);
  42.  
  43. InfoBuffer = (PSYSTEM_MODULE_INFORMATION) バッファ;
  44.  
  45.  
  46. ModuleBase=(PVOID)(InfoBuffer->ModuleInfo[0].Base);
  47. Orig_krnl=(ULONG)ModuleBase;
  48.  
  49. DbgPrint( "AvlBoot:Orig_krnl Base=%x\n" ,ModuleBase);
  50. ModuleSize=InfoBuffer->ModuleInfo[0] .Size ;
  51. makeKernelCopy((ULONG)ModuleBase,ModuleSize);
  52. DbgPrint( "AvlBoot:Avl_krnl Base=%x\n" ,Avl_krnl);
  53. ExFreePool(バッファ);
  54. }

初期化後、他のコンポーネントは Avlboot.sys にアクセスして疑似カーネル情報とカーネルのオリジナル情報を取得できます。

2. コピーされた仮想化

ここでは、Intel VT ハードウェア仮想化の手順を簡単に紹介します。

1. vt環境を確認する

2. vt機能を有効にする

3. 仮想マシンのステータスを保存するためにvtを入力します。

4. 傍受する必要がある項目を設定する

5. 仮想マシンを終了するときの戻りアドレスを設定する

6. 仮想マシンを起動し、傍受プロジェクトがトリガーされるのを待ちます。

7. 傍受プロジェクトが起動され、関連プロジェクトの処理ルーチンに入る

8. 仮想マシンを復元して実行を継続する

ここに少しトリッキーなコードがあります:

  1. /*
  2. Vmx 初期化
  3. */
  4. NTSTATUS NTAPI VmxInitialize (
  5. PCPU CPU、
  6. PVOIDゲストEip、
  7. PVOIDゲストEsp
  8. {
  9. PHYSICAL_ADDRESS が調整された VmcsPA;
  10. ULONG VaDelta;
  11. NTSTATUS ステータス;
  12.  
  13.  
  14. // VMXON領域にメモリスペースを割り当てる
  15. Cpu->Vmx.OriginaVmxonR = MmAllocateContiguousPages(
  16. VMX_VMXONR_SIZE_IN_PAGES、
  17. &Cpu->Vmx.OriginalVmxonRPA);
  18. (!Cpu->Vmx.OriginaVmxonR) の場合
  19. {
  20. DbgPrint( "VmxInitialize(): 元の VMCS にメモリを割り当てることができませんでした\n" );
  21. STATUS_INSUFFICIENT_RESOURCES を返します
  22. }
  23.  
  24. DbgPrint( "VmxInitialize(): OriginaVmxonR VA: 0x%x\n" 、 Cpu->Vmx.OriginaVmxonR);
  25. DbgPrint( "VmxInitialize(): OriginaVmxonR PA: 0x%llx\n" 、 Cpu->Vmx.OriginalVmxonRPA.QuadPart);
  26.  
  27. // VMCS のメモリ空間を申請する
  28. Cpu->Vmx.OriginalVmcs = MmAllocateContiguousPages(
  29. VMX_VMCS_SIZE_IN_PAGES、
  30. &Cpu->Vmx.OriginalVmcsPA);
  31. (!Cpu->Vmx.OriginalVmcs) の場合
  32. {
  33. DbgPrint( "VmxInitialize(): 元の VMCS にメモリを割り当てることができませんでした\n" );
  34. STATUS_INSUFFICIENT_RESOURCES を返します
  35. }
  36.  
  37. DbgPrint( "VmxInitialize(): Vmcs VA: 0x%x\n" 、 Cpu->Vmx.OriginalVmcs);
  38. DbgPrint( "VmxInitialize(): Vmcs PA: 0x%llx\n" 、 Cpu->Vmx.OriginalVmcsPA.QuadPart);
  39.  
  40. // vmx を有効にする
  41. if (!NT_SUCCESS (VmxEnable (Cpu->Vmx.OriginaVmxonR)))
  42. {
  43. DbgPrint( "VmxInitialize(): Vmx の有効化に失敗しました\n" );
  44. STATUS_UNSUCCESSFULを返します
  45. }
  46.  
  47. *((ULONG64 *)(Cpu->Vmx.OriginalVmcs)) =
  48. (MsrRead (MSR_IA32_VMX_BASIC) & 0xffffffff); // vmcs_revision_id を設定する
  49.  
  50. // VMCS構造体に記入する
  51. ステータス = VmxSetupVMCS (Cpu、GuestEip、GuestEsp);
  52. if (!NT_SUCCESS (ステータス))
  53. {
  54. DbgPrint( "VmxSetupVMCS() がステータス 0x%08hX\n で失敗しました" , Status);
  55. VmxDisable();
  56. ステータスを返します
  57. }
  58.  
  59. DbgPrint( "VmxInitialize(): Vmxが有効\n" );
  60.  
  61. // EFER を保存
  62. Cpu->Vmx.GuestEFER = MsrRead (MSR_EFER);
  63. DbgPrint( "ゲスト MSR_EFER 読み取り 0x%llx \n" 、 Cpu->Vmx.GuestEFER);
  64.  
  65. // 制御レジスタを保存する
  66. Cpu->Vmx.GuestCR0 = RegGetCr0();
  67. Cpu->Vmx.GuestCR3 = RegGetCr3();
  68. Cpu->Vmx.GuestCR4 = RegGetCr4();
  69.  
  70. CmCli();
  71. STATUS_SUCCESS を返します
  72. }
  73.  
  74.  
  75.  
  76. /*
  77. vmxを有効にする
  78. */
  79. NTSTATUS NTAPI VmxEnable (
  80. PVOID VmxonVA
  81. {
  82. ウロンcr4;
  83. ULONG64 vmxmsr;
  84. ULONG フラグ;
  85. 物理アドレス VmxonPA;
  86.  
  87. // VM モードを有効にするために cr4 ビットを設定します
  88. set_in_cr4 (X86_CR4_VMXE);
  89. cr4 = get_cr4();
  90. DbgPrint( "VmxEnable(): VmxEnable の後の CR4: 0x%llx\n" , cr4);
  91. もし (!(cr4 & X86_CR4_VMXE))
  92. STATUS_NOT_SUPPORTED を返します
  93.  
  94. // vmx がサポートされているかどうかを確認します
  95. vmxmsr = MsrRead (MSR_IA32_FEATURE_CONTROL);
  96. (!(vmxmsr & 4) の場合)
  97. {
  98. DbgPrint( "VmxEnable(): VMX はサポートされていません: IA32_FEATURE_CONTROL は 0x%llx\n です" , vmxmsr);
  99. STATUS_NOT_SUPPORTED を返します
  100. }
  101.  
  102. //bochs のバグ、IA32_FEATURE_CONTROL のロックを 1 に変更
  103. #if ボックデバッグ
  104. MSR_IA32_FEATURE_CONTROL 関数をオーバーライドします。
  105. #終了
  106.  
  107. MSR_IA32_VMX_BASIC の呼び出し。
  108. *((ULONG64 *) VmxonVA) = (vmxmsr & 0xffffffff); // vmcs_revision_id を設定する
  109. VmxonPA = MmGetPhysicalAddress (VmxonVA);
  110.  
  111. DbgPrint( "VmxEnable(): VmxonPA: 0x%llx\n" , VmxonPA.QuadPart);
  112.  
  113. // VMXを有効にする
  114. VmxTurnOn(VmxonPA);
  115. フラグ = RegGetEflags();
  116. DbgPrint( "VmxEnable(): vmcs_revision_id: 0x%x Eflags: 0x%x \n" , vmxmsr, flags);
  117.  
  118. STATUS_SUCCESS を返します
  119. }
  120.  
  121.  
  122.  
  123. /*
  124. 仮想マシンに入る
  125. */
  126. NTSTATUS NTAPI VmxVirtualize (
  127. PCPU CPU
  128. {
  129.  
  130. ULONG、特に;
  131. (!CPU)の場合
  132. STATUS_INVALID_PARAMETER を返します
  133.  
  134. *((PULONG) (g_HostStackBaseAddress + 0x0C00)) = (ULONG) CPU;
  135.            
  136. VmxLaunch();
  137.  
  138. // 決して返らない 
  139.  
  140. STATUS_UNSUCCESSFULを返します
  141. }

3. 面倒な傍受処理

sysenterの扱い方:

ハードウェア仮想化 (HVM) は sysenter 命令を直接インターセプトできないため、制御を取得するには他の方法しか使用できません。

これを行うには、次の 3 つの方法があります。

1. 割り込みまたは特権命令を使用して VM に入るには、kifastcallentery のヘッダーに cpuid、int3 などを書き込みます。

2. デバッグレジスタを使用してkifastcallenteryでハードウェア割り込みを実行し、その割り込みを使用してVMに入ります。

3. VMM に入った後、ゲストの sysenter_eip アドレスを直接変更し、msr の読み取りと書き込みを制御することで、msr にアクセスする他のプログラムを欺きます。

メモリ検出を回避し、デバッグ レジスタを最大限に活用するために、sysenter を実行した後、プロセスの実行方向を制御するために Avalon のソリューション 3 を選択しました。

コードの一部:

  1. 静的ブール型 NTAPI VmxDispatchMsrRead (
  2. PCPU CPU、
  3. PGUEST_REGS ゲスト登録、
  4. PNBP_TRAP トラップ、
  5. ブール型 WillBeAlsoHandledByGuestHv
  6. {
  7.  
  8. ...
  9.  
  10. スイッチ (ecx) {
  11. MSR_IA32_SYSENTER_CSの場合:
  12. MsrValue.QuadPart = VmxRead (GUEST_SYSENTER_CS);
  13. 壊す;
  14.  
  15. MSR_IA32_SYSENTER_ESPの場合:
  16. MsrValue.QuadPart = VmxRead (GUEST_SYSENTER_ESP);
  17. 壊す;
  18. MSR_IA32_SYSENTER_EIPの場合:
  19. MsrValue.QuadPart = Avlkrnlinfo->SysenterAddr;
  20.  
  21. ...
  22.  
  23. }

IDTリダイレクト処理方法:

1. IDTアドレスのなりすまし

2. IDTシミュレーション配信

最初のものは、sidt を傍受するスキームを指し、lidt 命令は偽造された idt アドレスを入力して訪問者を誤解させます (システムによる配信は比較的安定しています)。

2 番目の方法は、IDT の処理を​​シミュレートし、IDT を配信する独自​​のプログラムを作成することです。

最初のソリューションでは、特定のストレージ アドレスを分析するために逆アセンブリ エンジンを使用する必要があり、これが大きすぎるため、このバージョンの Avalon では 2 番目のソリューション、つまり idt シミュレーション配信を使用します。

コードの一部:

  1. 静的ブール型 NTAPI VmxDispatchException (
  2. PCPU CPU、
  3. PGUEST_REGS ゲスト登録、
  4. PNBP_TRAP トラップ、
  5. ブール型 WillBeAlsoHandledByGuestHv
  6.  
  7. {
  8.  
  9. ...
  10.  
  11. //SETP 7. EIPを設定する
  12.  
  13. if((uIntrInfo & 0xff) == 1){
  14. ComPrint( "VmxDispatchException():#BD ヒット /n" );
  15. VmxWrite(GUEST_RIP、Avlkrnlinfo->Fake_IDTMap[0]);
  16. }
  17. そうでない場合 ((uIntrInfo & 0xff) == 3){
  18. ComPrint( "VmxDispatchException():#BP ヒット /n" );
  19. VmxWrite(GUEST_RIP、Avlkrnlinfo->Fake_IDTMap[1]);}
  20.  
  21. ...
  22.  
  23. }

第3章 ユートピアの黄昏

1. (アバロン) アバロン検出

ハードウェア仮想化 (HVM) に基づくプログラムの場合、最初に思い浮かぶ方法は、ハードウェア仮想化を直接検出して対抗することです。

ハードウェア仮想化の主な検出は、efer 検出と vme 検出です。

割り込みを処理する vmm の場合は、割り込みの前後の時間差を計算することで仮想マシン内かどうかを判断することもできます。

もちろん、Avalonには他の検出方法もあります(xx文字は省略)

2. 今後のアップデート

Avalon はまだ始まったばかりで、その機能はまだ完成していません。追加したい機能がまだたくさんあります:

1. カーネルをEPT(NPT)に移動して、まったく見えないようにします。

2. ring3 プログラムとの対話...

3. その他の隠れた機能

要約する

Avalon は、ハードウェア仮想化アプリケーションの氷山の一角にすぎません。私たちが探索するのを待っているアプリケーションは他にもたくさんあります。私のレベルには限界があるので、今後も専門家のアドバイスを聞きながら頑張って勉強していきたいと思います。

ビンテスト環境は次のとおりです。

ボクサー2.4.5

ウィンドウズXP SP3

注: このビンは単なる単純なサンプルです。実機で実行する場合は青色で、ring0 の割り込みのみを対象とします。 ring3 には修正されていないバグが 3 つあります。

<<:  AWS がプライベートクラウドの空に残っていた最後の暗雲を吹き飛ばす

>>:  IT の進化を考察し、業界のデジタル変革を分析する | ITE 2018のハイライト

推薦する

WOT Shi Yang: IoT時代のインテリジェントエッジコンピューティング

[51CTO.com からのオリジナル記事] 7 年間の努力と見事な変貌。 2012年以降、6年連続...

キックオフ通知、WeChat赤い封筒1288元、50 1GメモリVPS、20香港VPS、20本物のRuisuなど。

ここにいる皆さんは、この活動が 2 年前に始まり、それがキックオフ活動であることをご存知でしょう。私...

vpsace - 4.75 ドル/Kvm/1g メモリ/25g ハードディスク/1.5T トラフィック/追加 IP 0.25 ドル/各

vpsaceは2011年に設立されました。コロクロッシングとの関係が曖昧だと言う人が多いようですが、...

JVM 全体のアーキテクチャとチューニングパラメータの説明

[[421897]]本日より、「Advanced Architect Series」の技術記事の更新...

ウェブサイトのトラフィックが多ければ多いほど良いです。正確なトラフィックが鍵となります。

ウェブサイトのトラフィックを増やすことは、多くの SEO 最適化担当者にとって常に究極の目標です。ウ...

SEOの成功は継続的な学習と探求から生まれる

私が初めて SEO について学んだのは、ボーイフレンドが、自分の Web サイトに外部リンクを貼り、...

広州の弁護士がiPhone 6sを広告法違反で訴え、2万元の損害賠償を請求

広州の弁護士である何干林氏は、iPhone 6sの広告スローガン「唯一の違いは、すべてが違うというこ...

タオバオはタオバオの顧客による商品検索サービスの利用を禁止しており、リベートサイトは存続できない可能性が高い

5月14日、Taobaoは最近規則を変更し、TaobaoのアプリケーションとツールがTaobaoの商...

クラウド コンピューティングを活用して IT 業界で環境の持続可能性を実現するにはどうすればよいでしょうか?

クラウド コンピューティング サービスは、主にエネルギー効率の向上と持続可能な慣行の促進を通じて、I...

ソーシャルメディアアーキテクチャのどの垂直分野がMeilishuoを再現できますか?

Meilishuoは、Weiboなどのソーシャルメディアを女性向けオンラインショッピングの分野に垂直...

Zhiqubaichuan: SCRMマーケティング自動化ソリューションのリーダー

[51CTO.com からのオリジナル記事] 大きな変動から利益を得ることは生物学の究極の能力です。...

「ファンを求める」から「いいねを求める」へ: いいねの背後にあるインターネット マーケティングの考え方の変化

親指を立てるまで、友達がどれだけ素晴らしいかはわかりません。WeChatモーメントで毎日どれだけの「...

病院のウェブサイト運営:特に注意が必要な4つの点

私は2年間SEO最適化とプロモーションの仕事に従事し、工業化学、生活サービス、ウェディング業界、医療...

ビリビリと西瓜動画、どちらも中国のYouTubeにはなれない

2018年6月20日、インターネット動画コラム「CamLogic」が最後の動画を更新しました。 「イ...