One of our minions (he was introduced in this blog entry a while ago) recently came to us asking for advice: he was about to automate yet another task, by using his Python-fu, and realized that he misses entries in the file system as well as in the registry.
Notably, he only sees this behaviour on 64bit-versions of the Windows operating system:
The left image shows the folder C:\Windows\System32\Tasks as seen in the Windows Explorer, the right image as seen in a simple 32bit-python application. Only the subfolder Microsoft is listed there. Something is amiss.
Below is the code to produce the right image, when executed in a 32bit-version of Python:
import glob, os for pathfilename in glob.glob(r"C:\Windows\System32\Tasks\*"): print pathfilename
File System Redirection
The operating system mechanism responsible for this behaviour is known as File System Redirection. It was introduced many years ago to allow for a rather smooth co-existence of 32bit- and 64bit-applications on Windows 64bit. By no means, this is something new, but every now and then, questions regarding this are being asked.
With help of the excellent tool Total Commander, the above observation can be nicely visualized and understood. If we use the 64bit-version of Total Commander, we will get the same output as Windows Explorer (see right pane below):
On the left pane, we see an excerpt of the directory listing of C:\Windows. Note that there is a folder C:\Windows\System32 as well as a folder C:\Windows\SysWOW64. Total Commander can be used to calculate the real size of these folders:
C:\Windows\System32 (64bit-view): 1’259’317 kB
C:\Windows\SysWOW64 (64bit-view): 901’928 kB
If we use the 32bit-version of Total Commander, we will get the same output as our 32bit-python application (see right pane below):
On the left pane, we see an excerpt of the directory listing of C:\Windows, but from a 32bit-point of view. Interestingly, there is yet another Sys*-folder: C:\Windows\Sysnative. Again, using Total Commander, the real size of these folders can be calculated:
C:\Windows\Sysnative (32bit-view): 1’259’317 kB
C:\Windows\System32 (32bit-view): 901’928 kB
C:\Windows\SysWOW64 (32bit-view): 901’928 kB
A 64bit-application (such as Windows Explorer) on Windows 64bit sees the physical (real, native) directory listing. For 32bit-applications to run smoothly in this environment, Windows uses File System Redirection: Access to C:\Windows\System32 is redirected to C:\Windows\SysWOW64 such that a 32bit-application loads the correct 32bit-version of system files. Therefore, the size of C:\Windows\System32 equals the size of C:\Windows\SysWOW64 when analyzed using the 32bit-version of Total Commander.
But what if a 32bit-applications wants to access the physical (real, native) folder C:\Windows\System32? Conveniently, for 32bit-applications there is a virtual folder C:\Windows\Sysnative to access the native system folder:
import glob, os for pathfilename in glob.glob(r"C:\Windows\System32\Tasks\*"): print pathfilename for pathfilename in glob.glob(r"C:\Windows\SysWOW64\Tasks\*"): print pathfilename for pathfilename in glob.glob(r"C:\Windows\Sysnative\Tasks\*"): print pathfilename
Registry Redirection
Unsurprisingly, the same effect can be seen when analyzing the Registry. It is known as Registry Redirection. The left image shows the registry key HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree as seen in the Registry Editor (a 64bit-application), the right image as seen in a simple 32bit-python application.
The code is as follows, executed in a 32bit-version of Python:
import _winreg key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree",0,_winreg.KEY_READ) nr_keys, nr_values, lastmodified = _winreg.QueryInfoKey(key) print r"HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree" print "\t#Keys: %u #Values: %u" % (nr_keys,nr_values)
There must be a way to have access to the 64bit-view also from a 32bit-application. Indeed, Windows provides such a mechanism, and it is very simple: instead of accessing the registry with a the flag _KEY_READ, one can use the flags _KEY_READ|_KEY_WOW64_64KEY. The flag _KEY_WOW64_64KEY (0x100) makes sure that the 64bit-key is accessed, regardless whether by an 32bit-application or an 64bit-application. Correspondingly, the flag _KEY_WOW64_32KEY (0x200) makes sure that the 32bit-key is accessed, regardless whether by an 32bit-application or an 64bit-application:
import _winreg key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree",0,_winreg.KEY_READ) nr_keys, nr_values, lastmodified = _winreg.QueryInfoKey(key) print r"HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree" print "\t#Keys: %u #Values: %u" % (nr_keys,nr_values) key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree",0,_winreg.KEY_READ|_winreg.KEY_WOW64_64KEY) nr_keys, nr_values, lastmodified = _winreg.QueryInfoKey(key) print r"HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree (64bit-view)" print "\t#Keys: %u #Values: %u" % (nr_keys,nr_values) for i in xrange(nr_keys): print _winreg.EnumKey(key, i) for i in xrange(nr_values): print _winreg.EnumValue(key,i)
Our minion is happy. He now knows how to look for all files and registry keys, regardless whether they are redirected or not. Not a single entry, be it malicious or not, will escape his Python-fu. Or will it?