65.9K
CodeProject 正在变化。 阅读更多。
Home

查看:在 Windows 7 中挂载 Azure 博客驱动器。

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2012 年 11 月 2 日

CPOL

11分钟阅读

viewsIcon

29850

downloadIcon

124

本文将教您了解其中发生的情况。并利用它。

引言

本文的重点不是如何让云驱动器在 Windows 7 上运行。

本文将教您了解其中发生的情况。并利用它。

这比依赖稀疏、过时或不存在的文档要好得多。

本文不是关于我使用的所有工具的逐步教程。这将毫无意义,可以在其网站上找到文档,当您理解了您想要的内容后,UI 会不言自明。

您也不需要了解 Azure。实际上,本文的目的并不重要。旅程才是重头戏。

但这是我的目标:我想在 Windows 7 上创建一个由 Azure 支持的新驱动器。

代码可以在 MSDN 上找到,所以我尝试在我的 Windows 7 机器上运行它。

您说:ERROR_UNSUPPORTED_OS

Google 上快速搜索 告诉我,我不能在 Azure 外部使用博客驱动器……

真可惜……但这并不是我的最后一句话!今天就决定了!今天我要战斗!

如何破解它

使用 ILSpy 深入挖掘 CloudDrive.Create,我找到了一个名为 mswacdmi.dll 的 DLL 中的方法。

这个程序集是 C++/CLI 的,有些部分是原生的,有些是托管的,而我在这里卡在一个非托管的部分……

这个 DLL 是 x64 的……我的 IDA Pro 免费版不支持 x64,ollydbg 也不支持,所以我无法深入研究。

但宝贵的信息可以来自代码以外的其他来源。代码逆向工程应该是最后的手段。

伟大的 Mark Russinovich 说:“如有疑问……运行 ProcMon”……所以我就这样做了,以了解底层的文件和注册表访问情况。

好的,似乎它正在查找注册表相关的内容。

此外,创建新驱动器是内核操作,所以我怀疑 mswacdmi.dll 模块会尝试启动一个驱动程序,或者与之通信。

所以我使用 API Monitor 来查看程序中发生的 WIN API 调用过滤器。

我决定跟踪所有与文件操作相关的 API,因为这是用户空间与驱动程序的通信方式(WriteFile, ReadFile, CreateFile, DeviceIOControl),以及与服务相关的 WIN API,例如 OpenSCManagerOpenService。(对于不知道的人来说,驱动程序由服务控制管理器启动

我再次运行我的代码,这是结果。


好的,所以我的计算机上缺少 CloudDrive 服务。

为了解更多关于此服务的信息,我创建一个新的 Azure 角色并部署它,并启用远程桌面。

我连接到该角色。

然后,快速运行 `sc qc CloudDrive` 表明该服务存在于 **Azure** 中,但它不像我想象的那样是一个驱动程序。(类型应为 KERNEL_DRIVER

我还转储了 procmon 之前告诉我的丢失的注册表。

Azure.reg

这让我想起 Microsoft 允许您从自己创建的映像创建 VM 角色,因此您可以横向扩展任何您想要的服务器或服务。

快速搜索互联网告知我,此类映像应安装 VM 角色集成组件,以便实例能够与 Azure 通信。

该安装程序位于 Azure SDK 中。“C:\Program Files\Microsoft SDKs\Windows Azure\.NET SDK\2012-06\iso\wavmroleic.iso”。

所以我启动了一个新的 **Azure VM**,并安装了它。(Azure VM 与我之前使用的 VM 角色不同!Azure VM 就是我们所熟知的普通 VM,VM 不会被像 VM 角色中的实例那样销毁,但它无法扩展。)

不幸的是,我的 VM 永远不会重启!

沮丧之下,我在我自己的服务器上用 Hyper-V 设置了一个新的 VM,并安装了 **Azure 集成组件**。

然后我检查了服务是否已安装。

我检查了注册表,并转储了之前丢失的注册表。

Integration.reg


我再次运行我的程序,结果……它成功了!我创建了一个由我的博客存储支持的新驱动器。现在我可以使用普通的 System.IO API 或使用 **Explorer** 在云端写入了!!

一切都很好,但我对结果并不满意。

现在我想把它安装在我的 **Windows 7** 上。此外,用 InstEd 快速查看 MSI 文件,向我展示了它在 VM 上安装的所有东西……其中大部分与 Azure 驱动器功能无关,只是 Azure 基础设施。这些额外的东西可能是导致我的 Azure VM 永远不会重启的原因。(可能是因为 **Azure 集成组件**只应由 **VM 角色**使用,而不是由 **Azure VM** 使用)

解决方案是移除所有与 **Azure Cloud Drive** 无关的功能。为此,MSI 文件原生支持 **转换文件**。**转换文件**将在安装开始前在内存中对 MSI 文件应用转换。

**InstEd** 使创建它变得轻而易举。

“**功能**”选项卡向您展示了 **WADrive** 功能将安装什么。当然,您可以识别出每一个组件。

**CloudDriveSvc.exe**,Cloud Drive 功能的用户端部分。
**WADrive_wadrive.sys**,该功能的核心部分。

**mswacdmi.dll**,用户代码中与该驱动程序交互的 C/C++ 接口。

**CloudDrive 和 StorageClient** 程序集,这是操作 CloudDrive 的高级 .NET API。

只需右键单击并删除另外两个功能。

要在 Windows 7 上安装这些东西,您需要移除 **LaunchCondition** 表中的启动条件。

保存您的转换。(.mst 文件)

然后运行 **msiexec** 并传入 msi 和转换文件。

很酷!!!

很高兴,我以为战斗结束了,但我错了,这仅仅是开始!!


我在 Windows 7 上运行安装,但我的 CSharp 程序只是挂起。

用 `sc query` 快速检查显示 **CloudDrive** 服务未启动并返回错误。

我用 API Monitor 监视我的应用程序。似乎它正在尝试与一个不存在的命名管道通信。


在我的 VM Windows Server 2008 R2 上用 Procexp 进行快速句柄搜索,表明这个命名管道已打开,并且可能由 CloudDrive 创建。

换句话说,在我的 Windows 7 盒子上,Cloud drive 的用户端部分 **CloudDriveSvc.exe** 无法启动。但是 CloudDrive 的 .NET API 直接与它通信……如果核心部分没有运行,事情就会变得困难,因为我需要使用 **windbg** 内核驱动程序,那将是另一回事……在内核模式下,您可以忘记我们用来监视的所有漂亮的工具。您的双手将变得非常脏。

所以我使用了 OSR 的 Driver Loader 来查看驱动程序是否正在运行。(我也可以使用 `sc query`)

好消息,驱动程序在我的 Windows 7 盒子上运行。

为了确保我没有从 MSI 中剥离太多东西,我运行了一个新的 VM,并创建了一个转换,而不删除功能,但我删除了启动条件……结果是一样的。

好了,现在让我们深入了解 **CloudDriveSvc.exe**,看看它为什么在 Win7 上无法启动。

为了查看问题出在哪里,我将在 Windows 2008 和 Windows 7 上启动 **CloudDriveSvc.exe**(使用 **sc start CloudDrive**),然后比较 **Procmon 跟踪**。

所以我停止了 Windows 2008 上的 **CloudService**,在两台机器上运行 Procmon,**sc start CloudDrive**,并保存跟踪。

我将它们都保存为 PML 文件(原生的 Process Monitor 文件,稍后在 Process Monitor 的另一个实例中打开),以及 XML 文件。(也许我需要运行一些代码来分析更复杂的东西)
这是 Windows 7 跟踪,这是 Windows 2008 R2 跟踪。


然后我并排打开两个跟踪,并尝试同步它们以查看执行路径在哪里发生分歧。


然后我找到了第一次分歧……(左边是 Windows 2008,右边是 Windows 7)

这是什么键?我转到注册表,看到它是一个 COM 组件,实现位于 **vss_ps.dll** 中。快速检查表明它是 卷影复制服务。它允许您备份即使被其他进程锁定的文件。

现在我知道了敌人是谁,我运行 **API Monitor**,过滤该 COM 组件的调用,并开始监视 **CloudDriveSvc**。

您可以要求 **API Monitor** 防止新程序启动,这样您就有时间附加到它,然后再让它关闭。我就是这样做的。

这是 Win7 盒子的结果……此调用失败。


在 Windows 2008 盒子上。

这是所有参数,在两台机器上都相同。

MSDN 上搜索 E_INVALIDARG 错误,我得到了

好吧,这解释了 MSI 中的启动条件……Smile | <img src= " src="https://codeproject.org.cn/script/Forums/Images/smiley_smile.gif" />

但事实是我不在乎卷影复制功能……所以,如果我能以某种方式将参数 VSS_PROV_HARDWARE (0x3) 修改为 VSS_PROV_SOFTWARE (0x2)。它应该能通过这个调用。

通过堆栈跟踪,我可以看到 RegisterProvider 是直接由 **CloudDriveSvc** 调用。

并且我知道调用将返回到 **RVA** **0xE3BC**。(偏移量列)

如果我打开一个反汇编器,在地址之前一点,我应该看到将参数压栈的指令,以及一个 x64 调用指令。

我能否修改 **CloudServiceSvc.exe** 并更改参数?当然可以。

所以我运行了很棒的 CFF Explorer!(一个小的 DLL 文件查看器、反汇编器和十六进制编辑器)

问题在于,**API Monitor** 中称为**偏移量**的东西实际上是**RVA**,即相对于拥有该函数的模块**基地址**的**相对虚拟内存**地址。

另一方面,对于 **CFF Explorer** 来说,**偏移量**是**文件偏移量**,即当一个字节或指令**在磁盘上**时的**位置**。

DLL 被分成多个节。这些节在**虚拟内存**(**虚拟地址或 RVA**)中的位置与其在**磁盘驱动器**(**原始地址或文件偏移量**)中的位置不同。

代码节是 **.text**(这是一个约定)。此外,您可以看到该节的 **RVA** 是 **0x1000**,其虚拟大小为 **25F06**。

正如您所见,我之前从 **API Monitor** 获得的 RegisterProvider 的**返回 RVA** 是 **E3BC**,所以它位于 **.text** 节中。

这是 **CloudDriveSvc.exe** 在进程的**虚拟内存**中映射的方式。

这是将 **RVA** 转换为**文件偏移量**的计算方法。

E3BC (RVA) - 1000 (rva of .text section) = D3BC (.text section 的相对地址)

D3BC + 400 (.text section 的文件偏移量) = D7BC (文件偏移量)

所以,换句话说,这是 **CloudDriveSvc.exe** 在**驱动器上**时的样子。

我用 CFF Explorer 的反汇编器跳转到**文件偏移量**,并往前移一点以查看参数如何压栈。

我在 **D7AB** 处停止。(不要理会“Base Address”文本框和 Address 列,您在这里选择的任何内容都不会改变结果,这只是一个可视化功能)


您可以看到值 **0x3** 被移入堆栈。所以我只需要将这个 **0x3**(VSS_PROV_HARDWARE)更改为 **0x2**(VSS_PROV_SOFTWARE)。

0x03 的地址是 **D7AB + 4 = D7AF**

保存您的修改,并覆盖 **CloudDriveSvc.exe**。

重启服务。

如果您监视 **CloudDriveSvc.exe**,您可以看到它确实现在使用了 VSS_PROV_SOFTWARE

我再次运行我的程序。


我焦急地等待……一分钟后,我的程序正常关闭,没有崩溃,我有了由 Azure VHD 支持的新驱动器!!!Smile | <img src= " src="https://codeproject.org.cn/script/Forums/Images/smiley_smile.gif" />

结论

最后,您可以通过**仅更改 CloudDriveSvc.exe 中的一个比特**来支持 **Windows 7 中的 Azure 驱动器**。

这让我想起我读过的一个故事

一家公司要求承包商修复一个停止工作的关键大型机。
承包商来了,打开了大型机,挠了挠头,更换了一个螺丝,关上了大型机,然后大型机就复活了。

-好的,这花费您 10,000 美元。
-仅仅换一个螺丝就这么贵吗?您能给我一份详细的发票吗?
-当然,螺丝成本:1 美元,运输费:10 美元……以及知道该换哪个螺丝的知识:9989 美元。

结果很棒,但不如旅程有趣。(说实话,我知道它奏效后就把 Azure 驱动器移除了)

希望您也喜欢。但最重要的是,要非常感谢这些工具的创造者。没有他们,这样的事情是不可能的。

谢谢


© . All rights reserved.