把包含了SRB参数的irp传递给了atapi,于是可以得知SRB结构中包含了SCSI命令,这
里给出SRB的结构: typedef struct _SCSI_REQUEST_BLOCK {
UCHAR Function; //SRB的功能码,可以设置为
来自己发送SRB指令给atapi,机器狗用过这种方法
UCHAR SrbStatus; //返回的状态
UCHAR ScsiStatus; //返回的状态
……
UCHAR CdbLength; //下文详细讲述
ULONG SrbFlags; //SRB_FLAGS_DATA_OUT读出内容,SRB_FLAGS_DATA_IN写入内
容
……
PVOID OriginalRequest; //原始的Irp。记住我们这个IRP是CLASSPNP自己分配
的
union {
ULONG InternalStatus;
ULONG QueueSortKey; //这个也很重要,下文详细讲述
};
UCHAR Cdb[16]; //这就是SCSI的命令了
} SCSIREQUESTBLOCK, *PSCSIREQUESTBLOCK;
UCHAR Reserved1 : 2;
UCHAR ForceUnitAccess : 1;
UCHAR DisablePageOut : 1;
UCHAR LogicalUnitNumber : 3;
UCHAR LogicalBlockByte0; // QueueSortKey的byte1
UCHAR LogicalBlockByte1; // QueueSortKey的byte2
UCHAR LogicalBlockByte2; // QueueSortKey的byte3
UCHAR LogicalBlockByte3; // QueueSortKey的byte4
UCHAR Reserved2;
UCHAR TransferBlocksMsb;//要读(写)的扇区个数高位
UCHAR TransferBlocksLsb;//要读(写)的扇区个数的低位
UCHAR Control;
} CDB10; 其中的最主要的是OperationCode 和LogicalBlockByteX成员。LogicalBlockByteX
成员是SRB. QueueSortKey的从低到高的4个byte的内容。
讲了这么多知识,这里总结下classpnp进行的一些主要操作,方便接下来的内容。当
一个irp传递给classpnp时,classpnp生成一个新的irp并运行代码:
nextSp = IoGetNextIrpStackLocation(Pkt->Irp)
然后对nextSpSrb.Cdb、 nextSp.Srb. CdbLength以及nextSp.Srb. QueueSortKey等
成员进行赋值,最后将irp通过IoCallDriverStackSafeDefault()传递给atapi.sys。
有了这些知识,接下来就是编写我们代理IdePortDispatch函数了,代理函数可以通过
对比QueueSortKey与想要保护的扇区来选择阻止还是放行,当然读者也可以尝试比对Cdb.
LogicalBlockByteX成员,或者再加上OperationCode的比对来阻止特定的操作。
那么又有一个问题了,假设我们想要保护文件,那怎么得到文件所在的扇区呢?有一个
方法是在ring3下DeviceIoControl发送FSCTL_GET_RETRIEVAL_POINTERS就可以得到文件
的簇号了,然后再根据给出的算式,可以得到相应的扇区号,算式如下:
fat32: 某文件或目录首逻辑扇区号 = data起始扇区号 +(该文件或目录起始簇号-2)
*每簇扇区数
ntfs:逻辑首扇区号=簇号*每簇扇区数
算式中涉及了一些磁盘格式的内容,如每簇扇区数和data起始扇区号,这不是本文重
点,请读者自行搜索解决。下面给出笔者得到文件起始扇区的核心代码:
hFile=CreateFile(_T("C:\\FsControl.exe"),GENERIC_READ,FILE_SHARE_RE
AD|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0);
STARTING_VCN_INPUT_BUFFER InBuf;
RETRIEVAL_POINTERS_BUFFER OutBuf;
DWORD dwBytesRet;
InBuf.StartingVcn.QuadPart = 0;
ZeroMemory(&OutBuf, sizeof(OutBuf));
DeviceIoControl(hFile,FSCTL_GET_RETRIEVAL_POINTERS,&InBuf,sizeof(In
Buf),&OutBuf, sizeof(OutBuf), &dwBytesRet, NULL);
笔者的文件驱动为ntfs。每簇扇区数为8,所以算出扇区为1564272,代理函数写完后
挂钩atapi的IRP_MJ_SCSI例程就行了。关于Dispatch hook之类的知识这里不再多说。代
理函数代码如下:
NTSTATUS
fake_handle(
PDEVICE_OBJECT DeviceObject,
PIRP Irp )
{
PIO_STACK_LOCATION irp_stack;
PFILE_OBJECT file_obj;
ULONG max,min;
irp_stack = IoGetCurrentIrpStackLocation( Irp );
max = 1564272+57; |