虚拟光驱探秘

现在网络上越来越流行使用虚拟光驱,由于虚拟光驱的使用,使得越来越多的PC拥有很以前所无法想象的特殊功能,如:
1. 应用虚拟光驱能够使没有dvd的用户直接使用网上可以下载的dvd镜像来欣赏dvd的影片。
2. 通过光盘镜像复制工具制作的光盘可以不必使用低速的刻录设备刻录而直接使用
3. 最实用的一点,借助虚拟光驱,可以模拟各种加密的光盘模式,即使在正版光盘不在身边的情况下也能使用。(对熟悉网络的人更为实用)
对于虚拟光驱工具的使用,网络上已经有不少相关的文章了,还有不少图文并茂的教程,在这里就不多赘述了,本文要研究的,是虚拟光驱软件的原理和编程实现。
首先,最常用的虚拟光驱软件是运行在windows操作系统之下的。对于微软的操作系统来说,任何应用层上的程序是不能直接与硬件打交道的,必须要通过操作系统内核(kernel)这个中介来实现对硬件的操作。微软为了最大限度的提供硬件层的抽象,把各种硬件设备相关的内核实现代码用各种驱动模块封装了起来,并提供动态加载接口。因此对于各种设备自身的I/O处理和数据流处理,微软只提供了一个接口框架,具体的流程是交给驱动程序自身的代码去解决的,并依靠各个设备的I/O管理器向各个在内核中注册的驱动发送IRP包的形式来进行统一的管理。这实际上也就意味着我们可以向系统注册一个实际上并不存在的硬件设备来欺骗操作系统的内核,而实际上的设备操作都是由我们自己编写的驱动模块来进行软件的实现。这也就是一切windows下虚拟设备存在的基础。存储设备驱动结构。
接下来就是如何做一个最基本的虚拟光驱并使他正常工作。众所周知,windows使用了“消息”这一数据结构来实现应用程序之间的通信,同样,在内核层,微软也定义了一套IO控制码(IOCTL)的结构来实现内核与驱动设备之间的数据流和控制流的传递。针对不同的设备,IO控制码的宏定义是不同的,这样就保证了各个设备之间的控制流不会传错地方。对于一个标准的CD-ROM设备,其关键的IOCTL的定义:
IOCTL_CDROM_GET_DRIVE_GEOMETRY :获得光盘物理结构
IOCTL_CDROM_GET_LAST_SESSION :获得光盘最后一个区段
IOCTL_CDROM_CHECK_VERIFY :光盘介质检查
IOCTL_CDROM_CLOSE_DOOR :光盘入仓
IOCTL_CDROM_RAW_READ :以raw方式读取光盘数据
IOCTL_CDROM_READ_TOC: 获得光盘存储内容结构
需要处理的关键IRP请求
IRP_MJ_READ:对设备的数据读请求(虚拟光驱的核心)
例子:一个最简单的虚拟光驱的驱动入口代码:
NTSTATUS
DriverEntry (
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
……
ZwMakeTemporaryObject(dir_handle);
for (n = 0; n < n_devices; n++)
{
status=DiskCreateDevice(DriverObject, n, FILE_DEVICE_CD_ROM);
if (NT_SUCCESS(status))
{
n_created_devices++;
}
}
if (n_created_devices == 0)
{
ZwClose(dir_handle);
return status;
}
//虚拟设备例程处理
DriverObject->MajorFunction[IRP_MJ_CREATE] = DiskCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE]= DiskCreateClose;
DriverObject->MajorFunction[IRP_MJ_READ] = DiskReadWrite;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=DiskDeviceControl;

 

DriverObject->DriverUnload = DiskUnload;

return STATUS_SUCCESS;
}
//虚拟设备创建注册函数
NTSTATUS
DiskCreateDevice (
IN PDRIVER_OBJECT DriverObject,
IN ULONG Number,
IN DEVICE_TYPE DeviceType
)
{
WCHAR device_name_buffer[MAXIMUM_FILENAME_LENGTH];
UNICODE_STRING device_name;
NTSTATUS status;
PDEVICE_OBJECT device_object;
PDEVICE_EXTENSION device_extension;
HANDLE thread_handle;
ASSERT(DriverObject != NULL);
if (DeviceType == FILE_DEVICE_CD_ROM)
{
swprintf(
device_name_buffer,
DEVICE_NAME_PREFIX L"Cd" L"%u",
Number
);
}
else
{
swprintf(
device_name_buffer,
DEVICE_NAME_PREFIX L"%u",
Number
);

RtlInitUnicodeString(&device_name, device_name_buffer);
status = IoCreateDevice(
DriverObject,
sizeof(DEVICE_EXTENSION),
&device_name,
DeviceType,
0,
FALSE,
&device_object
);
if (!NT_SUCCESS(status))
{
return status;
}

device_object->Flags |= DO_DIRECT_IO;
device_extension= (PDEVICE_EXTENSION) device_object->DeviceExtension;
device_extension->media_in_device = FALSE;
if (DeviceType == FILE_DEVICE_CD_ROM)
{
device_object->Characteristics |= FILE_READ_ONLY_DEVICE;
device_extension->read_only = TRUE;
}
InitializeListHead(&device_extension->list_head);
KeInitializeSpinLock(&device_extension->list_lock);
KeInitializeEvent(
&device_extension->request_event,
SynchronizationEvent,
FALSE
);
device_extension->terminate_thread = FALSE;
status = PsCreateSystemThread(
&thread_handle,
(ACCESS_MASK) 0L,
NULL,
NULL,
NULL,
DiskThread,
device_object
);
if (!NT_SUCCESS(status))
{
IoDeleteDevice(device_object);
return status;
}
status = ObReferenceObjectByHandle(
thread_handle,
THREAD_ALL_ACCESS,
NULL,
KernelMode,
&device_extension->thread_pointer,
NULL
);
if (!NT_SUCCESS(status))
{
ZwClose(thread_handle);
device_extension->terminate_thread = TRUE;
KeSetEvent(
&device_extension->request_event,
(KPRIORITY) 0,
FALSE
);
IoDeleteDevice(device_object);
return status;
}
ZwClose(thread_handle);
return STATUS_SUCCESS;
}
NTSTATUS
FileDiskDeviceControl (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
……
//处理IOCTL
witch (io_stack->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_CDROM_READ_TOC:
// IOCTL_CDROM_READ_TOC实现代码
case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
// IOCTL_CDROM_GET_DRIVE_GEOMETRY实现代码

}

}
对应每个控制码,都有一个相应的实现函数,对于是实在的硬件设备而言,每个硬件都会有一套自己的控制汇编来操作硬件。对于我们的虚拟光驱而言,我们并不需要了解光驱的专用汇编指令,我们只需要用一系列的api语句来实现数据读的功能就可以了。需要注意的是,在我们的虚拟光驱中使用的不是普通的win32 api,而是专门用于和windows内核交互的NATIVE API,即windows原生函数。
经过以上的步骤,我们已经实现了一个最基本的虚拟光驱,现在我们还需要为其添加一系列的辅助功能来实现对加密光盘的模拟。
一个能够虚拟加密光盘的虚拟光驱实际上是由三部分组成的:一是上面所述的内核驱动,就是虚拟光驱面向内核的实现部分,二是微端口过滤驱动部分(MINIPORT),这一部分是用来欺骗内核的总线驱动ATAPI.SYS(也有部分虚拟光躯有自己的总线驱动,如daemon tools),实现光驱的总线功能操作;三是光驱文件系统过滤驱动,其目的是使一些具有特殊文件结构和光轨分布结构的加密光盘虚拟变得可能,如何才能做好这一部分,实际上是所有商业化的虚拟光驱的技术核心。
微端口过滤驱动都具有比较固定的结构,其详细的例程在微软的驱动开发包中都有详细的表述,较为常用的SCSI_MINIPORT驱动有非常完整的例子,这里就不多做叙述了。
对于任何一种物理光盘保护来说,总面临着这样一个问题:是否能让普通光驱读出的数据无法完全被操作系统使用?假如能做到的话,无疑是一个非常完美的保护。但遗憾的是,目前的windows操作系统尚无法为光盘保护软件商们制作这样一个完美的机制,因此,也使各种对光盘的模拟的软件能够大行其道。这些软件的结构中,很重要的一个组件就是文件过滤系统驱动。
光驱文件过滤系统是比较特殊的一类驱动,它对光盘的数据文件读写格式进行规范和定义,好比是文件系统上的一个筛子,截获各种特殊的请求并自定义返回或者处理过程。常规的光盘采用的是ISO9660文件系统结构,微软在操作系统内部也有直接的函数支持,因此在虚拟光驱编写中并不要自己来处理文件系统相关的操作。而一些经过特殊加工的加密光盘采用一些比较特殊的方法人为制造可读取的坏道,用普通的ISO文件系统读写函数是无法获得加密光轨的信息的,再前期数据读取期必须激活光驱驱动的“RAW”模式来读取。在光盘虚拟的后期也要设计自己的读写函数来返回加密光轨的数据,这就是要引入光驱文件过滤系统的原因。
目前非常流行的“光盘特征识别(RMPS)”技术使一般的虚拟光驱无法实现这种特殊数据结构的读取状态,因此可以用来判断是否采用了正版的光盘。基于这个原理的保护技术大同小异(包括现在的号称最强的starforce)。现在仅就早期的一种名为“tages”的技术做一些说明:
tages中在光盘中的某些特殊区域存放着一种特殊的光轨,它由两条光轨组成,两条光轨有着相同的序号和盘内地址。由于光盘光头读取轨道的时候是采取最近最先的原则,在光头移动距离最短的光轨是最先被使用的,所以光头在不同的位置会读取到2条光轨中不同的数据。tages光轨的结构。

对于这种的加密光盘格式,由于其生产过程中加密光轨的分布位置各不相同,所以就形成了所谓的“光盘指纹”。因为,从本质上来说,启动加密过的执行文件,进行正版序列号的输入工作,实际上就是输入加密光轨的位置并让加密系统进行验证的过程。
对于某种特殊的加密如starforce,它甚至接管了ide总线驱动,它由它自己的总线驱动来实现对光盘数据的读取,并在读取过程中记录读取加密光轨的各种运行时刻参数(如读取一个光轨经历的时间等,starforce的新版本甚至精确到了毫秒级别),以此来作为是否正版光盘的认证。其实我个人认为starforce在光盘文件格式上并没有与其他保护系统有何种优越性,事实上它只在阻止调试者对受保护的程序进行调试方面做的非常成功(使用了伪代码,内存保护,进程保护,调试监控,禁止下断点,有些时候这样的保护使正版都无法通过检测),对于使用其保护的光盘复制并且模拟仍然是可能的。
对于这些加密光盘,可以在驱动中层结构中使用一些特殊的软件层驱动来过滤这些特殊光轨的I/O请求,并返回读取正版光盘时的系统变量和参数来对这个光盘进行模拟,也就是文件系统过滤驱动。
较为成功的文件过滤系统是Alochol 120%的rmps文件系统,其原理实际上就是对光盘某些区域的读取的实地情况进行类似“录像”的操作,并记录进文件,在模拟时进行回放。事实上,Alochol这种技术是相当成功的,starforce目前只能用使用自己的总线驱动并且在运行时封闭scsi总线的方法来规避Alochol的模拟。
文件过滤系统的技术难点在于原始光盘读取数据的采集,一旦其能够完整的采集到原始光盘的读写状态纪录,那么模拟将会是非常容易的。

附录:
一些文件过滤系统驱动的例子可以在网上找到,如:
ext2 IFS:
http://uranus.it.swin.edu.au/~jn/linux/ext2ifs.htm
ext2 FSD:
http://ext2fsd.sourceforge.net/projects/projects.htm#insider

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值