古月不傲 发表于 2020-3-10 01:19

系统调用和返回

本帖最后由 古月不傲 于 2020-3-10 03:03 编辑

_KiFastCallEntry:
.text:0046A520 ; PAE模式 系统调用必经之路
.text:0046A520
.text:0046A520 _KiFastCallEntry proc near            ; DATA XREF: KiLoadFastSyscallMachineSpecificRegisters(x)+24↑o
.text:0046A520                                       ; _KiTrap01+74↓o
.text:0046A520
.text:0046A520 Eflags_IF       = byte ptr -0Bh
.text:0046A520
.text:0046A520 ; FUNCTION CHUNK AT .text:0046A4ED SIZE 00000026 BYTES
.text:0046A520 ; FUNCTION CHUNK AT .text:0046A7C0 SIZE 00000014 BYTES
.text:0046A520
.text:0046A520               mov   ecx, 23h
.text:0046A525               push    30h
.text:0046A527               pop   fs            ; fs:30
.text:0046A529               mov   ds, ecx         ; ds:23
.text:0046A52B               mov   es, ecx         ; es:23
.text:0046A52D               mov   ecx, large fs:40h ; kpcr->ktss
.text:0046A534               mov   esp,     ; ktss->esp0 指向 _KTRAP_FRAME->+0x07c V86Es
.text:0046A537               push    23h             ; KTRAP_FRAME->HardwareSegSs
.text:0046A539               push    edx             ; KTRAP_FRAME->HardwareEsp 3环栈顶
.text:0046A53A               pushf                   ; KTRAP_FRAME->EFlags
.text:0046A53B
.text:0046A53B loc_46A53B:                           ; CODE XREF: _KiFastCallEntry2+23↑j
.text:0046A53B               push    2               ; KTRAP_FRAME->SegCs 暂存 2
.text:0046A53D               add   edx, 8          ; 3环第一个参数
.text:0046A540               popf                  ; KTRAP_FRAME->EFlags = 2
.text:0046A541               or      , 2 ; Eflags IF位置1 允许开启中断
.text:0046A546               push    1Bh             ; KTRAP_FRAME->SegCs
.text:0046A548               push    dword ptr ds:0FFDF0304h ; KTRAP_FRAME->Eip 3环Eip 返回地址
.text:0046A54E               push    0               ; KTRAP_FRAME->ErrCode
.text:0046A550               push    ebp             ; KTRAP_FRAME->Ebp
.text:0046A551               push    ebx             ; KTRAP_FRAME->Ebx
.text:0046A552               push    esi             ; KTRAP_FRAME->Esi
.text:0046A553               push    edi             ; KTRAP_FRAME->Edi
.text:0046A554               mov   ebx, large fs:1Ch ; 取出SEH 结构化异常链表
.text:0046A55B               push    3Bh             ; KTRAP_FRAME->SegFs
.text:0046A55D               mov   esi, ; kpcr->kprcb->_KTHREAD 当前CPU正在执行的线程
.text:0046A563               push    dword ptr ; KTRAP_FRAME->ExceptionList
.text:0046A565               mov   dword ptr , 0FFFFFFFFh ; 清除 SEH
.text:0046A56B               mov   ebp, ; 得到当前内核栈底
.text:0046A56E               push    1               ; KTRAP->FRAME->PreviousPreviousMode CPU先前模式 3环
.text:0046A570               sub   esp, 48h      ; 调整栈顶 指向KTRAP_FRAME +0x00
.text:0046A573               sub   ebp, 29Ch       ; 浮点堆栈大小+Ktrap->frame 大小
.text:0046A573                                       ; 让当前内核线程栈底 指向KTRAP_FRAME +0x00
.text:0046A573                                       ; 这样就达到了通过堆栈方式 访问3环的 数据
.text:0046A579               mov   byte ptr , 1 ; kthread->PreviousMode 设置先前模式 为3环
.text:0046A580               cmp   ebp, esp      ; 堆栈检查
.text:0046A582               jnz   short 跳到6号中断门
.text:0046A584               and   dword ptr , 0 ; KTRAP->FRAME->Dr7 清零
.text:0046A588               test    byte ptr , 0FFh ; kthread->DebugActive 检测有没有被调试
.text:0046A58C               mov   , ebp ; kthread->TrapFrame 备份陷阱帧
.text:0046A58C                                       ; 陷阱帧:就是TrapFrame结构体
.text:0046A58C                                       ; 用于保存3环的上下文环境
.text:0046A58C                                       ;
.text:0046A58C                                       ; 由于已经备份
.text:0046A58C                                       ; 下面操作不会影响原有的3环上下文环境
.text:0046A592               jnz   Dr_FastCallDrSave ; 调试状态 设置调试寄存器
.text:0046A598
.text:0046A598 内核权限跳转:                                 ; CODE XREF: Dr_FastCallDrSave+10↑j
.text:0046A598                                       ; Dr_FastCallDrSave+7C↑j
.text:0046A598               mov   ebx, ; KTRAP_FRAME->Ebp 3环栈底
.text:0046A59B               mov   edi, ; KTRAP_FRAME->Eip3环返回地址
.text:0046A59E               mov   , edx; KTRAP_FRAME->DbgArgPointer 3环第一个参数
.text:0046A5A1               mov   dword ptr , 0BADB0D00h ; KTRAP_FRAME->DbgArgMark
.text:0046A5A8               mov   , ebx    ; KTRAP_FRAME->DbgEbp 调试相关
.text:0046A5AB               mov   , edi    ; KTRAP_FRAME->DbgEip 调试相关
.text:0046A5AE               sti                     ; 开中断
.text:0046A5AF
.text:0046A5AF loc_46A5AF:                           ; CODE XREF: _KiBBTUnexpectedRange+18↑j
.text:0046A5AF                                       ; _KiSystemService+72↑j
.text:0046A5AF               mov   edi, eax      ; 系统服务号
.text:0046A5B1               shr   edi, 8
.text:0046A5B4               and   edi, 30h      ; 0:调用ntkrpa 10:调用Win32k
.text:0046A5B7               mov   ecx, edi
.text:0046A5B9               add   edi, ; kthread->ServiceTable 系统服务表基址
.text:0046A5B9                                       ; _KeDescriporServiceTable
.text:0046A5B9                                       ; 0x00 PULONG ServiceTableBase;      // 系统服务表基址
.text:0046A5B9                                       ; 0x04 PULONG ServiceCounterTableBase; // 系统服务表被调用的次数
.text:0046A5B9                                       ; 0x08 ULONGNumberOfServices;      // 系统服务表函数个数
.text:0046A5B9                                       ; 0x0C PULONG ParamTableBase;          // 系统服务表函数参数大小
.text:0046A5BF               mov   ebx, eax
.text:0046A5C1               and   eax, 0FFFh      ; 系统服务号保留低12位
.text:0046A5C6               cmp   eax,
.text:0046A5C9               jnb   _KiBBTUnexpectedRange ; 参数检查
.text:0046A5CF               cmp   ecx, 10h
.text:0046A5D2               jnz   short loc_46A5EF ; 调用ntkrnlpa.exe
.text:0046A5D4               mov   ecx, large fs:18h ; 取 当前的_kpcr
.text:0046A5DB               xor   ebx, ebx
.text:0046A5DD
.text:0046A5DD loc_46A5DD:                           ; DATA XREF: _KiTrap0E+117↓o
.text:0046A5DD               or      ebx, ; 检测.... 不清楚写的是什么
.text:0046A5E3               jz      short loc_46A5EF ; 调用ntkrnlpa.exe
.text:0046A5E5               push    edx             ; 三环第一个参数
.text:0046A5E6               push    eax             ; 系统服务号
.text:0046A5E7               call    ds:_KeGdiFlushUserBatch ; 跳转win32k.sys
.text:0046A5ED               pop   eax
.text:0046A5EE               pop   edx
.text:0046A5EF
.text:0046A5EF loc_46A5EF:                           ; CODE XREF: _KiFastCallEntry+B2↑j
.text:0046A5EF                                       ; _KiFastCallEntry+C3↑j
.text:0046A5EF               inc   large dword ptr fs:638h ; _KPRCB->KeSystemCalls 加1 我猜是系统服务表调用次数+1
.text:0046A5F6               mov   esi, edx      ; 3环第一个参数
.text:0046A5F8               mov   ebx, ; ServiceTable->ParamTableBase
.text:0046A5FB               xor   ecx, ecx
.text:0046A5FD               mov   cl,    ; 参数个数 (字节)
.text:0046A600               mov   edi,       ; ServiceTable
.text:0046A602               mov   ebx, ; 系统服务函数
.text:0046A605               sub   esp, ecx      ; 分配参数空间
.text:0046A607               shr   ecx, 2          ; 计算循环次数
.text:0046A60A               mov   edi, esp
.text:0046A60C               cmp   esi, ds:_MmUserProbeAddress ; 3环参数检查
.text:0046A612               jnb   loc_46A7C0      ; 非法跳转
.text:0046A618
.text:0046A618 loc_46A618:                           ; CODE XREF: _KiFastCallEntry+2A4↓j
.text:0046A618                                       ; DATA XREF: _KiTrap0E+10D↓o
.text:0046A618               rep movsd               ; rep movs dword ptr es:,dword ptr
.text:0046A61A               call    ebx             ; 调用系统服务
.text:0046A61C
.text:0046A61C loc_46A61C:                           ; CODE XREF: _KiFastCallEntry+2AF↓j
.text:0046A61C                                       ; DATA XREF: _KiTrap0E+12D↓o ...
.text:0046A61C               mov   esp, ebp
.text:0046A61E
.text:0046A61E loc_46A61E:                           ; CODE XREF: _KiBBTUnexpectedRange+38↑j
.text:0046A61E                                       ; _KiBBTUnexpectedRange+43↑j
.text:0046A61E               mov   ecx, large fs:124h ; 当前线程
.text:0046A625               mov   edx, ; KTRAP_FRAME->Edx
.text:0046A628               mov   , edx ; 指向原有的 陷阱帧 准备返回3环
.text:0046A628 _KiFastCallEntry endp
_KiServiceExit:
.text:0046A62E ; 系统调用返回 必经之路
.text:0046A62E
.text:0046A62E _KiServiceExitproc near               ; CODE XREF: KiCallUserMode(x,x)+EC↑j
.text:0046A62E                                       ; _KiSetLowWaitHighThread+80↓j ...
.text:0046A62E
.text:0046A62E tempCs          = dword ptr10h
.text:0046A62E tempEsp         = dword ptr14h
.text:0046A62E _Eax            = dword ptr44h
.text:0046A62E PreviousMode    = dword ptr48h
.text:0046A62E ExceptionList   = dword ptr4Ch
.text:0046A62E ErrCode         = dword ptr64h
.text:0046A62E _Eip            = dword ptr68h
.text:0046A62E SegCs         = dword ptr6Ch
.text:0046A62E EFlags          = dword ptr70h
.text:0046A62E
.text:0046A62E ; FUNCTION CHUNK AT .text:0046A738 SIZE 00000088 BYTES
.text:0046A62E
.text:0046A62E               cli                     ; 关闭中断
.text:0046A62F               test    dword ptr , 20000h ; _KTRAP_FRAME->Eflags 检查CPU模式
.text:0046A636               jnz   short loc_46A63E ; 虚拟8086模式
.text:0046A638               test    byte ptr , 1 ; 检测CS CPL检查
.text:0046A63C               jz      short 内核层处理   ; 内核
.text:0046A63E
.text:0046A63E loc_46A63E:                           ; CODE XREF: _KiServiceExit+8↑j
.text:0046A63E                                       ; _KiServiceExit+64↓j
.text:0046A63E               mov   ebx, large fs:124h ; 当前运行的 kthread
.text:0046A645               mov   byte ptr , 0 ; kthread->Alerted 该线程是否可以被唤醒 0:NO
.text:0046A649               cmp   byte ptr , 0 ; _KAPC_STATE->UserApcPending 判断是否有 用户APC要执行
.text:0046A64D               jz      short 内核层处理   ; 没有要执行的用户APC 跳转
.text:0046A64F               mov   ebx, ebp      ; _KTRAP_FRAME
.text:0046A651               mov   , eax; _KTRAP_FRAME->Eax
.text:0046A654               mov   dword ptr , 3Bh ; _KTRAP_FRAME->FS
.text:0046A65B               mov   dword ptr , 23h ; _KTRAP_FRAME->DS
.text:0046A662               mov   dword ptr , 23h ; _KTRAP_FRAME->ES
.text:0046A669               mov   dword ptr , 0 ; _KTRAP_FRAME->GS
.text:0046A670               mov   ecx, 1          ; APC_LEVEL
.text:0046A675               call    ds:__imp_@KfRaiseIrql@4 ; 提升中断请求级别
.text:0046A67B               push    eax             ; 源 中断级别
.text:0046A67C               sti                     ; 开启中断
.text:0046A67D               push    ebx             ; 传递 陷阱帧
.text:0046A67E               push    0
.text:0046A680               push    1               ; 0:处理内核APC 1:内核 用户都处理
.text:0046A682               call    _KiDeliverApc@12 ; 分发APC关键函数
.text:0046A682                                       ; 线程切换调用了APC分发函数 系统调用返回调用了APC分发函数
.text:0046A687               pop   ecx             ; NewIrql
.text:0046A688               call    ds:__imp_@KfLowerIrql@4 ; 降低中断请求级别
.text:0046A68E               mov   eax,
.text:0046A691               cli                     ; 关闭中断
.text:0046A692               jmp   short loc_46A63E ; 判断有没有下一个APC
.text:0046A694 ; ---------------------------------------------------------------------------
.text:0046A694
.text:0046A694 内核层处理:                                  ; CODE XREF: _KiServiceExit+E↑j
.text:0046A694                                       ; _KiServiceExit+1F↑j
.text:0046A694               mov   edx,
.text:0046A698               mov   ebx, large fs:50h ; kpcr->DebugActive 调试端口 用于保存调试对象 _DEBUG_OBJECT
.text:0046A69F               mov   large fs:0, edx ; 构造SEH
.text:0046A6A6               mov   ecx,
.text:0046A6AA               mov   esi, large fs:124h ; kthread 当前执行线程
.text:0046A6B1               mov   , cl; 设置先前模式
.text:0046A6B7               test    ebx, 0FFh       ; 判断当前线程有没有被调试
.text:0046A6BD               jnz   short 调试状态      ; 调试状态 跳转
.text:0046A6BF
.text:0046A6BF loc_46A6BF:                           ; CODE XREF: _KiServiceExit+11A↓j
.text:0046A6BF                                       ; _KiServiceExit+149↓j
.text:0046A6BF               test    , 20000h ; ‭00100000000000000000‬
.text:0046A6BF                                       ; 判断 VM位 虚拟8086模式
.text:0046A6BF                                       ; 0:保护模式 1:虚拟8086模式
.text:0046A6C7               jnz   loc_46AFD8      ; 虚拟8086模式返回
.text:0046A6CD               test    word ptr , 0FFF8h ; 不清楚在 判断什么
.text:0046A6D4               jz      和中断返回有关         ; 通过 iret返回
.text:0046A6DA               cmp   word ptr , 1Bh ; CPL 权限检查
.text:0046A6E0               bt      word ptr , 0 ; 取cs 第0位 给 CF
.text:0046A6E7               cmc                     ; CF取反
.text:0046A6E8               ja      主要恢复了段寄存器       ; 3环权限 就跳转
.text:0046A6EE               cmp   word ptr , 8 ; 判断 _KTRAP_FRAME->SegCs CPL权限检查
.text:0046A6F3               jz      short 内核层调用返回   ; 0环权限 跳转
.text:0046A6F5
.text:0046A6F5 loc_46A6F5:                           ; CODE XREF: _KiServiceExit+15B↓j
.text:0046A6F5               lea   esp, ; _KTRAP_FRAME->SegFs
.text:0046A6F8               pop   fs            ; 恢复3环的 FS
.text:0046A6FA               assume fs:nothing
.text:0046A6FA
.text:0046A6FA 内核层调用返回:                              ; CODE XREF: _KiServiceExit+C5↑j
.text:0046A6FA               lea   esp, ; _KTRAP_FRAME->Edi
.text:0046A6FD               pop   edi
.text:0046A6FE               pop   esi
.text:0046A6FF               pop   ebx
.text:0046A700               pop   ebp
.text:0046A701               cmp   word ptr , 80h
.text:0046A708               ja      loc_46AFF4
.text:0046A70E               add   esp, 4
.text:0046A711               test    , 1 ; 这里下面少了一句 判断是不是3环 是就跳转 _KiSystemCallExit2 回到3环
.text:0046A711 _KiServiceExitendp ; sp-analysis failed
.text:0046A711
.text:0046A711 ; ---------------------------------------------------------------------------
.text:0046A719 _KiSystemCallExitBranch db 75h
.text:0046A71A byte_46A71A   db 5                  ; DATA XREF: KiDisableFastSyscallReturn()+9↑w
.text:0046A71A                                       ; KiEnableFastSyscallReturn():loc_427854↑r ...
.text:0046A71B ; ---------------------------------------------------------------------------
.text:0046A71B               pop   edx             ; _KTRAP_FRAME->Eip
.text:0046A71C               pop   ecx             ; _KTRAP_FRAME->SegCs
.text:0046A71D               popf                  ; _KTRAP_FRAME->EFlags
.text:0046A71E               jmp   edx             ; 回到0环
.text:0046A720 ; ---------------------------------------------------------------------------
.text:0046A720 ; START OF FUNCTION CHUNK FOR _KiSystemCallExit2
.text:0046A720
.text:0046A720 _KiSystemCallExit:                      ; CODE XREF: _KiSystemCallExit2+5↓j
.text:0046A720                                       ; DATA XREF: KiRestoreFastSyscallReturnState()+1B↑o
.text:0046A720               iret
.text:0046A720 ; END OF FUNCTION CHUNK FOR _KiSystemCallExit2
.text:0046A721
.text:0046A721 ; =============== S U B R O U T I N E =======================================
.text:0046A721
.text:0046A721 ; 回到3环
.text:0046A721
.text:0046A721 _KiSystemCallExit2 proc near            ; DATA XREF: KiRestoreFastSyscallReturnState()+16↑o
.text:0046A721
.text:0046A721 Eflags_IF       = byte ptr9
.text:0046A721
.text:0046A721 ; FUNCTION CHUNK AT .text:0046A720 SIZE 00000001 BYTES
.text:0046A721
.text:0046A721               test    , 1 ; 当前Esp指向 _KTRAP_FRAME->ErrCode
.text:0046A721                                       ; +9 指向 EFlags 第二个字节
.text:0046A726               jnz   short _KiSystemCallExit ; 中断的形式进入0环的 直接通过 iretd 返回3环
.text:0046A728               pop   edx             ; _KTRAP_FRAME->Eip
.text:0046A729               add   esp, 4          ; _KTRAP_FRAME->SegCs
.text:0046A72C               and   , 0FDh ; 设置 Eflags寄存器
.text:0046A731               popf                  ; _KTRAP_FRAME->EFlags
.text:0046A732               pop   ecx             ; _KTRAP_FRAME->HardwareEsp
.text:0046A733               sti                     ; 开启中断
.text:0046A734               sysexit               ; 返回3环
.text:0046A736               iret

总结:
用户层和内核层返回都走的是:_KiServiceExit
但是系统调用 用户层走的是:_KiFastCallEntry PAE模式下 内核层走的是:_KiSystemService
然后直接跳到系统调用那一段了 因为两种方式调用的细节不一样
用户层是通过硬件方式 快速调用 直接设置寄存器
但是内核层不能这样做(因为每次调用函数 都要传递 Eflags Cs Eip 3个参数 _KTRAP_FRAME+0x68 - +0x70的值 每次都需要动态变化)
_KiFastCallEntry Esp指向_KTRAP_FRAME+0x+0x078
_KiSystemService Esp指向_KTRAP_FRAME+0x64

所以要通过_KiSystemService 设置堆栈
本质上都是通过 _KTRAP_FRAME结构体构造堆栈的



代码比较乱 有很多错误的地方 讲究看下吧

yiyedd 发表于 2020-3-10 09:10

一脸懵逼的进来,一脸懵逼的出去

古月不傲 发表于 2020-3-15 00:50

本帖最后由 古月不傲 于 2020-3-15 00:57 编辑

源码清晰多了
页: [1]
查看完整版本: 系统调用和返回