IOAPIC重定位中断处理函数思路整理

因为小可并非硬件编程出身,汇编基础又比较差。。。所以刚开始理解利用IOAPIC重定位技术的时候相当困难。

何为IOAPIC?

首先,必须认识到它是一个硬件,可编程的硬件。我理解的它在整个流程中的作用如图:

首先,必须创建一个新的中断项,也就是在IDT表中搜索到一个空闲的项,代码如下

P2C_U8 p2cGetIdleIdtVec()
{
    P2C_U8 i;
    PP2C_IDTENTRY idt_addr = (PP2C_IDTENTRY)p2cGetIdt();

    // 从vec20搜索到2a即可。
    for(i=0x20;i<0x2a;i++)
    {
        // 如果类型为0说明是空闲位置,返回即可。
        if(idt_addr[i].type == 0)
        {
            return i;
        }
    }
    return 0;
}

复制中断表中索引为0x93的项到新项

P2C_U8 p2cCopyANewIdt93(P2C_U8 id,void *interrupt_proc)
{
    // 我们写入一个新的中断门。这个门完全拷贝原来的0x93
    // 上的idtentry,只是中断处理函数的地址不同。
    PP2C_IDTENTRY idt_addr = (PP2C_IDTENTRY)p2cGetIdt();
    idt_addr[id] = idt_addr[0x93];
    idt_addr[id].offset_low = P2C_LOW16_OF_32(interrupt_proc);
    idt_addr[id].offset_high = P2C_HIGH16_OF_32(interrupt_proc);
    return id;
}

然后将ioapic重定位表中关于键盘中断IRQ1的处理地址替换掉,修改ioapic重定位表需要使用两个寄存器。

一个是IOREGSEL寄存器(只低8位有用)     一个是IOWIN寄存器(32位)

首先在IOREGSEL寄存器指定要访问的ioapic寄存器的编号,然后修改IOWIN寄存器中的内容即可达到目的

Windows把这两个寄存器分别映射到内存的物理地址0xFEC00000和0xFEC00010处

获取IOREGSEL寄存器的代码为

P2C_U8 *io_reg_sel;
    PHYSICAL_ADDRESS    phys ;
    PVOID paddr;
    RtlZeroMemory(&phys,sizeof(PHYSICAL_ADDRESS));
    phys.u.LowPart = 0xfec00000;
    paddr = MmMapIoSpace(phys, 0x14, MmNonCached);

IOWIN寄存器往后偏移0x10

    P2C_U32 *io_win;
    io_win = (P2C_U32 *)((P2C_U8 *)(paddr) + 0x10);

然后使用IOREGSEL寄存器选择第0x12项,为IRQ1的项

*io_reg_sel = 0x12;

设置新的中断号

        ch1 = *io_win;
        ch1 &= 0xffffff00;
        ch1 |= (P2C_U32)new_ch;
        *io_win = ch1;

完成!

时间: 2024-10-13 23:39:58

IOAPIC重定位中断处理函数思路整理的相关文章

ARM ELF函数重定位

ARM ELF的函数重定位与x86是一致的,但由于汇编指令不同,再鼓捣一遍. 示例代码: #include <stdio.h> #include <stdlib.h> int main () { puts ("Hello world"); sleep (1); FILE *fp = fopen ("1.c", "r"); fclose (fp); exit (0); } 通过 readelf -r 可以查看ELF中所有需要

IDT HOOK思路整理

IDT(中断描述符表)分为IRQ(真正的硬件中断)和软件中断(又叫异常). HOOK的思路为,替换键盘中断处理的函数地址为自己的函数地址.这样在键盘驱动和过滤驱动之前就可以截获键盘输入. 思路确定之后,可以写代码了 首先获取到IDT,这个需要使用汇编指令sidt来获取,这个指令读取了IDTR寄存器的内容,返回结构的格式为: typedef struct P2C_IDTR_ { P2C_U16 limit; // 范围 P2C_U32 base; // 基地址(就是开始地址) } P2C_IDTR

关于C++中的重定位

"标准库定义了4个IO对象,处理输入时使用命名为cin的istream类型对象,这个对象也成为标准输入.处理输出时使用命名为cout的ostream类型对象,这个对象也称为标准输出.标准库还定义了另外两个ostream对象,分别命名为cerr和clog.cerr对象又叫标准错误,通常用来输出警告和错误信息给程序的使用者,而clog对象用于产生程序执行的一般信息.一般情况下,系统将这些对象与执行窗口联系起来,这样,当我们从cin读入时,数据从执行程序的窗口读入,当写到cout.cerr.clog时

重定位与链接脚本

1.为什么需要重定位 位置无关编码(PIC,position independent code):汇编源文件被编码成二进制可执行程序时编码方式与位置(内存地址)无关. 位置有关编码:汇编源码编码成二进制可执行程序后和内存地址是有关的. 我们在设计一个程序时,会给这个程序指定一个运行地址(链接地址).就是说我们在编译程序时其实心里是知道我们程序将来被运行时的地址(运行地址)的,而且必须给编译器链接器指定这个地址(链接地址)才行.最后得到的二进制程序理论上是和你指定的运行地址有关的,将来这个程序被执

快速排序思路整理

引言: 快速排序和归并排序是面试当中常常被问到的两种排序算法,在研究过数据结构所有的排序算法后,个人认为最复杂的当属快速排序.从代码量上来看,快速排序并不多,我之所以认为快排难以掌握是因为快排是一种递归算法,同时终止条件较多.如果你刚刚把快排的思路整理过一遍可能觉得不难,然而一个月之后呢? 面试要求的是临场发挥,如果不是烂熟于心,基本就卡壳了.在面试官眼里,你和那些完全不懂快速排序算法的菜逼是一样的,也许实际上你可能私底下已经理解很多遍了,然而并没卵.所以当下问题就是,如何将快排烂熟于心?我觉得

解析PE资源表与重定位表

#include<Windows.h> #include<iostream> #include<stdio.h> #include<stdlib.h> #include<commdlg.h> using namespace std; DWORD dwFileSize; BYTE* g_pFileImageBase = 0; PIMAGE_NT_HEADERS g_pNt = 0; DWORD RVAtoFOA(DWORD dwRVA); //显示

了解动态链接(六)—— 重定位表

柳条青青,南风熏熏,幻化奇峰瑶岛,一天的黄云白云,那边麦浪中间,有农妇笑语殷殷.问后园豌豆肥否,问杨梅可有鸟来偷:好几天不下雨了,玫瑰花还未曾红透:梅夫人今天进城去,且看她有新闻无有.—— 徐志摩·夏日田间即景 无论是可执行文件还是 so,只要它依赖于其他 so(.dynsym 动态符号表中有导入符号存在),那么在编译链接阶段,这些符号的地址未知,所以只能在动态链接阶段对其进行地址重定位. 注意:以 PIC 编译的 so,虽然称“地址无关代码”,但也需要重定位.因为对于 PIC 的 so 来说,

也谈PE重定位表

最近研究脱壳,遇到了dll,所以不可避免的需要修复重定位表.以前研究过也脱过不少壳,但都是exe从来没有手工修过重定位表,于是搜索之,恩有这么一篇:<PE重定位表学习手记>,有刚巧手上有看雪段钢等编著的<加密与解密>,一并阅读. <PE重定位表学习手记>中说到: 每个块的首部是如下定义: typedef struct _IMAGE_BASE_RELOCATION { DWORD VirtualAddress; DWORD SizeOfBlock; } IMAGE_BAS

PE文件结构(五)基址重定位

PE文件结构(五) 参考 书:<加密与解密> 视频:小甲鱼 解密系列 视频 基址重定位 链接器生成一个PE文件时,它会假设程序被装入时使用的默认ImageBase基地址(VC默认exe基地址00400000h,dll基地址10000000h),并且会把代码中所有指令中用到的地址都使用默认的基地址(例如 程序代码中 push 10001000,就是把10000000h当做了基地址,把push 10001000写入到文件中).如果一个exe程序中一个dll装载时的地址与其它dll地址发生冲突(因为