虚拟光驱探秘
1. 應(yīng)用虛擬光驅(qū)能夠使沒有dvd的用戶直接使用網(wǎng)上可以下載的dvd鏡像來欣賞dvd的影片。
2. 通過光盤鏡像復(fù)制工具制作的光盤可以不必使用低速的刻錄設(shè)備刻錄而直接使用
3. 最實(shí)用的一點(diǎn),借助虛擬光驅(qū),可以模擬各種加密的光盤模式,即使在正版光盤不在身邊的情況下也能使用。(對(duì)熟悉網(wǎng)絡(luò)的人更為實(shí)用)
對(duì)于虛擬光驅(qū)工具的使用,網(wǎng)絡(luò)上已經(jīng)有不少相關(guān)的文章了,還有不少圖文并茂的教程,在這里就不多贅述了,本文要研究的,是虛擬光驅(qū)軟件的原理和編程實(shí)現(xiàn)。
首先,最常用的虛擬光驅(qū)軟件是運(yùn)行在windows操作系統(tǒng)之下的。對(duì)于微軟的操作系統(tǒng)來說,任何應(yīng)用層上的程序是不能直接與硬件打交道的,必須要通過操作系統(tǒng)內(nèi)核(kernel)這個(gè)中介來實(shí)現(xiàn)對(duì)硬件的操作。微軟為了最大限度的提供硬件層的抽象,把各種硬件設(shè)備相關(guān)的內(nèi)核實(shí)現(xiàn)代碼用各種驅(qū)動(dòng)模塊封裝了起來,并提供動(dòng)態(tài)加載接口。因此對(duì)于各種設(shè)備自身的I/O處理和數(shù)據(jù)流處理,微軟只提供了一個(gè)接口框架,具體的流程是交給驅(qū)動(dòng)程序自身的代碼去解決的,并依靠各個(gè)設(shè)備的I/O管理器向各個(gè)在內(nèi)核中注冊(cè)的驅(qū)動(dòng)發(fā)送IRP包的形式來進(jìn)行統(tǒng)一的管理。這實(shí)際上也就意味著我們可以向系統(tǒng)注冊(cè)一個(gè)實(shí)際上并不存在的硬件設(shè)備來欺騙操作系統(tǒng)的內(nèi)核,而實(shí)際上的設(shè)備操作都是由我們自己編寫的驅(qū)動(dòng)模塊來進(jìn)行軟件的實(shí)現(xiàn)。這也就是一切windows下虛擬設(shè)備存在的基礎(chǔ)。存儲(chǔ)設(shè)備驅(qū)動(dòng)結(jié)構(gòu)。
接下來就是如何做一個(gè)最基本的虛擬光驅(qū)并使他正常工作。眾所周知,windows使用了“消息”這一數(shù)據(jù)結(jié)構(gòu)來實(shí)現(xiàn)應(yīng)用程序之間的通信,同樣,在內(nèi)核層,微軟也定義了一套IO控制碼(IOCTL)的結(jié)構(gòu)來實(shí)現(xiàn)內(nèi)核與驅(qū)動(dòng)設(shè)備之間的數(shù)據(jù)流和控制流的傳遞。針對(duì)不同的設(shè)備,IO控制碼的宏定義是不同的,這樣就保證了各個(gè)設(shè)備之間的控制流不會(huì)傳錯(cuò)地方。對(duì)于一個(gè)標(biāo)準(zhǔn)的CD-ROM設(shè)備,其關(guān)鍵的IOCTL的定義:
IOCTL_CDROM_GET_DRIVE_GEOMETRY :獲得光盤物理結(jié)構(gòu)
IOCTL_CDROM_GET_LAST_SESSION :獲得光盤最后一個(gè)區(qū)段
IOCTL_CDROM_CHECK_VERIFY :光盤介質(zhì)檢查
IOCTL_CDROM_CLOSE_DOOR :光盤入倉
IOCTL_CDROM_RAW_READ :以raw方式讀取光盤數(shù)據(jù)
IOCTL_CDROM_READ_TOC: 獲得光盤存儲(chǔ)內(nèi)容結(jié)構(gòu)
需要處理的關(guān)鍵IRP請(qǐng)求
IRP_MJ_READ:對(duì)設(shè)備的數(shù)據(jù)讀請(qǐng)求(虛擬光驅(qū)的核心)
例子:一個(gè)最簡(jiǎn)單的虛擬光驅(qū)的驅(qū)動(dòng)入口代碼:
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;
}
//虛擬設(shè)備例程處理
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;
}
//虛擬設(shè)備創(chuàng)建注冊(cè)函數(shù)
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實(shí)現(xiàn)代碼
case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
// IOCTL_CDROM_GET_DRIVE_GEOMETRY實(shí)現(xiàn)代碼
…
}
…
}
對(duì)應(yīng)每個(gè)控制碼,都有一個(gè)相應(yīng)的實(shí)現(xiàn)函數(shù),對(duì)于是實(shí)在的硬件設(shè)備而言,每個(gè)硬件都會(huì)有一套自己的控制匯編來操作硬件。對(duì)于我們的虛擬光驅(qū)而言,我們并不需要了解光驅(qū)的專用匯編指令,我們只需要用一系列的api語句來實(shí)現(xiàn)數(shù)據(jù)讀的功能就可以了。需要注意的是,在我們的虛擬光驅(qū)中使用的不是普通的win32 api,而是專門用于和windows內(nèi)核交互的NATIVE API,即windows原生函數(shù)。
經(jīng)過以上的步驟,我們已經(jīng)實(shí)現(xiàn)了一個(gè)最基本的虛擬光驅(qū),現(xiàn)在我們還需要為其添加一系列的輔助功能來實(shí)現(xiàn)對(duì)加密光盤的模擬。
一個(gè)能夠虛擬加密光盤的虛擬光驅(qū)實(shí)際上是由三部分組成的:一是上面所述的內(nèi)核驅(qū)動(dòng),就是虛擬光驅(qū)面向內(nèi)核的實(shí)現(xiàn)部分,二是微端口過濾驅(qū)動(dòng)部分(MINIPORT),這一部分是用來欺騙內(nèi)核的總線驅(qū)動(dòng)ATAPI.SYS(也有部分虛擬光軀有自己的總線驅(qū)動(dòng),如daemon tools),實(shí)現(xiàn)光驅(qū)的總線功能操作;三是光驅(qū)文件系統(tǒng)過濾驅(qū)動(dòng),其目的是使一些具有特殊文件結(jié)構(gòu)和光軌分布結(jié)構(gòu)的加密光盤虛擬變得可能,如何才能做好這一部分,實(shí)際上是所有商業(yè)化的虛擬光驅(qū)的技術(shù)核心。
微端口過濾驅(qū)動(dòng)都具有比較固定的結(jié)構(gòu),其詳細(xì)的例程在微軟的驅(qū)動(dòng)開發(fā)包中都有詳細(xì)的表述,較為常用的SCSI_MINIPORT驅(qū)動(dòng)有非常完整的例子,這里就不多做敘述了。
對(duì)于任何一種物理光盤保護(hù)來說,總面臨著這樣一個(gè)問題:是否能讓普通光驅(qū)讀出的數(shù)據(jù)無法完全被操作系統(tǒng)使用?假如能做到的話,無疑是一個(gè)非常完美的保護(hù)。但遺憾的是,目前的windows操作系統(tǒng)尚無法為光盤保護(hù)軟件商們制作這樣一個(gè)完美的機(jī)制,因此,也使各種對(duì)光盤的模擬的軟件能夠大行其道。這些軟件的結(jié)構(gòu)中,很重要的一個(gè)組件就是文件過濾系統(tǒng)驅(qū)動(dòng)。
光驅(qū)文件過濾系統(tǒng)是比較特殊的一類驅(qū)動(dòng),它對(duì)光盤的數(shù)據(jù)文件讀寫格式進(jìn)行規(guī)范和定義,好比是文件系統(tǒng)上的一個(gè)篩子,截獲各種特殊的請(qǐng)求并自定義返回或者處理過程。常規(guī)的光盤采用的是ISO9660文件系統(tǒng)結(jié)構(gòu),微軟在操作系統(tǒng)內(nèi)部也有直接的函數(shù)支持,因此在虛擬光驅(qū)編寫中并不要自己來處理文件系統(tǒng)相關(guān)的操作。而一些經(jīng)過特殊加工的加密光盤采用一些比較特殊的方法人為制造可讀取的壞道,用普通的ISO文件系統(tǒng)讀寫函數(shù)是無法獲得加密光軌的信息的,再前期數(shù)據(jù)讀取期必須激活光驅(qū)驅(qū)動(dòng)的“RAW”模式來讀取。在光盤虛擬的后期也要設(shè)計(jì)自己的讀寫函數(shù)來返回加密光軌的數(shù)據(jù),這就是要引入光驅(qū)文件過濾系統(tǒng)的原因。
目前非常流行的“光盤特征識(shí)別(RMPS)”技術(shù)使一般的虛擬光驅(qū)無法實(shí)現(xiàn)這種特殊數(shù)據(jù)結(jié)構(gòu)的讀取狀態(tài),因此可以用來判斷是否采用了正版的光盤。基于這個(gè)原理的保護(hù)技術(shù)大同小異(包括現(xiàn)在的號(hào)稱最強(qiáng)的starforce)。現(xiàn)在僅就早期的一種名為“tages”的技術(shù)做一些說明:
tages中在光盤中的某些特殊區(qū)域存放著一種特殊的光軌,它由兩條光軌組成,兩條光軌有著相同的序號(hào)和盤內(nèi)地址。由于光盤光頭讀取軌道的時(shí)候是采取最近最先的原則,在光頭移動(dòng)距離最短的光軌是最先被使用的,所以光頭在不同的位置會(huì)讀取到2條光軌中不同的數(shù)據(jù)。tages光軌的結(jié)構(gòu)。
對(duì)于這種的加密光盤格式,由于其生產(chǎn)過程中加密光軌的分布位置各不相同,所以就形成了所謂的“光盤指紋”。因?yàn)?#xff0c;從本質(zhì)上來說,啟動(dòng)加密過的執(zhí)行文件,進(jìn)行正版序列號(hào)的輸入工作,實(shí)際上就是輸入加密光軌的位置并讓加密系統(tǒng)進(jìn)行驗(yàn)證的過程。
對(duì)于某種特殊的加密如starforce,它甚至接管了ide總線驅(qū)動(dòng),它由它自己的總線驅(qū)動(dòng)來實(shí)現(xiàn)對(duì)光盤數(shù)據(jù)的讀取,并在讀取過程中記錄讀取加密光軌的各種運(yùn)行時(shí)刻參數(shù)(如讀取一個(gè)光軌經(jīng)歷的時(shí)間等,starforce的新版本甚至精確到了毫秒級(jí)別),以此來作為是否正版光盤的認(rèn)證。其實(shí)我個(gè)人認(rèn)為starforce在光盤文件格式上并沒有與其他保護(hù)系統(tǒng)有何種優(yōu)越性,事實(shí)上它只在阻止調(diào)試者對(duì)受保護(hù)的程序進(jìn)行調(diào)試方面做的非常成功(使用了偽代碼,內(nèi)存保護(hù),進(jìn)程保護(hù),調(diào)試監(jiān)控,禁止下斷點(diǎn),有些時(shí)候這樣的保護(hù)使正版都無法通過檢測(cè)),對(duì)于使用其保護(hù)的光盤復(fù)制并且模擬仍然是可能的。
對(duì)于這些加密光盤,可以在驅(qū)動(dòng)中層結(jié)構(gòu)中使用一些特殊的軟件層驅(qū)動(dòng)來過濾這些特殊光軌的I/O請(qǐng)求,并返回讀取正版光盤時(shí)的系統(tǒng)變量和參數(shù)來對(duì)這個(gè)光盤進(jìn)行模擬,也就是文件系統(tǒng)過濾驅(qū)動(dòng)。
較為成功的文件過濾系統(tǒng)是Alochol 120%的rmps文件系統(tǒng),其原理實(shí)際上就是對(duì)光盤某些區(qū)域的讀取的實(shí)地情況進(jìn)行類似“錄像”的操作,并記錄進(jìn)文件,在模擬時(shí)進(jìn)行回放。事實(shí)上,Alochol這種技術(shù)是相當(dāng)成功的,starforce目前只能用使用自己的總線驅(qū)動(dòng)并且在運(yùn)行時(shí)封閉scsi總線的方法來規(guī)避Alochol的模擬。
文件過濾系統(tǒng)的技術(shù)難點(diǎn)在于原始光盤讀取數(shù)據(jù)的采集,一旦其能夠完整的采集到原始光盤的讀寫狀態(tài)紀(jì)錄,那么模擬將會(huì)是非常容易的。
附錄:
一些文件過濾系統(tǒng)驅(qū)動(dòng)的例子可以在網(wǎng)上找到,如:
ext2 IFS:
http://uranus.it.swin.edu.au/~jn/linux/ext2ifs.htm
ext2 FSD:
http://ext2fsd.sourceforge.net/projects/projects.htm#insider
總結(jié)
- 上一篇: 安卓-几种查看SHA1和MD5的方法
- 下一篇: 中国操纵杆电位计市场现状研究分析与发展前