{"id":2310,"date":"2015-07-07T19:53:29","date_gmt":"2015-07-07T23:53:29","guid":{"rendered":"https:\/\/www.tmurgent.com\/TmBlog\/?p=2310"},"modified":"2015-07-08T11:43:10","modified_gmt":"2015-07-08T15:43:10","slug":"the-app-v-virtual-device-driver-really","status":"publish","type":"post","link":"https:\/\/www.tmurgent.com\/TmBlog\/?p=2310","title":{"rendered":"The App-V Virtual Device Driver: Really!!!!"},"content":{"rendered":"<p>I&#8217;m not sure why I never thought of this before.\u00a0 All of the pieces were right there in front of me for a while, but it didn&#8217;t click until today.<\/p>\n<p><span style=\"color: #339966;\"><strong>Today I created my first Virtual Device Driver with App-V!!!!<\/strong><\/span><\/p>\n<p>OK.\u00a0 Time for the fine print:<\/p>\n<p><span style=\"font-size: xx-small; color: #d0d0d0;\">The driver isn&#8217;t really virtualized, I just make it only exist when it needs to and then goes away so that other software doesn&#8217;t know that it is there.<\/span><\/p>\n<h2>Background<\/h2>\n<p>So how does this work?<\/p>\n<p>First, you need an app that has a device driver associated with it that you can virtualize if you deploy the driver separately.<\/p>\n<p>But what is a driver?\u00a0 A specialized piece of software that runs inside the kernel.\u00a0 Typically delivered as a &#8220;.sys&#8221; file, it sometimes is also delivered with an inf file that explains how to install it.\u00a0 We can&#8217;t virtualize stuff running inside the kernel with App-V, but we can virtualize the control, which is what I will demonstrate in this blog post.<\/p>\n<p>You see, most of the drivers associated with a user mode app that you want to virtualize can actually be started and stopped at will.\u00a0 Drivers that can&#8217;t be started and stopped at will are things that are always processing stuff, but if your virtual app isn&#8217;t running then it isn&#8217;t processing stuff and no other app is going to trigger it to do work either,\u00a0then maybe we can start\/stop it at will.<\/p>\n<p>In fact, it probably is due to the stupidity of MSI that we don&#8217;t consider this.\u00a0 Packers never actually see the thing that does a driver install. Additionally, MSI generally will install or uninstall a driver, but starting\/stopping it is unusual.<\/p>\n<p>And this confuses a lot of IT experts.\u00a0 For example, if you read up on IT Ninja on the app used in this blog (Wireshark and the WinPCap driver), you&#8217;ll see a bunch of experts explain that after you install the driver, you <em><strong>must<\/strong><\/em> reboot before you can run Wireshark.<\/p>\n<p>Bullocks I say!\u00a0 You just have to start the driver first.\u00a0 Rebooting is the lazy man&#8217;s way of starting the driver. OK.<\/p>\n<p>So a bit about both drivers and windows services.\u00a0 Ultimatly, both store registration information in the same place &#8212; the <em>HKLM\\System\\CurrentControlSet\\Services<\/em> key.\u00a0 Both drivers and services use a key under this location with the name of the driver or service to store their parameters.\u00a0 In fact, drivers are just a special case of services as far as windows is concerned.<\/p>\n<p>Both may be created, controlled, and removed using the sc.exe utility.\u00a0 It&#8217;s just that drivers run in the kernel (as a kernel thread of the System process (processed 4, or 8 on DataCenter), and services run either as a user mode thread in one of the svchost processes (when delivered as a dll), or as a separate process (when delivered as an exe).<\/p>\n<p>[Side note: Why are there a bunch of svchost processes?\u00a0 Because each houses services that run under the same security context; one for Local System, one for Network System, etc.]<\/p>\n<h2><strong>Part 1: Creating a\u00a0Silent Driver Installer\/Controller\u00a0for our package!<\/strong><\/h2>\n<p>We want to use App-V 5 to virtualize Wireshark and dynamically deliver the WinPCap driver.<\/p>\n<p>In the past, we might have natively installed WinPCap, and then virtualized Wireshark.\u00a0 But maybe you consider a driver with an open interface so that another program can snoop in on all of the TCP\/IP traffic on the PC a security issue so you only want it enabled when it really has to be.\u00a0 I think we got you covered here.<\/p>\n<p>With some applications there is a nice separate device driver installer, but in others you must create your own. WinPCap is a separate install driver, but unfortunately one of the annoying things about the WinPCap installer is that is does not have a silent install option.\u00a0 Apparently, once upon a time it did but the developers got annoyed with third party products silently dropping it on peoples systems without telling them, so they removed it.\u00a0 It is an exe based installer without the typical &#8220;\/s&#8221; option.\u00a0 So we&#8217;ll have to create our own.\u00a0 This turns out to be easier than expected!<\/p>\n<p>To investigate WinPCap, I use the sequencer.\u00a0 For simplicity, we are only looking at the 32-bit case. I start the sequencer, enter monitoring mode, install WinPCap, and work my way to the Sequence Editor to review all of the file and registry changes made. When there, I discover that the installer pretty much does the following:<\/p>\n<ul>\n<\/ul>\n<ul>\n<li>Drops 3 dlls into the System32 folder.<\/li>\n<li>Drops the driver file into the System32\/drivers folder.<\/li>\n<li>Drops two exe files into Program Files\/WinPCap folder.\u00a0 One of those is an uninstaller that we do not need.<\/li>\n<li>It creates the driver, as can be\u00a0evidenced\u00a0under the HKLM\\System\\CurrentControlSet\\services\\NPF key.<\/li>\n<li>It creates a windows service, the evidence for which\u00a0we can see in HKLM\\System\\CurrentControlSet\\Services\\rpcapd key.\u00a0 From the entries, I can see that this is a manual start service that is the exe file I noticed earlier.<\/li>\n<\/ul>\n<p>I investigate the three dll files to see if they require COM registration, by attempting a manual regsvr32.exe on them.\u00a0 I find that they are not COM.\u00a0 So if I want to build my own script based installer, I just need to copy them in place.\u00a0 Nice.<\/p>\n<p>I gather the three dlls, the sys file, and the important exe.\u00a0 I start to create a powershell script that can do the install. The first step of the script will be to copy the dlls, the sys driver, and the required \u00a0exe into the locations that the real installer used.\u00a0 To make it easy for us later on, the PowerShell script is written to take an argument that supplies the location of the source files, which I&#8217;ll make available in a single folder as part of the package.<\/p>\n<p>You might hope that just copying the registry entries for the driver and services would be sufficient, but it is not.\u00a0 To install these you need to use a special system executable called &#8220;sc&#8221;, which will generate those keys and do some other undocumented magic. But using the information from those registry keys, I can come up with the command lines to install both the driver and the service. The captured entry for the windows service was:<\/p>\n<pre>HKLM\\System\\CurrentControlSet\\System\\npf\\\r\n    DisplayName    REG_SZ        NetGroup Packet Filter Driver\r\n    ErrorControl   REG_DWORD     0x00000001\r\n    ImagePath      REG_EXPAND_SZ \\\\?\\C:\\Windows\\System32\\drivers\\npf.sys\r\n    Start          REG_DWORD     0x00000002\r\n    TimestampMode  REG_DWORD     0x00000000\r\n    Type           REG_DWORD     0x00000001<\/pre>\n<p>The appropriate install command for the driver is thus:<\/p>\n<pre>sc.exe create npf binPath= \"C:\\Windows\\System32\\drivers\\npf.sys\" type= kernel start= auto error= normal tag= no DisplayName= \"NetGroup Packet Filter Driver\"<\/pre>\n<p>NOTES:<\/p>\n<ol>\n<li>sc.exe is part of the OS and is in the PATH variable so it is automatically found without path reference.<\/li>\n<li>The options are always the option name immediately followed by the equal sign, and then a space, and then the value for the option.\u00a0 No space before the =, must have one after.\u00a0 If the value has a space in it, you must enclose the value in quotation marks.<\/li>\n<li>type &#8220;sc.exe \/?&#8221; for more details on the command.<\/li>\n<\/ol>\n<p>The captured entry for the windows service was:<\/p>\n<pre>HKLM\\System\\CurrentControlSet\\System\\rpcapd\\\r\n    DisplayName        REG_SZ        Remote Package Capture Protocol...\r\n    ErrorControl       REG_DWORD     0x00000001\r\n    ImagePath          REG_EXPAND_SZ C:\\Program Files\\WinPcap\\rpcapd.exe\r\n    ObjectName         REG_SZ        LocalSystem\r\n    Start              REG_DWORD     0x00000003\r\n    Type               REG_DWORD     0x00000010<\/pre>\n<p>The appropriate install command for the service is thus:<\/p>\n<pre>sc.exe create rpcapd type= own start= demand binPath= \"C:\\Program Files\\WinPCap\\rpcad.exe\" DisplayName= \"Remote Package Capture Protocol...\"<\/pre>\n<p>Furthermore, in testing I find that the driver is stoppable The developer declares this in his code when he\/she writes the driver and when the driver starts up this information is given to the services controller. Once the driver is loaded you can use sc.exe with the queryex option to see if it is pause-able and\/or stoppable.<\/p>\n<p>The command to start the driver is:<\/p>\n<pre>sc.exe start npf<\/pre>\n<p>And the command to stop it is<\/p>\n<pre>sc.exe stop npf<\/pre>\n<p>So I can now make both an install and an uninstall PowerShell scripts. Here is the installer:<\/p>\n<pre>[CmdletBinding()]\r\nparam( [parameter(Mandatory=$true)][string]$SourceDir )\r\n\r\ncopy $SourceDir\\wpcap.dll C:\\Windows\\System32\\wpcap.dll\r\ncopy $SourceDir\\pthreadVC.dll C:\\Windows\\System32\\pthreadVC.dll\r\ncopy $SourceDir\\Packet.dll C:\\Windows\\System32\\Packet.dll\r\ncopy $SourceDir\\npf.sys C:\\Windows\\System32\\drivers\\npf.sys\r\ncopy $SourceDIr\\rpcapd.exe \"C:\\Program Files\\WinPCap\\rpcapd.exe\"\r\n\r\nsc.exe create rpcapd type= own start= demand binPath= \"C:\\Program Files\\WinPCap\\rpcad.exe\" DisplayName= \"Remote Package Capture Protocol...\"\r\nsc.exe create npf binPath= \"C:\\Windows\\System32\\drivers\\npf.sys\" type= kernel start= auto error= normal tag= no DisplayName= \"NetGroup Packet Filter Driver\"\r\nsc.exe start npf\r\n\r\nexit 0<\/pre>\n<p>And here is the uninstall:<\/p>\n<pre>[CmdletBinding()]\r\nparam( [parameter(Mandatory=$true)][string]$SourceDir )\r\n\r\nsc.exe stop npf\r\nsc.exe delete npf \r\nsc.exe delete rpcapd \r\n\r\nrm C:\\Windows\\System32\\wpcap.dll\r\nrm C:\\Windows\\System32\\pthreadVC.dll\r\nrm C:\\Windows\\System32\\Packet.dll\r\nrm C:\\Windows\\System32\\drivers\\npf.sys\r\nrm \"C:\\Program Files\\WinPCap\\rpcapd.exe\"\r\n\r\nexit 0<\/pre>\n<p>This kind-of takes me back to my SoftwareWow days!<\/p>\n<p>I place these two PowerShell script files (.ps1 files) and the 5 executable files into a folder for safe keeping on a separate machine, and move\u00a0on to the task of\u00a0making our virtual package.<\/p>\n<h2>Part 2: Creating the Virtual WireShark+WinPcap Driver<\/h2>\n<p>So next I revert the Sequencer and make the package.\u00a0 A summary of those steps:<\/p>\n<ol>\n<li>Natively install the WinPCap driver.\u00a0 I may either use provided installer or my own.<\/li>\n<li><\/li>\n<li>In Sequencer Monitor mode, install WireShark.\u00a0 When it asks about installing WinPCap, decline.<\/li>\n<li><\/li>\n<li>Also in monitoring mode, create a folder called &#8220;C:\\Script&#8221; and copy the two PowerShell scripts plus the 5 executable files in it.<\/li>\n<li><\/li>\n<li>Complete the package and save it off.<\/li>\n<\/ol>\n<p>Edit the DeploymentConfig file.\u00a0 Under the UserConfiguration section, add both a StartVirtualEnvironment script and an EndVirtualEnvironment script.\u00a0 Like this:<\/p>\n<pre>&lt;UserScripts&gt;\r\n   &lt;StartVirtualEnvironment RunInVirtualEnvironment=\"false\"&gt;\r\n      &lt;Path&gt;PowerShell.exe&lt;\/Path&gt;\r\n      &lt;Arguments&gt;-ExecutionPolicy ByPass -File [{AppvPackageDrive}]\\Script\\ScriptInstallWinPCap.ps1&lt;\/Arguments&gt;\r\n      &lt;Wait Timeout=\"300\" RollbackonError=\"true\"\/&gt;\r\n   &lt;\/StartVirtualEnvironment&gt;\r\n\u00a0\u00a0 &lt;TerminateVirtualEnvironment RunInVirtualEnvironment=\"false\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;Path&gt;PowerShell.exe&lt;\/Path&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;Arguments&gt;-ExecutionPolicy ByPass -File [{AppvPackageDrive}]\\Script\\ScriptUnInstallWinPCap.ps1&lt;\/Arguments&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;Wait Timeout=\"300\" RollbackonError=\"false\"\/&gt;\r\n\u00a0\u00a0 &lt;\/TerminateVirtualEnvironment&gt;\r\n&lt;UserScripts&gt;<\/pre>\n<h2>Summary<\/h2>\n<p>So now the driver only exists and will be running when WireShark is running.<\/p>\n<p>This wouldn&#8217;t be a good idea on an RDS server, where multiple users could conflict, but it works great on desktops and VDI instances.<\/p>\n<p>If you are less concerned with security, you can make the scripts into Add\/Remove package scripts in the MachineScripts portion of the file instead. I am hoping that someday we&#8217;ll be able to put those scripts directly into the AppXManifest file of the package rather than the external DeploymentConfig.xml file.<\/p>\n<p>The virtual Office2013 and 365 packages created by the Office Deployment Tool put scripts in this file today, so obviously the client can handle it.<\/p>\n<p>Maybe someday the sequencer will let us do that&#8230;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;m not sure why I never thought of this before.\u00a0 All of the pieces were right there in front of me for a while, but it didn&#8217;t click until today. Today I created my first Virtual Device Driver with App-V!!!! OK.\u00a0 Time for the fine print: The driver isn&#8217;t really virtualized, I just make it&hellip; <a class=\"more-link\" href=\"https:\/\/www.tmurgent.com\/TmBlog\/?p=2310\">Continue reading <span class=\"screen-reader-text\">The App-V Virtual Device Driver: Really!!!!<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"footnotes":""},"categories":[47,48,50],"tags":[31],"class_list":["post-2310","post","type-post","status-publish","format-standard","hentry","category-appv5","category-sequencing","category-tools","tag-appv5","entry"],"_links":{"self":[{"href":"https:\/\/www.tmurgent.com\/TmBlog\/index.php?rest_route=\/wp\/v2\/posts\/2310","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tmurgent.com\/TmBlog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tmurgent.com\/TmBlog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tmurgent.com\/TmBlog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tmurgent.com\/TmBlog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2310"}],"version-history":[{"count":7,"href":"https:\/\/www.tmurgent.com\/TmBlog\/index.php?rest_route=\/wp\/v2\/posts\/2310\/revisions"}],"predecessor-version":[{"id":2317,"href":"https:\/\/www.tmurgent.com\/TmBlog\/index.php?rest_route=\/wp\/v2\/posts\/2310\/revisions\/2317"}],"wp:attachment":[{"href":"https:\/\/www.tmurgent.com\/TmBlog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2310"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tmurgent.com\/TmBlog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2310"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tmurgent.com\/TmBlog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2310"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}