ring0下的 fs:[124]

   反汇编内核函数的时候经常会看到mov eax, fs:[124].一直没弄清楚fs寄存器在ring0存放的是什么。今天查了下资料。

    fs寄存器在Ring0中指向一个称为KPCR的数据结构,即FS段的起点与KPCR结构对齐。而在Ring0中fs寄存器一般为0x30。

    这样看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  

    这样fs:[124]就指向KPRCB数据结构的第四个字节。由于KPRCB比较大,再此就不列出来了。查看其数据结构可以看到第四个字节指向CurrentThead(KTHREAD类型)。这样fs:[124]其实是指向当前线程的_KTHREAD。


===============================================================================================

应用实例:

以前看某些文章的时候,知道可以利用“活动进程链”隐藏或者检测进程。对于如何定位活动进程链一直没搞清楚,在看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 -r1
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)就是我们要找的活动进程链了。





你可能感兴趣的:(ring0下的 fs:[124])