McAfee Labs

Windows 7 – Kernel API Refactoring

0
By , on Jan 05, 2010

After the public release of Microsoft Windows 7, I saw many people were curious about and showed great interest in “MinWin”, but most of them were not able to understand or explain it correctly and they often confused “MinWin” with “Server Core”. So what does exactly the term “MinWin” mean?
One of Microsoft goals for Windows Server 2008, “Server Core” (formerly known as “Server Foundation”) is a variant with a sub-set of the entire Windows operating system that contains enough components to run various common server roles, such as AD, DNS, DHCP Server and IIS. On the other hand, the “MinWin” is a small, self-contained operating system that has no dependencies on higher-level components, and is most well-known for being minimalistic, self-contained set of Windows components was shipped as part of Windows 7.
One Microsoft Windows developer describes “MinWin” as “refactoring code along architectural layering lines”. Actually from Windows Vista (some of the componentization and refactoring work was already shipped with Windows Vista) which is arguably the first “MinWin” based operating system, every component of the operating system was assigned a “layer number” that represents its dependency position relative to other components, with more lower-numbered components being more closer to the core of the operating system, and “code refactoring” need to be done by the core architecture team to resolve the dependency issues where low-level components were reliant on high-level components. Next let’s look at how this “layering” and “code refactoring” are implemented in Windows 7 by using an example.

From the screenshot above (kernel32.dll opened in dependency walker utility), we can see that Windows 7 introduces a set of new DLL files which export many well-known Win32 APIs, the newly introduced DLLs include kernelbase.dll (Windows NT BASE API Client DLL) and 34 hidden ApiSet Stub DLLs (listed below), and each such stub DLL belongs to a separate function category as its name indicates. For example, api-ms-win-core-processthreads-l1-1-0.dll exports process/thread related APIs (CreateProcessA/W, CreateRemoteThread etc), and api-ms-win-core-heap-l1-1-0.dll exports user-mode heap management APIs (HeapCreate, HeapAlloc etc).

ApiSet Stub DLLs:
api-ms-win-core-console-l1-1-0.dll
api-ms-win-core-datetime-l1-1-0.dll
api-ms-win-core-debug-l1-1-0.dll
api-ms-win-core-delayload-l1-1-0.dll
api-ms-win-core-errorhandling-l1-1-0.dll
api-ms-win-core-fibers-l1-1-0.dll
api-ms-win-core-file-l1-1-0.dll
api-ms-win-core-handle-l1-1-0.dll
api-ms-win-core-heap-l1-1-0.dll
api-ms-win-core-interlocked-l1-1-0.dll
api-ms-win-core-io-l1-1-0.dll
api-ms-win-core-libraryloader-l1-1-0.dll
api-ms-win-core-localization-l1-1-0.dll
api-ms-win-core-localregistry-l1-1-0.dll
api-ms-win-core-memory-l1-1-0.dll
api-ms-win-core-misc-l1-1-0.dll
api-ms-win-core-namedpipe-l1-1-0.dll
api-ms-win-core-processenvironment-l1-1-0.dll
api-ms-win-core-processthreads-l1-1-0.dll
api-ms-win-core-profile-l1-1-0.dll
api-ms-win-core-rtlsupport-l1-1-0.dll
api-ms-win-core-string-l1-1-0.dll
api-ms-win-core-synch-l1-1-0.dll
api-ms-win-core-sysinfo-l1-1-0.dll
api-ms-win-core-threadpool-l1-1-0.dll
api-ms-win-core-util-l1-1-0.dll
api-ms-win-core-xstate-l1-1-0.dll
api-ms-win-security-base-l1-1-0.dll
api-ms-win-security-lsalookup-l1-1-0.dll
api-ms-win-security-sddl-l1-1-0.dll
api-ms-win-service-core-l1-1-0.dll
api-ms-win-service-management-l1-1-0.dll
api-ms-win-service-management-l2-1-0.dll
api-ms-win-service-winsvc-l1-1-0.dll

Here we can see clearly that Kernel32!OpenProcess will not do much work actually, it simply jumps to OpenProcess_0 which is imported from one of the stub DLLs (api-ms-win-core-synch-l1-1-0.dll).

The IDA Pro and Dependency Walker show this dependency explicitly, however when we further look into the disassembly code of api-ms-win-core-synch-l1-1-0!OpenProcess, we will be surprised to find the function is actually an empty function which just returns 0, and all its exported functions with 3 arguments share the same function stub (see the screenshot below). So how does Kernel32!OpenProcess work properly if it is resolved to an empty function?

The secret lies in the DLL loading process, Windbg debugging output tells us Kernel32!OpenProcess will not jump to api-ms-win-core-synch-l1-1-0!OpenProcess at runtime, and the import table entry of OpenProcess is actually filled with the address of Kernelbase!OpenProcess, and all api-ms-win-*.dll are never loaded into the process address space (refer to !peb output)

The real implementation code was moved from Kernel32!OpenProcess to Kernelbase!OpenProcess (see below), which further invokes Ntdll!ZwOpenProcess. In fact, not only OpenProcess, most Win32 APIs have been undergone the same “refactoring along architectural layering lines”.

In my next blog on Windows 7 internals, we are going to look inside a cool feature of Windows 7 – “XP Mode”, please stay tuned.


Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>