上文说到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