Windows APC机制(二)

上文中讲到投递User Mode APCs是很特殊的,道理很简单,因为User Mode APC是ring3下的回调函数,显然ring0中的KiDeliverAPC()不能像Kernel Mode APC那样直接call,必须要先回到ring3环境下。当然不能像普通情况那样返回(否则就回到ring3系统调用的地方了),只有一个办法,那就是修改TrapFrame ,欺骗系统返回“APC回调函数”!KiInitializeUserApc就是这么做的!

该函数首先把TrapFrame转化为ContextFrame,然后移动用户态ESP指针,分配大约sizeof(CONTEXT)+sizeof(KAPC_RECORD)个字节:

UserStack->   ……

              KAPC_RECORD

              ……

……

CONTEXT

TopOfStack->  ……

KAPC_RECORD就是KiInitializeUserApc的最后四个参数

nt!_KAPC_RECORD

   +0x000 NormalRoutine    : Ptr32     void

   +0x004 NormalContext    : Ptr32 Void

   +0x008 SystemArgument1  : Ptr32 Void

   +0x00c SystemArgument2  : Ptr32 Void

CONTEXT结构主要来存放被修改前的TrapFrame,之所以用CONTEXT结构是跟APC函数返回有关!

 

TrapFrame->HardwareEsp = UserStack;

TrapFrame->Eip = (ULONG)KeUserApcDispatcher;

TrapFrame->ErrCode = 0;

从上面的代码看到确实修改了TrapFrame,并且返回到的是ring3下的KeUserApcDispatcher,刚才说的_KAPC_RECORD其实也是它的参数!真正我们的User APC回调函数是由KeUserApcDispatcher调用的!

 

.func KiUserApcDispatcher@16

.globl _KiUserApcDispatcher@16

_KiUserApcDispatcher@16:

 

    /* Setup SEH stack */

    lea eax, [esp+CONTEXT_ALIGNED_SIZE+16]

    mov ecx, fs:[TEB_EXCEPTION_LIST]

    mov edx, offset _KiUserApcExceptionHandler

    mov [eax], ecx

    mov [eax+4], edx

 

    /* Enable SEH */

    mov fs:[TEB_EXCEPTION_LIST], eax

 

    /* Put the Context in EDI */

    pop eax

    lea edi, [esp+12]

 

    /* Call the APC Routine */

    call eax

 

    /* Restore exception list */

    mov ecx, [edi+CONTEXT_ALIGNED_SIZE]

    mov fs:[TEB_EXCEPTION_LIST], ecx

 

    /* Switch back to the context */

    push 1    ; TestAlert

    push edi  ;edi->CONTEXT结构

call _ZwContinue@8

;;不会返回到这里的

 

上面的代码并不难理解,我们的User APC回调函数返回后,立即调用了ZwContinue,这是个ntdll中的导出函数,这个函数又通过系统调用进入kernel中的NtContinue!

NTSTATUS

; NtContinue (

;    IN PCONTEXT ContextRecord,

;    IN BOOLEAN TestAlert

;    )

;

; Routine Description:

;

;    This routine is called as a system service to continue execution after

;    an exception has occurred. Its function is to transfer information from

;    the specified context record into the trap frame that was built when the

;    system service was executed, and then exit the system as if an exception

;    had occurred.

;

;   WARNING - Do not call this routine directly, always call it as

;             ZwContinue!!!  This is required because it needs the

;             trapframe built by KiSystemService.

;

; Arguments:

;

;    KTrapFrame (ebp+0: after setup) -> base of KTrapFrame

;

;    ContextRecord (ebp+8: after setup) = Supplies a pointer to a context rec.

;

;    TestAlert (esp+12: after setup) = Supplies a boolean value that specifies

;       whether alert should be tested for the previous processor mode.

;

; Return Value:

;

;    Normally there is no return from this routine. However, if the specified

;    context record is misaligned or is not accessible, then the appropriate

;    status code is returned.

;

;--

 

NcTrapFrame             equ     [ebp + 0]

NcContextRecord         equ     [ebp + 8]

NcTestAlert             equ     [ebp + 12]

 

align dword

cPublicProc _NtContinue     ,2

 

        push    ebp         ;ebp->TrapFrame

 

;

; Restore old trap frame address since this service exits directly rather

; than returning.

;

 

        mov     ebx, PCR[PcPrcbData+PbCurrentThread] ; get current thread address

        mov     edx, [ebp].TsEdx        ; restore old trap frame address

        mov     [ebx].ThTrapFrame, edx  ;

 

;

; Call KiContinue to load ContextRecord into TrapFrame.  On x86 TrapFrame

; is an atomic entity, so we don't need to allocate any other space here.

;

; KiContinue(NcContextRecord, 0, NcTrapFrame)

;

 

        mov     ebp,esp

        mov     eax, NcTrapFrame

        mov     ecx, NcContextRecord

        stdCall  _KiContinue, <ecx, 0, eax>

        or      eax,eax                 ; return value 0?

        jnz     short Nc20              ; KiContinue failed, go report error

 

;

; Check to determine if alert should be tested for the previous processor mode.

;

 

        cmp     byte ptr NcTestAlert,0  ; Check test alert flag

        je      short Nc10              ; if z, don't test alert, go Nc10

        mov     al,byte ptr [ebx]+ThPreviousMode ; No need to xor eax, eax.

        stdCall _KeTestAlertThread, <eax> ; test alert for current thread

;如果User APCs不为空,它会设置UserApcPending,

;跟Alertable无关

Nc10:   pop     ebp                     ; (ebp) -> TrapFrame

        mov     esp,ebp                 ; (esp) = (ebp) -> trapframe

        jmp     _KiServiceExit2         ; common exit

 

Nc20:   pop     ebp                     ; (ebp) -> TrapFrame

        mov     esp,ebp                 ; (esp) = (ebp) -> trapframe

        jmp     _KiServiceExit          ; common exit

 

stdENDP _NtContinue

 

NtContinue把CONTEXT结构转化成TrapFrame(回复原来的陷阱帧),然后就从KiServiceExit2处退出系统调用!

;++

;

;   _KiServiceExit2 - same as _KiServiceExit BUT the full trap_frame

;       context is restored

;

;--

        public  _KiServiceExit2

_KiServiceExit2:

 

        cli                             ; disable interrupts

        DISPATCH_USER_APC   ebp

 

;

; Exit from SystemService

;

 

        EXIT_ALL                            ; RestoreAll

 

KiServiceExit2跟KiServiceExit差不多,只是宏参数的不同!同样如果还有User APC又会进入上文描述的情形,直到没有User APC,至此才会返回真正发起原始系统调用的地方!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Windows Internals.深入解析windows 操作系统第6版第2-3章.Russinovich.范德成.中文.扫描 内容目录 第2章系统架构 33 2.1 需求和设计目标 33 2.2 操作系统模型 34 2.3 总体架构 35 可移植性 37 对称多处理 38 可伸缩性 40 客户机和服务器版本之间的差异 41 检查版本 44 2.4 关键的系统组件 46 环境子系统和子系统DLL 47 NTDLL.DLL 53 执行体 54 内核 56 硬件抽象层(HAL) 60 设备驱动程序 62 系统进程 67 2.5 本章总结 77 第3章系统机制 79 3.1 陷阱分发 79 中断分发 81 定时器处理 110 异常分发 120 系统服务分发 130 3.2 对象管理器 137 执行体对象 139 对象结构 142 3.3 同步 174 高IRQL的同步 175 低IRQL的同步 180 3.4 系统辅助线程 202 3.5 WINDOWS全局标志 205 3.6 高级本地过程调用(ALPC) 206 连接模型 207 消息模型 208 异步操作 211 视图、区域和内存区 211 属性 212 BLOB、句柄和资源 213 安全性 214 性能 214 调试和跟踪 215 3.7 内核事件跟踪 217 3.8 WOW64 220 WOW64进程地址空间布局结构 221 系统调用 221 异常分发 222 用户APC分发 222 控制台支持 222 用户回调 222 文件系统重定向 222 注册表的重定向 223 I/O控制请求 224 16位安装器应用程序 225 打印 225 一些限制 225 3.9 用户模式调试 226 内核支持 226 原生支持 227 WINDOWS子系统支持 229 3.10 映像加载器 229 进程初始化早期工作 231 DLL名称解析 232 DLL名称重定向 233 已加载模块数据库 235 导入信息解析 239 导入过程初始化的后期处理 241 SWITCHBACK 242 API集 243 3.11 超级监督者(HYPER-V) 245 分区 246 父分区 247 子分区 249 硬件仿真和支持 251 3.12 内核事务管理器 265 3.13 热补丁支持 267 3.14 内核补丁保护 269 3.15 代码完整性 271 3.16 本章总结 272
漫谈兼容内核之一:ReactOS怎样实现系统调用 漫谈兼容内核之二:关于kernel-win32的对象管理 漫谈兼容内核之三:Kernel-win32的文件操作 漫谈兼容内核之四:Kernel-win32的进程管理 漫谈兼容内核之五:Kernel-win32的系统调用机制 漫谈兼容内核之六:二进制映像的类型识别 漫谈兼容内核之七:Wine的二进制映像装入和启动 漫谈兼容内核之八:ELF映像的装入(一) 漫谈兼容内核之九:ELF映像的装入(二) 漫谈兼容内核之十:Windows的进程创建和映像装入 漫谈兼容内核之十一:Windows DLL的装入和连接 漫谈兼容内核之十二:WindowsAPC机制 漫谈兼容内核之十三:关于“进程挂靠” 漫谈兼容内核之十四:Windows的跨进程操作 漫谈兼容内核之十五:Windows线程的等待、唤醒机制 漫谈兼容内核之十六:Windows的进程间通信 漫谈兼容内核之十七:再谈Windows的进程创建 漫谈兼容内核之十八:Windows的LPC机制 漫谈兼容内核之十九:Windows线程间的强相互作用 漫谈兼容内核之二十:Windows线程的系统空间堆栈 漫谈兼容内核之二十一:Windows进程的用户空间 漫谈兼容内核之二十二:Windows线程的调度和运行 漫谈兼容内核之二十三:关于TLS 漫谈兼容内核之二十四:Windows的结构化异常处理(一) 漫谈兼容内核之二十五:Windows的结构化异常处理(二) 漫谈兼容内核之二十六:Windows的结构化异常处理(三)

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值