文件的保护有很多很多种方法。从ring3到ring0,从占坑到文件系统驱动的hook,等 等。而本文向大家介绍一种比文件系统更底层的方法,也就是port级的文件保护。抛开了 文件系统层次美观的文件名和文件对象,当irp传递到atapi.sys驱动后,有的只是磁盘的 物理偏移和SCSI指令。下面让我们开始对atapi的探索。 首先,让我们来了解一下写文件操作在内核中大致的流程。当你在用户层修改一个文件并 保存的时候,内核中生成了一个irp并开始处理它。在经过一系列无关重点的操作后,irp最 终会传到 Ntfs驱动的NtfsCommonWrite中,之后irp 依次传递给 VolSnap!VolSnapWrite->Ftdisk!FtDiskReadWrite->CLASSPNA!ClassReadWrite->CLASSPNP!S erviceTransferRequest->CLASSPNP!SubmitTransferPacket,最后SubmitTransferPacket() 会生成一个新的irp, 并传递给我们的今天的主角atapi! IdePortDispatch(), 该函数是atapi 的IRP_MJ_SCSI处理例程。在IdePortDispatch()之下就是hal层了,再下面就是端口的IO 操作了。 看到这里,这里大多数的读者应该都想到了hook IdePortDispatch就可以禁止特定扇 区的读写了。但是在这之前,我们更有必要看看SubmitTransferPacket()和 ServiceTransferRequest()这两个函数,因为我们需要知道SubmitTransferPacket()新生 成的irp有什么特别之处,因为这个irp将传递给atapi,并且决定此后的操作。 先来看看SubmitTransferPacket()中的代码。函数里有如下的代码: nextSp = IoGetNextIrpStackLocation(Pkt->Irp); nextSp->MajorFunction = IRP_MJ_SCSI; nextSp->Parameters.Scsi.Srb = &Pkt->Srb; Pkt->Srb.ScsiStatus = Pkt->Srb.SrbStatus = 0; Pkt->Srb.SenseInfoBufferLength = sizeof(SENSE_DATA); …… return IoCallDriverStackSafeDefault(nextDevObj, Pkt->Irp); 经过笔者的调试,确定了nextDevObj是atapi.sys生成名为 “DR0” 的设备对象。 而Pkt->Irp 中的Pkt是一个结构,笔者在这里不准备讲Pkt,它只是一个classpnp驱动里的一个结构, 我们只要知道Pkt->Irp是一个classpnp生成的新的irp就行了。通过源码可以发现,主要 的参数包含在nextSp->Parameters.Scsi.Srb里。 继续看上层函数ServiceTransferRequest()的代码。笔者发现这个函数里发现了一处 调用: SetupReadWriteTransferPacket(pkt, bufPtr, thisPieceLen, targetLocation, Irp); pktStat = SubmitTransferPacket(pkt); 让我们进SetupReadWriteTransferPacket中看看。笔者在这个函数发现以下对 Pkt->Srb操作的代码: Pkt->Srb.DataBuffer = Buf; Pkt->Srb.DataTransferLength = Len; Pkt->Srb.QueueSortKey = logicalBlockAddr.LowPart; Pkt->Srb.OriginalRequest = Pkt->Irp; Pkt->Srb.SenseInfoBuffer = &Pkt->SrbErrorSenseData; Pkt->Srb.TimeOutValue = fdoExt->TimeOutValue; pCdb = (PCDB)Pkt->Srb.Cdb; if (TEST_FLAG(fdoExt->DeviceFlags, DEV_USE_16BYTE_CDB)) { REVERSE_BYTES_QUAD(&pCdb->CDB16.LogicalBlock, &logicalBlockAddr); REVERSE_BYTES(&pCdb->CDB16.TransferLength, &numTransferBlocks); pCdb->CDB16.OperationCode=(majorFunc==IRP_MJ_READ)?SCSIOP_READ16:SCSIOP_WRI TE16; Pkt->Srb.CdbLength = 16; }else{ pCdb->CDB10.LogicalBlockByte0=((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte 3; pCdb->CDB10.LogicalBlockByte1=((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte 2; pCdb->CDB10.LogicalBlockByte2=((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte 1; pCdb->CDB10.LogicalBlockByte3=((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte 0; pCdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&numTransferBlocks)->Byte1; pCdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&numTransferBlocks)->Byte0; pCdb->CDB10.OperationCode=(majorFunc==IRP_MJ_READ)?SCSIOP_READ:SCSIOP_WRITE ;} 到这里,看到如此多的CDB和SRB,想必不少读者已经晕了。那么是时候对这些结构做 些说明了。 Atapi.sys接收的是SCSI命令, 这个开篇就提到了, 而SubmitTransferPacket( |