DSP

3.API的调用过程(保存现场)

2019-07-13 18:27发布

class="markdown_views prism-dracula"> _KTrap_Frame 结构 kd> dt _KTrap_Frame ntdll!_KTRAP_FRAME //调试系统服务 +0x000 DbgEbp : Uint4B +0x004 DbgEip : Uint4B +0x008 DbgArgMark : Uint4B +0x00c DbgArgPointer : Uint4B //当需要调整栈时以下作为临时变量 +0x010 TempSegCs : Uint4B +0x014 TempEsp : Uint4B //调试寄存器 +0x018 Dr0 : Uint4B +0x01c Dr1 : Uint4B +0x020 Dr2 : Uint4B +0x024 Dr3 : Uint4B +0x028 Dr6 : Uint4B +0x02c Dr7 : Uint4B //段寄存器 +0x030 SegGs : Uint4B +0x034 SegEs : Uint4B +0x038 SegDs : Uint4B //易失寄存器 +0x03c Edx : Uint4B +0x040 Ecx : Uint4B +0x044 Eax : Uint4B //非易失性寄存器需要在中断例程中先保存 +0x048 PreviousPreviousMode : Uint4B +0x04c ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD +0x050 SegFs : Uint4B //非易失寄存器 +0x054 Edi : Uint4B +0x058 Esi : Uint4B +0x05c Ebx : Uint4B +0x060 Ebp : Uint4B +0x064 ErrCode : Uint4B//硬件填充 (通过中断门进入的,这个值为NULL) //中断发生时保存被中断的代码段和地址,iret返回到此地址 +0x068 Eip : Uint4B//硬件填充 +0x06c SegCs : Uint4B//硬件填充 +0x070 EFlags : Uint4B//硬件填充 //中断发生时,若发生权限变换,则要保存旧堆栈 +0x074 HardwareEsp : Uint4B//硬件填充,仅当有模式切换时才会使用 +0x078 HardwareSegSs : Uint4B//硬件填充,仅当有模式切换时才会使用 //这4个在保护模式下没有使用 +0x07c V86Es : Uint4B//硬件填充 +0x080 V86Ds : Uint4B//硬件填充 +0x084 V86Fs : Uint4B//硬件填充 +0x088 V86Gs : Uint4B//硬件填充 无论是通过中断门进入的0环,还是快速调用,3环所有的寄存器都会保存在这个结构体里。
通过快速调用68~78是没有的

在这里插入图片描述
权限发生切换时堆栈也会改变,这里听不懂的话去学习保护模式 内核层的ESP = TSS+4
Windows操作系统在每个处理器初始化时,会在GDT中为它构造一个TSS段,然后利用ltr指令设置处理器的任务环境段。(参考_KiSystemStartup函数)
另外,Windows每次切换线程时,总是会设置好TSS中Ring0的esp,使指向当前线程的内核栈。(参考SwapContext函数) 保存3环寄存器值到_KTrap_Frame的0x50~0x64
fs :0030 拆分 0000 0000 0011 0 0 00,RPL为0 ,查gdt,第六组
ffc093df`f0000001
ffdff000这个地址刚好指向的就是CUP的KPCR结构,fs在3环指向的是PEB结构,0环就是kpcr。 继续上面
在这里插入图片描述
Exceptionlist是异常链表。
把老的Exceptionlist保存到_KTRAP_FRAME的+0x4c位置,然后把它置为空白。
将kpcr+0x124放到esi中,也就是CurrentThread。 将[esi+140]保存先前模式到_KTRAP_FRAME的+048位置,_KTHREAD.PreviousMode 。
提升堆栈0x48
取出3环的CS放到ebx,然后and 上1结果放到esi+0x140,也就是新的先前模式。 先前模式:当你调用这段代码的时候,如果是0环的程序先前模式就存0,3环就存1。操作系统想知道是哪一环的程序调用我只需要查看调用者的先前模式即可 提升栈底ebp与esp指向同一个位置_KTRAP_FRAME最开始的位置
取出esi+0x134的位置_KTHREAD.TrapFrame (+0x134 当前线程的信息),放到ebp+3c_KTHREAD.Edx 。 在这里插入图片描述
_KTRAP_FRAME放到_KTHREAD.TrapFrame
把3环的ebp放到ebx
把3环的eip放到edi
把3环的参数指针放到_KTRAP_FRAME.DbgArgPointer 在这里插入图片描述
在这里插入图片描述 0x0dadb0d0(操作系统用到的一个标志)放到_KTRAP_FRAME.DbgArgMark
ebp+0 = _KTRAP_FRAME.DbgEbp
ebp+04 = _KTRAP_FRAME.DbgEip
比较_KTHREAD.DebugActive(当前线程是否处于调试状态如果处于调试状态这个值就不是0ff),如果你处于调试状态他就会跳转到下面的代码。他
就是将dr0~dr7存到_KTRAP_FRAME的+0x18到+0x2c。 如果不处于调试状态跳转到以下代码
无论是从KiFastCallEntry还是kisystenService都会最终都会调用一下的代码 两空进来最中执行的代码是一样的,中断进来和快速调用的他们填表(_KTrap_Frame)的方式不一样但是最终调用的代码都是一样的
在这里插入图片描述
  • kiSystenService:
    进入0环后原来3环的寄存器保存在_KTrap_Frame的0x50~0x64
    把3环的参数指针放到_KTRAP_FRAME.DbgArgPointer
以上都kiSystenService从0环进入3环的填表过程

KiFastCallEntry的填表过程

在这里插入图片描述
KPCR+40就是TSS,TSS+4就是esp0 push 到_KTrap_Frame
+0x078 HardwareSegSs : Uint4B
+0x074 HardwareEsp : Uint4B
+0x070 EFlags : Uint4B 直接贴ida分析代码了 mov ecx, 23h push 30h pop fs ; 修改fs寄存器为30 mov ds, ecx mov es, ecx mov ecx, ds:0FFDFF040h ; 获取当前TSS mov esp, [ecx+4] ; TSS中得到ESP push 23h ; 原ss压栈 push edx ; 原esp压栈 pushf ; EFLAGS压栈 loc_40770A: ; CODE XREF: _KiFastCallEntry2+22j push 2 add edx, 8 ; 当前保存着sysentet进入前的ESP的值 ; +8 = 参数指针 popf or [esp+0Ch+var_B], 2 ; KtrapFrame->Eflags.if = 1 push 1Bh ; KtrapFrame->CS=0x1b 保存r3的cs push dword ptr ds:0FFDF0304h ; KtrapFrame->EIP =返回地址 push 0 ; KtrapFrame->Error = 0 push ebp ; KtrapFrame->ebp = ebp push ebx ; KtrapFrame->ebx = ebx push esi ; KtrapFrame->esi = esi push edi ; KtrapFrame->edi = edi mov ebx, ds:0FFDFF01Ch push 3Bh ; KtrapFrame->SegFs = 0x3b 保存r3的fs mov esi, [ebx+124h] ; 得到当前线程结构 push dword ptr [ebx] ; KtrapFrame->0x4c 保存原异常链 mov dword ptr [ebx], 0FFFFFFFFh ; 设置为空的异常链 mov ebp, [esi+18h] ; 得到初始堆栈KtrapFrame->0x48 push 1 ; KtrapFrame->PreviousPreviousMode = 1 sub esp, 48h ; 提升栈顶指针到_Ktrap_Frame sub ebp, 29Ch ; Ktrap_Frame mov byte ptr [esi+140h], 1 ; 先前模式 cmp ebp, esp jnz loc_4076C8 and dword ptr [ebp+2Ch], 0 ; 清零dr7 test byte ptr [esi+2Ch], 0FFh ; 检查是否处于调试状态 mov [esi+134h], ebp ; ; jnz Dr_FastCallDrSave loc_40776A: ; CODE XREF: Dr_FastCallDrSave+10j ; Dr_FastCallDrSave+7Cj mov ebx, [ebp+60h] ; ebp = KtrapFrame->ebp mov edi, [ebp+68h] ; edi = KtrapFrame->eip mov [ebp+0Ch], edx ; KtrapFrame->DbgArgPointer = 参数指针 mov dword ptr [ebp+8], 0BADB0D00h mov [ebp+0], ebx ; KtrapFrame->DbgEbp = ebx mov [ebp+4], edi ; KtrapFrame->DbgEip = edi sti