Protectet Process #2
前回の続き。保護されたプロセスは、そのプロセスやスレッドハンドルの取得の際に、特定のアクセス権での取得を禁止する。その結果、たとえば以下のアクションの対象にならない。
- リモートスレッドの作成
- 仮想メモリ空間へのアクセス
- アクティブな状態でのデバッガによるアタッチ
- スレッドコンテキストの取得や変更
というわけで今度は通常プロセスを保護状態に変更してみる。対象は PID=3904 Game.exe。
これでYouのGame.exeもProtectedだZE☆
おk、ドライバ。
すばらしい。
欲張ってPsSetCreateProcessNotifyRoutineに呼応して、起動時から必ず保護されるように実装してみたが、こちらはプロセスの起動に失敗するようになってしまった。適当な保護開始のタイミングはどこなのかな。
実装
前回から続く、Protected Process 操作の実装は EPROCESS 内の ProtectedProcess フラグを切り替えるだけだったりする。以下はEPROCESS構造体定義(の簡略版)。
#include <pshpack1.h> #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *) 0)->MEMBER) struct V6KRNL { struct EPROCESS { UCHAR Spare0[0x0a0]; _LIST_ENTRY ActiveProcessLinks; // +0x0a0 UCHAR Spare1[0x0a4]; char ImageFileName[16]; // +0x14c UCHAR Spare2[0x0c8]; union { ULONG Flags2; // +0x224 struct { ULONG JobNotReallyActive: 1; ULONG AccountingFolded: 1; ULONG NewProcessReported: 1; ULONG ExitProcessReported: 1; ULONG ReportCommitChanges: 1; ULONG LastReportMemory: 1; ULONG ReportPhysicalPageChanges: 1; ULONG HandleTableRundown: 1; ULONG NeedsHandleRundown: 1; ULONG RefTraceEnabled: 1; ULONG NumaAware: 1; ULONG ProtectedProcess: 1; // <- こいつな ULONG DefaultPagePriority: 3; ULONG PrimaryTokenFrozen: 1; ULONG ProcessVerifierTarget: 1; ULONG StackRandomizationDisabled: 1; }; }; UCHAR Spare3[0x034]; }; C_ASSERT(offsetof(EPROCESS, ActiveProcessLinks) == 0x0a0); C_ASSERT(offsetof(EPROCESS, ImageFileName) == 0x14c); C_ASSERT(offsetof(EPROCESS, Flags2) == 0x224); C_ASSERT(sizeof(EPROCESS) == 0x25c); }; #include <poppack.h>
very easy.
じつはユーザーモードのPEB構造体にも IsProtectedProcess というフラグが用意されている。以下はPEB構造体定義の一部抜粋。
typedef struct _PEB { BYTE Reserved1[2]; BYTE BeingDebugged; union { BYTE BitField; struct { BYTE ImageUsesLargePages: 1; BYTE IsProtectedProcess: 1; // <- こいつな BYTE IsLegacyProcess: 1; BYTE IsImageDynamicallyRelocated: 1; BYTE SkipPatchingUser32Forwarders: 1; BYTE SpareBits: 3; }; }; PVOID Reserved3[2]; // ... } PEB, *PPEB;
1 を設定すると確かに影響はあるらしいが、正確なところは未調査。少なくとも記事内のスクリーンショットはカーネル空間のフラグのみを操作している。EPROCESSのフラグとPEBのフラグは自動で同期しないっぽい。