涨姿势系列之——内核环境下花式获得CSRSS进程id
这个是翻别人的代码时看到的,所以叫涨姿势系列。作者写了一个获取CSRSS进程PID的函数,结果我看了好久才看懂是这么一个作用。先放上代码
1 HANDLE GetCsrPid() 2 { 3 HANDLE Process, hObject; 4 HANDLE CsrId = (HANDLE)0; 5 OBJECT_ATTRIBUTES obj; 6 CLIENT_ID cid; 7 UCHAR Buff[0x100]; 8 POBJECT_NAME_INFORMATION ObjName = (PVOID)&Buff; 9 PSYSTEM_HANDLE_INFORMATION_EX Handles; 10 ULONG r; 11 12 Handles = GetInfoTable(SystemHandleInformation); 13 14 if (!Handles) return CsrId; 15 16 for (r = 0; r < Handles->NumberOfHandles; r++) 17 { 18 if (Handles->Information[r].ObjectTypeNumber == 21) //Port object 19 { 20 InitializeObjectAttributes(&obj, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); 21 22 cid.UniqueProcess = (HANDLE)Handles->Information[r].ProcessId; 23 cid.UniqueThread = 0; 24 25 if (NT_SUCCESS(NtOpenProcess(&Process, PROCESS_DUP_HANDLE, &obj, &cid))) 26 { 27 if (NT_SUCCESS(ZwDuplicateObject(Process, (HANDLE)Handles->Information[r].Handle,NtCurrentProcess(), &hObject, 0, 0, DUPLICATE_SAME_ACCESS))) 28 { 29 if (NT_SUCCESS(ZwQueryObject(hObject, ObjectNameInformation, ObjName, 0x100, NULL))) 30 { 31 if (ObjName->Name.Buffer && !wcsncmp(L"\\Windows\\ApiPort", ObjName->Name.Buffer, 20)) 32 { 33 CsrId = (HANDLE)Handles->Information[r].ProcessId; 34 } 35 } 36 37 ZwClose(hObject); 38 } 39 40 ZwClose(Process); 41 } 42 } 43 } 44 45 ExFreePool(Handles); 46 return CsrId; 47 }
作者干了以下这几件事:执行ZwQuerySystemInfo函数的第16号功能,这个第16号功能就是SystemHandleInformation,作用是获取句柄表。之前没用过这个功能号,MSDN上的页面也找不到了,找不到页面大概是因为这个函数现在已经不被支持了吧(Win8)。搜了半天找到了这个功能的结构
typedef struct _SYSTEM_HANDLE_INFORMATION_EX { ULONG NumberOfHandles; SYSTEM_HANDLE_INFORMATION Information[1]; }SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
typedef struct _SYSTEM_HANDLE_INFORMATION { ULONG ProcessId; UCHAR ObjectTypeNumber; UCHAR Flags; USHORT Handle; PVOID Object; ACCESS_MASK GrantedAccess; }SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
就是说每个句柄项都被解释成
- 句柄所属进程的PID
- 句柄对应对象的类型
- 句柄值(数字)
- 句柄对应的对象指针
这个函数查到句柄后,匹配所有的port对象的句柄。然后把这些句柄dump到本进程(因为只有这样才可以操作句柄),用ZwQueryObject查询port对象的名称,匹配\\Windows\\ApiPort,而这个port对象正是csrss进程创建的,也就说只有csrss进程的句柄表中才会有这个句柄,这样就实现了查找的csrss进程的目的。
其实我觉得不需要把句柄复制到自己的进程中了,因为已经有对象的指针了,可以直接获取对象名了。这个做法对我来说比较新鲜,即用句柄来查找进程。