Windows api实现 虚拟光驱

news/2024/12/5 3:25:04/

代码有点乱。凑合着看吧   
       一直以来对虚拟光驱的实现都很好奇,也曾想试着做一个,但查遍网上资料,基本上没找到过什么有用的。所以一直没有实现。感于这方面资料的缺少。所以准备研究一下这方面的技术。              
在没有什么资料的情况下,要想研究某方面的技术,最好的办法,当然是逆向。选择作为逆向目标的软件。一定不能过大。二要不是商业软件。所以选了MINICD这款软件。这款软件用UPX压缩了。压缩后只有几百K。不过作者对UPX压缩后的软件做了些处理,使用UPX –d 是无法解压缩的。所有只有手脱了。UPX的变化壳手脱几乎可以讲是秒脱。用OD载入。一进来就是一个pushad 往下拉一拉就能看到一个popad 再往下就是一个大跳。跳到的地址就是OEP了。脱壳后发现是使用DELPHI写的。使用DELPHI写的。最好的辅助破解工具当然是DEDE。但用DEDE载入后看不到窗体信息,用EXESCOPE打开资源的时候也会报错。这是UPX压缩的东西解压后的后遗症,使用RESCOPE就可以查看到窗体的信息了。里面也有按钮的信息。利用他就可以找到点击插入按 钮的事件处理过程了。找到后就可以开始分析了。当然这篇文章是来讲虚拟光驱的实现原理的。破解过程和分析过程。在这里不作进一步的说明。会另开一篇文章来描述分析过程。破解过程就不讲了。网上到处可以找得到。在这里。只讲分析的结果。      
   MINICD实现虚拟光驱。有两个文件共同完成。一个是用户层的EXE文件(MINICD.exe)。一个是驱动文件(minicd.sys)这个驱动文件是由minicd.exe在创建设备失败并且发现system32\drivers\目录里没有minicd.sys文件时创建的(此文件被嵌入到了minicd.exe的内部)
    其中minicd.exe 用于向驱动文件发送消息以使驱动工作。驱动则实现虚拟一个设备。在驱动没有被安装的情况下,minicd.exe也负责安装并启动驱动。
    故而下面我们将分两篇文章来讲述虚拟光驱的实现原理。这篇文章只讲述用户层也就是minicd.exe里所作的事情。Minicd.sys也就是驱动里所作的事情。在下一篇作描述。
    为了使你们跟着做能够实现功能,当然我们要做一些准备工作了。首先是从网上下一个 “迷你虚拟光盘”版本是1.0 在网上搜索minicd 多的很。我的这个后面加了一个皮鲁专版。运行一下。做这个的目的是让MINICD释放已经嵌入到他内部的minicd.sys. 运行后。映射一个ISO。成功后。你就会发现在 system32\drivers目录里多了一个minicd.sys文件。这个就是驱动文件。同时他还帮你安装了这个驱动。故而我们就可以直接对其进行访问。以实现虚拟一个光驱的目的了。下面我们就讲一讲如何通过程序和minicd.sys进行通讯,以创建一个虚拟光驱出来(这个也就是minicd.exe里所作的事了)。至于如何在驱动没有安装的情况进行驱动的安装我准备在讲述完通讯后再接着讲。因为目前驱动已经被你下载的minicd.exe 安装好了。
   Minicd.sys 是一个典型的NT驱动文件,所以要实现和其通讯,也就是一般的和NT驱动通讯的基本步骤。当然Minicd.exe里也是这样做的。在驱动已经安装并启动的情况下,只须简单的两步即可。   
Device = CreateFile(“\\.\\minicd”…….); // 使用CreateFile创建一个设备(设备名叫\\.\\minicd),这里为了说明过程不必要的参数先不列出
DeviceIOControl(Device,…inBuffer,..,outBuffer,…..); // 使用DeviceIOControl 和设备进行通讯,主要通过 inBuffer 和 outBuffer 在这里只需要使用outBuffer即可。
知道步骤后,下面结合一下。Minicd.exe的实际例子详细的对这两个过程进行描述一下。
第一步:
HANDLE device = CreateFile("\\\\.\\MINICD", 
        GENERIC_READ,        
        FILE_SHARE_READ,   
        0, 
        OPEN_EXISTING,        
        0, 
        0);
CreateFile 是一个万能的API函数。能干很多事情。创建文件,创建管道等。当然也可以创建一个驱动。他的原形如下
HANDLE CreateFile(
LPCTSTR lpFileName, // 如果是文件就是文件名,如果是设备当然是设备名
DWORD dwDesiredAccess, // 对创建的对象的访问权限 GENERIC_READ GENERIC_WRITE 
DWORD dwShareMode, // 共享模式
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 安全属性,一般传null默认就行了 
DWORD dwCreationDisposition, // 对象创建方式 
DWORD dwFlagsAndAttributes, // 设置一些其它属性或者标志 默认即可
HANDLE hTemplateFile // 默认即可
);

我在注释里已经大致讲了每个参数的作用。这里只作些必要的补充。
lpFileName 在这里用的是 \\.\\minicd 这个是设备的符号名。是在驱动里使用IoCreateSymbolicLink 创建的。主要用于用户层程序访问驱动用的。注:符号名称和设备名是不同的(从IoCreateSymbolicLink就可以看出来,其实符号名就类似于设备的一个链接,这个链接是给用户层程序使用的)。当然这里不明白也不要紧。在这里只知道怎么用的就行了。
dwDesiredAccess 访问权限可以是 GENERIC_READ(只读) GENERIC_WRITE(只写)
或者 GENERIC_READ | GENERIC_WRITE 读写
dwShareMode 共享模式 主要是用于其它程序也使用这个对象时设置共享的方式。这里设置的是FILE_SHARE_READ。也就是其它进程仍然可以对这个设备进行读。
lpSecurityAttributes 标志默认就可以了。只要用于设置权限用的。很多API都用到这个。例如要实现关机,你就必须讲你当前进程的安全属性设置成允许关机的权限才可以实现关机。否则普通的用户层进程的安全权限是无法使用ExitWindows这个函数的。
dwCreationDisposition 创建方式,设置一些诸如文件不存在是创建还是返回错误等的一些方式而已。当然如果是创建设备的不存在刚才讲的这些问题。设置成OPEN_EXISTING 即可。就是如果驱动没有安装就返回失败。
其它两个默认即可,是些额外的属性和标志设置。对于创建文件,这里可以设置诸如只读等的额外属性或者标志等。和dwDesiredAccess的区别是dwDesiredAccess的权限是运行时的权限。而这里设置的是文件自身的权限。当然对设备来讲不需要这两个属性。传0即可

设备创建成功后,就要和 设备通讯了。和设备通讯(就是和驱动通讯)要用到DeviceIOControl (主要用于一些自定义的或者扩展的操作,一般性的读和写有专门的例程)在minicd.exe 里这个参数的调用是这样的

WCHAR outBuffer[501] = L"MF:\\DevelopeTool\\SQL2000SP4.ISO";
DWORD bufferSize = 0x3EA;

DeviceIoControl(
            device,
            0x22008,
            NULL,
            0,
            outBuffer,
            sizeof(outBuffer),
            &bufferSize,
NULL)

这个函数的原型 
BOOL DeviceIoControl(
HANDLE hDevice,    // 设备句柄,也就刚才CreateFile的返回值 
DWORD dwIoControlCode, // 控制码 驱动可以接收到
LPVOID lpInBuffer,   // 输入缓冲
DWORD nInBufferSize, // 输入缓冲大小
LPVOID lpOutBuffer, // 输出缓冲
DWORD nOutBufferSize, // 输出缓冲大小   
LPDWORD lpBytesReturned, // 这是一个返回值,返回驱动存储在输出缓冲里的数据的大小
LPOVERLAPPED lpOverlapped // 直接设null 保留用的吧
);
hDevice 注释里很明白了
dwIoControlCode 用户层发给驱动程序的指令码(发给IRP_MJ_DEVICE_CONTROL例程),可以自定义。驱动程序根据传过来的指令码,进行相应的操作。在minicd.exe 里这个指令码 是通过 移位和或操作得到的。其实就是CTL_CODE 宏。在这里就不用管那么多了,直接传 0x22008即可。
lpInBuffer lpOutBuffer 用于和驱动交换数据用的。这里只用到了lpOutBuffer. LpOutBuffer 指向的是一个LPVOID。你需要传的是一个UNICODE的字符串即可。字符串如下面的样子(前面已列出)
WCHAR outBuffer[501] = L"MF:\\DevelopeTool\\SQL2000SP4.ISO";
第一个字符M。是你求出来的目前可用的盘符。也就是你要映射的盘符。当然这个是要你自己去得出来的。不可能写死在这里,我只是测试用的而已。这方面的资料很多,你可以上网去查。紧跟后面的就是你要映射的ISO文件的全   路径 。 其实这样的输入应该放在lpInBuffer里,但这里放在了lpOutBuffer 感觉不是很爽。但不影响,因为,在驱动里无论是 inBuffer和outBuffer都是一视同仁的。都可以往这两上缓冲区里,写或者 读

如果这个执行成功后。光驱已经被虚拟出来了。

分析minicd.sys得知 在IRP_MJ_DEVICE_CONTROL例程里接收到的指令码是0x22008时。做的事情其实很简单。

1.使用IoCreateDevice 创建一个名为 minicd+盘符索引 的设备 例如 如果是M盘则 创建了个minicd12的设备 其中12 就是(M-A)的值。设备类型为 FILE_DEVICE_UNKNOWN 型的,一般虚拟设备都是这种类型

2.使用 IoCreateSymbolicLink 创建一个 符号 链接 和 这个设备关联起来 。 符号链接 的名字 为 你要创建的盘符名。

如要创建 M盘,则符号名为 M 。 当使用此函数时,符号名若为 A-Z 则系统会自动通知 资源管理器 创建相应的盘符。

当然 这个函数是在驱动层使用的。在用户层有一个 和他类似的函数,也可以实现同样的功能。就是

DefineDosDevice(
__in          DWORD dwFlags,
__in          LPCTSTR lpDeviceName,
__in          LPCTSTR lpTargetPath
);

其中第二个参数 就是 符号名 (如果符号为 A-Z 则同样的系统会自动通知资源管理器创建相应的盘符)

其中第三个参数 是设备名 
经过上面两步。就已经创建了 相应的 盘符,而且系统会将对于此盘符的所有操作指令(例如 读数据,写数据等等)全部发给 他所关联的设备。也就是前面讲的诸如minicd12 这样的设备。而发给设备其实就是发给创建设备的驱动(一个驱动可创建多个设备)。所以系统会把对于新创建的盘符的所有操作都发给由minicd.sys所对应的驱动对象。并准确分发到驱动的各个例程。因此,此时只要在minicd.sys的各例程中对所发过来的操作指令进行模拟。并按规定返回相应的数据即可实现虚拟了。例如。当对盘符进行双击查看等操作时,其实,系统会将此操作包装成一个IRP。并发送给 minicd.sys里的 IRP_MJ_READ 例程。这样你只须在这个例程里,分析 IRP 里的 指令,并对 ISO文件进行操作,并将得到的结果返回给操作系统就行了      

虽然到这里,虚拟的工作已经做完了。但要想正常工作还得使用   
BroadcastSystemMessage 向系统广播消息 
在minicd.exe 的实际调用是这样的 
DEV_BROADCAST_VOLUME minicd;
minicd.dbcv_size = 0x00000012;
minicd.dbcv_devicetype = 0x00000002;
minicd.dbcv_reserved = 0x00000001;
minicd.dbcv_unitmask = 0x00001000;
minicd.dbcv_flags = 0x0002;
PDEV_BROADCAST_VOLUME pminicd = &minicd;
BroadcastSystemMessage(
      BSF_IGNORECURRENTTASK, 
      BSM_ALLCOMPONENTS, 
       WM_DEVICECHANGE, 
       0x8000, //DBT_DEVICEARRIVAL
(LPARAM)pminicd);

这个函数的原型
long BroadcastSystemMessage(     

    DWORD dwFlags, // 标志值,用于设置一些广播方式
    LPDWORD lpdwRecipients, // 指定消息的接收者
    UINT uiMessage, // 消息号(消息类型)
    WPARAM wParam, // 扩展消息的信息
    LPARAM lParam // 一般根据wParam的不同传不同
);

这个函数其实没什么好讲的。和经常使用的SendMessage 等消息处理函数没什么区别。在这里只根据实际的参数作些说明。
在minicd.exe 里使用这个函时 
dwFlags 传的是 BSF_IGNORECURRENTTASK 就是消息不发给自己。
lpdwRecipients是 BSM_ALLCOMPONENTS 就是向所有的组件广播消息,主要是向 WINDOWS资源管理器广播了。
uiMessage是 WM_DEVICECHANGE 也就是讲消息类型是 设备改变 消息。这个消息是系统的内部消息。
WParam 是 0x8000 你也可以直接写DBT_DEVICEARRIVAL.不过要引用一下dbt.h头文件 就是设备已经到达的意思。
LParam 是一个 DEV_BROADCAST_VOLUME 类型的指针,DEV_BROADCAST_VOLUME 类型是对 DEV_BROADCAST_HDR的扩展。定义如下
typedef struct _DEV_BROADCAST_VOLUME {
DWORD dbcv_size;
DWORD dbcv_devicetype;
DWORD dbcv_reserved;
DWORD dbcv_unitmask;
WORD dbcv_flags;
} DEV_BROADCAST_VOLUME, 
*PDEV_BROADCAST_VOLUME;

DEV_BROADCAST_HDR 的定义如下
typedef struct _DEV_BROADCAST_HDR {
DWORD dbch_size;
DWORD dbch_devicetype;
DWORD dbch_reserved;
} DEV_BROADCAST_HDR, 
*PDEV_BROADCAST_HDR;

其中dbch_size 指示这个结构的大小。如果是用在扩展结构中,其实就是此结构大小加上扩展结构其它部分的大小之和,其实也就是扩展结构的大小了。如在这里 
DEV_BROADCAST_VOLUME minicd;
minicd.dbch_size = 0x00000012; 是 0x12 也就是18个字节。这明显是 DEV_BROADCAST_VOLUME 的大小。
dbch_devicetype 是指 设备类型 。使用的是什么扩展结构设备类型就是什么。在这里使用的是 DEV_BROADCAST_VOLUME 故而是 DBT_DEVTYP_VOLUME(0x2)
dbch_reserved 保留使用的。这里 设置 为 0x1

这是 DEV_BROADCAST_HDR 的结构介绍,所有的扩展其的结构的第一项必须是 DEV_BROADCAST_HDR 所以我们看 DEV_BROADCAST_VOLUME的定义的前三项和 DEV_BROADCAST_HDR 是一样的。只是名字不同而已。
下面再介绍一下。DEV_BROADCAST_VOLUME 扩展的两个属性。看 DEV_BROADCAST_VOLUME的第四项。
dbcv_unitmask 这一项很重要。具体的意思不好解释。应该类似于网络里的掩码。这是一个整型值。也就是说有32位。从右往左数。每一位都映射一个盘符。如果右边第一个位为0
的话,就是指A盘。依次类推,第二个就是B盘。
还记得这句话不
WCHAR outBuffer[501] = L"MF:\\DevelopeTool\\SQL2000SP4.ISO";
从前面介绍知道,我们要映射的盘符是M盘。那么自然应该是在 M减去A 的那个位上是1. 那么实际上也就是 1 << (M-A) 也就是 2 的 (M-A) 次幂。所以为了测试,当时并没有使用公式计算。只是硬写了一个 minicd.dbcv_unitmask = 0x00001000 进去。 很明显 0x1000 就是 2 的 (M-A)=12 次幂。 
最后一项 dbcv_flags 可以有两个选择
DBTF_MEDIA
0x0001
DBTF_NET
0x0002

这里选择 DBTF_NET 直接 写 0x0002 如果要写DBTF_NET 需要引用 dbt.h

好了。到了这里。看一下,是不是M盘已经被映射出来了。当然如果你的M盘已经被占用了。你就得换一个盘作测试用了。如果换盘的话。知道怎么换吧。前面讲的已经很清楚了。只须在DeviceIOControl的lpOutBuffer里的UNICODE字符串的第一个字符改成相应的盘符名就行了。当然还要记的是要把 BroadCastSystemMessage 的参数lParam DEV_BROADCAST_VOLUME 结构的 dbcv_unitmask 重新计算一下。否则映射会不成功的。
通过他们的对于实际传进去的参数的介绍。其实这个函SHU在这里的作用已经很明显了。就是向系统中除了自己以外的所有的程序啊,驱动啊,反正所有的对象广播一条消息。就是讲,有设备改变(WM_DEVICECHANGE)了,是什么改变呢。是设备已经到达(DBT_DEVICEARRIVAL)了.那么他的具体信息呢。就是 到达的是M盘,是DBT_NET网络型驱动器等(DEV_BROADCAST_VOLUME结构里的项)。这样WINDOWS资源管理器也会接到这样一个消息。他就会在我的电脑里建立一个驱动盘符了
好了。到这里,在驱动(minicd.sys)已经被安装和启动的情况下已经可以创建一个虚拟光驱了。
虽然有点成就感,但目前还有很多工作没有做。例如。如果是在一台新机子上,也没有运行MINICD.EXE 这样驱动不就没有安装也没有启动了。这样我们不就不可以和设备进行通讯。当然不用怕。后面,我们继续讲。怎么在没有驱动的情况下。动态安装和启动这个驱动(minicd.sys)。
除了安装和启动驱动,还有一个就是映射了怎么去除映射的问题也留在后面补吧。现在已经快一点了。最近得早点睡。工作要紧啊。要不然明天又没精力了。
 


http://www.ppmy.cn/news/376657.html

相关文章

光驱不见了

光驱不见了 有时候&#xff0c;我们会发现电脑里面的光驱图标不见了&#xff0c;会影响电脑的运行吗&#xff1f;光驱不见了怎么办&#xff1f;有什么解决办法吗&#xff1f; 硬件方面的原因   1、数据线接反或者数据线损坏  2、跳线设置与硬盘有冲突   当光驱的跳线和在同…

[转载]linux查看硬件信息及驱动设备相关整理

linux查看硬件信息及驱动设备相关整理 来源: ChinaUnix博客  日期&#xff1a; 2009.07.24 12:13 (共有条评论) 我要评论 在LINUX环境开发驱动程序&#xff0c;首先要探测到新硬件&#xff0c;接下来就是开发驱动程序。 常用命令整理如下&#xff1a; 用硬件检测程序kuduz探…

在桌面计算机找不到光盘驱动,驱动程序存放在Windows7系统光盘的哪 – 手机爱问...

2018-04-06 怎么安装驱动程序、声卡驱动程序 用软件也可安装声卡驱动。安装声卡驱动的方法&#xff1a;(一)右击“我的电脑”/“属性”/“硬件”/“设备管理器”&#xff0c;展开“声音、视频和游戏控制器”&#xff0c;看前面有没有黄色的“&#xff1f;”号&#xff0c;有&am…

win8/8.1改win7原版系统全部教程之先把驱动精灵万能网卡版存到U盘(2)

驱动精灵万能网卡版 分步阅读 Windows操作系统安装好之后&#xff0c;一般是不能上网的&#xff0c;原因是操作系统并没有集成所有的网卡设备的驱动程序。如果是品牌机&#xff0c;那么购机时附带的驱动程序光盘&#xff0c;那就是最合适的设备驱动程序。但现在很多笔记本电脑因…

usb万能驱动win7_8代能不能装win7?测给你看

店铺经常接到客人的咨询&#xff0c;问游戏本能不能装好win7再发货 这里统一回答一下 能&#xff0c;但是别装 首先&#xff0c;先从理论上解释一下&#xff0c;再用一台GL63给大家做一个测试 USB 从6代酷睿开始&#xff0c;Intel更改了USB控制器&#xff0c;Skylake相比前期的…

2012 r2 万能网卡驱动_老旧台式机也可升级WiFi6和蓝牙5.1,仅安装百元网卡即可...

大部分的家用电脑都会选择台式机&#xff0c;最主要是台式机无论是价格还是性能&#xff0c;都要优于同配置的笔记本。现在主流的主板都会内置无线网卡模块&#xff0c;但是对于游戏用户来说&#xff0c;还是比较喜欢通过网线连接&#xff0c;最主要的原因还是部分无线网卡信号…

宝鸡陇县中学弱电系统集成设计方案_kaic

摘 要 随着世界各国教育信息化的推进&#xff0c;我国在教育信息基础设施和资源上也在逐步加快步伐。校园信息化平台的建设关系到校园网站的技术实现、广播系统、视频监控系统的建设&#xff0c;能够使知识获取更便捷、校园文化生活更丰富、校园管理更精准。利用信息交互的特性…

制作万能光驱中文启动盘

笔者最近在一些报刊上看了几篇关于制作中文启动盘的文章以后&#xff0c;就亲自动手做了一张中文启动盘&#xff0c;刚开始时确实成功了&#xff0c;能在用软盘启动后的DOS中使用中文平台&#xff0c;效果不错&#xff0c;但是在我将操作系统升级到Windows XP以后中文启动盘失灵…