IDTHook 深入学习
在之前的一篇文章中介绍了替换IDT向量表中的地址来达到Hook的目的 IDT hook KiTrap03 但是这样很容易就可以被检测了。接下来要学习就是通过patch GDT来达到Hook IDT的目的。
首先,我们要了解一下,当触发INT 3号中断之后,CPU是如何找到接下来要执行的指令的地址。
CPU 在执行中断的时候,先会得到中断描述符表中该中断的中断例程(InterruptFunc ),然后得到该中断描述符中的段选择符,解析出段选择符对应的GDT(因为中断例程全都是在内核层中)中的地址(Base),然后执行:Base + InterruptFunc = 目标真正要执行的地址。
可能到这里还不太理解,我们以KiTrap03 3号中断为例来学习。
kd> !pcr
KPCR for Processor at 83f6bc00:
Major Minor
NtTib.ExceptionList: 83f680ac
NtTib.StackBase:
NtTib.StackLimit:
NtTib.SubSystemTib: 801e4000
NtTib.Version: 000bd40c
NtTib.UserPointer:
NtTib.SelfTib: SelfPcr: 83f6bc00
Prcb: 83f6bd20
Irql: 0000001f
IRR:
IDR: ffffffff
InterruptMode:
IDT: 80b95400
GDT: 80b95000
TSS: 801e4000 CurrentThread: 83f75380
NextThread:
IdleThread: 83f75380 DpcQueue:
我们可以看到当前处理器的控制块地址和IDT,GDT地址。
80b95400 83e78e000008efc0 83e78e000008f150
80b95418 83e7ee000008f5c0 83e7ee000008f748 83e78e000008f8a8
我们可以看到3号中断的描述项的地址是0x80b95418
typedef struct _IDTENTRY
{
unsigned short LowOffset;
unsigned short selector;
unsigned char retention:;
unsigned char zero1:;
unsigned char gate_type:;
unsigned char zero2:;
unsigned char interrupt_gate_size:;
unsigned char zero3:;
unsigned char zero4:;
unsigned char DPL:;
unsigned char P:;
unsigned short HiOffset;
} IDTENTRY,*PIDTENTRY;
kd> db 80b95418
80b95418 c0 f5 ee e7
我们可以得到LowOffset = 0xf5c0,HiOffset = 83e7 所以3号中断的InterruptFunc = 0x83e7f5c0。
段选择符selector = 0x08 二进制表示即1000。这里就又牵扯到另一个概念,段选择符。
比如我们通知都知道 FS:[0] 指向的地址在内核层是处理器控制块,在应用层是当前线程的TEB的首地址。
之前分析KiTrap03的汇编的时候有几条指令:
.text:00436C5F mov ebx, 30h
.text:00436C64 mov fs, bx
.text:00436C67 mov ebx, large fs: ; fs对应处理器相关的_KPCR结构,kpcr,那么得到的是
.text:00436C67 ; kpcr.NtTib.ExceptionList
这里,为什么fs=0x30了以后,fs:0指向的就是kpcr?
FS 寄存器在Windows下表示的不是我们通常意义上的段基址,而是段选择符。就是说CPU对于FS寄存器的寻址不是通常意义上的段基址+段偏移的方式,而是采用了另外的一种解析方式。我们这里还是以fs=0x30为例来讲解。
FS寄存器是16位寄存器,先大致了解一下每一位的意义:
0和1位:代表当前特权级,用户层:11 内核层:00::
2位:表指示位,0 表示在GDT(全局)中 ,1表示在LDT(局部)中:
3--15位:段索引。
先了解这么多就够了,然后回到我们的问题 FS=0x30 二进制表示就是110 0 00,特权级是0 内核态, GDT表,段索引是0x6。
我们之前有得到过GDT的地址,然后索引值为6的地址为0x80b95030
80b95000 00cf9b000000ffff 00cf93000000ffff0b95018 00cffb000000ffff 00cff3000000ffff 80008b1e400020ab0b95030 834093f6bc003748
kd> db 80b95030
80b95030 bc f6
typedef struct _KGDTENTRY // 3 elements, 0x8 bytes (sizeof)
{
/*0x000*/ UINT16 LimitLow;
/*0x002*/ UINT16 BaseLow;
union // 2 elements, 0x4 bytes (sizeof)
{
struct // 4 elements, 0x4 bytes (sizeof)
{
/*0x004*/ UINT8 BaseMid;
/*0x005*/ UINT8 Flags1;
/*0x006*/ UINT8 Flags2;
/*0x007*/ UINT8 BaseHi;
}Bytes;
struct // 10 elements, 0x4 bytes (sizeof)
{
/*0x004*/ ULONG32 BaseMid : ; // 0 BitPosition
/*0x004*/ ULONG32 Type : ; // 8 BitPosition
/*0x004*/ ULONG32 Dpl : ; // 13 BitPosition
/*0x004*/ ULONG32 Pres : ; // 15 BitPosition
/*0x004*/ ULONG32 LimitHi : ; // 16 BitPosition
/*0x004*/ ULONG32 Sys : ; // 20 BitPosition
/*0x004*/ ULONG32 Reserved_0 : ; // 21 BitPosition
/*0x004*/ ULONG32 Default_Big : ; // 22 BitPosition
/*0x004*/ ULONG32 Granularity : ; // 23 BitPosition
/*0x004*/ ULONG32 BaseHi : ; // 24 BitPosition
}Bits;
}HighWord;
}KGDTENTRY, *PKGDTENTRY;
我们对照着GDTENTRY的结构体,得出BaseLow = 0xbc00 , BaseMid = 0xf6 , BaseHi = 0x83,于是就得到了一个地址 0x83f6bc00 。
是不是很熟悉,没错,这就是我们KPCR的地址,也就是说CPU是按照段选择符的方式来解析FS寄存器的。
回到我们的问题,IDTENTRY中的selector域也是一个段选择符,它所解析出来的地址,就是我们要加上的Base,得到真正的中断例程的地址。
还是以 3号中断为例,selector = 0x08,二进制表示为1 0 00,也就是说是GDT表中的索引为1的项,
kd> db 80b95000+0x8
80b95008 ff ff 9b cf
可以得出 BaseLow = 0 , BaseMid = 0 , BaseHi = 0 ,得出的Base = 0;
所以真的执行的例程地址就是我们的lpInterruptFunc 。
既然中断向量的真正执行地址要经过GDT的查询,那么如果我们替换GDT中的内容,使最后CPU得到的Base = NewKiTrap03 - KiTrap03,就可以达到对IDT隐蔽性Hook的目的。但是这样又会出现一个问题,很多IDT处理例程的selector都是0x08,就是说和KiTrap03的段索引是一样的,也就是说我们不能直接替换KiTrap03对应的GDT中的内容,而是应该找一个没有用过的GDT表项,然后将KiTrap03的selector的段索引指向我们选定的GDT表项。
typedef struct _KGDTENTRY // 3 elements, 0x8 bytes (sizeof)
{
/*0x000*/ UINT16 LimitLow;
/*0x002*/ UINT16 BaseLow;
union // 2 elements, 0x4 bytes (sizeof)
{
struct // 4 elements, 0x4 bytes (sizeof)
{
/*0x004*/ UINT8 BaseMid;
/*0x005*/ UINT8 Flags1;
/*0x006*/ UINT8 Flags2;
/*0x007*/ UINT8 BaseHi;
}Bytes;
struct // 10 elements, 0x4 bytes (sizeof)
{
/*0x004*/ ULONG32 BaseMid : ; // 0 BitPosition
/*0x004*/ ULONG32 Type : ; // 8 BitPosition
/*0x004*/ ULONG32 Dpl : ; // 13 BitPosition
/*0x004*/ ULONG32 Pres : ; // 15 BitPosition
/*0x004*/ ULONG32 LimitHi : ; // 16 BitPosition
/*0x004*/ ULONG32 Sys : ; // 20 BitPosition
/*0x004*/ ULONG32 Reserved_0 : ; // 21 BitPosition
/*0x004*/ ULONG32 Default_Big : ; // 22 BitPosition
/*0x004*/ ULONG32 Granularity : ; // 23 BitPosition
/*0x004*/ ULONG32 BaseHi : ; // 24 BitPosition
}Bits;
}HighWord;
}KGDTENTRY, *PKGDTENTRY; typedef struct _IDTR{
USHORT IDT_limit;
USHORT IDT_LOWbase;
USHORT IDT_HIGbase;
}IDTR,*PIDTR; typedef struct _IDTENTRY
{
unsigned short LowOffset;
unsigned short selector;
unsigned char retention:;
unsigned char zero1:;
unsigned char gate_type:;
unsigned char zero2:;
unsigned char interrupt_gate_size:;
unsigned char zero3:;
unsigned char zero4:;
unsigned char DPL:;
unsigned char P:;
unsigned short HiOffset;
} IDTENTRY,*PIDTENTRY; typedef struct _X86_KTRAP_FRAME {
ULONG DbgEbp;
ULONG DbgEip;
ULONG DbgArgMark;
ULONG DbgArgPointer;
ULONG TempSegCs;
ULONG TempEsp;
ULONG Dr0;
ULONG Dr1;
ULONG Dr2;
ULONG Dr3;
ULONG Dr6;
ULONG Dr7;
ULONG SegGs;
ULONG SegEs;
ULONG SegDs;
ULONG Edx;
ULONG Ecx;
ULONG Eax;
ULONG PreviousPreviousMode;
ULONG ExceptionList;
ULONG SegFs;
ULONG Edi;
ULONG Esi;
ULONG Ebx;
ULONG Ebp;
ULONG ErrCode; ULONG Eip;
ULONG SegCs;
ULONG EFlags;
ULONG HardwareEsp; // WARNING - segSS:esp are only here for stacks
ULONG HardwareSegSs; // that involve a ring transition.
ULONG V86Es; // these will be present for all transitions from
ULONG V86Ds; // V86 mode
ULONG V86Fs;
ULONG V86Gs;
} X86_KTRAP_FRAME, *PX86_KTRAP_FRAME;
KIRQL Irql;
ULONG_PTR g_jmp_offset = ;
ULONG_PTR OldBase;
PKGDTENTRY NewGDTAddr;
ULONG_PTR g_OrigKiTrap03;
unsigned short OldSelector;
IDTENTRY* idt_entries; __declspec(naked) void NewKiTrap03()
{
__asm
{
push ;ErrorCode
push ebp
push ebx
push esi
push edi
push fs
mov ebx,30h
mov fs,bx
mov ebx,dword ptr fs:[]
push ebx
sub esp,
push eax
push ecx
push edx
push ds
push es
push gs sub esp,30h //esp此时就指向陷阱帧 push esp //FilterExceptionInfo自己清理了 call FilterExceptionInfo //过滤函数 add esp , 0x30
pop gs
pop es
pop ds
pop edx
pop ecx
pop eax
add esp ,
pop ebx
pop fs
pop edi
pop esi
pop ebx
pop ebp
add esp , 0x4
jmp g_OrigKiTrap03 }
} VOID __stdcall FilterExceptionInfo(PX86_KTRAP_FRAME pTrapFrame)
{ //eip的值减一过int3,汇编代码分析中dec,
DbgPrint("Eip:%x\r\n",(pTrapFrame->Eip)-);
} NTSTATUS
DriverEntry(IN PDRIVER_OBJECT pDriverObj, IN PUNICODE_STRING pRegistryString)
{
ULONG oriaddr=;
ULONG newaddr=;
PKGDTENTRY GDT_Addr;
KGDTENTRY GDTInfo;
PKGDTENTRY Gdt_Addr3e0;
PKGDTENTRY Gdt_Addr8;
ULONG jmpoffset=;
IDTR idt_info;
unsigned short selector; #ifdef _DBG
__asm int
#endif
pDriverObj->DriverUnload = DriverUnLoad; __asm
{
sidt idt_info
push edx
sgdt [esp-]
pop edx
mov GDT_Addr,edx }
idt_entries = (IDTENTRY*) MAKELONG(idt_info.IDT_LOWbase,idt_info.IDT_HIGbase);
g_OrigKiTrap03 = MAKELONG(idt_entries[].LowOffset,idt_entries[].HiOffset);
jmpoffset = (ULONG)NewKiTrap03 - g_OrigKiTrap03;
selector = idt_entries[].selector;
//我选择的是索引为0x10的,空白的GDT表项
NewGDTAddr = GDT_Addr + 0x10; //保存原来的
memcpy((UCHAR*)&OldBase,(char*)(&(NewGDTAddr->BaseLow)),);
memcpy((UCHAR*)&OldBase+,(char*)(&(NewGDTAddr->HighWord.Bytes.BaseMid)),);
memcpy((UCHAR*)&OldBase+,(char*)(&(NewGDTAddr->HighWord.Bytes.BaseHi)),); //修改
WPOFF();
memcpy((char*)(&(NewGDTAddr->BaseLow)),(UCHAR*)&jmpoffset,);
memcpy((char*)(&(NewGDTAddr->HighWord.Bytes.BaseMid)),(UCHAR*)(&jmpoffset)+,);
memcpy((char*)(&(NewGDTAddr->HighWord.Bytes.BaseHi)),(UCHAR*)(&jmpoffset)+,);
OldSelector = idt_entries[].selector;
idt_entries[].selector = 0x80;
WPON(); return STATUS_SUCCESS;
} void DriverUnLoad(PDRIVER_OBJECT pDriverObject)
{
WPOFF();
memcpy((char*)(&(NewGDTAddr->BaseLow)),(UCHAR*)(&OldBase),);
memcpy((char*)(&(NewGDTAddr->HighWord.Bytes.BaseMid)),(UCHAR*)(&OldBase)+,);
memcpy((char*)(&(NewGDTAddr->HighWord.Bytes.BaseHi)),(UCHAR*)(&OldBase)+,);
idt_entries[].selector = OldSelector;
WPON();
} VOID WPOFF()
{
ULONG_PTR cr0 = ;
Irql = KeRaiseIrqlToDpcLevel();
cr0 =__readcr0();
cr0 &= 0xfffffffffffeffff;
__writecr0(cr0); } VOID WPON()
{ ULONG_PTR cr0=__readcr0();
cr0 |= 0x10000;
__writecr0(cr0);
KeLowerIrql(Irql);
}
IDTHook 深入学习的更多相关文章
- 从直播编程到直播教育:LiveEdu.tv开启多元化的在线学习直播时代
2015年9月,一个叫Livecoding.tv的网站在互联网上引起了编程界的注意.缘于Pingwest品玩的一位编辑在上网时无意中发现了这个网站,并写了一篇文章<一个比直播睡觉更奇怪的网站:直 ...
- Angular2学习笔记(1)
Angular2学习笔记(1) 1. 写在前面 之前基于Electron写过一个Markdown编辑器.就其功能而言,主要功能已经实现,一些小的不影响使用的功能由于时间关系还没有完成:但就代码而言,之 ...
- ABP入门系列(1)——学习Abp框架之实操演练
作为.Net工地搬砖长工一名,一直致力于挖坑(Bug)填坑(Debug),但技术却不见长进.也曾热情于新技术的学习,憧憬过成为技术大拿.从前端到后端,从bootstrap到javascript,从py ...
- 消息队列——RabbitMQ学习笔记
消息队列--RabbitMQ学习笔记 1. 写在前面 昨天简单学习了一个消息队列项目--RabbitMQ,今天趁热打铁,将学到的东西记录下来. 学习的资料主要是官网给出的6个基本的消息发送/接收模型, ...
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- Unity3d学习 制作地形
这周学习了如何在unity中制作地形,就是在一个Terrain的对象上盖几座小山,在山底种几棵树,那就讲一下如何完成上述内容. 1.在新键得项目的游戏的Hierarchy目录中新键一个Terrain对 ...
- 《Django By Example》第四章 中文 翻译 (个人学习,渣翻)
书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:祝大家新年快乐,这次带来<D ...
- 菜鸟Python学习笔记第一天:关于一些函数库的使用
2017年1月3日 星期二 大一学习一门新的计算机语言真的很难,有时候连函数拼写出错查错都能查半天,没办法,谁让我英语太渣. 关于计算机语言的学习我想还是从C语言学习开始为好,Python有很多语言的 ...
- 多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)
前言:刚学习了一段机器学习,最近需要重构一个java项目,又赶过来看java.大多是线程代码,没办法,那时候总觉得多线程是个很难的部分很少用到,所以一直没下决定去啃,那些年留下的坑,总是得自己跳进去填 ...
随机推荐
- wpa_supplicant软件架构分析
wpa_supplicant软件架构分析 1. 启动命令 wpa supplicant 在启动时,启动命令可以带有很多参数,目前我们的启动命令如下: wpa_supplicant /system/bi ...
- [转]分布式文件系统FastDFS架构剖析
[转]分布式文件系统FastDFS架构剖析 http://www.programmer.com.cn/4380/ 文/余庆 FastDFS是一款类Google FS的开源分布式文件系统,它用纯C语言实 ...
- ABAP后台JOB数量控制
数据库视图:V_OP 可以查看JOB信息 FORM sub_check_job. * 通过JOB名称,控制活动JOB的数量 , jobname TYPE btcjob , strtdate TYPE ...
- vsftpd配置文件说明
(1)常用选项: chroot_local_user=YES #限制所有的用户均不能切换到其他目录 allow_writeable_chroot=YES #允许根目录可写 FTP的工作模式有两种,一种 ...
- C#中如何利用操作符重载和转换操作符
操作符重载 有的编程语言允许一个类型定义操作符应该如何操作类型的实例,比如string类型和int类型都重载了(==)和(+)等操作符,当编译器发现两个int类型的实例使用+操作符的时候,编译器会生成 ...
- Windows Server 2008R2配置MySQL Cluster并将管理节点和数据节点配置成windows服务
说明:将mysql的管理节点和数据节点配置成windows服务是为了防止有人手误关闭管理节点或数据节点的dos命令窗口,管理节点或数据节点的命令窗口误关闭可能会造成mysql某台或某几台mysql不能 ...
- 文本阴影text-shadow
文本阴影text-shadow text-shadow可以用来设置文本的阴影效果. 语法: text-shadow: X-Offset Y-Offset blur color; X-Offset:表示 ...
- SVG基本图形及clipPath;
利用SVG可以实现很多复杂的图形,SVG的功能开发者们已经开发许多,今天初识一下SVG的基本图形绘制, <svg viewbox="0,0,400,400" style=&q ...
- quartz2D简单使用
quartz2D绘图 1:上下文:context,这个翻译不好理解,其实翻译环境更好一点,就是给了你一个画板,你看不到而已 在: CGContextRef ctx = UIGraphicsGetCur ...
- 向Array中添加归并排序
归并排序思路 1) 归并 从两个有序表R[low...mid]和R[mid+1...high],每次从左边依次取出一个数进行比较,将较小者放入tmp数组中,最后将两段中剩下的部分直接复制到tmp中. ...