BASIC INTERRUPT 1

本文介绍了一个简单的Windows内核模式下基本中断钩子(Basic Interrupt Hook)的实现方法。通过定义IDT表项结构和使用旁路指令(sidt)获取当前IDT信息,遍历并打印所有中断向量的地址。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

// --------------------
// BASIC INTERRUPT HOOK
// --------------------

#include "ntddk.h"
#include <stdio.h>

#define MAKELONG(a, b) ((unsigned long) (((unsigned short) (a)) | ((unsigned long) ((unsigned short) (b))) << 16))

#define MAX_IDT_ENTRIES 0xFF

#define NT_INT_UNUSED_A    0x20

#define NT_INT_UNUSED_B    0x22
#define NT_INT_UNUSED_C    0x23
#define NT_INT_UNUSED_D    0x24
#define NT_INT_UNUSED_E    0x25
#define NT_INT_UNUSED_F    0x26
#define NT_INT_UNUSED_G    0x27
#define NT_INT_UNUSED_H    0x28
#define NT_INT_UNUSED_I    0x29

#define NT_INT_SYSTEMSERVICE  0x2E

///////////////////////////////////////////////////
// IDT structures
///////////////////////////////////////////////////
#pragma pack(1)

// entry in the IDT, this is sometimes called
// an "interrupt gate"
typedef struct
{
 unsigned short LowOffset;
 unsigned short selector;
 unsigned char unused_lo;
 unsigned char segment_type:4; //0x0E is an interrupt gate
 unsigned char system_segment_flag:1;
 unsigned char DPL:2; // descriptor privilege level
 unsigned char P:1; /* present */
 unsigned short HiOffset;
} IDTENTRY;

/* sidt returns idt in this format */
typedef struct
{
 unsigned short IDTLimit;
 unsigned short LowIDTbase;
 unsigned short HiIDTbase;
} IDTINFO;

#pragma pack()

VOID OnUnload( IN PDRIVER_OBJECT DriverObject )

 DbgPrint("ROOTKIT: OnUnload called/n");
}

NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{
 IDTINFO  idt_info;  // this structure is obtained by calling STORE IDT (sidt)
 IDTENTRY* idt_entries; // and then this pointer is obtained from idt_info
 unsigned long count;

 theDriverObject->DriverUnload  = OnUnload;

 // load idt_info
 __asm sidt idt_info
 
 idt_entries = (IDTENTRY*) MAKELONG(idt_info.LowIDTbase,idt_info.HiIDTbase);

 for(count=0;count < MAX_IDT_ENTRIES;count++)
 {
  char _t[255];
  IDTENTRY *i = &idt_entries[count];
  unsigned long addr = 0;
  addr = MAKELONG(i->LowOffset, i->HiOffset);
  
  _snprintf(_t, 253, "Interrupt %d: ISR 0x%08X", count, addr);
  DbgPrint(_t);
 }

 return STATUS_SUCCESS;
}
 

/* ----------------------- Start implementation -----------------------------*/ BOOL xMBPortTimersInit( USHORT usTim1Timerout50us ) { std_tim_basic_init_t basic_init_struct = {0}; uint32_t tmp_psc_value; /* TIM1时钟使能 */ std_rcc_apb2_clk_enable(RCC_PERIPH_CLK_TIM1); tmp_psc_value = (uint32_t)(((SystemCoreClock) / 10000) - 1); //Tout=(ARR+1)(PSC+1)/Tclk (4799+1)(PSC+1)/(48M) basic_init_struct.prescaler = usTim1Timerout50us ; basic_init_struct.counter_mode = TIM_COUNTER_MODE_UP; basic_init_struct.period = tmp_psc_value; basic_init_struct.clock_div = TIM_CLOCK_DTS_DIV1; basic_init_struct.repeat_counter = 0x00; std_tim_init(TIM1, &basic_init_struct); NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, NVIC_PRIO_0); NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn); /* 清除更新事件标志 */ std_tim_clear_flag(TIM1, TIM_FLAG_UPDATE); /* 使能更新中断 */ std_tim_interrupt_enable(TIM1, TIM_INTERRUPT_UPDATE); /* 清除更新事件标志 */ std_tim_clear_flag(TIM1, TIM_FLAG_UPDATE); /* 开启定时器计数 */ std_tim_disable(TIM1); //DISABLE TIMER return TRUE; } void vMBPortTimersEnable( ) { std_tim_clear_flag(TIM1, TIM_FLAG_UPDATE); std_tim_interrupt_enable(TIM1, TIM_INTERRUPT_UPDATE); std_tim_set_counter(TIM1,0); std_tim_enable(TIM1); // Enable Timer } void vMBPortTimersDisable( ) { std_tim_clear_flag(TIM1, TIM_FLAG_UPDATE); std_tim_interrupt_disable(TIM1, TIM_INTERRUPT_UPDATE); std_tim_set_counter(TIM1,0); std_tim_disable(TIM1); // Disable Timer and Reset Counter } void prvvTIMERExpiredISR( void ) // __irq { ( void )pxMBPortCBTimerExpired( ); // VICVectAddr = 0xFF; // Acknowledge Interrupt } Cortex-M0 C代码转汇编程序
07-24
<think>我们有一个Cortex-M0的C代码片段,需要将其转换为汇编代码。由于Cortex-M0使用Thumb指令集,我们将使用ARM汇编语言(Thumb模式)进行转换。 注意:由于不同的编译器生成的汇编可能不同,这里我们根据代码逻辑手动转换,并尽量保持功能一致。 给定的C代码包括三个函数:xMBPortTimersInit, vMBPortTimersEnable, vMBPortTimersDisable,以及一个中断服务程序prvvTIMERExpiredISR。 我们假设: - 寄存器使用:遵循AAPCS(ARM Architecture Procedure Call Standard),函数调用时,参数通过r0, r1等传递,返回值在r0中。 - 中断服务程序需要保存和恢复上下文。 由于prvvTIMERExpiredISR是一个中断服务程序,我们需要在汇编中正确保存和恢复寄存器,并正确返回。 另外,代码中使用了外设寄存器(如TIM1)和一些标准外设库函数(如std_rcc_apb2_clk_enable, std_tim_init等),这些在汇编中需要替换为直接操作寄存器。 由于外设寄存器操作的具体地址取决于具体的微控制器,这里我们使用宏定义来代替具体的寄存器地址。在实际应用中,需要根据数据手册定义这些地址。 由于代码较长,我们将分函数进行转换。 首先,我们定义一些必要的寄存器地址和位定义(根据STM32F0系列或其他Cortex-M0芯片的TIM1和RCC寄存器定义): - RCC_APB2ENR 地址(假设为0x40021018),其中TIM1时钟使能位(第11位) - TIM1相关寄存器:CR1, CR2, SMCR, DIER, SR, CNT, PSC, ARR, EGR等。 但是,由于原代码使用了库函数,我们有两种选择: 1. 在汇编中调用C库函数(不推荐,因为这样汇编代码仍然依赖库)。 2. 将库函数展开为直接操作寄存器。 这里我们选择第二种方法,但是需要知道库函数的具体操作。由于原代码中库函数的具体实现未知,我们将根据函数名和参数推测其操作。 我们按照函数逐个转换: 1. xMBPortTimersInit( USHORT usTim1Timerout50us ) 参数:usTim1Timerout50us(16位)在r0中传递。 返回值:BOOL(TRUE=1)在r0中返回。 步骤: a. 使能TIM1时钟:设置RCC_APB2ENR寄存器的TIM1EN位(第11位)。 b. 计算预分频值:tmp_psc_value = (SystemCoreClock / 10000) - 1; 这里SystemCoreClock是系统时钟频率,假设为48MHz,则tmp_psc_value = (48000000/10000)-1 = 4799。 但是注意,代码中计算tmp_psc_value是作为ARR(自动重装载值)使用的,而参数usTim1Timerout50us被赋值给了预分频器(PSC)。 实际上,原代码中: basic_init_struct.prescaler = usTim1Timerout50us; // 预分频器 basic_init_struct.period = tmp_psc_value; // 自动重装载值 c. 初始化TIM1:设置TIM1的PSC和ARR等寄存器。 d. 配置NVIC:设置TIM1中断的优先级并使能。 e. 清除更新事件标志和使能更新中断。 f. 禁用定时器。 注意:由于Cortex-M0的NVIC寄存器是内存映射的,我们需要访问NVIC的寄存器。 2. vMBPortTimersEnable: 使能定时器,包括清除标志、使能中断、计数器清零、使能计数器。 3. vMBPortTimersDisable: 禁用定时器,包括清除标志、禁用中断、计数器清零、禁用计数器。 4. prvvTIMERExpiredISR: 中断服务程序,调用pxMBPortCBTimerExpired函数(函数指针),然后中断返回。 由于汇编代码较长,我们只写出关键步骤,并尽量使用伪代码(使用EQU定义寄存器地址)和注释。 注意:在中断服务程序中,我们需要保存和恢复寄存器(除了PC, PSR外,还需要保存r0-r3, r12, lr),因为C函数调用会修改这些寄存器。但是,Cortex-M0在进入中断时自动保存了部分寄存器(R0-R3, R12, LR, PC, PSR),而我们在中断服务程序中调用的函数可能会修改其他寄存器(r4-r11),所以如果使用了这些寄存器,则需要手动保存。然而,我们的中断服务程序很简单,只调用了一个函数,该函数可能会修改r0-r3, r12, lr,所以我们需要手动保存r4-r11吗?实际上,根据AAPCS,被调用的函数会保存r4-r11,所以中断服务程序本身不需要额外保存,但为了安全,我们保存r0-r3和r12以及lr(因为lr在中断服务程序中有特殊用途)。 然而,在Cortex-M中,中断服务程序使用一个特殊的返回指令(bx lr)并不正确,应该使用中断返回指令(通常使用汇编器提供的宏)。在汇编中,我们可以直接使用“bx lr”返回,但需要将lr设置为特殊的值(0xFFFFFFFx)。实际上,在进入中断时,硬件将lr设置为特殊的值(EXC_RETURN),所以我们不能破坏lr。因此,在中断服务程序中,我们只需要保存可能被修改的寄存器(r0-r3, r12)以及lr(因为lr中保存了EXC_RETURN),然后调用函数,最后恢复这些寄存器并使用bx lr返回。 但是,根据AAPCS,函数调用会破坏r0-r3和r12,所以我们只需要保存这些寄存器以及lr(即EXC_RETURN)。注意,在中断服务程序中,lr在进入时已经被设置为一个特殊值(例如0xFFFFFFF9),所以我们需要保存它。 步骤: 保存r0-r3, r12, lr到栈中。 调用pxMBPortCBTimerExpired(函数指针,假设该函数指针在某个全局变量中,或者它是一个已知的函数?) 恢复r0-r3, r12, lr。 使用bx lr返回。 然而,pxMBPortCBTimerExpired是一个函数指针,我们需要知道它的地址。假设它的地址保存在一个全局变量中,比如`pxMBPortCBTimerExpired`。 但是,原代码中调用方式为:`( void )pxMBPortCBTimerExpired( );`,说明pxMBPortCBTimerExpired是一个无参数、无返回值的函数指针。 在汇编中,我们可以这样调用: ldr r0, =pxMBPortCBTimerExpired ; 将函数指针的地址加载到r0 ldr r0, [r0] ; 加载函数指针的值到r0 blx r0 ; 调用函数 由于我们保存了lr(EXC_RETURN),在调用函数后,我们恢复lr,然后返回。 现在,我们开始编写汇编代码。由于代码量很大,我们只写出关键部分的伪代码,并假设寄存器地址已定义。 注意:我们使用ARM汇编语法(GNU汇编器)。 定义寄存器地址: RCC_BASE: 0x40021000 RCC_APB2ENR: 0x18 (相对于RCC_BASE的偏移) TIM1_BASE: 0x40012C00 TIM_CR1: 0x00 TIM_CR2: 0x04 TIM_SMCR: 0x08 TIM_DIER: 0x0C TIM_SR: 0x10 TIM_EGR: 0x14 TIM_CNT: 0x24 TIM_PSC: 0x28 TIM_ARR: 0x2C NVIC_ISER: 0xE000E100 // 中断使能寄存器 NVIC_IPR0: 0xE000E400 // 中断优先级寄存器0(因为TIM1_BRK_UP_TRG_COM_IRQn的中断号可能是17,所以优先级寄存器偏移为17*4/4=17,但每个优先级寄存器有4个字节对应一个中断?实际上每个优先级寄存器是32位,每8位一个中断优先级,所以一个寄存器可以容纳4个中断。因此中断号17的优先级在NVIC_IPR4的字节1(因为17/4=4余1)) 但是,由于直接操作NVIC寄存器比较复杂,而且原代码使用了NVIC_SetPriority和NVIC_EnableIRQ函数,我们也可以调用这两个函数(如果我们在汇编中保留C库函数调用)或者展开它们。 为了简化,我们假设在汇编中直接操作寄存器,并假设TIM1中断号为17(具体根据芯片而定,例如STM32F0中TIM1_BRK_UP_TRG_COM_IRQn为17)。 设置中断优先级:NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, NVIC_PRIO_0); NVIC_PRIO_0为0,所以优先级寄存器中对应位设为0。 中断使能:NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn) -> 设置NVIC_ISER寄存器的第17位。 由于代码较长,我们只转换第一个函数xMBPortTimersInit作为示例,其他函数类似。 注意:由于汇编代码很长,我们只写出函数体,并假设一些常量。 我们使用以下寄存器映射: r0: 参数和临时值 r1, r2, r3, r4: 临时寄存器 开始编写xMBPortTimersInit的汇编代码:</think>### Cortex-M0 C代码转汇编程序 以下是将提供的C代码转换为Cortex-M0汇编语言的实现。Cortex-M0使用Thumb指令集,所有指令都是16位的。转换过程涉及寄存器操作、内存访问和中断处理。 ```assembly ; 假设寄存器地址定义 ; RCC_APB2ENR = 0x40021018 ; TIM1_CR1 = 0x40012C00 ; TIM1_DIER = 0x40012C0C ; TIM1_SR = 0x40012C10 ; TIM1_CNT = 0x40012C24 ; NVIC_ISER = 0xE000E100 ; NVIC_IPR0 = 0xE000E400 ; BOOL xMBPortTimersInit(USHORT usTim1Timerout50us) xMBPortTimersInit: PUSH {R4-R7, LR} ; 保存寄存器 MOVS R4, R0 ; 保存参数 usTim1Timerout50us 到 R4 ; 使能 TIM1 时钟 (RCC_APB2ENR |= (1 << 11)) LDR R0, =0x40021018 ; RCC_APB2ENR 地址 LDR R1, [R0] MOVS R2, #0x800 ; 第11位掩码 (1 << 11) ORRS R1, R1, R2 STR R1, [R0] ; 计算 tmp_psc_value = (SystemCoreClock/10000) - 1 ; 假设 SystemCoreClock = 48000000 (48MHz) LDR R5, =4799 ; (48000000/10000)-1 = 4799 ; 配置 TIM1 寄存器 (伪代码简化) ; std_tim_init(TIM1, &basic_init_struct) LDR R0, =0x40012C00 ; TIM1_CR1 地址 MOVS R1, #0 ; 向上计数模式 STR R1, [R0, #0x00] ; CR1 STR R4, [R0, #0x28] ; PSC = usTim1Timerout50us STR R5, [R0, #0x2C] ; ARR = tmp_psc_value ; 设置 NVIC 优先级和使能 ; TIM1_BRK_UP_TRG_COM_IRQn = 17 LDR R0, =0xE000E400 ; NVIC_IPR0 MOVS R1, #0 ; 最高优先级 STRB R1, [R0, #17] ; 设置优先级 LDR R0, =0xE000E100 ; NVIC_ISER MOVS R1, #0x00020000 ; 第17位 STR R1, [R0] ; 清除标志和禁用定时器 LDR R0, =0x40012C10 ; TIM1_SR MOVS R1, #0 STR R1, [R0] ; 清除更新标志 LDR R0, =0x40012C0C ; TIM1_DIER STR R1, [R0] ; 禁用更新中断 MOVS R0, #1 ; 返回 TRUE POP {R4-R7, PC} ; 恢复寄存器并返回 ; void vMBPortTimersEnable() vMBPortTimersEnable: LDR R0, =0x40012C10 ; TIM1_SR MOVS R1, #0 STR R1, [R0] ; 清除标志 LDR R0, =0x40012C0C ; TIM1_DIER MOVS R1, #1 STR R1, [R0] ; 使能更新中断 LDR R0, =0x40012C24 ; TIM1_CNT STR R1, [R0] ; 计数器清零 LDR R0, =0x40012C00 ; TIM1_CR1 MOVS R1, #1 STR R1, [R0] ; 使能定时器 BX LR ; void vMBPortTimersDisable() vMBPortTimersDisable: LDR R0, =0x40012C10 ; TIM1_SR MOVS R1, #0 STR R1, [R0] ; 清除标志 LDR R0, =0x40012C0C ; TIM1_DIER STR R1, [R0] ; 禁用更新中断 LDR R0, =0x40012C24 ; TIM1_CNT STR R1, [R0] ; 计数器清零 LDR R0, =0x40012C00 ; TIM1_CR1 STR R1, [R0] ; 禁用定时器 BX LR ; 中断服务程序 TIM1_BRK_UP_TRG_COM_IRQHandler: PUSH {R0-R3, LR} ; 保存上下文 LDR R0, =0x40012C10 ; TIM1_SR MOVS R1, #0 STR R1, [R0] ; 清除中断标志 BL pxMBPortCBTimerExpired ; 调用回调函数 POP {R0-R3, PC} ; 恢复上下文并返回 ``` ### 代码解释: 1. **寄存器使用**: - `R0-R3`:用于参数传递和临时计算 - `R4-R7`:保存长期变量(如函数参数) - `LR`:链接寄存器,保存返回地址 2. **关键操作**: - **时钟使能**:通过设置`RCC_APB2ENR`寄存器的第11位来使能TIM1时钟 - **定时器配置**:设置预分频器(PSC)和自动重装载值(ARR) - **NVIC配置**:设置中断优先级并启用TIM1中断 - **中断处理**:保存上下文→清除中断标志→调用回调函数→恢复上下文 3. **中断处理流程**: - 中断发生时自动跳转到`TIM1_BRK_UP_TRG_COM_IRQHandler` - 使用`PUSH`/`POP`保存和恢复寄存器 - 必须手动清除中断标志位 4. **优化特点**: - 使用`STR`/`LDR`直接操作寄存器提高效率 - 最小化栈操作(仅保存必要寄存器) - 利用立即数加载优化常数操作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值