首页
社区
课程
招聘
[原创]奇虎360第1题 hook WRITE_PORT_UCHAR
发表于: 2008-12-19 10:57 61329

[原创]奇虎360第1题 hook WRITE_PORT_UCHAR

2008-12-19 10:57
61329

懒得打字了,直接copy 答案提交区的帖子吧,有什么不好的不要笑俺,俺是初学
由于里面废话太多,大概内容为:mbrprot.sys  会定时检查 01 号扇区,发现不对就清0。我的方法是 阻止  mbrprot.sys  清 0,通过 hook  HAL!WRITE_PORT_UCHAR,控制对硬盘端口的访问  使得任何 利用atapi.sys 访问 01 扇区的方法都无效。

我的看法是其实 这题是要我们写一个 驱动来保护 01 号扇区, 这题太**了

第一题解题报告

一、分析
    刚开始我认为解这题的方法很简单,不管三七二十一直接io端口读写硬盘,然后解题完毕。压根不用管

mbrprot.sys 如何工作的,因为 mbrprot.sys 很难拦截 io 操作,难到几乎不可能。
代码写出来的时候我很高兴,因为在虚拟机(xp)上成功了,然而其实并没有,当我在真机子(2003)上运行时,失败了...。这要批评一下mbrprot.sys  的稳定性了, mbrprot.sys  老是 无缘罢工,而且貌似在 xp 下有点问题。走题了,不好意思...。

    经我观察 mbrprot.sys 并没有保护 硬盘的 1 号扇区,而是一味的向 1 号 扇区写入 0 。用 softice 设这样的断点 bpio 1f7 w   我发现(没弄错的话) mbrprot.sys 每隔一段时间(约5s)检查 1 号扇区。 同时我也发现 系统只有 atapi.sys 访问了硬盘, 也就是说 mbrprot.sys 是利用 atapi.sys 访问硬盘的,并非直接 io 之类的。 那么现在的任务就很清楚了:只要阻止 mbrprot.sys 往 01 号写入 0 就可以了 (出这道题的用意也清楚了,嘿嘿 ) 。

     怎么阻止 ? hook atapi.sys 的派遣函数吧 ,不过我第一时间想到的方法 说不定出题的人也早就想到了... 。通过 跟踪断点 bpio 1f7 w ,我发现 atapi.sys 是通过 HAL!WRITE_PORT_UCHAR 向硬盘的寄存器写数据的,如果 hook 掉 HAL!WRITE_PORT_UCHAR ,将 atapi.sys 向 硬盘写入的数据过滤掉,那么...

    但这方法是否可行呢,不用理论证明,因为我已经实践证明了。通过 hook 掉 HAL!WRITE_PORT_UCHAR 向 atapi.sys 提供一个虚假的硬件,拦截向真实硬盘发送的数据。其实该方法之所以可行完全依赖于 当向硬盘写入 扇区号,磁道号,磁头号 等等时 ,硬盘不会有任何反应,所以把这些数据拦截下来 延迟发送才不会出错。

二、我的实现方法
    由于在虚拟机上 mbrprot.sys 老是罢工,因此我只能在真机上进行了(不知道评委能不能看在 我蓝屏了无数次,mbr被写坏了一次 的份上给俺多加几分呢...)。由于是在自己的机子上试,为了减小程序出错时的严重性 我决定 只 hook atapi.sys 的 IAT(导入地址表),又因为 HAL!WRITE_PORT_UCHAR 这个函数本身就只有几个指令,不用 hook 直接替换就可以了。
    总的来说,程序只有两步:1、直接 io 向硬盘 01 扇区写入 数据;2、替换 atapi.sys IAT 中的 HAL!WRITE_PORT_UCHAR 为自己的 write_port 。

三、关键代码 (write_port 的代码)

放血了,有点痛,评委加点分鼓励一下吧。

1、直接 io 向硬盘 01 扇区写入 数据 的代码 网上到处都有。
2、hook 驱动导入表的代码 ,rootkit.com 上有, 看雪里面也有人(sysnap)发过 ,我是学习了他的一部分(发扬了大学生的借鉴风格)
3、write_port 完全原创 (如果要“借鉴”请申明以下出处:zdg102
申明:write_port 完全没有考虑 lba48 的情况(本人没有 160G 的硬盘),lba48 下无法正常工作

#define REG_CMD_BASE0  0x1F0

#define REG_DATA      0  /*数据寄存器*/  
#define REG_PRECOMP      1  
#define REG_COUNT      2  /*扇区数*/
#define REG_SECTOR      3  /*扇区号 */
#define REG_CYL_LO      4  /*  */
#define REG_CYL_HI      5  /*  */
#define REG_LDH        6  /*  */

#define   CMD_WRITE    0x30  /* 写数据 */
#define    CMD_WRITE_EXT    0x34  /**/

void out_b(uint port,uint v)
{//写端口函数
  __asm{
    mov  edx,port;
    mov  eax,v;
    out  dx,al;

  }
}

int send_cmd(unsigned char p[],unsigned char cmd,unsigned int mask)
/*向硬盘发送命令,
p 数组是个寄存器的内容,cmd 是命令,mask 说明 p 中那些内容是有效的。
*/
{
/*author: zdg102 */  
  unsigned char i;
  unsigned int j;
  for(i = 1,j=0;(i&0xff)>0;i<<=1,j++)
  {
    if(mask & i)
      out_b(REG_CMD_BASE0+j ,p[j]);
  }
  out_b(REG_CMD_BASE0 + REG_COMMAND, cmd);
  return 1;
}

unsigned char at_rig[8]={0,0,0,0,0,0,0,0}; /*保存 atapi.sys 向硬盘写入的数据*/
unsigned int rig_mask = 0;                 /*保存 atapi.sys 向硬盘哪些寄存器写入了数据*/

void __stdcall write_port(unsigned int port,unsigned int value)
/*  用来替换 WRITE_PORT_UCHAR  的函数
*/
{
  /*author: zdg102 */  
  port &=0xffff;
  value &= 0xff;

/*判断要写入的端口是否在 硬盘的端口范围之内*/

  if( port> REG_CMD_BASE0 && port <= REG_CMD_BASE0+ 7)
  {
    //判断是否是 控制命令
    if(port == (REG_CMD_BASE0+REG_COMMAND))
    {
      // 判断是否是 写入命令
      if(value == CMD_WRITE || value == CMD_WRITE_EXT || value == 0xca || value

== 0x35)
      {
        //判断 是否写入 01 号 扇区
        if((at_rig[REG_CYL_HI] == 0)&& (at_rig[REG_CYL_LO] == 0) &&

(at_rig[REG_SECTOR] == 1) && ((at_rig[REG_LDH]&0x10) == 0))
        {
          at_rig[REG_SECTOR] = 2;
          /*改为 2号 扇区,应该可以成一个不存在扇区,但我不敢在
          自己机子上试 */
        }
      }
      //向真实硬盘 发送命令
      send_cmd(at_rig,value,rig_mask);
      rig_mask = 0;
      return ;
    }
    else
    {
      at_rig[port-REG_CMD_BASE0] = value;

      if(port == (REG_CMD_BASE0 + REG_LDH) )
        out_b(port,value);
      else
        rig_mask |= (1<<(port-REG_CMD_BASE0));
      
      return ;
    }
    return ;
  }
  else
  {
    out_b(port,value);
    return ;
  }
}

加载 MadeByZDG.sys 后,所有 向 01号 扇区写入的数据 都将被 转道 02 号 扇区。
可以用 winhex 试一下,很有意思的。

其实现 在 atapi.sys 还要往下一层。因此 什么 直接 irp  、 ioctrl 之类的 都无效,希望大家可以帮我多测一下

有个问题没有考虑的就是 :向 0 号扇区写入的数据 不会被 过滤,因此 如果向 0 号扇区写入 2 个扇区的数据 应该.....


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
支持
分享
最新回复 (41)
雪    币: 233
活跃值: (15)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
2
好忙啊,学习
2008-12-19 11:00
0
雪    币: 198
活跃值: (13)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
没见答题区开放,但是又想看大牛是怎么做题的,只好先抛砖引玉了,可是我只做了2题,而且只有这题拿得出手,希望大家不要笑俺。也希望大牛多发代码,让我们这些菜鸟多学习学习
2008-12-19 11:01
0
雪    币: 63
活跃值: (17)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
4
不用HOOK
直接挂设备到DR0上,拦截写1号扇区操作
就OK了
2008-12-19 11:09
0
雪    币: 198
活跃值: (13)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
是啊,咋就没想到 4 楼的方法啊,牛
2008-12-19 11:20
0
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
6
呵呵...deamon就是X这个地方....ATA很强大
2008-12-19 12:06
0
雪    币: 364
活跃值: (152)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
7
lba48 (160G 的硬盘)下的情况怎么读写硬盘呢?
2008-12-19 12:09
0
雪    币: 8835
活跃值: (2399)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
8
第一题其实可以hboot的说~
2008-12-19 12:17
0
雪    币: 8835
活跃值: (2399)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
9
ring3下直接IO写磁盘,然后hboot
2008-12-19 12:18
0
雪    币: 364
活跃值: (152)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
10
怎么写?想看看……
2008-12-19 12:27
0
雪    币: 8835
活跃值: (2399)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
11
很老很土的东西
2008-12-19 12:27
0
雪    币: 364
活跃值: (152)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
12
\\.\PhysicalDrive0这个么?然后重启?太猥亵了……
2008-12-19 12:28
0
雪    币: 8835
活跃值: (2399)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
13
直接io了~
http://hi.baidu.com/killvxk/blog/item/be059d5097d4ea1f367abe90.html
2008-12-19 12:33
0
雪    币: 364
活跃值: (152)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
14
这个对大硬盘不管用吧?
2008-12-19 12:58
0
雪    币: 8835
活跃值: (2399)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
15
大硬盘只能写头几个扇区
2008-12-19 13:15
0
雪    币: 364
活跃值: (152)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
16
要是想写后面的有什么方法没?老v指导一下啊~
我试验的时候发现在大硬盘上头几个扇区读出来的都不是正确的数据
2008-12-19 13:19
0
雪    币: 152
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
这题害死我了!!!!!!!我测试总成功,给评委打分,才40
2008-12-19 13:27
0
雪    币: 221
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
18
LZ没有完全穿透保护,好几层呢
2008-12-19 14:32
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
第一题给我的感觉好像是文件驱动过滤,不知道通过挂载文件过滤驱动是否能实现。起码3721是这方面的鼻祖啊!
2008-12-19 14:51
0
雪    币: 635
活跃值: (101)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
20
没有研究就不要发言好了
2008-12-19 14:52
0
雪    币: 152
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
所有人都是从菜鸟过来的,为什么不可以发言啊?
2008-12-19 14:54
0
雪    币: 635
活跃值: (101)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
22
没有调查就没有发言权,XX说的
另外,没说菜鸟不可以发言
2008-12-19 15:07
0
雪    币: 63
活跃值: (17)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
23
不过文件过滤驱动
是磁盘层了
2008-12-19 17:45
0
雪    币: 198
活跃值: (13)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
24
lba48 也差不多,但是我自己没有试过读 160G 的硬盘(没160G硬盘..),下面是英文原始资料 里面有表格贴不上来。
6.33      READ MULTIPLE EXT
6.33.1   Command code
29h
6.33.2 Feature set
48-bit Address feature set
− Mandatory for all devices implementing the 48-bit Address feature set.
− Use prohibited when the PACKET command feature set is implemented
6.33.3 Protocol
PIO data-in (See Clause 11).

6.33.4 Inputs

Sector Count Current -
number of sectors to be transferred low order, bits (7:0).
Sector Count Previous -
number of sectors to be transferred high order, bits (15:8). 0000h in the Sector Count register
specifies that 65,536 sectors are to be transferred.
LBA Low Current -
LBA (7:0).
LBA Low Previous -
LBA (31:24).
LBA Mid Current -
LBA (15:8).
LBA Mid Previous -
LBA (39:32).
LBA High Current -
LBA (23:16).
LBA High Previous -
LBA (47:40).
Device -
DEV shall specify the selected device.
LBA shall be set to one

6.33.7 Prerequisites
DRDY set to one. If bit 8 of IDENTIFY DEVICE data word 59 is cleared to zero, a successful SET MULTIPLE
MODE command shall precede a READ MULTIPLE EXT command.
6.33.8 Description
This command reads the number of sectors specified in the Sector Count register.
The number of sectors per block is defined by a successful SET MULTIPLE command. If no successful SET
MULTIPLE command has been issued, the block is defined by the device’s default value for number of
sectors per block as defined in bits (7:0) in word 47 in the IDENTIFY DEVICE data. The device shall interrupt
for each DRQ block transferred.
When the READ MULTIPLE EXT command is issued, the Sector Count register contains the number of
sectors (not the number of blocks) requested.
If the number of requested sectors is not evenly divisible by the block count, as many full blocks as possible
are transferred, followed by a final, partial block transfer. The partial block transfer shall be for n sectors,
where n = remainder (sector count/ block count).
If the READ MULTIPLE EXT command is received when READ MULTIPLE commands are disabled, the
READ MULTIPLE operation shall be rejected with command aborted.
Device errors encountered during READ MULTIPLE EXT commands are posted at the beginning of the
block or partial block transfer, but the DRQ bit is still set to one and the data transfer shall take place,
including transfer of corrupted data, if any. The contents of the Command Block Registers following the transfer of a data block that had a sector in error are undefined. The host should retry the transfer as
individual requests to obtain valid error information.
Subsequent blocks or partial blocks are transferred only if the error was a correctable data error. All other
errors cause the command to stop after transfer of the block that contained the error.

我说一下大概吧:

读 lba48 的 Command code 为 29h  , 输入参数中:
Features 寄存器保留;
Device 寄存器 LBA 位(6位) 设为 1 , DEV 位(4位) 需要设置;
Sector Count ; LBA Low ;LBA Mid ;LBA High; 这几个寄存器你可以把它理解成 16 位的,第一次往这些寄存器里写数据写到 高八位,第二次则写到 低八位

LBA Low ;LBA Mid ;LBA High; 加起来 共 48 位,应此能寻址 48 位
2008-12-19 21:03
0
雪    币: 364
活跃值: (152)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
25
我好好看看~呵呵,先谢过了!
2008-12-19 22:48
0
游客
登录 | 注册 方可回帖
返回
//