吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 9290|回复: 52
收起左侧

[系统底层] Windows 7 x86下hook 中断函数

  [复制链接]
Panel 发表于 2022-9-7 00:06
本帖最后由 Panel 于 2022-9-7 00:28 编辑

windows7 x86下hook int3 中断

1.准备工具

windbg x86、windows7 32位虚拟机、勤劳的双手和不怕蓝屏的勇气

2.原理讲解

先来看官方话:

外部中断、软件中断和异常是通过中断描述符表(①DT)处理的,如图2-1。IDT包含了访问中
断和异常处理程序的门描述表的集合。像GDT一样,IDT不是一个段,IDT的线性基地址包含
在IDT寄存器中(IDTR)。IDT中的门描述符包括有中断-、陷阱-、或任务门类型。在运行中
断或异常处理程序时,处理器必须先从内部硬件、外部中断控制器、或通过执行IT,ITO,
INT3或BOUND指令的软件中断中接到一个中断向量(中断数字)。中断向量包含了IDT中的门
描述符的索引。如果选中的门描述符是一个中断门或者陷阱门,相应的处理程序是通过非
常类似于通过调用门调用过程了。如果描述符是一个任务门,处理程序是通过任务切换进
行的。

那我就来翻译成我的话:

中断就是一个系统在特殊时间点触发的一种行为,这种行为通常伴随着一些函数过程的发生

细述原理,一看就会(狗头护体):

以int3中断为例,当系统调用int3中断的时候那么int3中断会触发一个函数来对应该中断的发生,那么这个函数是什么呢?
要知道这个函数的来源之前必须得知道两个知识点的概念:IDT(interrupt describe table)和GDT(global describe table )。
首先IDT:中断系列描述表,该表中存放了所有中断的描述符,用来描述不同中断的权限和对应函数地址等的一张表,可以粗略地理解为每一个系统中断的发生之后都会来解析该IDT中对应的中断描述符,比如int1 则解析IDT中索引为1的那段中断描述符,通过解析该描述符便可以得到该中断过程所具有的权限和函数地址等行为。
其次GDT:GDT则是用来存储几乎所有段描述符等的一张表,比如cs、ds等,描述了这些段所具有的权限,基地址等

那我们开始利用以上粗略的介绍来说明int3的实现过程:

1.通过系统调用不同的int中断来解析在IDT中指定索引的中断描述符。这里我们还是使用windbg来查看一下IDT具体的模样,首先利用命令 r idtr得到idt表中内核中的地址,再使用 dq idt地址便可得到idt表,如下图:

1

1

2.系统又会解析中断描述符中的Segment Selector来得到中断函数将要触发函数的基地址,随后将Segment Selector中解析出来的基地址再加上中断描述符中的offset作为偏移便得到了将要触发函数的地址,再通过检查该中断描述符和对应Segment Selector描述符(GDT中的段描述符)便获取到了该函数的权限等信息,最后系统据此调用指定中断触发函数。
原理图如下:

4

4

这里附上GDT和IDT描述符略图,大家可以网上查看对应位的详解,如下图:

IDT:

2

2

GDT:

3

3

3.实现hook

既然上面我们知道了中断调用函数的原理过程了,那我们就知道我们居然想hook指定中断函数,那么我们就只需要使得系统通过解析IDT中的描述符后得到要触发函数的地址等于我们要执行的函数地址就行了。

查看int3的中断描述符:

索引从0开始,所以int3的中断描述符是第四个,操作指令和结果如下图:

5

5

83e8ee00000855c0`,根据下表和网上的信息我们对该描述符进行关键信息解析:

6

6

offset:0x83e855c0
Segment Selector:0008
此时的Segment Selector就是IDT中的偏移,那么我们进入GDT中去查看该偏移的段描述符,操作指令和结果如下图:

7

7

00cf9b000000ffff` 那此时我们对应表和网上信息解析一下该段描述符所描述的基地址和段权限:

8

8

Base:00000000
DPL(描述了该base段所具有的执行权限,基本上都是要么是0环权限要么是3环权限):0x9(hex)->‭1001‬,那么DPL的只就是0,也就是0环权限
综上所述,那么该中断触发的函数地址就是00000000+0x83e855c0 = 0x83e855c0,那么咱们u一下看看,操作指令和结果如下图:

9

9

那么我们就开始动手脚:

#include "stdafx.h"
#include <windows.h>
int val = 0;
char *txt = (char *)malloc(sizeof(char)*260);
void __declspec(naked) test()
{
        __asm
        {
                //再次跨段,防止缓存区清空问题
                push 0x8;
                push NewSeg;
                jmp fword ptr [esp];
NewSeg:
                //保存现场环境
                add esp,8;
                pushad;
                pushfd;

                //自定义逻辑部分
            cli;//关闭时钟中断
                mov eax,0x840599dc;
                mov ecx,[eax];
                mov val,ecx;
            sti;//开启时钟中断
                popfd;
                popad;
                mov dword ptr [esp-4],0x83e855c0;
                jmp dword ptr [esp-4];
                retf;
        }

}

int _tmain(int argc, _TCHAR* argv[])
{

        memset(txt,0,260);
        memcpy(txt,"demoless",strlen("demoless")+1);
        __asm
        {
                int 3;
        }
        printf("%x",val);
        system("pause");

}
代码思路以及逻辑:
①调用int3
②跳转我们指定的段,因为缓存大小问题所以我们跳段保险
③保存现场环境,防止hook结束后由于环境问题蓝屏
④编写hook代码:通过读取0x840599dc(实验时NtOpenProcess函数的地址)处字节,如果能读到则说明我们hook成功了,因为内核函数在3环读取不到
⑤跳回int3原触发函数地址,不影响正常中断
⑥通过打印val值是否是NtOpenProcess的字节码来验证是否hook成功
那此时还差最后一步,修改int3的中断描述符:
①修改segment selector为我们构造的一段新描述符,注意,我们想要的只是这段新描述符的base直接等于我们的函数地址,而权限不变,为了不影响其他解析这个段描述符的正常流程,我们就构造新的描述符在idt中空白的位置,这里是0x48偏移处,操作指令和结果如下图:

10

10

②修改segment selector为0x48,操作指令和结果如下图:

11

11

4.验证hook是否成功

12

12

13

13

所以,兄弟们,hook成功了

5.总结:

这个过程可能会遇到蓝屏等问题,这个我给兄弟们留下坑,自己踩了实验出来以后效果更好,这个重点关注int3触发的环境可以帮助大家找到蓝屏原因,最后,由于第一次写内核帖,如有不对地方请大家斧正,各位大牛嘴下留情!





免费评分

参与人数 19威望 +2 吾爱币 +121 热心值 +16 收起 理由
zx9997 + 1 + 1 我很赞同!
Majestry + 1 我很赞同!
wxhwxdp + 1 + 1 用心讨论,共获提升!
fengbolee + 2 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
allspark + 1 + 1 用心讨论,共获提升!
xzhtx + 1 + 1 谢谢@Thanks!
lgc81034 + 1 谢谢@Thanks!
Mofecx + 1 + 1 热心回复!
L9651165 + 1 + 1 用心讨论,共获提升!
gaosld + 1 + 1 热心回复!
yxys + 1 + 1 感谢您的宝贵建议,我们会努力争取做得更好!嗯嗯嗯
雪流星 + 1 + 1 我很赞同!
xiong930626 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
哥哥的肥皂 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
Hmily + 2 + 100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
唐小样儿 + 1 + 1 我很赞同!
tzblue + 1 谢谢@Thanks!
bullshit + 1 + 1 谢谢@Thanks!
ICEY + 3 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| Panel 发表于 2022-9-7 00:40
本帖最后由 Panel 于 2022-9-7 07:36 编辑

【更正】忘记说了,为什么我们新构造的段描述符的地址是7ccfba40,因为我们上面说到过触发函数地址为base+offset,所以我们需要填充的基地址为 hook函数地址-offset = base,感谢@ICEY 的指正
 楼主| Panel 发表于 2022-9-7 07:51
本帖最后由 Panel 于 2022-9-7 07:54 编辑

  经过测试,直接修改int3的中断描述符的offset跳到401000去也是可以的,但是这有点类似构造中断门了,你说的是不是容易寄这个问题的话只要不触发windbg之类内核调试就基本不会寄,因为我在代码末尾是跳回了原int3中断的函数去了,也就是说我们的hook只是增加了一部分代码,但是没有去除原有的中断触发函数@ICEY
ICEY 发表于 2022-9-7 09:46
Panel 发表于 2022-9-7 07:51
经过测试,直接修改int3的中断描述符的offset跳到401000去也是可以的,但是这有点类似构造中断门了,你说 ...

你这个程序触发int3不会寄,但是其他程序就说不准了,毕竟其他程序401000的位置并没有你构造的这个函数(蓝屏应该不至于,但是程序应该会寄)。内核调试应该是必寄的(蓝屏)。
ICEY 发表于 2022-9-7 01:38
段描述符得到的基址说错了吧,是0x7c57ba40吧,和0x83e855c0相加是0x100401000。楼主有没有试过直接修改int3 idt中的offset直接指向0x401000,不用改段选择子。

ps:在ring3hook 内核怕不是很容易寄,万一其他进程正好要int3的话。。
 楼主| Panel 发表于 2022-9-7 07:24
本帖最后由 Panel 于 2022-9-7 07:35 编辑

对的,我刚开始置顶的评论说错了,应该是利用公式我们在gdt中填充描述符的基地址是0x7c57ba40,所以最后触发的函数地址应该是中断描述符的offset+选择子的base
 楼主| Panel 发表于 2022-9-7 07:25
ICEY 发表于 2022-9-7 01:38
段描述符得到的基址说错了吧,是0x7c57ba40吧,和0x83e855c0相加是0x100401000。楼主有没有试过直接修改int ...

对的,上面评论说错了,应该是利用公式我们在gdt中填充描述符的基地址是0x7c57ba40,所以最后触发的函数地址应该是中断描述符的offset+选择子的base,感谢指正
sgyfxa 发表于 2022-9-7 08:40
windows7操作系统很好用,用x64位的应该多些,用x86应该不多了。非常感谢楼主的分析教学。
aa2923821a 发表于 2022-9-7 08:43
膜拜大佬!!
抱薪风雪雾 发表于 2022-9-7 09:05
太难,看来不是俺不是干这个的料
cyril007 发表于 2022-9-7 09:20
支持一下
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-14 12:41

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表