驱动-系统调用

系统调用

  • 在用户层与内核层分别定义了一个_KUSER_SHARED_DATA结构体,用于用户层与内核层共享某些数据
    • 用户层地址为:0x7ffe0000
    • 内核层地址为:0xffdf0000
  • 虽然指向同一个物理页,用户层是只读的,内核层是可写的
  • 所有应用程序共享的,一改全部都会改
  • 如果调用函数,会调用0x7ffe0300是kifastsystemcall函数
  • 0xffdf0000是KPCR

kifastsystemcall函数

EAX放入调用号,edx是栈顶。MSR寄存器174-CS、175-ESP、176-EIP,SS是CS值+8,如果是以int 2E方式进入0环,里面调用KISTSTEMSERVICE如果是stsenter方式进入0环,会调用KIFASTCALLENTRY函数

KiFastCallEntry

进入0环 
	eax: 调用号
	edx: 用户栈
		[edx +0x00 ] : 返回地址1
		[edx +0x04 ] : 返回地址2
		[edx +0x08 ] : 参数1
		[edx +0x0c ] : 参数2
		[edx +0x10 ] : 参数3	

nt!KiFastCallEntry:
83e810c0 b923000000      mov     ecx,23h

83e810c5 6a30            push    30h
83e810c7 0fa1            pop     fs    ; 内核FS保存一个_KPRC结构体

									   ;加载内核段选择子
83e810c9 8ed9            mov     ds,cx
83e810cb 8ec1            mov     es,cx

								
83e810cd 648b0d40000000  mov     ecx,dword ptr fs:[40h] ;KPCR->TSS
83e810d4 8b6104          mov     esp,dword ptr [ecx+4]  ;TSS->ESP0 ;加载零环ESP

83e810d7 6a23            push    23h		;压入三环 SS
83e810d9 52              push    edx		;压入三环 esp

83e810da 9c              pushfd				;压入三环 EFLAGS
83e810db 6a02            push    2			
83e810dd 83c208          add     edx,8		;将edx指向用户层参数 
83e810e0 9d              popfd				;EFLAGS = 2 ,清空EFLAGS

83e810e1 804c240102      or      byte ptr [esp+1],2  ; 栈上EFLAGS->IF位置1, 开启中断


83e810e6 6a1b            push    1Bh				;三环用户层的CS, TRAP_FRAM->CS

83e810e8 ff350403dfff    push    dword ptr ds:[0FFDF0304h] ; 返回用户层EIP 
83e810ee 6a00            push    0						   ; 错误码
83e810f0 55              push    ebp					   ; 用户层的ebp
83e810f1 53              push    ebx
83e810f2 56              push    esi
83e810f3 57              push    edi					   ;用户层的edi

83e810f4 648b1d1c000000  mov     ebx,dword ptr fs:[1Ch]    ;FS[1Ch]->自己  EBX保存KPCR

83e810fb 6a3b            push    3Bh					   ;用户层FS寄存器

83e810fd 8bb324010000    mov     esi,dword ptr [ebx+124h]  ;esi->ETHREAD 结构体


83e81103 ff33            push    dword ptr [ebx]		   ;TRAP_FRAME->Exceptiolist

83e81105 c703ffffffff    mov     dword ptr [ebx],0FFFFFFFFh ; 异常链第一个节点-1
83e8110b 8b6e28          mov     ebp,dword ptr [esi+28h]	; 内核栈底

83e8110e 6a01            push    1    						;先前模式


83e81110 83ec48          sub     esp,48h					;构建好TRAP_FRAME

83e81113 81ed9c020000    sub     ebp,29Ch

83e81119 c6863a01000001  mov     byte ptr [esi+13Ah],1		;保存ETHREAD->PreviousMode = 1
83e81120 3bec            cmp     ebp,esp					;是否是V86模式
83e81122 7597            jne     nt!KiFastCallEntry2+0x49 (83e810bb)

															;ebp和Esp都指向陷阱帧
83e81124 83652c00        and     dword ptr [ebp+2Ch],0		;DR7 = 0

83e81128 f64603df        test    byte ptr [esi+3],0DFh		;用于检查是否处于调试模式

83e8112c 89ae28010000    mov     dword ptr [esi+128h],ebp   ;将陷阱帧保存到 ETHREAD->Trap_frame 

83e81132 0f8538feffff    jne     nt!Dr_FastCallDrSave (83e80f70) ; 如果是调试模式,就保存DR寄存器

83e81138 8b5d60          mov     ebx,dword ptr [ebp+60h]  ;用户ebp
83e8113b 8b7d68          mov     edi,dword ptr [ebp+68h]  ;用户eip

83e8113e 89550c          mov     dword ptr [ebp+0Ch],edx  ;Trap_frame->参数指针 = 用户层参数

83e81141 c74508000ddbba  mov     dword ptr [ebp+8],0BADB0D00h ;参数掩码

83e81148 895d00          mov     dword ptr [ebp],ebx    ;Trap_frame->dbgebp = 用户层ebp
83e8114b 897d04          mov     dword ptr [ebp+4],edi  ;Trap_frame->dbgeip = 用户层eip

83e8114e fb              sti				;开中断

;-------------------------------上面都是保存陷阱帧

;-------------------调用内核中API SSDT 表中的函数

83e8114f 8bf8            mov     edi,eax 		;edi保存调用号

83e81151 c1ef08          shr     edi,8		    
83e81154 83e710          and     edi,10h		;判断使用哪个SSDT (ShadowSSDT)

83e81157 8bcf            mov     ecx,edi		;ecx表示使用哪个表有效	 

83e81159 03bebc000000    add     edi,dword ptr [esi+0BCh] ; 找到ETHREAD->ServiceTable 找到真正SSDT表

83e8115f 8bd8            mov     ebx,eax			
83e81161 25ff0f0000      and     eax,0FFFh			;eax保存真实调用号

83e81166 3b4708          cmp     eax,dword ptr [edi+8] ;必须小于 SSDT服务表最大支持的函数个数

83e81169 0f8333fdffff    jae     nt!KiBBTUnexpectedRange (83e80ea2) ;大于表示调用号无效

83e8116f 83f910          cmp     ecx,10h   ; 表示ecx表示使用哪个表有效	 

83e81172 751a            jne     nt!KiFastCallEntry+0xce (83e8118e)  ;SSDT 有效

83e81174 8b8e88000000    mov     ecx,dword ptr [esi+88h]				;ShadowSSDT有效
83e8117a 33f6            xor     esi,esi
83e8117c 0bb1700f0000    or      esi,dword ptr [ecx+0F70h]
83e81182 740a            je      nt!KiFastCallEntry+0xce (83e8118e)
83e81184 52              push    edx
83e81185 50              push    eax
83e81186 ff154cd9fa83    call    dword ptr [nt!KeGdiFlushUserBatch (83fad94c)]
83e8118c 58              pop     eax
83e8118d 5a              pop     edx



83e8118e 64ff05b0060000  inc     dword ptr fs:[6B0h] ; KPCR->KeSystemCalls 调用次数+1

83e81195 8bf2            mov     esi,edx			;edx ->用户参数
83e81197 33c9            xor     ecx,ecx

								;edx指向参数表
83e81199 8b570c          mov     edx,dword ptr [edi+0Ch]	;SSDT->ParamTableBase 
								;edi指向函数基址表
83e8119c 8b3f            mov     edi,dword ptr [edi] 		;SSDT->ServiceTableBase

83e8119e 8a0c10          mov     cl,byte ptr [eax+edx]		; ecx保存这个函数所需要的参数个数

83e811a1 8b1487          mov     edx,dword ptr [edi+eax*4]  ;edx保存真实函数地址(NtCreateProcess)

83e811a4 2be1            sub     esp,ecx				;内核栈开辟一段空间用于存放函数参数

83e811a6 c1e902          shr     ecx,2					;参数所需字节/4,表示需要几个参数

83e811a9 8bfc            mov     edi,esp				;esi->用户参数,edi->内核参数

83e811ab 3b351cd7fa83    cmp     esi,dword ptr [nt!MmUserProbeAddress (83fad71c)]
83e811b1 0f832e020000    jae     nt!KiSystemCallExit2+0xa5 (83e813e5)

83e811b7 f3a5            rep movs dword ptr es:[edi],dword ptr [esi] ;用户栈上的参数拷贝内核栈上

83e811b9 f6456c01        test    byte ptr [ebp+6Ch],1    ;调用来自用户层CS 
83e811bd 7416            je      nt!KiFastCallEntry+0x115 (83e811d5) 
83e811bf 648b0d24010000  mov     ecx,dword ptr fs:[124h]
83e811c6 8b3c24          mov     edi,dword ptr [esp]
83e811c9 89993c010000    mov     dword ptr [ecx+13Ch],ebx
83e811cf 89b92c010000    mov     dword ptr [ecx+12Ch],edi


83e811d5 8bda            mov     ebx,edx		;ebx保存真实函数地址

83e811d7 f60508a9f78340  test    byte ptr [nt!PerfGlobalGroupMask+0x8 (83f7a908)],40h
83e811de 0f954512        setne   byte ptr [ebp+12h]
83e811e2 0f858c030000    jne     nt!KiServiceExit2+0x17b (83e81574)
;	esp 保存用户参数
;   edx 保存真实函数地址
;   eax 保存调用号
;   ecx 保存参数个数
83e811e8 ffd3            call    ebx  ;调用真实函数 (NtCreateProcess)

SystemServiceTable系统服务表

SystemServiceTable分为两张,一种函数在Ntoskrl.exe中,一种函数Win32k.sys中,Win32k.sys是页面图形相关的,两张表中都有4个字段
ServiceTable: 函数地址表
count
servicelimit: 函数地址表多大(函数个数)
ArgmentTable:函数参数表-记录了参数多少个字节,以4字节对齐
Ntoskrl.exe中函数个数小于0x1000

  • Ntoskrl.exe的SSDT可以通过KeServiceDescriptorTable全局变量找到
  • Win32k.sys的SSDT可以通过未导出全局变量KeServiceDescriptorTableShadow的第二项找到,第一项为Ntoskrl.exe的SSDT,这一项只有GDI(界面)程序才有
// KeServiceDescriptorTable变量,声明就可以直接使用
typedef struct _ServiceDesriptorEntry
{
	ULONG* ServiceTableBase;		//服务表基址
	ULONG* ServiceCounterTableBase;	//函数表中每个函数被调用的次数
	ULONG NumberOfService;			//服务函数的个数,
	ULONG ParamTableBase;			//参数表基址
}SSDTEntry, * PSSDTEntry;

// 导入SSDT全局变量
NTSYSAPI SSDTEntry KeServiceDescriptorTable;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值