PsGetCurrentProcess为什么能定位活动进程链

 

以前看某些文章的时候,知道可以利用“活动进程链”隐藏或者检测进程。对于如何定位活动进程链一直没搞清楚,在看Rootkit那本书上说,通过PsGetCurrentProcess函数可以获得EPROCESS,但是书中解释的很模糊,一直没看明白。
今天利用WinDbg查看了各个结构,终于把疑问搞清楚了。
PsGetCurrentProcess函数反汇编后是这样:

lkd> u nt!PsGetCurrentProcess
nt!PsGetCurrentProcess:
8052b52c 64a124010000         mov          eax,dword ptr fs:[00000124h]
8052b532 8b4044                   mov          eax,dword ptr [eax+44h]
8052b535 c3                          ret


在用户模式下,FS指向TEB结构,而在内核模式下FS却指向KPCR(Kernel's Processor Control Region)结构。那么可以看到FS:[0x120]处就是KPRCB(Kernel's Processor Cotrol Block)结构(看下图红色高亮处)

lkd> dt nt!_kpcr
nt!_KPCR
        +0x000 NtTib                 : _NT_TIB
        +0x01c SelfPcr               : Ptr32 _KPCR
        +0x020 Prcb                  : Ptr32 _KPRCB
        +0x024 Irql                  : UChar
        +0x028 IRR                   : Uint4B
        +0x02c IrrActive             : Uint4B
        +0x030 IDR                   : Uint4B
        +0x034 KdVersionBlock        : Ptr32 Void
        +0x038 IDT                   : Ptr32 _KIDTENTRY
        +0x03c GDT                   : Ptr32 _KGDTENTRY
        +0x040 TSS                   : Ptr32 _KTSS
        +0x044 MajorVersion          : Uint2B
        +0x046 MinorVersion          : Uint2B
        +0x048 SetMember             : Uint4B
        +0x04c StallScaleFactor : Uint4B
        +0x050 DebugActive           : UChar
        +0x051 Number                : UChar
        +0x052 Spare0                : UChar
        +0x053 SecondLevelCacheAssociativity : UChar
        +0x054 VdmAlert              : Uint4B
        +0x058 KernelReserved        : [14] Uint4B
        +0x090 SecondLevelCacheSize : Uint4B
        +0x094 HalReserved           : [16] Uint4B
        +0x0d4 InterruptMode         : Uint4B
        +0x0d8 Spare1                : UChar
        +0x0dc KernelReserved2       : [17] Uint4B
   +0x120 PrcbData              : _KPRCB

展开KPRCB结构继续观察可以看到FS:[0x124]指向了KTHREAD结构

lkd> dt nt!_kprcb
nt!_KPRCB
        +0x000 MinorVersion          : Uint2B
        +0x002 MajorVersion          : Uint2B
   +0x004 CurrentThread         : Ptr32 _KTHREAD
        +0x008 NextThread            : Ptr32 _KTHREAD
        +0x00c IdleThread            : Ptr32 _KTHREAD
......本结构更多成员省略

继续查看KTHREAD结构可以看到KTHREAD+0x44处成员就是KPROCESS指针

lkd> dt nt!_kthread -v -r
Matched nt!_KTHREAD
nt!_KTHREAD
struct _KTHREAD, 73 elements, 0x1c0 bytes
        +0x000 Header                : struct _DISPATCHER_HEADER, 6 elements, 0x10 bytes
           +0x000 Type                  : UChar
           +0x001 Absolute              : UChar
           +0x002 Size                  : UChar
           +0x003 Inserted              : UChar
           +0x004 SignalState           : Int4B
           +0x008 WaitListHead          : struct _LIST_ENTRY, 2 elements, 0x8 bytes
              +0x000 Flink                 : Ptr32 to struct _LIST_ENTRY, 2 elements, 0x8 bytes
              +0x004 Blink                 : Ptr32 to struct _LIST_ENTRY, 2 elements, 0x8 bytes
        +0x010 MutantListHead        : struct _LIST_ENTRY, 2 elements, 0x8 bytes
           +0x000 Flink                 : Ptr32 to struct _LIST_ENTRY, 2 elements, 0x8 bytes
              +0x000 Flink                 : Ptr32 to struct _LIST_ENTRY, 2 elements, 0x8 bytes
              +0x004 Blink                 : Ptr32 to struct _LIST_ENTRY, 2 elements, 0x8 bytes
           +0x004 Blink                 : Ptr32 to struct _LIST_ENTRY, 2 elements, 0x8 bytes
              +0x000 Flink                 : Ptr32 to struct _LIST_ENTRY, 2 elements, 0x8 bytes
              +0x004 Blink                 : Ptr32 to struct _LIST_ENTRY, 2 elements, 0x8 bytes
        +0x018 InitialStack          : Ptr32 to Void
        +0x01c StackLimit            : Ptr32 to Void
        +0x020 Teb                   : Ptr32 to Void
        +0x024 TlsArray              : Ptr32 to Void
        +0x028 KernelStack           : Ptr32 to Void
        +0x02c DebugActive           : UChar
        +0x02d State                 : UChar
        +0x02e Alerted               : [2] UChar
        +0x030 Iopl                  : UChar
        +0x031 NpxState              : UChar
        +0x032 Saturation            : Char
        +0x033 Priority              : Char
  +0x034 ApcState              : struct _KAPC_STATE, 5 elements, 0x18 bytes
           +0x000 ApcListHead           : [2] struct _LIST_ENTRY, 2 elements, 0x8 bytes
              +0x000 Flink                 : Ptr32 to struct _LIST_ENTRY, 2 elements, 0x8 bytes
              +0x004 Blink                 : Ptr32 to struct _LIST_ENTRY, 2 elements, 0x8 bytes
       +0x010 Process               : Ptr32 to struct _KPROCESS, 29 elements, 0x6c bytes

至此,我们已经搞清了PsGetCurrentProcess的流程
通过查DDK DOC发现MS对PsGetCurrentProcess函数是这样描述的:

PsGetCurrentProcess returns a pointer to the process of the current thread.
PEPROCESS
       PsGetCurrentProcess(
         );

该函数的返回值是EPROCESS指针。但是我们分析的结果是函数的返回值是KPROCESS的指针。
这样的话难道PsGetCurrentProcess 函数返回值既是EPROCESS的指针又是KPROCESS的指针?
带着疑问我们继续往下看:

lkd> dt nt!_eprocess
nt!_EPROCESS
   +0x000 Pcb                   : _KPROCESS
        +0x06c ProcessLock           : _EX_PUSH_LOCK
        +0x070 CreateTime            : _LARGE_INTEGER
        +0x078 ExitTime              : _LARGE_INTEGER
        +0x080 RundownProtect        : _EX_RUNDOWN_REF
   +0x084 UniqueProcessId       : Ptr32 Void
        +0x088 ActiveProcessLinks : _LIST_ENTRY

可以看到EPROCESS的第一个成员就是KPROCESS,这样我们就明白了为什么PsGetCurrentProcess 函数返回值既是EPROCESS的地址又是KPROCESS的地址了。在EPROCESS偏移0x84是进程的PID,偏移0x88(我的系统是XP SP2)就是我们要找的活动进程链了。

以上是我今天学习的一些收获,如果大家认为有哪些不对的地方,请指正。

你可能感兴趣的:(process)