[原创]PsLookupProcessByProcessId执行流程学习笔记
文章作者:sudami [[email]xiao_rui_119@163.com[/email]]信息来源:邪恶八进制信息安全团队([url]www.eviloctal.com[/url])
本来偶在学习内核线程调度的东西,发现里面有关于[b]HANDLE_TABLE[/b]的知识.于是参照[b]WRK[/b]把附带的一些东西深入学习了一下子--[b][color=#0000FF]关于PsLookupProcessByProcessId的执行流程[/color][/b][写点心得存档,供以后学习的同学参考.老鸟飘过~[s:267]]
[b]NtOpenProcess->PsLookupProcessByProcessId->ExMapHandleToPointer->ExpLookupHandleTableEntry[/b]
关于[b]RK[/b]和[b]ARK[/b],大概都很关注[b][color=#FF0066]PsLookupProcessByProcessId[/color][/b]吧.无论是HOOK还是DKOM,还是其他的,都先得把函数在底层的实现细节完全搞明白才行. so,the following may be helpful for you and me:
---->
进入PsLookupProcessByProcessId内,它有2个参数
[b] __in HANDLE ProcessId[/b], // 传进来进程ID
[b]__deref_out PEPROCESS *Process [/b] // 传出去进程的EPROCESS
首先使当前线程的内核APC无效,然后调用 [b]ExMapHandleToPointer[/b] 函数.它有2个参数
[b]__in PHANDLE_TABLE HandleTable[/b],
[b]__in HANDLE Handle[/b]
第1个参数传进来是全局变量 [b]PspCidTable [/b](它包含了系统所有进程的线程对象的指针);第2个参数传进来进程ID (它被赋予给 [b]EXHANDLE [/b]结构体中的 [b]GenericHandleOverlay[/b] 变量)
---->
进入此函数后,将进程ID加入到 EXHANDLE 结构体中,进行必要的检查,确保ID的有效性:
[attach]7101[/attach]
EXHANDLE 是一个[b]union[/b], 其中的 [b]Index[/b] 即是 GenericHandleOverlay 的低[b]30[/b]位.这个检查是确保 [b]2~10[/b]这[b]9[/b]位存在,[b]即3层表的0级的索引存在.[/b]
然后该函数调用[b] ExpLookupHandleTableEntry [/b]函数,同样为此函数传递上面的2个参数,不过此时的第2个参数已经转换成另一种形式----EXHANDLE结构了.此函数做的工作才是重点,它负责通过索引在这个句柄3层表中寻找到指定的进程对象
[color=#666666][关于它的内部实现细节及注释过程, 句柄3层表,一些结构体。见附件] [/color]
最终它返回一个 [b]HANDLE_TABLE_ENTRY [/b]的地址,里面的前4字节包含了指定进程的对象地址.
---->
返回到 ExMapHandleToPointer 函数中后,此函数获得控制权,便接着往下执行.它会调用
[b]ExpLockHandleTableEntry[/b] 来锁定当前的 handle table entry ([b]InterlockedCompareExchangePointer [/b]---->[b]InterlockedCompareExchange[/b]).如果不成功或者ExpLookupHandleTableEntry返回结果为0,则可能是进程句柄处于被调试状态, 通过 HANDLE_TABLE 结构中的 [b]DebugInfo [/b]来判断当前句柄是否处于被调试状态.
若是,则调用[b] ExpUpdateDebugInfo [/b]函数填充 [b]HANDLE_TRACE_DEBUG_INF[/b]O 结构体以保存当前的调试信息; 否则返回NULL,调用失败.
当函数调用成功时,便返回从ExpLookupHandleTableEntry得到的HANDLE_TABLE_ENTRY 的地址.
---->
这样就回到了PsLookupProcessByProcessId函数中,它将 HANDLE_TABLE_ENTRY 中的[b]Object[/b]转化为[b]EPROCESS[/b]类型,确保这个对象是[b]ProcessObject[/b]且有继承权限,将此对象的计数+1:
[attach]7100[/attach]
然后将此EPROCESS装入到参数2中, 解锁当前的handle table entry,恢复当前线程的内核APC,成功返回.
[attach]7099[/attach]
这个是用相机扫的图,用软件处理了下,懒得画了~~
[attach]7103[/attach]
-------------------------------------------------------------------------------------
这只是茫茫内核函数中的一个,相关联的还有比如很重要的[b][color=#0000FF]PspTerminateThreadByPointer[/color][/b],大家可以参照WRK、reactOS学习,对理解RK运用DKOM这些手段会有更进一步的印象了~ 顺便提一下:
用完 PsLookupProcessByProcessId 后记得要用 DereferenceObject 来减少引用计数
否则很可能BSOD
Win2k源码(private\ntos\ps\pscid.c)
[language=c]
NTSTATUS
PsLookupProcessByProcessId(
IN HANDLE ProcessId,
OUT PEPROCESS *Process
)
/*++
Routine Description:
This function accepts the process id of a process and returns a
referenced pointer to the process.
Arguments:
ProcessId - Specifies the Process ID of the process.
Process - Returns a referenced pointer to the process specified by the
process id.
Return Value:
STATUS_SUCCESS - A process was located based on the contents of
the process id.
STATUS_INVALID_PARAMETER - The process was not found.
--*/
{
PHANDLE_TABLE_ENTRY CidEntry;
PEPROCESS lProcess;
NTSTATUS Status;
CidEntry = ExMapHandleToPointer(PspCidTable, ProcessId);
Status = STATUS_INVALID_PARAMETER;
if (CidEntry != NULL) {
lProcess = (PEPROCESS)CidEntry->Object;
if (lProcess != (PEPROCESS)PSP_INVALID_ID && lProcess->Pcb.Header.Type == ProcessObject && lProcess->GrantedAccess ) {
ObReferenceObject(lProcess);
*Process = lProcess;
Status = STATUS_SUCCESS;
}
ExUnlockHandleTableEntry(PspCidTable, CidEntry);
}
return Status;
}
[/language]
是由代码中的这行:
ObReferenceObject(lProcess);
导致的。
XP中用的是ObReferenceObjectSafe
类似的还有PsLookupThreadByThreadId 哦。是啊,
XP下是ObReferenceObjectSafe
调用完后里面确实没有-1。
呵呵,谢谢提醒~
页:
[1]