共有回帖数 0 个
-
win支持两种系统调用进入内核的方式,对于没有SYSENTER_CS_MSR,SYSENTER_EIP_MSR,SYSENTER_ESP_MSR的CPU,采用传统的int 2e指令进入。而现在的CPU基本都有了这几个MSR寄存器,所以咱们的系统一般通过sysenter快速系统调用进入内核。实际上,这两种方式的框架是大体相同的。
首先来看看int 2e吧。
执行int 2e时,CPU自动从当前任务TSS中取出ring0的SS和ESP并装入相应寄存器,接着依次将用户空间SS,ESP,EFLAGS,CS,EIP压入用户空间堆栈。然后从IDT表中取出0x2e号的向量,得到程序入口指针(KiSystemService)。关闭中断。跳转到KiSystemService处执行。
nt!KiSystemService:
80541441 6a00 push 0
80541443 55 push ebp
80541444 53 push ebx
80541445 56 push esi
80541446 57 push edi
80541447 0fa0 push fs
保存寄存器,建立框架
80541449 bb30000000 mov ebx,30h
8054144e 668ee3 mov fs,bx
fs中是0x30,相应的gdt表项指向内核中一片固定区域,里面有重要数据结构。最开始是一个称为_KPCR的数据结构。
lkd 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
80541451 64ff3500000000 push dword ptr fs:[0]
80541458 64c70500000000ffffffff mov dword ptr fs:[0],0FFFFFFFFh
fs:[0]在_NT_TIB中,看看
lkd 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
fs:[0]指向异常处理队列。结构化异常处理,即SEH,大家都懂的。
首先将指向的队列指针保存,然后清空。
80541463 648b3524010000 mov esi,dword ptr fs:[124h]
fs:[124]在_KPRCB中。这个结构很长,我们只看关心的
lkd dt !_KPRCB
nt!_KPRCB
+0x000 MinorVersion : Uint2B
+0x002 MajorVersion : Uint2B
+0x004 CurrentThread : Ptr32 _KTHREAD
+0x008 NextThread : Ptr32 _KTHREAD
+0x00c IdleThread : Ptr32 _KTHREAD
所以esi现在指向表示当前线程的数据结构_KTHREAD
8054146a ffb640010000 push dword ptr [esi+140h]
继续看_KTHREAD这个结构,也很长
nt!_KTHREAD
+0x000 Header : _DISPATCHER_HEADER
+0x010 MutantListHead : _LIST_ENTRY
……
+0x140 PreviousMode : Char
……
将先前的模式保存。先前模式即KernelMode或UserMode。
80541470 83ec48 sub esp,48h
开辟一片栈空间,用以保存其他寄存器。
80541473 8b5c246c mov ebx,dword ptr [esp+6Ch]
即保存在堆栈中的cs
80541477 83e301 and ebx,1
若是从UserMode发起的调用,则cs最低两位为00b,否则,11b
8054147a 889e40010000 mov byte ptr [esi+140h],bl
新的当前线程PreviousMode
80541480 8bec mov ebp,esp
ebp based frame
80541482 8b9e34010000 mov ebx,dword ptr [esi+134h]
_KTHREAD中
+0x134 TrapFrame : Ptr32 _KTRAP_FRAME
用以保存框架的。
80541488 895d3c mov dword ptr [ebp+3Ch],ebx
将先前框架保存在本用于保存edx的地方。因为edx用于传递用户堆栈中参数块的指针
8054148b 89ae34010000 mov dword ptr [esi+134h],ebp
保存当前框架
80541491 fc cld
80541492 8b5d60 mov ebx,dword ptr [ebp+60h]
即ebp
80541495 8b7d68 mov edi,dword ptr [ebp+68h]
即eip
80541498 89550c mov dword ptr [ebp+0Ch],edx
用户堆栈参数块
8054149b c74508000ddbba mov dword ptr [ebp+8],0BADB0D00h
805414a2 895d00 mov dword ptr [ebp],ebx
805414a5 897d04 mov dword ptr [ebp+4],edi
805414a8 f6462cff test byte ptr [esi+2Ch],0FFh
_KTHREAD中
+0x02c DebugActive : UChar
是否处于处于受调试状态中
805414ac 0f858afeffff jne nt!Dr_kss_a (8054133c)
上面若不在调试状态,便接着走下来到了这里。
nt!KiSystemService+0x71:
805414b2 fb sti
开中断
805414b3 e9e7000000 jmp nt!KiFastCallEntry+0x8f (8054159f)
看到这里是nt!KiFastCallEntry,说明将要跳转的是和FastCall公用的。
nt!KiFastCallEntry+0x8f:
8054159f 8bf8 mov edi,eax
eax中是系统调用号
805415a1 c1ef08 shr edi,8
805415a4 83e730 and edi,30h
805415a7 8bcf mov ecx,edi
XP中将图形界面的操作也移动到了内核(win32k.sys),其系统调用号大于0x1000,而传统的则小于0x1000
故操作之后若为ntoskrnl导出,则ecx == 0x0,否则,0x10(0x20,,0x30会出现吗?不知道。。不过XP应该是不会了)
805415a9 03bee0000000 add edi,dword ptr [esi+0E0h]
这里是_KTHREAD的
+0x0e0 ServiceTable : Ptr32 Void
这个是指向系统调用表的。
之后edi指向KeServiceDescriptorTable(ecx == 0x0)KeServiceDescriptorTableShadow(ecx == 0x10),?(ecx == 20),?(ecx == 0x30)
805415af 8bd8 mov ebx,eax
805415b1 25ff0f0000 and eax,0FFFh
805415b6 3b4708 cmp eax,dword ptr [edi+8]
是否超出了最大表项
805415b9 0f8333fdffff jae nt!KiBBTUnexpectedRange (805412f2)
若超出了范围(调用号超过0x1000,即调用win32k中的服务,因为系统调用表第0项是表示ntoskrnl导出的服务,是小于0x1000的),则到了这里
nt!KiBBTUnexpectedRange:
805412f2 83f910 cmp ecx,10h
805412f5 7539 jne nt!KiBBTUnexpectedRange+0x3e (80541330)
若不等于0x10h,则失败,到了这里
nt!KiBBTUnexpectedRange+0x3e:
80541330 b81c0000c0 mov eax,0C000001Ch
80541335 e9d4020000 jmp nt!KiFastCallEntry+0xfe (8054160e)
0x0C000001C即STATUS_UNSUCCESSFUL,然后该干嘛干嘛了。这些之后调用PsConvertToGuiThread,这些不是重点,咱们就不看了。有兴趣可以自己看看。
楼主 2015-11-26 14:24 回复
Copyright © 2010~2015 直线网 版权所有,All Rights Reserved.沪ICP备10039589号
意见反馈 |
关于直线 |
版权声明 |
会员须知