Just Let It Flow

January 17, 2012

Chroot-ing in Windows – As Easy as A:, B:, C:…

Filed under: Code,Windows — adeyblue @ 12:06 am

Contents:

  1. Introduction
  2. What’s a Device Map?
  3. How’s it Work?
  4. Usages
  5. What’s the Catch?
  6. Enough Talk – Gimme

Introduction

Linux people who have to work in Windows are often talking about the basic tools it has which are absent from Microsoft’s product. While recent developments of Windows are slowly catching up with variously featured versions of whoami, ln (mklink) cat (copy con), grep (find), ps (tasklist, taskkill) and chmod (icacls), one app that’s so far evaded the conversion is chroot.

For those unaware, chroot allows you to run an application using some specified directory as its filesystem root dir instead of the normal filesystem root. Whatever the reason may be for its absence, it is definitely not because there’s is no support mechanism for it. Just like in Linux, it’s a single function call.

NtSetInformationProcess(hProcess, ProcessDeviceMap, &hObjectDirectory, sizeof(hObjectDirectory));

What’s a Device Map?

Ok, so it’s technically one function call, but there needs to be a bit of setup beforehand. The first step is understanding what a device map is, and the answer is… a bog standard object manager directory [1]. Sllightly underwhelming I know, though that’s only half the story. It’s actually a bog standard object manager directory filled with bog standard symlinks.

If you’ve never poked around before or read anything about what drive letters represent to the object manager, then you may not know that drive letters are merely syntactically sugary symbolic links pointing to the portion of the actual device, volume, or file system directory they reside on:

The global device map

The global device map with drive letters highlighted

The symbolic links in the device map directory perform exactly the same purpose. In fact, they take exactly the same format too. In a chroot situation, the only thing that you wouldn’t want to be the same are the targets of the symlinks.

How’s it Work?

The process device map is the first port of call in the lookup of dos device names. This MSDN page explains the lookup process and seperation between Local [1] and Global names. Setting an explicit device map effectively replaces the local DosDevices directory in the lookup process.

Every time a program passes a path starting with the \??\ prefix to a kernel function, this two stage lookup process is activated [2]. The searching looks at the first component of the path, if an entry for it exists in the device map directory then that’s used and everything is well and good. If it doesn’t, the same thing is looked for in the global directory before being given up as a bad job. it’s called an invalid name.

Two things we can make from that:
1) Drive letters aren’t the only things you can redirect. The Pipe, Mailslot and UNC roots are in the global dos directory, so they’re fair game too.
2) You cannot take away any devices from being looked up, only overwrite them or add new ones. Of course, you can overwrite entries to point to an invalid location

Usages

For typical chrooting purposes, starting a suspended process and setting the device map before resuming it is the optimal usage but there’s nothing stopping you from using it on any already running process you have the required access to.

Also, unlike the Linux call, you don’t need elevated permissions to foist it upon a process. As long as you can open a process handle with the PROCESS_SET_INFORMATION right (the Vista+ PROCESS_SET_LIMITED_INFORMATION won’t cut it) you can change the device map and thus curtail its access.

What’s the Catch?

There are a few points to consider on its ultimate usefulness. Since anybody can set a device map at any time with no special privileges, just like in Linux, there’s no guarantee that a rooted process will stay rooted (though in Linux it requires root permissions to escape).

Another downside is that, as of Win7, child processes don’t inherit the device map of their parent. Instead they revert to the default global and local directories.

A third is that, unlike Linux, you can’t use this to create a second ‘version’ of Windows in the chroot dir due the effects of KnownDLL loading, which overrides the device map paths. You will need to copy any non-KnownDll system dlls a program depends on to the chroot dir in order to run them.

There’s also a bug in the WoW64 layer which makes it impossible for a 32-bit process to set a new device map on a 64-bit process [3].

Enough Talk, Gimme

Even with all its flaws, somebody might find a use for such a utility. with that, you can find the C++ source code and a 32/64 bit exe for a chroot-esque program here. Happy rooting.

 

 

 


Notes:

[1]: The default Local directory isn’t actually \Sessions\\DosDevices though that can exist, it is \Sessiona\0\HighLogonLuid-LowLogonLuid\. You can change or add mappings to this directory, and they will affect all processes launched in that session.

[2]: If you’ve never seen paths starting like this, that’s because CreateFile internally prepends it to the normal C:\blah\de\blah for you. If you pass CreateFile with a path starting \\.\ (like pipes and mailslots), \\?\ (like for long paths), or \\ (as in a UNC \\server\share path) that prefix is switched to \??\ and still follows the lookup process.

[3]: There is an oversight in the WoW64 layer for NtSetInformationProcess which makes it impossible for any 32-bit app to use this method. In native circumstances, a call to NtSetInformationProces enters the kernel immediately and validates that you passed a buffer whose size equalled sizeof(HANDLE) and you live and die by that.

In WoW64 circumstances, a call to NtSetInformationProcess is routed through wow64cpu’s X86SwitchTo64BitMode to whNtSetInformationProcess. This function is responsible for ensuring buffer sizes are big enough to call the real NtSetInformationProcess and for unpacking what it returns so the values are manageable to the 32-bit code, herein lies the bug.

00000000`73ab1fec       mov     edx,17h ; 17h is ProcessDeviceMap
00000000`73ab1ff1       cmp     r10d,edx ; if the info level is higher than that, jump
00000000`73ab1ff4       jg      wow64!whNtSetInformationProcess+0x285 (00000000`73ab2245)
00000000`73ab1ffa       cmp     r10d,edx ; if it ProcessDeviceMap, jump to below
00000000`73ab1ffd       je      wow64!whNtSetInformationProcess+0x25b (00000000`73ab221b)
....
00000000`73ab221b       cmp     r9d,24h ; if the buffer size is greater than or equal to 36 (0x24) jump to the call below
00000000`73ab221f       jae     wow64!whNtSetInformationProcess+0x26b (00000000`73ab222b)
00000000`73ab2221       mov     eax,0C0000004h ; otherwise return STATUS_INFO_LENGTH_MISMATCH
00000000`73ab2226       jmp     wow64!whNtSetInformationProcess+0x46b (00000000`73ab242b)
00000000`73ab222b       mov     ecx,dword ptr [r8]
00000000`73ab222e       mov     qword ptr [r8],rcx
00000000`73ab2231       mov     r9d,28h
00000000`73ab2237       mov     rcx,r11
00000000`73ab223a       call    qword ptr [wow64!_imp_NtSetInformationProcess (00000000`73aa1ad8)]

The thunk checks the input buffer size as greater than or equal to the whole PROCESS_DEVICE_MAP structure, including the significant portion used only by NtQueryInformationProcess. Since you cannot satisfy both equal to sizeof(HANDLE) (8 on x64) and greater than 36, it is impossible to use.

7 Comments »

  1. Thank you for this awesome article! I do have a question for you.. On Vista+, drives mapped in non-elevated processes are not visible to elevated processes, and vice-versa. An Admin CMD can see different network drives than a non-elevated CMD.

    What is the cause of this separation? I poked around in WinObj but wasn’t able to find clear mappings to all of the network drive letters I had.. Wasn’t sure how to explain things. Thoughts?

    Comment by Ian — January 24, 2012 @ 12:33 am

  2. […] Chroot-ing in Windows – As Easy as A:, B:, C:… « Just Let It Flow 1) Drive letters aren’t the only things you can redirect. The Pipe, Mailslot and UNC roots are in the global dos directory, so they’re fair game too. […]

    Pingback by Ideas & goodies | Pearltrees — January 24, 2012 @ 7:40 am

  3. @Ian It’s likely to be because different logon sessions (and thus the processes aligned with them) use different object directories as their base. MSDN briefly explains it in the first paragraph of the remarks for WNetAddConnection2 [http://msdn.microsoft.com/en-us/library/aa385413(v=vs.85).aspx], ignore the XP/2003 restriction it’s the same on modern versions. In Vista+, running as an elevated user constitutes a different logon session.

    These per logon drives are located in WinObj at \Sessions\0\DosDevices\LogonIDHigh-LogonIDLow (where the LogonId(High|Low) values are hex strings). 3e4 and 3e5 are for the NetworkService and LocalService accounts respectively, the higher values are for actual user sessions though AFAIK nothing in Windows or Process Explorer can tell you which corresponds to what session short of scouring the Security event logs.

    Comment by adeyblue — January 24, 2012 @ 8:10 pm

  4. Hah, awesome! That had been bothering me for pretty much forever, thank you very much for the explanation and link!

    Comment by Ian — January 26, 2012 @ 1:50 am

  5. Hi there,

    Many thanks for this great tool.

    I am trying to run this on Windows XP SP3, 32bit from command prompt:

    C:\chroot>”Chroot.exe” %temp% %comspec%
    And I receive the following error: Couldn’t launch process – Error: The directory name is invalid.

    It doesn’t matter what directory name I use I get the above error. I verified that both %temp% %comspec% environment variables are correct on my system. Also does this work on Windows 2012 64bit?

    Cheers… Steve

    Comment by Steven — December 20, 2013 @ 3:55 am

  6. I also used the following commend:

    C:\chroot>Chroot.exe %temp% %comspec%

    I got the same same error.

    Thanks again for your help.

    Steve

    Comment by Steven — December 20, 2013 @ 3:57 am

  7. its not working on windows 7

    Comment by tanmay — August 18, 2014 @ 11:04 am

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress