1、rootkit hook之四 IDT Hook标 题:【原创】rootkit hook之四- IDT Hook作 者:combojiang时 间:2008-02-19,17:05:37链 接:今天我们一起来学习下Rootkit里面的IDThook.由于涉及到一些基本概念,在这里也顺便提一下。呵呵,帖子比较长,慢慢看。闲话少说,直奔主题。我们首先来了解下什么是IDT?IDT=InterruptDescriptorTable中断描述表IDT是一个有256个入口的线形表,每个IDT的入口是个8字节的描述符,所以整个IDT表的大小为256*8=2048bytes,每个中断向量关联了一个中断处理过程。所
2、谓的中断向量就是把每个中断或者异常用一个0-255的数字识别。Intel称这个数字为向量(vector).如图所示。对于中断描述表,操作系统使用IDTR寄存器来记录idt位置和大小。IDTR寄存器是48位寄存器,用于保存idt信息。其中低16位代表IDT的大小,大小为7FFH,高32位代表IDT的基地址。在我的机器上,基地址是8003F400H.我们可以利用指令sigt读出IDTR寄存器中的信息,从而找到IDT在内存中的位置。IDT有三种不同的描述符或者说是入口,分别是:1。任务门描述符2。中断门描述符3。陷阱门描述符也就是说,在保护模式下,80386只有通过中断门、陷阱门或任务门才能转移到对
3、应的中断或异常处理程序。Intel参考手册上指出“同步中断”(在一个指令执行完成后,由CPU控制单元产生的)作为“异常”。异步中断(可能会在任意时刻由其他硬件产生的)才称为“中断”。中断被外部的I/O设备产生。但是异常是由编程错误或者是由反常情况(必须由内核来处理)触发的。在该文档中,术语“中断信号”既指异常又指中断。中断分为两种类型:可屏蔽中断-它在短时间片段里可被忽略;不可屏蔽中断-它必须被立即处理。例如:硬件失败为不可屏蔽中断,IRQS(中断请求)失败为可屏蔽中断。异常被分为不同的两类:处理器产生的异常(Faults,Traps,Aborts)和编程安排的异常(用汇编指令intorint
4、3触发)。后一种就是我们经常说到的软中断。我们先看看这三种描述符:其中:后两种描述符,非常的相似,只有1个bit位的差别。在处理上,采用相同的处理方式。如图所示,在这后两类的描述符里面记录了一个中断服务程序(ISR)的地址offset.在IDT的256个向量中,除3个任务门入口外,其他都是这两种门的入口。并且所有的trap/interruptgate的入口,他们的segmentselector都是一样的,即:08h.我们察看GDT中Selector=8的描述符,描述的是00000000h0ffffffffh的4G地址空间。因此,在描述符中的中断服务程序(ISR)的地址offset就代表了函数的
5、入口地址。windows在处理的时候,按照下图方式,来处理这两类的描述符入口。即:根据segmentselector在GDT中找出段基地址等信息,然后跟描述符中的中断服务程序(ISR)的地址offset相加得到代码段中的函数入口地址。然后调用该函数。这个过程,我写得比较直接,在操作系统执行这过程时,还有很多的出错判断和异常保护,这里我们略过。接下来,我们看看任务门描述符的情况。首先,根据IDT中任务门描述符的TSSSegmentSelector,我们在GDT中找出这个选择子。在这个选择子中,对应一个tss描述符,即:任务状态段描述符。这个描述符大小为068h,即104字节。下面是这个任务状态段
6、描述符的格式。我们看到在这个描述符中记录了任务状态段的位置和大小。我们根据任务状态段描述符中的baseAddress,找到TSS的内存位置。然后我们就可以进行任务切换。所谓任务切换是指,挂起当前正在执行的任务,恢复或启动另一任务的执行。在任务切换过程中,首先,处理器中各寄存器的当前值被自动保存到TR所指定的TSS中;然后,下一任务的TSS的选择子被装入TR;最后,从TR所指定的TSS中取出各寄存器的值送到处理器的各寄存器中。由此可见,通过在TSS中保存任务现场各寄存器状态的完整映象,实现任务的切换。TR寄存器可见部分保存了tssselector,不可见部分,保存了任务状态段的位置和大小.如下图
7、所示。任务状态段TSS的基本格式如下图所示。从图中可见,TSS的基本格式由104字节组成。这104字节的基本格式是不可改变的,但在此之外系统软件还可定义若干附加信息。理论的部分,我们简单介绍这么多。接下来,我们透过几个例子来说明下,IDTHOOK。一。透过一个简单的代码,看看256个中断向量对应的ISR.,其中任务门的ISR没有,由于整个IDT中只有3个任务门,我们忽略这部分。代码如下:#includentddk.h#include#defineMAKELONG(a,b)(unsignedlong)(unsignedshort)(a)|(unsignedlong)(unsignedshort)
8、(b)DriverUnload=OnUnload;/loadidt_info_asmsidtidt_infoidt_entries=(IDTENTRY*)MAKELONG(idt_info.LowIDTbase,idt_info.HiIDTbase);for(count=0;countLowOffset,i-HiOffset);_snprintf(_t,253,Interrupt%d:ISR0x%08X,count,addr);DbgPrint(_t);returnSTATUS_SUCCESS;我们使用DebugView工具软件,就可以看到打印出来的信息。二、直接替换idt中某个中断向量的IS
9、R.这里采用的办法是,首先保存出中断向量0x30的ISR,然后直接修改中断向量0x30的ISR为我们自定义的函数my_interrupt_hook,每当0x30号中断产生,就会调用我们自定义的函数。由于我们自定义的函数里面执行完我们的功能后再跳转到原isr函数处执行。因此这种hook用户感觉不到,不影响原有功能。在OnUnload时,恢复原有的中断向量ISR.#includentddk.h#include#defineMAKELONG(a,b)(unsignedlong)(unsignedshort)(a)|(unsignedlong)(unsignedshort)(b)16);_asmsti
10、DbgPrint(UnHookingInterruptcomplete.);/usingstdcallmeansthatthisfunctionfixesthestackbeforereturning(oppositeofcdecl)void_stdcallcount_syscall(unsignedlongsystem_call_number)g_i_count+;/nakedfunctionshavenoprolog/epilogcode-theyarefunctionallylikethe/targetofagotostatement_declspec(naked)my_interrup
11、t_hook()_asmpusheaxcallcount_syscalljmpold_ISR_pointerNTSTATUSDriverEntry(INPDRIVER_OBJECTtheDriverObject,INPUNICODE_STRINGtheRegistryPath)IDTINFOidt_info;/thisstructureisobtainedbycallingSTOREIDT(sidt)IDTENTRY*idt_entries;/andthenthispointerisobtainedfromidt_infoIDTENTRY*i;unsignedlongaddr;unsigned
12、longcount;char_t255;theDriverObject-DriverUnload=OnUnload;/loadidt_info_asmsidtidt_infoidt_entries=(IDTENTRY*)MAKELONG(idt_info.LowIDTbase,idt_info.HiIDTbase);for(count=0;countLowOffset,i-HiOffset);_snprintf(_t,253,Interrupt%d:ISR0x%08X,count,addr);DbgPrint(_t);DbgPrint(HookingInterrupt.);/letshooka
13、ninterrupt/exercise-chooseyourowninterruptold_ISR_pointer=MAKELONG(idt_entriesNT_INT_TIMER.LowOffset,idt_entriesNT_INT_TIMER.HiOffset);/debug,usethisifyouwantsomeadditionalinfoonwhatisgoingon#if0_snprintf(_t,253,oldaddressforISRis0x%08x,old_ISR_pointer);DbgPrint(_t);_snprintf(_t,253,addressofmyfunct
14、ionis0x%08x,my_interrupt_hook);DbgPrint(_t);#endif/rememberwedisableinterruptswhilewepatchthetable_asmcliidt_entriesNT_INT_TIMER.LowOffset=(unsignedshort)my_interrupt_hook;idt_entriesNT_INT_TIMER.HiOffset=(unsignedshort)(unsignedlong)my_interrupt_hook16);_asmsti/debug-usethisifyouwanttocheckwhatisno
15、wplacedintheinterruptvector#if0i=&idt_entriesNT_INT_TIMER;addr=MAKELONG(i-LowOffset,i-HiOffset);_snprintf(_t,253,InterruptISR0x%08X,addr);DbgPrint(_t);#endifDbgPrint(HookingInterruptcomplete);returnSTATUS_SUCCESS;三、这个示例中hook了整个idt表,采用的方式是:1)首先保留出每个中断向量的ISR.为每一个中断向量的调用设置了一个计数器,并将计数器清零。2)为整个IDT建立一个det
16、our内存表,内存表中的每一项对应于每个中断向量。每一项的空间中保存了一个函数,在这个函数中,会调用一个公共的计数函数,用于统计每个中断ISR调用的次数,函数的最后会调用该中断向量原ISR.3)修改IDT表中的每一个中断向量ISR为detour内存表中相应项的函数。4)OnUnload中打印出每个中断向量ISR调用的次数,并恢复原ISR.#includentddk.h#include#defineMAKELONG(a,b)(unsignedlong)(unsignedshort)(a)|(unsignedlong)(unsignedshort)(b)16)/setthistothemaxint
17、youwanttohook#defineMAX_IDT_ENTRIES0xFF/thestartinginterruptforpatching/toskipsometroublesomeinterrupts/atthebeginningofthetable(TODO,findoutwhy)#defineSTART_IDT_OFFSET0x00unsignedlongg_i_countMAX_IDT_ENTRIES;unsignedlongold_ISR_pointersMAX_IDT_ENTRIES;/bettersavetheoldone!#ifdef_DEBUG/debuggeringve
18、rsionnopsoutourhook/thisworksw/nocrashescharjump_template=0x90,/nop,debug0x60,/pushad0x9C,/pushfd0xB8,0xAA,0x00,0x00,0x00,/moveax,AAh0x90,/pusheax0x90,0x90,0x90,0x90,0x90,0x90,0x90,/call08:44332211h0x90,/popeax0x9D,/popfd0x61,/popad0xEA,0x11,0x22,0x33,0x44,0x08,0x00/jmp08:44332211h;#elsecharjump_template=0x90,/nop,debug0x60,/pushad0x9C,/pushfd0xB8,0xAA,0x00,0x00,0x00,/moveax,AAh0x50,/pusheax0x9A,0x11,0x22,0x33,0x44,0x08,0x00,/call08:44332211h0x58,/popeax0x9D,
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1