Let's see : Attach an Azure blob drive in windows 7.





5.00/5 (2 votes)
This article will teach you how to see what is going on inside. And take advantage from it.
Introduction
This main point of this article is not about how to make cloud drive works on Windows 7.
This article will teach you how to see what is going on inside. And take advantage from it.
It is even better than relying on sparse, outdated or non-existant documentation.
This article is not a step by step tutorial of every tools I use. This would be useless, documentation can be found on their website, and when you understand what you want to, the UI is self descriptive.
You also don't need to be knowledgeable about Azure. In fact the destination of this article is not important. The trip is the big deal.
But here is my goal : I want to create a new drive backed by Azure on Windows 7.
The code can be found on MSDN, so I tried to run it on my windows 7 machine.
ERROR_UNSUPPORTED_OS you say ?
A quick search on Google tells me that I can't use a blob drive outside Azure...
What a shame... But this is not my last word ! Today it is decided ! Today I'm gonna fight !
How to hack your way through it
Digging deep inside CloudDrive.Create
with ILSpy
led me to this method
in a dll called mswacdmi.dll.
This assembly is a C++/CLI one, some parts are native, other managed, and here I'm stuck at an unmanaged one...
This dll is in x64... my free edition of IDA Pro does not support x64, ollydbg also does not support it, so I can't dig deeper.
But precious information can come from other sources than code. Code reverse engineering should be used at the last resort.
"When in doubt... run ProcMon" the great Mark Russinovich said... So that's what I did to see what file and registry access was going on under the hood.
Ok it seems to be looking for registry stuff.
Moreover, creating a new drive is a kernel stuff, so I suspect that somehow, this mswacdmi.dll module should try to start a driver, or communicate with it.
So I use API monitor to see filter WIN API calls happening in my program.
I decide to trace all file operation related API because that's how userland communicate
with a driver (WriteFile, ReadFile, CreateFile, DeviceIOControl
) as
well as WIN
API relating to services like OpenSCManager
and OpenService
.
(for those who do not
know,
drivers are started by the Service Control Manager)
I run again my code, and here is the result.

Ok, so the CloudDrive service is missing on my computer.
To know more about this service, I create and deploy a new Azure role with remote desktop enabled.
I connect to the role.
Then a quick sc qc CloudDrive show that the service exists in Azure,
but it is not a driver
as I thought.
(The type would be KERNEL_DRIVER
)
I also dump the missing registry that procmon told be earlier.
This remind me that Microsoft permit you to create a VM Role from an image created by yourself, so you can scale out any server or service you want.
A quick search on internet inform me that such image should have VM role integration components installed, so instances will be able to communicate with Azure.
This installer is in the Azure SDK. "C:\Program Files\Microsoft SDKs\Windows Azure\.NET SDK\2012-06\iso\wavmroleic.iso".
So I start a new Azure VM, and install it. (A Azure VM is different from the VM role I did previously ! An Azure VM is a plain old VM as we know it, the VM is never trashed unlike instances in VM roles, but it can't scale.)
Unfortunately, my VM never reboot !
Frustrated, I set up a new VM hosted in my own server with Hyper-V and install azure integration components.
Then I check that the service is installed.
I check the registry, and take a dump of the registry that was missing.
I run my program aaand... it works !! I create a new drive backed by my blob storage.
Now I can use normal System.IO
API or use explorer
to write on the cloud !!
All is good, but I was not satisfied with the result.
Now I want to install it on my windows 7. Moreover a quick look at the msi with InstEd, show me all the stuff it installed on my VM... most of this stuff is not related with the azure drive feature, and is just azure infrastructure. This extra stuff is maybe the reason why my Azure VM never reboot. (Probably because the Azure Integration Components should only be used by VM roles, and not by Azure VM)
The solution is to remove all features not related with Azure Cloud Drive from the install. For that, msi files have native support for transform files. A transform file will apply a transformation on the msi file in memory just before starting the installation.
InstEd makes it dead easy to create one.
The Features tab show you what the Features WADrive will install. And surely enough, you can recognize every single components.
CloudDriveSvc.exe, the userland part of the Cloud drive feature.
WADrive_wadrive.sys
the kernel part of the feature.
mswacdmi.dll the C/C++ interface in user code that interact with this driver.
CloudDrive and StorageClient assemblies that are the high level
.NET API to manipulate CloudDrive
.
Just right click and delete the two other features.
To install this stuff on windows 7 you need to remove launch conditions in the LaunchCondition table.
Save your transformation. (mst file)
Then run msiexec and pass the msi and the transform file.
Cool !!!
Happy from myself, I thought the battle was over, but I was wrong that's only the beginning !!
I run the install on my Windows 7 but my CSharp program is just hanging.
A quick check with sc query show that the CloudDrive service is not started and returned an error.
I spy my application with API monitor. It seems that it is trying to communicate with a named pipe that does not exist.
A quick handle search with procexp on my VM Windows server 2008 R2, show me that this named pipe is opened, and probably created by CloudDrive.
In other words, on my windows 7 box, CloudDriveSvc.exe, the user
land part of cloud
drive, can't start. But the .NET API of CloudDrive
communicates
directly with it...
If the kernel part is not running, things will get hard because I will need
to use
windbg on a kernel driver, and that would be a different
story... In kernel mode,
you can forget all the nice tool we used to spy. Your hands would become
really
dirty.
So I used Driver Loader from OSR to see if the driver is running. (I could also use sc query)
Good news, the driver is running on my windows 7 box.
Just to be sure I did not stripped too much stuff from the MSI, I run a new VM, and create a transform without deleting features, but I remove launch conditions... The result is the same.
Ok so now, let's dive in CloudDriveSvc.exe to see why it can't start on win7.
To see where thing break, I will start CloudDriveSvc.exe (with sc start CloudDrive) on Windows 2008 and Windows 7 and then compare the procmon traces.
So I stop CloudService on windows 2008, run procmon on both machine, sc start CloudDrive, and save the traces.
I save in both, PML file (native process monitor file, to open in in another instance
of procmon later), and in XML file. (Maybe I will need to run some code on the trace
to analyze more complicated stuff)
Here is the Windows 7 trace, and here the Windows 2008 R2 one.
Then I open side by side both traces, and try to sync them to see where the execution path diverges.
And then I find the first divergence... (Left is Windows 2008, right is Windows 7)
What is this key ? I go to the registry and see that it is a COM component, and the implementation is in vss_ps.dll . A quick check tell me that it is the Volume Shadow Copy Service. It allows you to backup files even if they are locked by other processes.
Now I know who is the enemy, I run API Monitor, filter call for this COM component, and start spying CloudDriveSvc.
You can ask API Monitor to prevent new programs from starting so you have time to attach to it before it closes. That's what I did.
Here is the result on win7 box... this call is failing.
On the windows 2008 box.
And here are all the parameters, same on both machine.
A search on the E_INVALIDARG error on MSDN tells me :
Ok that explained the launch condition in the MSI... " src="http://www.codeproject.com/script/Forums/Images/smiley_smile.gif" />
But the truth is that I don't care about the volume shadow copy feature... so,
if somehow I can modify the parameter VSS_PROV_HARDWARE (0x3)
to be VSS_PROV_SOFTWARE
(0x2)
. It should pass this call.
With the stack trace, I can see that RegisterProvider
is called directly
by
CloudDriveSvc.
And I know that the call will return to the RVA 0xE3BC. (offset column)
If I open a disassembler a little bit before this address, I should see instructions that push parameters on the stack, and a call x64 instruction.
Can I modify CloudServiceSvc.exe and change parameters ? Definitively.
So I run the great CFF explorer ! (a small dll file viewer, disassembler and hex editor)
The problem is that what is called offset in API monitor is in reality a RVA, ie, the Relative Virtual Memory address relative to the base address of the module that own the function.
On the other hand, for CFF explorer, an offset is a file offset, ie the position of a byte or instruction when it sit on the disk.
A dll is divided in multiple section. The position of these section is different in virtual memory (Virtual Address, or RVA) than on the disk drive (Raw Address, or file offset).
The code section is .text (it is a convention). Moreover, you can see that the RVA of this section is 0x1000, and its virtual size 25F06.
The return RVA of RegisterProvider
that I got earlier with
API Monitor
is E3BC, so, as you can see, it sits in the .text
section.
Here is how CloudDriveSvc.exe is mapped in the process's virtual memory.
Here is the math to convert an RVA to a file offset.
E3BC (RVA) - 1000 (RVA of .text section) = D3BC (Relative address to the .text section)
D3BC + 400 (File offset of .text section) = D7BC (File Offset)
So in other word, here is CloudDriveSvc.exe when it is sitting on the drive.
I jump to the file offset with the disassembler from CFF explorer, and move a little bit before to see how the parameters are stacked.
I stop at D7AB. (Do not pay attention to "Base Address" textbox and to the Address column, whatever you choose here will not change the result, it is just a visualization feature)
You can see the value 0x3 is moved into the stack. So I just need
to change this
0x3 (VSS_PROV_HARDWARE
) with 0x2
(VSS_PROV_SOFTWARE
).
The address of 0x03 is D7AB + 4 = D7AF
Save your modification, and overwrite CloudDriveSvc.exe.
Restart the service.
If you spy CloudDriveSvc.exe, you can see that it effectively use
VSS_PROV_SOFTWARE
now.
I run again my program.
I wait, very anxious... and 1 min later, my program close without any crash and
I have
my new drive backed by a Azure VHD !!! " src="http://www.codeproject.com/script/Forums/Images/smiley_smile.gif" />
Conclusion
Finally, you can support azure drive in windows 7 just by changing just one bit in CloudDriveSvc.exe.
It reminds me a tale I read somewhere :
A company asks for a contractor to fix
this important mainframe that stopped to work.
The contractor comes, opens
the mainframe,
scratches his head, changes one screw, closes the mainframe, then the mainframe
comes
back from the dead.
-Ok, it cost you 10 000$.
-Isn't it expensive just for one screw ? Can you give me the detail of your invoice
?
-Sure, the screw costs : 1$, transport fees : 10$... and the knowledge for which
screw to change : 9989$
The result is cool but less interesting than the trip. (Truth to be told, I removed the Azure drive once I knew it worked)
I hope you enjoyed it as well. But most importantly, be very grateful to the creators of these tools. Without them, such thing would be impossible.
Thanks
- To Rohitab for API Monitor.
- To Mark Russinovich for Process Monitor (procmon) and Process Explorer (procexp).
- To Daniel Pistelli for CFF Explorer.
- To InstEdit for InstEd, the MSI tool.
- To OSR for the driver loader. (And the device tree, I did not used in this article)