本文主要描述 win10_x64 + IA32-E 的中断处理流程 从I/O APIC开始 至调用用户注册的 ISR 函数被调用结束 ,分为上下两篇 本章为 下篇 主要逆向 win10_x64 对中断的处理过程
会用到的东西:Win10_x64 + Windbg + IDA + Xp源代码 + Intel手册 二本 大三 水平有限 还请各位前辈多多指点
书接上文,在CPU接收到local APIC 发来的中断请求后,在栈中自动压入必要参数并跳转至中断描述符中所指地址后,win10_x64 内核代码开始接管中断处理流程。 从两个方向来分析 NT 内核的中断处理: 1) 收到中断后的处理流程 2) 驱动程序注册ISR(Interrupt Service Routines)的过程
在windbg 中使用 !idt 命令 列出相关信息 可以明显看出: 0-0x15(21)号中断 :用于对CPU中产生的异常的处理 22-31(1f) 号中断 :未被使用 31-255 号中断 : 由系统自行分配 以0x35号向量为例开始分析 使用 u ffff803801dee38 指令对IDT描述符所指中断处理例程进行反汇编,发现其存在明显特征 即在栈中压入其中断向量号0x35 和 rbp 寄存器地址后,进行跳转且 下文存在同样结构,在压入0x36和rbp后进行跳转,且跳转地址一致,我们猜测0x36号中断的中断处理例程指向push 0x36 首地址,通过分析证明此猜测正确。 在IDA中加载内核文件,并重定位基址使其于windbg中一致,发现大量一致性结构 ,证明 对所有中断处理的第一步 是首先执行 KiIsrThunkShadow 中对应的代码,用于在栈中压入对应的中断向量,和保存rbp 开启页表隔离后应为,可以看出少压入了rbp 少压入的rbp参数会在进入KiIsrLinkage 前被补充,所以页表隔离并不影响中断处理的主要逻辑 分析KxIsrLinkageShadow函数(开启页表隔离的情况下的中断处理流程) 分析KxIsrLinkage的主要部分 _guard_dispatch_icall 函数用作指令流保护,意在利用编译时产生的cfgbitmap,检测出 被跳转位置是否为合法地址,已阻止 shellocde 的执行此处等价于 jmp rax 总结上文所述 NT内核 在接管中断后动作如下 1) 在栈中压入中断号 2) 处理页表隔离 3) 保存好中断前的线程上下文 4) 根据中断向量号 在此核心的KPCR中找到对应的中断对象 5) 调用中断对象的 DispatchAddress函数 下文开始分析驱动程序注册ISR(Interrupt Service Routines)的过程
中断处理过程的最后调用了_KINTERRUPT.DispatchAddress中所指函数,通过分析ISR注册过程得到DispatchAddress所对应的函数。
msdn中对IoConnectInterrupt 给出的解释: The IoConnectInterrupt routine registers a device driver's InterruptService routine (ISR), so that it will be called when a device interrupts on any of a specified set of processors.
我们只分析四个参数 [out] InterruptObject 输出参数,返回被初始化好的中断对象 [in] ServiceRoutine 由用户驱动实现的中断响应函数 [in, optional] ServiceContext 调用用户中断响应函数时传递的参数 [in] Vector 中断响应函数对应的中断向量 IoConnectInterruptEx -> IopConnectInterrupt -> KeInitializeInterruptEx KeInitializeInterruptEx 用于初始化一个中断对象: IoConnectInterruptEx -> IopConnectInterrupt -> KeConnectInterrupt—>KiConnectInterrupt KiConnectInterrupt用于将一个被初始化好的中断对象插入目标核心的KPCR中 由此得出_KINTERRUPT.DispatchAddress = KiChainedDispatch 总结上文: 1)NT内核将用户注册的中断例程抽象为一个中断对象 2)NT内核将此对象初始化完毕后挂入KPCR.InterruptObject 3) 在发生中断后调用 _KINTERRUPT.DispatchAddress 函数 即KiChainedDispatch 下文开始分析 KiChainedDispatch KiChainedDispatch->KiScanInterruptObjectList ->KiCallInterruptServiceRoutine KiScanInterruptObjectList 扫描此KPCR(核心)相关联的所有中断对象 KiCallInterruptServiceRoutine 调用由用户注册的ISR函数 总结一下上文: 由用户设定的ISR 由 KeInitializeInterruptEx 函数写入中断对象中 _KINTERRUPT.ServiceRoutine = isr_callback //用户注册的isr 从一个中断到达I/O APIC 至用户注册的ISR被调用的过程: 1)I/O APIC 2)local APIC 3)IDT 3)KiIsrThunkShadow 4)KxIsrLinkageShadow 5)KiChainedDispatch 6)KiCallInterruptServiceRoutine 7)_KINTERRUPT.ServiceRoutine
先写到这里,难免由疏漏,请各位斧正。
NTSTATUS IoConnectInterrupt(
[out] PKINTERRUPT
*
InterruptObject,
[
in
] PKSERVICE_ROUTINE ServiceRoutine,
[
in
, optional] PVOID ServiceContext,
[
in
, optional] PKSPIN_LOCK SpinLock,
[
in
] ULONG Vector,
[
in
] KIRQL Irql,
[
in
] KIRQL SynchronizeIrql,
[
in
] KINTERRUPT_MODE InterruptMode,
[
in
] BOOLEAN ShareVector,
[
in
] KAFFINITY ProcessorEnableMask,
[
in
] BOOLEAN FloatingSave
);
NTSTATUS IoConnectInterrupt(
[out] PKINTERRUPT
*
InterruptObject,
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!