首页
社区
课程
招聘
[原创]rootkit 直接访问硬件之[二]
发表于: 2008-3-28 11:17 22114

[原创]rootkit 直接访问硬件之[二]

2008-3-28 11:17
22114

关于ring3访问硬件,今天我们将采用另外的方法来进行I/O访问。为了找出方法,我们还是要继续看看I/O保护的八条规则:呵呵,正所谓“知己知彼,百战不殆。“
(1)若CPL<=IOPL,则直接转步骤(8);
(2)取得I/O位图开始偏移;
(3)计算I/O地址对应位所在字节在I/O许可位图内的偏移;
(4)计算位偏移以形成屏蔽码值,即计算I/O地址对应位在字节中的第几位;
(5)把字节偏移加上位图开始偏移,再加1,所得值与TSS界限比较,若越界,则产生出错码为0的通用保护故障;
(6)若不越界,则从位图中读对应字节及下一个字节;
(7)把读出的两个字节与屏蔽码进行与运算,若结果不为0表示检查未通过,则产生出错码为0的通用保护故障;
(8)进行I/O访问。

上一篇中我们已经介绍了修改IOPL = 3,使其顺利通过保护规则。因此八条规则中的第一条我们已经用过了,今天我们从第二条开始找办法。

我们先看看I/O许可位图,它位于任务状态段TSS中。要找出tss段所在的线性地址,需要先从tr寄存器中,找出任务状态段的选择子,根据这个选择子我们可以在GDT中找到任务状态段描述符,根据这个描述符,我们可以找出TSS在内存中的位置。TSS是保存一个任务重要信息的特殊段。我们先看看其内存结构。
lkd> dt _ktss
nt!_KTSS
   +0x000 Backlink         : Uint2B
   +0x002 Reserved0        : Uint2B
   +0x004 Esp0             : Uint4B
   +0x008 Ss0              : Uint2B
   +0x00a Reserved1        : Uint2B
   +0x00c NotUsed1         : [4] Uint4B
   +0x01c CR3              : Uint4B
   +0x020 Eip              : Uint4B
   +0x024 EFlags           : Uint4B
   +0x028 Eax              : Uint4B
   +0x02c Ecx              : Uint4B
   +0x030 Edx              : Uint4B
   +0x034 Ebx              : Uint4B
   +0x038 Esp              : Uint4B
   +0x03c Ebp              : Uint4B
   +0x040 Esi              : Uint4B
   +0x044 Edi              : Uint4B
   +0x048 Es               : Uint2B
   +0x04a Reserved2        : Uint2B
   +0x04c Cs               : Uint2B
   +0x04e Reserved3        : Uint2B
   +0x050 Ss               : Uint2B
   +0x052 Reserved4        : Uint2B
   +0x054 Ds               : Uint2B
   +0x056 Reserved5        : Uint2B
   +0x058 Fs               : Uint2B
   +0x05a Reserved6        : Uint2B
   +0x05c Gs               : Uint2B
   +0x05e Reserved7        : Uint2B
   +0x060 LDT              : Uint2B
   +0x062 Reserved8        : Uint2B
   +0x064 Flags            : Uint2B
   +0x066 IoMapBase        : Uint2B
   +0x068 IoMaps           : [1] _KiIoAccessMap
   +0x208c IntDirectionMap  : [32] UChar
lkd> dt _KiIoAccessMap
nt!_KiIoAccessMap
   +0x000 DirectionMap     : [32] UChar
   +0x020 IoMap            : [8196] UChar
根据这个结构我们可以计算出其长度为 :0x208c + 32 - 1 = 0x20ab
其中的IoMapBase就是I/O许可位图的在TSS段中的偏移位置。也就是说在TSS段中从这个位置开始就是I/O许可位图了。

对于本机操作系统,我们可以通过WINDBG察看下该结构的值。
首先我们找到TSS的内存位置,我们可以通过如下指令得到TSS: 80042000
lkd> !PCR
KPCR for Processor 0 at ffdff000:
    Major 1 Minor 1
        NtTib.ExceptionList: b2616c7c
            NtTib.StackBase: b2616df0
           NtTib.StackLimit: b2614000
         NtTib.SubSystemTib: 00000000
              NtTib.Version: 00000000
          NtTib.UserPointer: 00000000
              NtTib.SelfTib: 7ffde000

                    SelfPcr: ffdff000
                       Prcb: ffdff120
                       Irql: 00000000
                        IRR: 00000000
                        IDR: ffffffff
              InterruptMode: 00000000
                        IDT: 8003f400
                        GDT: 8003f000
                        TSS: 80042000

              CurrentThread: 88fb6da8
                 NextThread: 00000000
                 IdleThread: 80552d20

                  DpcQueue:

接下来,我们看看这个结构中每一项的实际值。
lkd> dt _ktss 80042000
nt!_KTSS
   +0x000 Backlink         : 0
   +0x002 Reserved0        : 0x838d
   +0x004 Esp0             : 0xb1da5de0
   +0x008 Ss0              : 0x10
   +0x00a Reserved1        : 0xb9fc
   +0x00c NotUsed1         : [4] 0x1000
   +0x01c CR3              : 0x12640740
   +0x020 Eip              : 0x14453b02
   +0x024 EFlags           : 0x8a870f
   +0x028 Eax              : 0xc18b0000
   +0x02c Ecx              : 0x8d02e9c1
   +0x030 Edx              : 0xfb8b0272
   +0x034 Ebx              : 0xc88ba5f3
   +0x038 Esp              : 0xf303e183
   +0x03c Ebp              : 0xc5d03a4
   +0x040 Esi              : 0x3bf8558b
   +0x044 Edi              : 0x7174fc5d
   +0x048 Es               : 0x458b
   +0x04a Reserved2        : 0x8314
   +0x04c Cs               : 0xfec0
   +0x04e Reserved3        : 0xd03b
   +0x050 Ss               : 0x6777
   +0x052 Reserved4        : 0xc2f6
   +0x054 Ds               : 0x7401
   +0x056 Reserved5        : 0x8a0d
   +0x058 Fs               : 0x8802
   +0x05a Reserved6        : 0x1045
   +0x05c Gs               : 0x428a
   +0x05e Reserved7        : 0x8801
   +0x060 LDT              : 0
   +0x062 Reserved8        : 0x7eb
   +0x064 Flags            : 0
   +0x066 IoMapBase        : 0x20ac
   +0x068 IoMaps           : [1] _KiIoAccessMap
   +0x208c IntDirectionMap  : [32]  "???"
我们看IoMapBase值为: 20ac. 而在上面我们看到TSS的大小是0x20ab,说明已经越界,根据前面我们列出的检测规则第五条,产生出错码为0的通用保护故障;因此,看到这里,我们可以考虑一种办法,就是扩充下这个结构的大小,让tss的结构大小大于0x20ac,
也就是说在tss中给I/O许可位图留出一块空间来。考虑到增加部分不能增加物理分页,因此我们可以设置的结构体最大值就是0x2fff。这样,我们扩充的大小是0x2fff-0x20ab = 0xf54;
因为I/O许可位图中每一bit代表一个端口,因此,0xf54字节对应的可访问的最大端口是:
0xf54 * 8 = 0x7aa0,对应于10进制,就是31392。因此我们可访问的i/o口范围是0 ~ 31392。

因为每个进程都有自己的I/O许可位图,每个单独的I/O端口的访问权限都可以对每个进程进行单独授权,如果相关的位被设置的话,对对应端口的访问就是被禁止的,如果相关的位被清除,那么进程就可以访问对应的端口。
TSS的设计意图是为了在任务切换的时候保存处理器状态,从执行效率的考虑出发,Windows NT并没有使用这个特征,它只维护一个TSS供多个进程共享,因此本篇中我们扩展了tss结构大小,扩展部分会影响到所有进程。

其实这种做法,早在1995年Dale Roberts 写了一个名叫totalio的例子影响较广,后来在2002年,sinister大牛在此基础上改写了一个。虽然做法早就有了,但是网上并没有过多地介绍其中的原理。

今天我们贴出的代码就是sinister大牛的。大家一起来学习。我在其代码上作了一个小小的调整,就是原来其扩展到0x2fab, 我把这个扩展范围扩大到了0x2fff. 反正分页是0x1000大小对齐,剩余的空间闲着也是浪费。

测试代码:
#include "stdio.h"
void main()
{
     _asm
    {
           mov dx,0x64
           mov al,0xfe
           out  dx,al
    }
}


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (17)
雪    币: 424
活跃值: (1884)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
太牛了~~总不见你在群里讲讲课
2008-3-28 11:20
0
雪    币: 1852
活跃值: (504)
能力值: (RANK:1010 )
在线值:
发帖
回帖
粉丝
3
偶也抢个板凳学习!
2008-3-28 11:27
0
雪    币: 272
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
如果要用来做正经事的话,不应该在R3直接IO端口,原因很明显。。。

不过理论上研究一下还是很值得的,看了楼主的文章,我对TSS了解就少走了很多弯路
2008-3-28 11:28
0
雪    币: 272
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
支持楼主的共享精神

我见过很多所谓的大牛,虽然也发表文章,但纯粹是为了哗众取宠,出风头!
关键技术一笔带过,更没什么注释。。。

像楼主这样的好人这年头太少了,感动
2008-3-28 11:34
0
雪    币: 272
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
我发觉楼主一直默默无闻,为人低调,字句入微,虽然技术不能说是最好的,
但人品,绝对没得说!

祝楼主事业有成!!
2008-3-28 11:38
0
雪    币: 272
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
马云说得对,秘密不是你的核心竞争力!

你做出实用的东西了,就算技巧全部公开,源码公开,人们只会更尊敬你,并且永远记得你!
事实上我们也很少发现开源的东西被成功模仿并被超越的!

严重鄙视那些找到点技巧,说话含混不清,总是 ob*****  ,*****的人!!
2008-3-28 11:42
0
雪    币: 451
活跃值: (78)
能力值: ( LV12,RANK:470 )
在线值:
发帖
回帖
粉丝
8
赶紧跟着学习123456
2008-3-28 13:09
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
跟着赶紧学习
2008-3-28 17:11
0
雪    币: 156
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
搬个小板凳,学习!
2008-3-29 17:13
0
雪    币: 215
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
楼主,你这篇帖子不是ring3下直接硬件访问啊,而是采用驱动的方式啊,既然已经有了驱动,就已经在0环了,何必多此一举呢?
2008-4-25 17:29
0
雪    币: 321
活跃值: (271)
能力值: ( LV13,RANK:1050 )
在线值:
发帖
回帖
粉丝
12
这个例子的目的主要是为了遵循着保护模式的那个规则走下来。呵呵。
2008-4-25 18:09
0
雪    币: 197
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
IO端口操作,都可以做些什么呢?除了可以操作下串口键盘。读写硬盘可以吗?
2008-4-26 14:25
0
雪    币: 186
活跃值: (221)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
在双核的CPU上操作失败,要怎样修改才行啊
2008-4-28 13:52
0
雪    币: 242
活跃值: (473)
能力值: ( LV11,RANK:188 )
在线值:
发帖
回帖
粉丝
15
好实例贴!
发觉时间接近5个月了,赶紧顶贴防止被锁..
2008-8-19 22:24
0
雪    币: 331
活跃值: (57)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
16
例子中没有把I/O许可位图置零!!
2008-12-2 15:58
0
雪    币: 411
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
学习了
2010-9-29 19:15
0
雪    币: 203
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
的确是厉害人物,不仅仅是技术厉害,最让人佩服的是共享精神,记住你拉
2010-12-23 16:01
0
游客
登录 | 注册 方可回帖
返回
//