この記事では、Windowsサブシステムの本物のプロセスを見つける方法を示します。たとえば、アクティブなプロセスのリストを取得しようとするときに便利です(この方法では、Windowsサブシステムで動作するプロセスのみを見つけることができますが、Windowsサブシステムに加えてサブシステムもありますPOSIXおよびOS / 2(これらはサポートされなくなったと言われるかもしれません)、
CSRSSの処理中のリストである
CSR_PROCESS構造をリストします。
CSRSSプロセスを見つける最も簡単な方法は、
PsActiveProcessHead (これは任意の
EPROCESS構造にある二重リンクリストの最上部へのポインターです)を使用し、
「csrss.exe」と呼ばれる最初のプロセスを検索することです。 -ルートキットモジュールの場合、このアルゴリズムは信頼できません(実際、どのような状況でも信頼できません)。 たとえば、ルートキットはプロセスのリストを(
DKOMを使用して)変更し、検出を回避できます。 したがって、より良いオプションを紹介したいと思います。
システムのブート中、
CSRSSプロセスを開始した後、多くの初期化タスクの中で、
CSRSSは
ApiPortと呼ばれる
ALPCポートも作成します。これにより、
CSRSSはそのAPIを実装します。
ApiPortポートを作成した直後に、
CSRSSは
CsrApiRequestThreadスレッドを作成し、次に
NtAlpcSendWaitReceivePortを呼び出して、ポートで待機するためのパラメーターとしてポートハンドルを渡します(クライアントが通信するのを待機します)。

図から
わかるように 、
ApiPortは
\ Windowsオブジェクトディレクトリの下にあります。 後続のセッションごとに新しい
CSRSSプロセスが作成されるため、各セッションの
ApiPortは
\ Sessions \ N \ Windowsディレクトリに既に作成され
ます 。
ALPCモデルを開発する際の明確なアーキテクチャ上の決定の1つは、サーバーポート(サーバーポート)を作成するプロセスのみがハンドルを受け取ることができ、
NtCreatePortを呼び出すことでそれを受け取ること
でした 。 したがって、
ApiPortにオープン記述子を持つ唯一のプロセスは
CSRSSです。
これらすべての議論の後、真の
CSRSSプロセスを識別するための一般的な手順を説明できます。
1.どういうわけか
ApiPortオブジェクトを取得します。
2.ポートへの開いたハンドルを持つプロセスを取得します。
ステップ1。すでに述べたように、
ObOpenObjectByNameプロシージャ
はALPCサーバー
ポートでは機能しません(他のすべてのタイプのポートは名前がないことに注意する価値があります)。
ALPCサーバー
ポートで
ObOpenObjectByNameを使用しようとすると、エラーコード
STATUS_NOT_IMPLEMENTEDが表示されます。 しかし、実際には私たちを助けることができる関数があります:
ObReferenceObjectByNameこの関数は文書化されていません、そのプロトタイプがあります:
NTKERNELAPI NTSTATUS ObReferenceObjectByName( __in PUNICODE_STRING ObjectName, __in ULONG Attributes, __in_opt PACCESS_STATE AccessState, __in_opt ACCESS_MASK DesiredAccess, __in POBJECT_TYPE ObjectType, __in KPROCESSOR_MODE AccessMode, __inout_opt PVOID ParseContext, __out PVOID *Object );
明らかに、最後のパラメーターはオブジェクトのアドレスを取得します。
ApiPortオブジェクトを取得するサンプルコード:
UNICODE_STRING apiport; PVOID pApiPort; NTSTATUS ret; RtlInitUnicodeString(&apiport,L"\\Windows\\ApiPort"); ret = ObReferenceObjectByName(&apiport,0,0,GENERIC_READ,*LpcPortObjectType,KernelMode,NULL,&pApiPort); DbgPrint("ObOpenObjectByName returned: %x\nOBJECT: %p",ret,pApiPort); if(!NT_SUCCESS(ret)) {
注!
LpcPortObjectType 、 LpcWaitablePortObjectType 、 AlpcPortObjectType-これらはすべて同じOBJECT_TYPE構造体を指しているため、どちらを使用するかは問題ではありませんステップ2。2番目のステップで何をする必要があるかを理解するには、最初にObject Managerの調査に少し飛び込む必要があります。
Object Managerによって作成された各オブジェクトの構造は次のとおりです。

オブジェクトヘッダー(OBJECT_HEADERS)は、「オブジェクトオプションヘッダー」と「オブジェクトヘッダー」で構成されます。オブジェクトヘッダーは、オブジェクトオプションヘッダーの直後にあります。
1.オブジェクトヘッダーは、_OBJECT_HEADER構造で表されます。
2.追加のオブジェクト見出しは、次の構造で表されます。
_OBJECT_HEADER_CREATOR_INFO 、
_OBJECT_HEADER_NAME_INFO 、
_OBJECT_HEADER_HANDLE_INFO 、
_OBJECT_HEADER_QUOTA_INFO 、
_OBJECT_HEADER_PROCESS_INFOどの追加ヘッダーが存在するかを判断するには、
_OBJECT_HEADER-> InfoMask構造体フィールドを使用します。 一般に、
InfoMaskは、ビットが追加ヘッダーの存在を検出するビットマスクです。
0x1
_OBJECT_HEADER_CREATOR_INFO0x2
_OBJECT_HEADER_NAME_INFO0x4
_OBJECT_HEADER_HANDLE_INFO0x8
_OBJECT_HEADER_QUOTA_INFO0x10
_OBJECT_HEADER_PROCESS_INFOInfoMaskは 、オブジェクトボディの先頭からの相対的な目的の追加ヘッダーのオフセットを取得するために使用される
ObpInfoMaskToOffset配列(エクスポートされない)でオフセットを計算するためにも使用されます。
BYTE HeaderOffset = ObpInfoMaskToOffset[_OBJECT_HEADER->InfoMask & (HeaderBit | (HeaderBit-1))].
さらに、追加のヘッダーは、示されているとおりに厳密に配置されます。

問題は、
ObpInfoMaskToOffsetがエクスポートされないことです。つまり、パターン検索を使用して取得するか、すでに持っている知識に基づいて変位を計算する独自の関数を実装することができます(さらに3つの方法があります:独自の配列
ObpInfoMaskToOffsetを実装します)。
2番目の方法を選択しました。
enum OBJ_HEADER_INFO_FLAG { HeaderCreatorInfoFlag = 0x1, HeaderNameInfoFlag = 0x2, HeaderHandleInfoFlag= 0x4, HeaderQuotaInfoFlag= 0x8, HeaderProcessInfoFlag= 0x10 }; BYTE GetObjectHeaderOffset( BYTE InfoMask,OBJ_HEADER_INFO_FLAG Flag) { BYTE OffsetMask,HeaderOffset=0; if( (InfoMask & Flag) == 0 ) return 0; OffsetMask = InfoMask & ( Flag | (Flag - 1) ); if((OffsetMask & HeaderCreatorInfoFlag) != 0) HeaderOffset += (BYTE)sizeof(OBJECT_HEADER_CREATOR_INFO); if((OffsetMask & HeaderNameInfoFlag) != 0) HeaderOffset += (BYTE)sizeof(OBJECT_HEADER_NAME_INFO); if((OffsetMask & HeaderHandleInfoFlag) != 0) HeaderOffset += (BYTE)sizeof(OBJECT_HEADER_HANDLE_INFO); if((OffsetMask & HeaderQuotaInfoFlag) != 0) HeaderOffset += (BYTE)sizeof(OBJECT_HEADER_QUOTA_INFO); if((OffsetMask & HeaderProcessInfoFlag) != 0) HeaderOffset += (BYTE)sizeof(OBJECT_HEADER_PROCESS_INFO); return HeaderOffset; } POBJECT_HEADER_HANDLE_INFO GetObjectHeaderHandleInfo(POBJECT_HEADER pObjHeader) {
ご覧のとおり、
GetObjectHeaderHandleInfo()も実装しました
。これは
、次のような
_OBJECT_HEADER_HANDLE_INFO構造が必要であることを示唆するものです。
typedef struct _OBJECT_HANDLE_COUNT_ENTRY // 3 elements, 0x10 bytes (sizeof) { PEPROCESS Process; struct // 2 elements, 0x4 bytes (sizeof) { ULONG32 HandleCount : 24;
_OBJECT_HEADER_HANDLE_INFOには 1つの要素が含まれます。これはunionであり、unionは2つのフィールド
HandleCountDataBase 、
SingleEntryで構成されます(_OBJECT_HEADER-> Flagは使用するフィールドを決定します)。 特に、
OB_FLAG_SINGLE_HANDLE_ENTRY (0x40)フラグは、SingleEntryフィールドを使用する必要があることを決定し、他の場合には、
HandleCountDataBaseを使用します(原則として、
ALPCポートオブジェクトには常にHandleCountDataBaseが使用されます).ALPCサーバーポートの場合、
HandleCountDataBaseには常に2つの要素が含まれます= )および2番目の要素は常にゼロになります。
コードの最後の部分は次のとおりです。
UNICODE_STRING apiport; POBJECT_HEADER pApiPortHeader; POBJECT_HEADER_HANDLE_INFO pHandleInfo; PVOID pApiPort; NTSTATUS ret; PEPROCESS procCSRSS; RtlInitUnicodeString(&apiport,L"\\Windows\\ApiPort"); ret = ObReferenceObjectByName(&apiport,0,0,GENERIC_READ,*LpcPortObjectType,KernelMode,NULL,&pApiPort); DbgPrint("ObOpenObjectByName returned: %x\nOBJECT: %p \nIndex: %d",ret,pApiPort,(*LpcPortObjectType)->Index); if(!NT_SUCCESS(ret)) DbgPrint("Can not reference ApiPort: %x",ret); pApiPortHeader = OBJECT_TO_OBJECT_HEADER(pApiPort); pHandleInfo = GetObjectHeaderHandleInfo(pApiPortHeader); DbgPrint("Handle Info:%p\nOBject:%p\nSIZEOF:%d",pHandleInfo,pApiPortHeader,sizeof(OBJECT_HEADER_NAME_INFO)); if(pHandleInfo != NULL) { if(pApiPortHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) procCSRSS = pHandleInfo->SingleEntry.Process; else procCSRSS = pHandleInfo->HandleCountDataBase->HandleCountEntries[0].Process; DbgPrint("CSRSS: %p",procCSRSS); } else { DbgPrint("Can not obtain Handle Info Header for ApiPort"); } ObDereferenceObject(pApiPort);
オブジェクトとオブジェクトヘッダーに関するこの大騒ぎはすべて、フィールドALPC_PORT-> OwnerProcessを使用することで回避できます( ObReferenceObjectByNameからALPC_PORTへのポインターを取得します)。 ALPC_PORTの構造を詳細に調べるのは面倒ですが、腎臓にぶつからないでください。 オブジェクトとオブジェクトヘッダーに関する資料はまだ有用だと思います。以上です!
リンク集
Windows 7オブジェクトヘッダー