[windows内核]中断门

要说中断门,不得不先说一个概念就是IDT表(中断描述符表),用来存放中断门描述符的地方,IDT也用来存放任务门,以及陷阱门描述符,具体在手册中第三卷:6.11 IDT DESCRIPTORS
在这里插入图片描述
我们在windbg中可以使用如下指令查看idt表地址以及表的大小
在这里插入图片描述
下图是中断门描述符的格式
在这里插入图片描述
字段的具体含义如下
在这里插入图片描述
现在我们了大概了解了中断门描述符,我们再来了解一下异常和中断处理
在这里插入图片描述
大概意思是说
处理器对异常和中断调用的处理方式与用 CALL 指令调用例程和任务的处理十分相近。响应异常和中断时,处理器将异常或中断向量作为 IDT 中描述符的索引。若该索引指向一个中断门或陷阱门,那么处理器会象处理 CALL 指令引用调用门一样,引用异常或中断例程.
比如说我们常见的软件调试断点,也就是通过INT 3 来触发的,也被称为0xCC断点
这条指令触发时CUP会寻找IDT表中第4个个中断门描述符来相应这条指令,之后就是windows系统里的中断和异常处理函数,要判断异常再第几环,然后检查调试器,分发异常,如果没有调试器程序接管异常,那就尝试执行VEH和SEH,如果都没有,那就再寻找一次调试器,如果还没有,程序就崩溃或者系统蓝屏,当然这都是后话了,以后学到再详谈。
我们可以先看看INT N指令
在这里插入图片描述

The INT n instruction generates a call to the interrupt or exception handler specified with the destination operand
(see the section titled “Interrupts and Exceptions” in Chapter 6 of the Intel® 64 and IA-32 Architectures Software
Developer’s Manual, Volume 1). The destination operand specifies an interrupt vector number from 0 to 255,
encoded as an 8-bit unsigned intermediate value. Each interrupt vector number provides an index to a gate
descriptor in the IDT. The first 32 interrupt vector numbers are reserved by Intel for system use. Some of these
interrupts are used for internally generated exceptions.
The INT n instruction is the general mnemonic for executing a software-generated call to an interrupt handler. The
INTO instruction is a special mnemonic for calling overflow exception (#OF), interrupt vector number 4. The overflow interrupt checks the OF flag in the EFLAGS register and calls the overflow interrupt handler if the OF flag is set
to 1. (The INTO instruction cannot be used in 64-bit mode.)
The INT 3 instruction generates a special one byte opcode (CC) that is intended for calling the debug exception
handler. (This one byte form is valuable because it can be used to replace the first byte of any instruction with a
breakpoint, including other one byte instructions, without over-writing other code). To further support its function
as a debug breakpoint, the interrupt generated with the CC opcode also differs from the regular software interrupts
as follows:
• Interrupt redirection does not happen when in VME mode; the interrupt is handled by a protected-mode
handler.
• The virtual-8086 mode IOPL checks do not occur. The interrupt is taken without faulting at any IOPL level.
Note that the “normal” 2-byte opcode for INT 3 (CD03) does not have these special features. Intel and Microsoft
assemblers will not generate the CD03 opcode from any mnemonic, but this opcode can be created by direct
numeric code definition or by self-modifying code.
The action of the INT n instruction (including the INTO and INT 3 instructions) is similar to that of a far call made
with the CALL instruction. The primary difference is that with the INT n instruction, the EFLAGS register is pushed
onto the stack before the return address. (The return address is a far address consisting of the current values of
the CS and EIP registers.) Returns from interrupt procedures are handled with the IRET instruction, which pops the
EFLAGS information and return address from the stack.
The interrupt vector number specifies an interrupt descriptor in the interrupt descriptor table (IDT); that is, it
provides index into the IDT. The selected interrupt descriptor in turn contains a pointer to an interrupt or exception
handler procedure. In protected mode, the IDT contains an array of 8-byte descriptors, each of which is an interrupt gate, trap gate, or task gate. In real-address mode, the IDT is an array of 4-byte far pointers (2-byte code
segment selector and a 2-byte instruction pointer), each of which point directly to a procedure in the selected
segment. (Note that in real-address mode, the IDT is called the interrupt vector table, and its pointers are called
interrupt vectors.)
The following decision table indicates which action in the lower portion of the table is taken given the conditions in
the upper portion of the table. Each Y in the lower section of the decision table represents a procedure defined in
the “Operation” section for this instruction (except #GP).

这里已经已经解释得很清楚,cpu首先根据IDTR找到IDT,再利用向量号码(N)找到门描述符。再去判断门描述符的类型,如果是任务描述符,如果是陷阱或中断描述符,那么会去调用处理例程。很像远距离调用与CALL指令,但是不同的是会将EFLAGS寄存器压入返回地址之前的堆栈

When the processor performs a call to the exception- or interrupt-handler procedure:
• If the handler procedure is going to be executed at a numerically lower privilege level, a stack switch occurs.
When the stack switch occurs:
a. The segment selector and stack pointer for the stack to be used by the handler are obtained from the TSS
for the currently executing task. On this new stack, the processor pushes the stack segment selector and
stack pointer of the interrupted procedure.
b. The processor then saves the current state of the EFLAGS, CS, and EIP registers on the new stack (see
Figures 6-4).
c. If an exception causes an error code to be saved, it is pushed on the new stack after the EIP value.
• If the handler procedure is going to be executed at the same privilege level as the interrupted procedure:
a. The processor saves the current state of the EFLAGS, CS, and EIP registers on the current stack (see
Figures 6-4).
b. If an exception causes an error code to be saved, it is pushed on the current stack after the EIP value

在这里插入图片描述
也就是当处理器转去执行一个异常或中断处理例程时,会将 EFLAGS 寄存器,CS 寄存器,EIP 寄存器的当前值保存进栈(参考图 6-4)。(CS 和 EIP 寄存器为中断提供了一个返回地址指针.)
如果异常同时产生了一个出错码,则该值也会压入栈中,位于 EIP 之后.
从图6-4,可以看到,若未发生特权级的改变,被中断的进程和处理例程使用的是同一个堆栈,即被中断进程的堆栈;而特权级发生改变时,则被中断的进程和处理例程将使用是不同的堆栈,而此时堆栈的指针由 TSS 中的相应字段给出。即处理例程使用的是被中断进程的高特权级堆栈,每个任务都有自己的独立的高特权级堆栈。

下面我们来看一下中断后的返回
在这里插入图片描述
大概意思就是
从异常或中断处理例程返回必须使用 IRET(或 IRETD)指令。IRET 指令与 RET 指令的唯一不同在于前者将恢复标志位。只有当 CPL 为 0 时,EFLAGS 寄存器的 IOPL 位才恢复。IF 位只有在 CPL 小于或等于 IOPL 时才改变
在这里插入图片描述

Returns program control from an exception or interrupt handler to a program or procedure that was interrupted by
an exception, an external interrupt, or a software-generated interrupt. These instructions are also used to perform
a return from a nested task. (A nested task is created when a CALL instruction is used to initiate a task switch or
when an interrupt or exception causes a task switch to an interrupt or exception handler.) See the section titled
“Task Linking” in Chapter 7 of the Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A.
IRET and IRETD are mnemonics for the same opcode. The IRETD mnemonic (interrupt return double) is intended
for use when returning from an interrupt when using the 32-bit operand size; however, most assemblers use the
IRET mnemonic interchangeably for both operand sizes.
In Real-Address Mode, the IRET instruction preforms a far return to the interrupted program or procedure. During
this operation, the processor pops the return instruction pointer, return code segment selector, and EFLAGS image
from the stack to the EIP, CS, and EFLAGS registers, respectively, and then resumes execution of the interrupted
program or procedure.
In Protected Mode, the action of the IRET instruction depends on the settings of the NT (nested task) and VM flags
in the EFLAGS register and the VM flag in the EFLAGS image stored on the current stack. Depending on the setting
of these flags, the processor performs the following types of interrupt returns:
• Return from virtual-8086 mode.
• Return to virtual-8086 mode.
• Intra-privilege level return.
• Inter-privilege level return.
• Return from nested task (task switch).
If the NT flag (EFLAGS register) is cleared, the IRET instruction performs a far return from the interrupt procedure,
without a task switch. The code segment being returned to must be equally or less privileged than the interrupt
handler routine (as indicated by the RPL field of the code segment selector popped from the stack).
As with a real-address mode interrupt return, the IRET instruction pops the return instruction pointer, return code
segment selector, and EFLAGS image from the stack to the EIP, CS, and EFLAGS registers, respectively, and then
resumes execution of the interrupted program or procedure. If the return is to another privilege level, the IRET
instruction also pops the stack pointer and SS from the stack, before resuming program execution. If the return is
to virtual-8086 mode, the processor also pops the data segment registers from the stack.
If the NT flag is set, the IRET instruction performs a task switch (return) from a nested task (a task called with a
CALL instruction, an interrupt, or an exception) back to the calling or interrupted task. The updated state of the
task executing the IRET instruction is saved in its TSS. If the task is re-entered later, the code that follows the IRET
instruction is executed.
If the NT flag is set and the processor is in IA-32e mode, the IRET instruction causes a general protection exception.
In 64-bit mode, the instruction’s default operation size is 32 bits. Use of the REX.W prefix promotes operation to 64
bits (IRETQ). See the summary chart at the beginning of this section for encoding data and limits.

下面我们做个小实验构造个中断门试试
中断门地址设为0401000h

Offset in Segment 31:16   P   DPL     D        
000000000100 00001110  1110  0000  0000
Segment Selector        Offset in Segment 15:000000 0000 0000 1000‬     ‭0001 0000 0000 0000

windbg中修改
在这里插入图片描述
编译如下代码

#include <iostream>
#include <windows.h>

int g_high2G; // 在中断门中读取高2G内存保存进来。
int g_eflagsBefore; // 保存进入中断门前的 EFLAGS 寄存器。
int g_eflagsAfter; // 保存进入中断门里的 EFLAGS 寄存器。
int g_eax; // 待会在中断门里要用到 eax ,先把旧的保存到这里。




//0401000h
void __declspec(naked)GetRegister()
{
	__asm
	{

		/*
		  此时栈结构(当你执行 int 指令的时候,CPU 会自动在0环栈中压入这些值):
			| eip3 | <- esp0
			| cs3  |
			|eflags|
			| esp3 |
			| ss3  |
		 */
		mov g_eax, eax;
		// 保存当前 eflags
		pushfd;
		pop g_eflagsAfter;
		// 保存原始 eflags
		mov eax, [esp + 0x08];
		mov g_eflagsBefore, eax;
		// 读取 0x80b95400 处的值
		mov eax, ds:[0x80b95400];
		mov g_high2G, eax;
		// 恢复 eax
		mov eax, g_eax;

		// 中断门返回
		iretd;

	}

}





int main()
{
	
	__asm {
		// 构造的中断门描述符安装在 IDT[20] 这个位置。
		int 0x20;
	}
	printf("0x80b95400: %08x\n", g_high2G);
	printf("进入中断门前的 EFLAGS = %08x\n", g_eflagsBefore);
	printf("进入中断门后的 EFLAGS = %08x\n", g_eflagsAfter);
	system("pause");
	GetRegister();
	return 0;
}

执行
在这里插入图片描述
成功执行我们自己构建的中断门代码并返回

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值