KiFastCallEntry from wrk 注释、简单分析

KiFastCallEntry from wrk 注释、简单分析


创建时间:2010-02-02
文章类别:内核研究
文章大小:8972 Bytes

基本分为以下基本
1. 转配TrapFrame
2. 获取服务表地址,测试是否需要转化为GUI线程。
3. R3参数复制到内核栈 (顺便说一下某安全助手就是在这一步的最后进行HOOK的)
4. 系统调用
5. 返回操作。。。大部分在EXIT_ALL宏中。。。没看懂。。。

;eax指向服务编号
;edx指向当前用户栈、edx+8为参数列表

_KiFastCallEntry        proc

;
; Sanitize the segment registers
; 初始化fs指向PCR的选择子,ds、es指向ring3数据选择子
        mov     ecx, KGDT_R3_DATA OR RPL_MASK
        push    KGDT_R0_PCR
        pop     fs
        mov     ds, ecx
        mov     es, ecx

;
; When we trap into the kernel via fast system call we start on the DPC stack. We need
; shift to the threads stack before enabling interrupts.
; 从PCR->tss.TssEsp0中获得系统栈的地址,赋值给esp。
; 所以sysenter指令中设置的esp其实没有用处, MS还很happy给它起名叫DPC stack >_<
        mov     ecx, PCR[PcTss]        ;
        mov     esp, [ecx]+TssEsp0
; 在这里建立_KTRAP_FRAME, 也就是intel执行int指令时在系统堆栈中建立的自陷框架
; 具体结构请dt
push    KGDT_R3_DATA OR RPL_MASK   ; Push user SS   HardwareSegSs
        push    edx                         ; Push ESP   HardwareEsp
        pushfd               ;        EFlags
Kfsc10:
        push    2                           ; Sanitize eflags, clear direction, NT etc
        add     edx, 8                      ; (edx) -> arguments 调整edx指向可爱的参数们
        popfd                               ; 设置eflag寄存器为2, 有兴趣请自行查询其意义...
.errnz(EFLAGS_INTERRUPT_MASK AND 0FFFF00FFh)
        or      byte ptr [esp+1], EFLAGS_INTERRUPT_MASK/0100h ; Enable interrupts in eflags 打开用户态EFlags的中断

        push    KGDT_R3_CODE OR RPL_MASK    ; Push user CS  SegCs
        push    dword ptr ds:[USER_SHARED_DATA+UsSystemCallReturn] ; push return address Eip返回R3时就从这里开始执行
        push    0                           ; put pad dword for error on stack ErrCode
        push    ebp                         ; save the non-volatile registers  各寄存器值
        push    ebx                         ;
        push    esi                         ;
        push    edi                         ;
        mov     ebx, PCR[PcSelfPcr]         ; Get PRCB address
        push    KGDT_R3_TEB OR RPL_MASK     ; Push user mode FS  用户态FS指向的是TEB选择子
        mov     esi, [ebx].PcPrcbData+PbCurrentThread   ; get current thread address
;
; Save the old exception list in trap frame and initialize a new empty
; exception list.
;

        push    [ebx].PcExceptionList       ; save old exception list  从PCR中获得ExceptionList
        mov     [ebx].PcExceptionList, EXCEPTION_CHAIN_END ; set new empty list
        mov     ebp, [esi].ThInitialStack  ;ebp是内核栈顶(最高的地址)

;
; Save the old previous mode in trap frame, allocate remainder of trap frame,
; and set the new previous mode.
;
        push    MODE_MASK                  ; Save previous mode as user  设置PreviousPreviousMode为UserMode(1)
        sub     esp,TsPreviousPreviousMode ; allocate remainder of trap frame  分配了48h字节, 也就是DbgEbp到Eax所占据的空间
        sub     ebp, NPX_FRAME_LENGTH + KTRAP_FRAME_LENGTH 
        mov     byte ptr [esi].ThPreviousMode,MODE_MASK ; set new previous mode of user 设置ETHREAD中的PREVIOUSMode未UserMode
;
; Now the full trap frame is build.
; Calculate initial stack pointer from thread initial stack to contain NPX and trap.
; If this isn't the same as esp then we are a VX86 thread and we are rejected
;

        cmp     ebp, esp   ;这里比较堆栈是否正确建立、谁告诉我NPX在哪建的??
        jne     short Kfsc91 ;正确就不会跳

;
; Set the new trap frame address.
; ebp指向了自陷框架
; esi指向ETHREAD
        and     dword ptr [ebp].TsDr7, 0
        test    byte ptr [esi].ThDebugActive, 0ffh ; See if we need to save debug registers
        mov     [esi].ThTrapFrame, ebp   ; set new trap frame address  在ETHREAD中设置自陷框架地址

        jnz     Dr_FastCallDrSave       ; if nz, debugging is active on thread

Dr_FastCallDrReturn:                       ;

        SET_DEBUG_DATA                  ; Note this destroys edi
        sti                             ; enable interrupts

?FpoValue = 0

;到这里TRAP_FRAME设置完毕了, 开始调用系统服务的准备工作
; (eax) = Service number     服务号
; (edx) = Callers stack pointer  指向R3中的参数
; (esi) = Current thread address 指向ETHREAD结构
;
; All other registers have been saved and are free.
;所有寄存器随便用, 以为在框架中已经设置好备份了
;
; Check if the service number within valid range
; 首先验证服务号是否在合法的范围内

_KiSystemServiceRepeat:
; 服务号由16位组成  4位表号A + 12位服务索引B
; 从ethread中取得ServiceTable数组,取第A项为服务表地址
        mov     edi, eax                ; copy system service number
        shr     edi, SERVICE_TABLE_SHIFT ; isolate service table number SERVICE_TABLE_SHIFT == 8
        and     edi, SERVICE_TABLE_MASK ; SERVICE_TABLE_MASK == 30h
        mov     ecx, edi                ; save service table number
        add     edi, [esi]+ThServiceTable ; compute service descriptor address
        mov     ebx, eax                ; save system service number
        and     eax, SERVICE_NUMBER_MASK ; isolate service table offset SERVICE_NUMBER_MASK == 0xFFF
                         ; eax为服务索引

;
; If the specified system service number is not within range, then attempt
; to convert the thread to a GUI thread and retry the service dispatch.
;

        cmp     eax, [edi]+SdLimit      ; check if valid service SdLimit==8
        jae     Kss_ErrorHandler        ; if ae, try to convert to GUI thread
                        ; 服务号太大了, 就试试win32k模块吧

;
; If the service is a GUI service and the GDI user batch queue is not empty,
; then call the appropriate service to flush the user batch.
;

        cmp     ecx, SERVICE_TABLE_TEST ; test if GUI service   SERVICE_TABLE_TEST==10h
        jne     short Kss40             ; if ne, not GUI service 非win32k系统调用应该跳走
        mov     ecx, PCR[PcTeb]         ; get current thread TEB address
        xor     ebx, ebx                ; get number of batched GDI calls

KiSystemServiceAccessTeb:
        or      ebx, [ecx]+TbGdiBatchCount ; may cause an inpage exception

        jz      short Kss40             ; if z, no batched calls
        push    edx                     ; save address of user arguments
        push    eax                     ; save service number
        call    [_KeGdiFlushUserBatch]  ; flush GDI user batch
        pop     eax                     ; restore service number
        pop     edx                     ; restore address of user arguments

;
; The arguments are passed on the stack. Therefore they always need to get
; copied since additional space has been allocated on the stack for the
; machine state frame.  Note that we don't check for the zero argument case -
; copy is always done regardless of the number of arguments because the
; zero argument case is very rare.
;
; 将R3的参数复制到R0堆栈中
Kss40:  inc     dword ptr PCR[PcPrcbData+PbSystemCalls] ; system calls

; edx R3参数首地址
; edi SSDT or shadowSSDT
; eax 服务索引
FPOFRAME ?FpoValue, 0

        mov     esi, edx                ; (esi)->User arguments
        mov     ebx, [edi]+SdNumber     ; get argument table address   SdNumber==0ch
        xor     ecx, ecx
        mov     cl, byte ptr [ebx+eax]  ; (ecx) = argument size
        mov     edi, [edi]+SdBase       ; get service table address
        mov     ebx, [edi+eax*4]        ; (ebx)-> service routine
        ; 在系统堆栈上申请参数空间
        sub     esp, ecx                ; allocate space for arguments
        shr     ecx, 2                  ; (ecx) = number of argument DWORDs
        mov     edi, esp                ; (edi)->location to receive 1st arg
        cmp     esi, _MmUserProbeAddress ; check if user address
        jae     kss80                   ; if ae, then not user address
    ; 从R3复制到R0的堆栈上
KiSystemServiceCopyArguments:
        rep     movsd                   ; copy the arguments to top of stack.
                                        ; Since we usually copy more than 3
                                        ; arguments.  rep movsd is faster than
                                        ; mov instructions.

;
; Make actual call to system service
; 这里开始系统调用

kssdoit:
        call    ebx                     ; call system service

kss60:

; 完成系统调用,开始返回R3
kss61:

;
; Upon return, (eax)= status code. This code may also be entered from a failed
; KiCallbackReturn call.
; ebp  指向自陷框架
        mov     esp, ebp                ; 销毁系统调用时的参数

;
; Restore old trap frame address from the current trap frame.
;

kss70:  mov     ecx, PCR[PcPrcbData+PbCurrentThread] ; get current thread address
        mov     edx, [ebp].TsEdx        ; 自陷框架中的edx指向原R3堆栈顶
        mov     [ecx].ThTrapFrame, edx  ; 

;
;   System service's private version of KiExceptionExit
;   (Also used by KiDebugService)
;
;   Check for pending APC interrupts, if found, dispatch to them
;   (saving eax in frame first).
;
        public  _KiServiceExit
_KiServiceExit:

        cli                                         ; disable interrupts
        DISPATCH_USER_APC   ebp, ReturnCurrentEax  ; 派遣用户APC

;
; Exit from SystemService
;

        EXIT_ALL    NoRestoreSegs, NoRestoreVolatile ;返回操作
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值