Windows XP/2003 系统调用(二)

上文说到sysenter后进入内核空间后的函数是_KiFastCallEntry,在/WRK-v1.2/base/ntos/ke/i386/trap.asm中,里头有好多定义常量、宏、结构,真是麻烦!先帖几个结构上来:

typedef struct _KTRAP_FRAME {


//
//  Following 4 values are only used and defined for DBG systems,
//  but are always allocated to make switching from DBG to non-DBG
//  and back quicker.  They are not DEVL because they have a non-0
//  performance impact.
//

    ULONG   DbgEbp;         // Copy of User EBP set up so KB will work.
    ULONG   DbgEip;         // EIP of caller to system call, again, for KB.
    ULONG   DbgArgMark;     // Marker to show no args here.
    ULONG   DbgArgPointer;  // Pointer to the actual args

//
//  Temporary values used when frames are edited.
//
//
//  NOTE:   Any code that want's ESP must materialize it, since it
//          is not stored in the frame for kernel mode callers.
//
//          And code that sets ESP in a KERNEL mode frame, must put
//          the new value in TempEsp, make sure that TempSegCs holds
//          the real SegCs value, and put a special marker value into SegCs.
//

    ULONG   TempSegCs;
    ULONG   TempEsp;

//
//  Debug registers.
//

    ULONG   Dr0;
    ULONG   Dr1;
    ULONG   Dr2;
    ULONG   Dr3;
    ULONG   Dr6;
    ULONG   Dr7;

//
//  Segment registers
//

    ULONG   SegGs;
    ULONG   SegEs;
    ULONG   SegDs;

//
//  Volatile registers
//

    ULONG   Edx;
    ULONG   Ecx;
    ULONG   Eax;

//
//  Nesting state, not part of context record
//

    ULONG   PreviousPreviousMode;

    PEXCEPTION_REGISTRATION_RECORD ExceptionList;
                                            // Trash if caller was user mode.
                                            // Saved exception list if caller
                                            // was kernel mode or we're in
                                            // an interrupt.

//
//  FS is TIB/PCR pointer, is here to make save sequence easy
//

    ULONG   SegFs;

//
//  Non-volatile registers
//

    ULONG   Edi;
    ULONG   Esi;
    ULONG   Ebx;
    ULONG   Ebp;

//
//  Control registers
//

    ULONG   ErrCode;
    ULONG   Eip;
    ULONG   SegCs;
    ULONG   EFlags;

    ULONG   HardwareEsp;    // WARNING - segSS:esp are only here for stacks
    ULONG   HardwareSegSs;  // that involve a ring transition.

    ULONG   V86Es;          // these will be present for all transitions from
    ULONG   V86Ds;          // V86 mode
    ULONG   V86Fs;
    ULONG   V86Gs;
} KTRAP_FRAME;

dt _KTHREAD
nt!_KTHREAD
   +0x000 Header           : _DISPATCHER_HEADER
   +0x010 MutantListHead   : _LIST_ENTRY
   +0x018 InitialStack     : Ptr32 Void
   +0x01c StackLimit       : Ptr32 Void
   +0x020 Teb              : Ptr32 Void
   +0x024 TlsArray         : Ptr32 Void
   +0x028 KernelStack      : Ptr32 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         : _KAPC_STATE
   +0x04c ContextSwitches  : Uint4B
   +0x050 IdleSwapBlock    : UChar
   +0x051 Spare0           : [3] UChar
   +0x054 WaitStatus       : Int4B
   +0x058 WaitIrql         : UChar
   +0x059 WaitMode         : Char
   +0x05a WaitNext         : UChar
   +0x05b WaitReason       : UChar
   +0x05c WaitBlockList    : Ptr32 _KWAIT_BLOCK
   +0x060 WaitListEntry    : _LIST_ENTRY
   +0x060 SwapListEntry    : _SINGLE_LIST_ENTRY
   +0x068 WaitTime         : Uint4B
   +0x06c BasePriority     : Char
   +0x06d DecrementCount   : UChar
   +0x06e PriorityDecrement : Char
   +0x06f Quantum          : Char
   +0x070 WaitBlock        : [4] _KWAIT_BLOCK
   +0x0d0 LegoData         : Ptr32 Void
   +0x0d4 KernelApcDisable : Uint4B
   +0x0d8 UserAffinity     : Uint4B
   +0x0dc SystemAffinityActive : UChar
   +0x0dd PowerState       : UChar
   +0x0de NpxIrql          : UChar
   +0x0df InitialNode      : UChar
   +0x0e0 ServiceTable     : Ptr32 Void
   +0x0e4 Queue            : Ptr32 _KQUEUE
   +0x0e8 ApcQueueLock     : Uint4B
   +0x0f0 Timer            : _KTIMER
   +0x118 QueueListEntry   : _LIST_ENTRY
   +0x120 SoftAffinity     : Uint4B
   +0x124 Affinity         : Uint4B
   +0x128 Preempted        : UChar
   +0x129 ProcessReadyQueue : UChar
   +0x12a KernelStackResident : UChar
   +0x12b NextProcessor    : UChar
   +0x12c CallbackStack    : Ptr32 Void
   +0x130 Win32Thread      : Ptr32 Void
   +0x134 TrapFrame        : Ptr32 _KTRAP_FRAME
   +0x138 ApcStatePointer  : [2] Ptr32 _KAPC_STATE
   +0x140 PreviousMode     : Char
   +0x141 EnableStackSwap  : UChar
   +0x142 LargeStack       : UChar
   +0x143 ResourceIndex    : UChar
   +0x144 KernelTime       : Uint4B
   +0x148 UserTime         : Uint4B
   +0x14c SavedApcState    : _KAPC_STATE
   +0x164 Alertable        : UChar
   +0x165 ApcStateIndex    : UChar
   +0x166 ApcQueueable     : UChar
   +0x167 AutoAlignment    : UChar
   +0x168 StackBase        : Ptr32 Void
   +0x16c SuspendApc       : _KAPC
   +0x19c SuspendSemaphore : _KSEMAPHORE
   +0x1b0 ThreadListEntry  : _LIST_ENTRY
   +0x1b8 FreezeCount      : Char
   +0x1b9 SuspendCount     : Char
   +0x1ba IdealProcessor   : UChar
   +0x1bb DisableBoost     : UChar

dt _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

 dt _KPRCB
nt!_KPRCB
   +0x000 MinorVersion     : Uint2B
   +0x002 MajorVersion     : Uint2B
   +0x004 CurrentThread    : Ptr32 _KTHREAD
   +0x008 NextThread       : Ptr32 _KTHREAD
   +0x00c IdleThread       : Ptr32 _KTHREAD
   +0x010 Number           : Char
   +0x011 Reserved         : Char
   +0x012 BuildType        : Uint2B
   +0x014 SetMember        : Uint4B
   +0x018 CpuType          : Char
   +0x019 CpuID            : Char
   +0x01a CpuStep          : Uint2B
   +0x01c ProcessorState   : _KPROCESSOR_STATE
   +0x33c KernelReserved   : [16] Uint4B
   +0x37c HalReserved      : [16] Uint4B
   +0x3bc PrcbPad0         : [92] UChar
   +0x418 LockQueue        : [16] _KSPIN_LOCK_QUEUE
   +0x498 PrcbPad1         : [8] UChar
   +0x4a0 NpxThread        : Ptr32 _KTHREAD
   +0x4a4 InterruptCount   : Uint4B
   +0x4a8 KernelTime       : Uint4B
   +0x4ac UserTime         : Uint4B
   +0x4b0 DpcTime          : Uint4B
   +0x4b4 DebugDpcTime     : Uint4B
   +0x4b8 InterruptTime    : Uint4B
   …………

   …………

    typedef struct _SYSTEM_SERVICE_TABLE
    {
          PNTPROC  ServiceTable;  // array of entry points
          PDWORD  CounterTable;  // array of usage counters
          DWORD  ServiceLimit;    // number of table entries
          PBYTE    ArgumentTable;  // array of byte counts
    }
    SYSTEM_SERVICE_TABLE,
    *PSYSTEM_SERVICE_TABLE,
    **PPSYSTEM_SERVICE_TABLE;
    //-----------------------------------------------------------------------------------------------------------
    typedef struct _SERVICE_DESCRIPTOR_TABLE
    {
          SYSTEM_SERVICE_TABLE ntoskrnl;  // ntoskrnl.exe ( native api )
          SYSTEM_SERVICE_TABLE win32k;    // win32k.sys (gdi/user support)
          SYSTEM_SERVICE_TABLE Table3;    // not used
          SYSTEM_SERVICE_TABLE Table4;    // not used
    }
    SYSTEM_DESCRIPTOR_TABLE,
    *PSYSTEM_DESCRIPTOR_TABLE,
    **PPSYSTEM_DESCRIPTOR_TABLE;

_KiFastCallEntry        proc

;
; Sanitize the segment registers
;
        mov     ecx, KGDT_R3_DATA OR RPL_MASK ;mov     ecx, 23h
        push    KGDT_R0_PCR   ;push    30h
        pop     fs    ;FS->PCR
        mov     ds, ecx    ;DS=23h
        mov     es, ecx    ;ES=23h

;
; 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.
;
        mov     ecx, PCR[PcTss]        ;
        mov     esp, [ecx]+TssEsp0 ;其实DPC栈只是临时过度,基本没有使用,这里才切换为线程相关的内核栈!

        push    KGDT_R3_DATA OR RPL_MASK   ; Push user SS (push    23h),_KTRAP_FRAME.HardwareSegSs
        push    edx                        ; 用户栈指针,_KTRAP_FRAME.HardwareEsp
        pushfd       ;_KTRAP_FRAME.EFags,<1>
Kfsc10:
        push    2                           ; Sanitize eflags, clear direction, NT etc
        add     edx, 8                      ; (edx) -> arguments
        popfd                               ; 使当前EFLAGS=2
.errnz(EFLAGS_INTERRUPT_MASK AND 0FFFF00FFh)
        or      byte ptr [esp+1], EFLAGS_INTERRUPT_MASK/0100h ; Enable interrupts in eflags
               ;or      byte ptr [esp+1], 2 ,对应<1>,因为sysenter会清除IF!

        push    KGDT_R3_CODE OR RPL_MASK    ; Push user CS (push    1Bh),_KTRAP_FRAME.SegCs
        push    dword ptr ds:[USER_SHARED_DATA+UsSystemCallReturn] ; push return address,_KTRAP_FRAME.Eip
        push    0                           ; put pad dword for error on stack,_KTRAP_FRAME.ErrorCode
        push    ebp                         ; save the non-volatile registers,_KTRAP_FRAME.Ebp
        push    ebx                         ;_KTRAP_FRAME.Ebx
        push    esi                         ;_KTRAP_FRAME.Esi
        push    edi                         ;_KTRAP_FRAME.Edi
        mov     ebx, PCR[PcSelfPcr]         ; Get PRCB address,不是PRCB,应该是PCR,(ebx->PCR)
        push    KGDT_R3_TEB OR RPL_MASK     ; Push user mode FS (push    3Bh),_KTRAP_FRAME.SegFs
        mov     esi, [ebx].PcPrcbData+PbCurrentThread   ; get current thread address,(esi->_KTHREAD)
;
; Save the old exception list in trap frame and initialize a new empty
; exception list.


        push    [ebx].PcExceptionList       ; save old exception list,_KTRAP_FRAME.ExceptionList
        mov     [ebx].PcExceptionList, EXCEPTION_CHAIN_END ; set new empty list,EXCEPTION_CHAIN_END=-1
        mov     ebp, [esi].ThInitialStack

;
; 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,_KTRAP_FRAME.PreviousPreviousMode=1,UserModel
        sub     esp,TsPreviousPreviousMode ; allocate remainder of trap frame(sub     esp, 48h)
        sub     ebp, NPX_FRAME_LENGTH + KTRAP_FRAME_LENGTH ;(sub     ebp, 29Ch)
               ;NPX_FRAME_LENGTH=210h,KTRAP_FRAME_LENGTH=8C
        mov     byte ptr [esi].ThPreviousMode,MODE_MASK ; set new previous mode of user
;
; 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
        jne     short Kfsc91

;
; Set the new trap frame address.

        and     dword ptr [ebp].TsDr7, 0 ;(and     dword ptr [ebp+2Ch], 0),_KTRAP_FRAME.Dr7 = 0
        test    byte ptr [esi].ThDebugActive, 0ffh ; See if we need to save debug registers
        mov     [esi].ThTrapFrame, ebp    ; set new trap frame address

        jnz     Dr_FastCallDrSave        ; if nz, debugging is active on thread

Dr_FastCallDrReturn:

ife FPO                  ;;我把原来的SET_DEBUG_DATA宏展开了

;
; This macro is used by ENTER_SYSCALL, ENTER_TRAP and ENTER_INTERRUPT
; and is used at the end of above macros.  It is safe to destroy ebx, edi.
;

        mov     ebx,[ebp]+TsEbp
        mov     edi,[ebp]+TsEip
        mov     [ebp]+TsDbgArgPointer,edx
        mov     [ebp]+TsDbgArgMark,0BADB0D00h
        mov     [ebp]+TsDbgEbp,ebx
        mov     [ebp]+TsDbgEip,edi
endif


        sti                             ; enable interrupts,sysenter会把IF清零

?FpoValue = 0

;
; (eax) = Service number
; (edx) = Callers stack pointer
; (esi) = Current thread address
;
; All other registers have been saved and are free.
;
; Check if the service number within valid range
;

_KiSystemServiceRepeat:
        mov     edi, eax                ; copy system service number
        shr     edi, SERVICE_TABLE_SHIFT ; isolate service table number,SERVICE_TABLE_SHIFT=8H(除以256)
        and     edi, SERVICE_TABLE_MASK ; SERVICE_TABLE_MASK=10H
        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=00FFFH

;
; 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
        jae     Kss_ErrorHandler        ; if ae, try to convert to GUI thread

;
; 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=00010H
        jne     short Kss40             ; if ne, not GUI service
        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.
;

Kss40:  inc     dword ptr PCR[PcPrcbData+PbSystemCalls] ; system calls

FPOFRAME ?FpoValue, 0

        mov     esi, edx                ; (esi)->User arguments
        mov     ebx, [edi]+SdNumber     ; get argument table address
        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

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

上面的_KiFastCallEntry我做了一定的整理,也写了很多注释!只写到 call    ebx (call system service),后面的代码以后再看……

KTRAP_FRAME是非常重要的一个结构,不管以何种方式进入内核都要在栈上构造该结构,但红色部分可能是CPU自动完成的:

When the processor performs a call to the exception- or interrupt-handler procedure:

 If the handler procedure is going to be executed at a numerically lower privilege
level, a stack switch occurs. When the stack switch occurs:
a. The segment selector and stack pointer for the stack to be used by the
handler are obtained from the TSS for the currently executing task. On this
new stack, the processor pushes the stack segment selector and stack
pointer of the interrupted procedure.
b. The processor then saves the current state of the EFLAGS, CS, and EIP
registers on the new stack (see Figures 5-4).
c. If an exception causes an error code to be saved, it is pushed on the new
stack after the EIP value.
 If the handler procedure is going to be executed at the same privilege level as the
interrupted procedure:
a. The processor saves the current state of the EFLAGS, CS, and EIP registers
on the current stack (see Figures 5-4).
b. If an exception causes an error code to be saved, it is pushed on the current
stack after the EIP value.


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/better0332/archive/2009/06/19/4283313.aspx

你可能感兴趣的:(windows,exception,service,table,System,Descriptor)