系统调用002 KiSystemService函数逆向分析

前言

之前我们详细了解了API从三环进到零环的过程,API会通过两种方式进入到零环,如果通过中断门的方式进入零环,最终会进入到KiSystemService这个函数。接下来就来分析KiSystemService这个函数的内部实现细节。

用IDA打开ntkrnlpa.exe,找到KiSystemService函数

在这里插入图片描述

程序想要运行必须要有两样东西,分别是EIP和ESP。一旦进入零环,就需要把寄存器保存到一个结构体,这个结构体就是_KTRAP_FRAME,也就是零环的堆栈。

保存现场

_KTRAP_FRAME

_KTRAP_FRAME这个结构体由操作系统维护 数据如下所示:

kd> dt _KTRAP_FRAME
nt!_KTRAP_FRAME
   +0x000 DbgEbp           : Uint4B
   +0x004 DbgEip           : Uint4B
   +0x008 DbgArgMark       : Uint4B
   +0x00c DbgArgPointer    : Uint4B
   +0x010 TempSegCs        : Uint2B
   +0x012 Logging          : UChar
   +0x013 Reserved         : UChar
   +0x014 TempEsp          : Uint4B
   +0x018 Dr0              : Uint4B
   +0x01c Dr1              : Uint4B
   +0x020 Dr2              : Uint4B
   +0x024 Dr3              : Uint4B
   +0x028 Dr6              : Uint4B
   +0x02c Dr7              : Uint4B
   +0x030 SegGs            : Uint4B
   +0x034 SegEs            : Uint4B
   +0x038 SegDs            : Uint4B
   +0x03c Edx              : Uint4B
   +0x040 Ecx              : Uint4B
   +0x044 Eax              : Uint4B
   +0x048 PreviousPreviousMode : Uint4B
   +0x04c ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD
   +0x050 SegFs            : Uint4B
   +0x054 Edi              : Uint4B
   +0x058 Esi              : Uint4B
   +0x05c Ebx              : Uint4B
   +0x060 Ebp              : Uint4B
   +0x064 ErrCode          : Uint4B
   +0x068 Eip              : Uint4B
   +0x06c SegCs            : Uint4B
   +0x070 EFlags           : Uint4B
   +0x074 HardwareEsp      : Uint4B
   +0x078 HardwareSegSs    : Uint4B
   +0x07c V86Es            : Uint4B
   +0x080 V86Ds            : Uint4B
   +0x084 V86Fs            : Uint4B
   +0x088 V86Gs            : Uint4B

这个结构体的最后四个成员只有在虚拟8086模式下才会用到,保护模式下不用。

当API通过中断门进入到零环之前,ESP0指向+0x078 HardwareSegSs的这个位置。

接着,中断门提权后会将SS ESP EFlags CS和EIP压入堆栈。此时,ESP0指向+0x064 ErrCode的位置。

到这里,我们就知道了KiSystemService函数前几行汇编代码的含义:

.text:00465651                 push    0			   ; 保存ErrCode到esp0
.text:00465653                 push    ebp             ; 保存ebp到esp0
.text:00465654                 push    ebx             ; 保存ebx到esp0
.text:00465655                 push    esi             ; 保存esi到esp0
.text:00465656                 push    edi             ; 保存edi到esp0
.text:00465657                 push    fs              ; 保存fs到esp0

KRPC

接下来继续分析后面的代码

.text:00465659                 mov     ebx, 30h
.text:0046565E                 mov     fs, bx

这里将0x30赋值给FS寄存器,通过拆分0x30段选择子可以得到GDT表下标为6的段描述符:FFC093DF`F0000001。这个段描述符的基址为FFDFF0000,指向当前的KPCR结构体。

KPCR结构体如下所示:

kd> dt _KPCR
nt!_KPCR
   +0x000 NtTib            : _NT_TIB
   +0x000 Used_ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD
   +0x004 Used_StackBase   : Ptr32 Void
   +0x008 Spare2           : Ptr32 Void
   +0x00c TssCopy          : Ptr32 Void
   +0x010 ContextSwitches  : Uint4B
   +0x014 SetMemberCopy    : Uint4B
   +0x018 Used_Self        : Ptr32 Void
   +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 SpareUnused      : 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

KPCR叫CPU控制区(Kernel Processor Control Region),每个CPU有一个。如果想查看当前的CPU数量,可以用下面这条指令。

kd> dd KeNumberProcessors
83fb096c  00000001 83f3cf33 00000001 00000001
83fb097c  00000000 00000000 00000020 1fc10000
83fb098c  00110006 00003c03 776c7058 776c6f58
83fb099c  776c6fc0 776c7008 776b5a8f 776b5a8d
83fb09ac  776b5a64 00000000 00ce6126 842095b0
83fb09bc  841734f2 83ec4d9c 00000000 00000191
83fb09cc  83ec53e4 00000000 00000000 00000000
83fb09dc  00000000 83f236af 00000000 026b2372

我当前的虚拟机只有一个核,所以数量是1。用下面这条指令可以查看每个核对应的KPCR分别是什么

kd> dd KiProcessorBlock l2
8055a320 ffdff120 00000000

这个地址显示的是ffdff120,也就是KPCR偏移0x120的位置。KPCR偏移0x120的位置是 _KPRCB,可以理解为扩展的KPCR。

所以下面这两句代码执行完之后,FS就指向KPCR

.text:00465659                 mov     ebx, 30h
.text:0046565E                 mov     fs, bx          ; 使FS指向KPCR

ExceptionList

接下来继续向下分析

.text:00465661                 push    dword ptr ds:0FFDFF000h 
.text:00465667                 mov     dword ptr ds:0FFDFF000h, 0FFFFFFFFh 

这里将0FFDFF000h压入堆栈,也就是KPCR的结构体的第一个成员

+0x000 NtTib            : _NT_TIB

这个NtTib是个子结构体,这个子结构体很大

kd> dt _NT_TIB
nt!_NT_TIB
   +0x000 ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD
   +0x004 StackBase        : Ptr32 Void
   +0x008 StackLimit       : Ptr32 Void
   +0x00c SubSystemTib     : Ptr32 Void
   +0x010 FiberData        : Ptr32 Void
   +0x010 Version          : Uint4B
   +0x014 ArbitraryUserPointer : Ptr32 Void
   +0x018 Self             : Ptr32 _NT_TIB

这个结构体的第一个成员是ExceptionList

.text:00465661                 push    dword ptr ds:0FFDFF000h ; 保存老的ExceptionList到esp0
.text:00465667                 mov     dword ptr ds:0FFDFF000h, 0FFFFFFFFh ; 将新的ExceptionList赋值为-1

这两行代码首先保存老的ExceptionList,并将新的ExceptionList赋值为-1,。继续往下分析

.text:00465671                 mov     esi, ds:0FFDFF124h

_KTHREAD结构体

这里将0FFDFF124h保存到esi。KPCR偏移0x120的位置是_KPRCB

+0x120 PrcbData         : _KPRCB

继续查看一下_KPRCB结构体0x4的位置

kd> dt _KPRCB
nt!_KPRCB
   +0x000 MinorVersion     : Uint2B
   +0x002 MajorVersion     : Uint2B
   +0x004 CurrentThread    : Ptr32 _KTHREAD

CurrentThread是当前CPU所执行线程的_ETHREAD结构体,继续查看一下_ETHREAD结构体。

kd> dt _ETHREAD
nt!_ETHREAD
   +0x000 Tcb              : _KTHREAD

_ETHREAD结构体的第一个成员是_KTHREAD,所以下面这行代码的具体含义是将当前线程的_KTHREAD结构体保存到esi

.text:00465671                 mov     esi, ds:0FFDFF124h ; 将当前线程的_KTHREAD结构体保存到esi

继续往下分析

.text:00465677                 push    dword ptr [esi+140h]

这里将esi+140压入堆栈,esi指向_KTHREAD结构体,查看一下_KTHREAD0x140的位置

kd> dt _KTHREAD
nt!_KTHREAD
   +0x140 PreviousMode

先前模式

0x140的位置保存的是先前模式,先前模式的作用就是记录当前调用的这段代码之前是被零环调用还是被三环调用

.text:00465677                 push    dword ptr [esi+140h] ; 保存老的先前模式到esp0

抬高堆栈

继续往下分析

.text:0046567D                 sub     esp, 48h

回顾一下当前的堆栈情况

kd> dt _KTRAP_FRAME
nt!_KTRAP_FRAME
   +0x000 DbgEbp           : Uint4B
   +0x004 DbgEip           : Uint4B
   +0x008 DbgArgMark       : Uint4B
   +0x00c DbgArgPointer    : Uint4B
   +0x010 TempSegCs        : Uint2B
   +0x012 Logging          : UChar
   +0x013 Reserved         : UChar
   +0x014 TempEsp          : Uint4B
   +0x018 Dr0              : Uint4B
   +0x01c Dr1              : Uint4B
   +0x020 Dr2              : Uint4B
   +0x024 Dr3              : Uint4B
   +0x028 Dr6              : Uint4B
   +0x02c Dr7              : Uint4B
   +0x030 SegGs            : Uint4B
   +0x034 SegEs            : Uint4B
   +0x038 SegDs            : Uint4B
   +0x03c Edx              : Uint4B
   +0x040 Ecx              : Uint4B
   +0x044 Eax              : Uint4B
   +0x048 PreviousPreviousMode : Uint4B
   +0x04c ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD
   +0x050 SegFs            : Uint4B
   +0x054 Edi              : Uint4B
   +0x058 Esi              : Uint4B
   +0x05c Ebx              : Uint4B
   +0x060 Ebp              : Uint4B
   +0x064 ErrCode          : Uint4B
   +0x068 Eip              : Uint4B
   +0x06c SegCs            : Uint4B
   +0x070 EFlags           : Uint4B
   +0x074 HardwareEsp      : Uint4B
   +0x078 HardwareSegSs    : Uint4B
   +0x07c V86Es            : Uint4B
   +0x080 V86Ds            : Uint4B
   +0x084 V86Fs            : Uint4B
   +0x088 V86Gs            : Uint4B

通过前面的代码分析我们可以知道当前零环的堆栈已经压入了下面这些值

+0x048 PreviousPreviousMode : Uint4B
+0x04c ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD
+0x050 SegFs            : Uint4B
+0x054 Edi              : Uint4B
+0x058 Esi              : Uint4B
+0x05c Ebx              : Uint4B
+0x060 Ebp              : Uint4B
+0x064 ErrCode          : Uint4B

而除去已经压入堆栈的值,这个结构体正好剩下0x48个字节,sub,esp 0x48将当前的esp0指向_KTRAP_FRAME0x00的位置

.text:0046567D                 sub     esp, 48h        ; 将esp0指向_KTRAP_FRAME头

判断当前权限

继续往下分析

.text:00465680                 mov     ebx, [esp+68h+arg_0]
.text:00465684                 and     ebx, 1

这里将esp+0x68+4的值保存到ebx,当前的esp指向``_KTRAP_FRAME`头部,esp+6C的位置就是CS

+0x06c SegCs            : Uint4B

取出CS之后,和1做与运算。

如果是3环的CS段选择子,那么最后两个二进制位是11。11和1进行与运算结果还是1。

如果是0环的CS段选择子,那么最后两个二进制位是00。00和1进行与运算结果还是00。

这里实际上是通过与运算的结果来判断当前代码是三环还是零环。

.text:00465687                 mov     [esi+140h], bl  ; 赋值新的先前模式

接下来将bl赋值给esi+140h的位置,也就是之前分析过的先前模式

.text:0046568D                 mov     ebp, esp        ; ebp=esp=_KTRAP_FRAME

接下来上面这行代码执行完成之后ebp和esp都指向_KTRAP_FRAME结构体,继续往下分析

更新_KTRAP_FRAME

.text:0046568F                 mov     ebx, [esi+134h]

这里将esi+0x134的位置保存到ebx,esi指向的是_ETHREAD,查看一下 +0x134的位置保存的内容

+0x134 TrapFrame        : Ptr32 _KTRAP_FRAME

+0x134的位置保存的_KTRAP_FRAME结构体指针,_KTRAP_FRAME这个结构体以线程为单位保存在_ETHREAD结构体里面,每个线程都有一份。

.text:0046568F                 mov     ebx, [esi+134h] ; 保存_KTRAP_FRAME结构体到ebx
.text:00465695                 mov     [ebp+3Ch], ebx  ; 将KTHREAD中的_KTRAP_FRAME保存到[ebp+0x3C]

所以这一句的含义实际上是先将_KTRAP_FRAME结构体保存到ebx,然后再存到[ebp+0x3C]的位置。继续往下分析

.text:00465698                 mov     [esi+134h], ebp ; 更新当前线程的_KTRAP_FRAME

这里将ebp保存到[esi+134h],此时ebp指向_KTRAP_FRAME头部位置,而[esi+134h]也是_KTRAP_FRAME头,所以这行代码执行完,就会更新当前线程的_KTRAP_FRAME结构体。继续往下分析

保存三环的寄存器环境

.text:0046569F                 mov     ebx, [ebp+60h]
.text:004656A2                 mov     edi, [ebp+68h]

当前的ebp=esp指向了_KTRAP_FRAME头的位置,

kd> dt _KTRAP_FRAME
nt!_KTRAP_FRAME
   +0x060 Ebp              : Uint4B
   +0x064 ErrCode          : Uint4B
   +0x068 Eip              : Uint4B

[ebp+0x60]的位置是三环的ebp,[ebp+0x68]的位置是三环的eip,

.text:0046569F                 mov     ebx, [ebp+60h]  ; 取出三环的ebp放到ebx
.text:004656A2                 mov     edi, [ebp+68h]  ; 取出三环的eip放到edi
.text:004656A5                 mov     [ebp+0Ch], edx
.text:004656A8                 mov     dword ptr [ebp+8], 0BADB0D00h
.text:004656AF                 mov     [ebp+0], ebx    ; 将三环的ebp备份到_KTRAP_FRAME DbgEbp的位置
.text:004656B2                 mov     [ebp+4], edi    ; 将三环的eip备份到_KTRAP_FRAME DbgEip的位置
.text:004656B5                 test    byte ptr [esi+2Ch], 0FFh

这里先将三环的ebp和eip保存到寄存器,然后再备份到_KTRAP_FRAME结构体DbgEbp和DbgEip的位置。然后继续看中间两行代码

.text:004656A5                 mov     [ebp+0Ch], edx
.text:004656A8                 mov     dword ptr [ebp+8], 0BADB0D00h

这里将edx存到ebp+0xC的位置

kd> dt _KTRAP_FRAME
nt!_KTRAP_FRAME
   +0x000 DbgEbp           : Uint4B
   +0x004 DbgEip           : Uint4B
   +0x008 DbgArgMark       : Uint4B
   +0x00c DbgArgPointer    : Uint4B

ebp+0xC的位置是DbgArgPointer,那么这个edx是什么呢?这里要回顾之前学习的内容。三环进零环的两种方式,不管是哪一种,都会用到eax和edx两个寄存器,其中eax保存的是服务号,而edx存储的是三环的参数开始的位置。

.text:004656A5                 mov     [ebp+0Ch], edx  ; 将三环的参数指针存到DbgArgPointer
.text:004656A8                 mov     dword ptr [ebp+8], 0BADB0D00h ; 将DbgArgMark赋值为0BADB0D00

判断调试状态

那么这行汇编代码的作用就是将三环的参数指针存到DbgArgPointer,继续往下分析

.text:004656B5                 test    byte ptr [esi+2Ch], 0FFh
.text:004656B9                 jnz     Dr_kss_a

当前的esi指向KTHRAD结构体, [esi+2Ch]是位置是DebugActive,这个字段是调试状态,如果当前的线程处于调试状态,那么这里面的值不为零

+0x02C DebugActive

这里将DebugActive和FF做与运算,根据运算的结果决定是否跳转,那么这两句汇编的含义就很明显了

.text:004656B5                 test    byte ptr [esi+2Ch], 0FFh ; 判断KTHREAD结构体的DebugActive是否为零
.text:004656B9                 jnz     Dr_kss_a        ; 如果处于调试状态 跳转

到此,整个KiSystemService函数保存现场的部分就已经完成了。

FFh
.text:004656B9 jnz Dr_kss_a


当前的esi指向KTHRAD结构体, [esi+2Ch]是位置是DebugActive,这个字段是调试状态,如果当前的线程处于调试状态,那么这里面的值不为零

```assembly
+0x02C DebugActive

这里将DebugActive和FF做与运算,根据运算的结果决定是否跳转,那么这两句汇编的含义就很明显了

.text:004656B5                 test    byte ptr [esi+2Ch], 0FFh ; 判断KTHREAD结构体的DebugActive是否为零
.text:004656B9                 jnz     Dr_kss_a        ; 如果处于调试状态 跳转

到此,整个KiSystemService函数保存现场的部分就已经完成了。

发布了99 篇原创文章 · 获赞 89 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq_38474570/article/details/103652993