Nytro Posted March 27, 2013 Report Posted March 27, 2013 Windows Architecture and User/Kernel ModeDejan Lukan March 27, 2013Introduction Each process started on x86 version of Windows uses a flat memory model that ranges from 0×00000000 – 0xFFFFFFFF. The lower half of the memory, 0×00000000 – 0x7FFFFFFF, is reserved for user space code.While the upper half of the memory, 0×80000000 – 0xFFFFFFFF, is reserved for the kernel code. The Windows operating system also doesn’t use the segmentation (well actually it does, because it has to), but the segment table contains segment descriptors that use the entire linear address space. There are four segments, two for user and two for kernel mode, which describe the data and code for each of the modes. But all of the descriptors actually contain the same linear address. This means they all point to the same segment in memory that is 0xFFFFFFFF bits long, proving that there is no segmentation on Windows systems. Let’s execute the “dg 0 30? command to display the first 7 segment descriptors that can be seen on the picture below: Notice that the 0008, 0010, 0018 and 0020 all start at base address 0×00000000 and end at address 0xFFFFFFFF: They represent the data and code segments of user and kernel mode. This also proves that the segmentation is actually not used by the Windows system. Therefore we can use the terms”virtual address space” and “linear address space” interchangeably, because they are the same in this particular case. Because of this, when talking in user space code being loaded in the virtual address space from 0×00000000 to 0x7FFFFFFF, we’re actually talking about linear addresses. Those addresses are then sent into the paging unit to be translated into physical addresses. We’ve just determined that even though each process uses a flat memory model that spans the entire 4GB linear address space, it can only use half of it.This is because the other half is reserved for kernel code: the program can thus use, at most, 2GB of memory. Every process has its own unique value in the CR3 register that points to the process’ page directory table. Because each process has its own page directory table that is used to translate the linear address to physical address, two processes can use the same linear address, while their physical address is different. Okay, so each program has its own address space reserved only for that process, but what about the kernel space? Actually, the kernel is loaded only once in memory and each program must use it. This is why each process needs appropriate pointers set-up that do just that. It means that the PDEs stored in the page directory of every process point to the same kernel page table. We know that the kernel’s memory is protected by various mechanisms, so the user process can’t call it directly, but can call into the kernel by using special gates that only allow certain actions to be requested of kernel. Thus, we can’t simply tell a program to go into kernel mode and do whatever it pleases,because the code that does whatever we want is in user space. Therefore,the programs can only request a special action that’s already provided by a kernel’s code to do it for them. If we would like to run our own code in kernel memory, we must first find a way to pass the code to the kernel and stay there. One such example would be the installation of some driver that requires kernel privileges to be run,because it’s interacting more or less directly with the hardware component for which the driver has been written. The user processes can then use that driver’s functionality to request certain actions to be done: but only those that have been implemented in the driver itself. I hope I made it clear that the functionality run in kernel mode is limited to the functionality of the code loaded in kernel mode, and thus the code from user mode is not allowed to be executed with kernel privileges. Let’s take a look at an example. On the Windows system being debugged by Windbg, I started Internet Explorer and Opera to analyze their memory space. After the programs have been started, I run the “!process 0 0? command to get the basic information about all the processes currently active on a system. The result of the command can be shown below where we’ve only listed the two processes in question (not all of them): [TABLE][TR][TD=class: gutter]12345678[/TD][TD=class: code]kd> !process 0 0PROCESS 821e23c0 SessionId: 0 Cid: 0380 Peb: 7ffd4000 ParentCid: 05d4DirBase: 094c01a0 ObjectTable: e1e88650 HandleCount: 307. Image: opera.exePROCESS 81f799f8 SessionId: 0 Cid: 047c Peb: 7ffd8000 ParentCid: 05d4DirBase: 094c0200 ObjectTable: e1c7b630 HandleCount: 570. Image: IEXPLORE.EXE[/TD][/TR][/TABLE] The DirBase element above is actually the value that gets stored in the CR3 register every time a context-switch to a particular process occurs. That value is used as a pointer to the page table directory that contains PDEs. The page directory table of process opera.exe is stored at physical address 0x094c01a0, while the page directory table of process IEXPLORE.EXE is stored at physical address 0x094c0200. Because the 0×00000000 to 0x7FFFFFFF linear address space is used by the program and not the kernel, the program will use the first half of the PDE entries in its page directory, while the kernel will use the second half. Since, if PAE is disabled, each program has 1024 PDE entries, 512 of them refer to user space memory, and the other 512 refer to kernel space memory. The !process commands above have been used to get the pointer to the process’s EPROCESS structure in memory. With the .process command, we can set the context to the current process. This is mandatory step if we would like to run some other commands that require us to be in the process’s context in order to be run successfully. To switch to the context of the iexplore.exe process, we have to execute the “.process 81f799f8? command as can be seen below: There was some warning message about forcedecodeuser not being enabled. The problem with this is that the context switch won’t occur to the requested process. To solve that we need to enabled the forcedecodeuser with the “.cache forcedecodeuser” command. The output from that command can be seen on the picture below: Notice that we’ve first enabled the forcedecodeuser, and then run the .process command to switch to the context of the iexplore.exe’s process? This time there was no error message and the context-switch actually occurred. Notice that all the loaded DLLs that the program uses have been loaded in the user space (keep in mind that we didn’t present all the DLLs because the iexplore.exe uses too many of them to be presented in a sane manner). All the loaded DLLs also have their path displayed, which makes it very easy to find them on the hard drive. Let’s also present the second part of the output, which has long lines, so they can’t be presented here. Luckily the windbg has a “word wrap” functionality that can be enabled by right-clicking on the window and selecting “Word wrap” as can be seen below: Notice that the “Word wrap” is enabled, which means that the lines will only be as long as the window’s width.If lines are longer they will be wrapped and put into the second line. Let’s now present the second half of the output from running the !peb command: There are quite many information available on the picture above, like the address of the process heap, the process parameters, the command line used to invoke the program, the path where to search for DLLs, etc. Also all the environment variables of this process are shown, but only the first three are presented for clarity. Let’s now download the Sysinternals Suite and run the vmmap tool, which will ask us to select a process when launching. We can see that on the picture below, where we must select the IEXPLORE.EXE to view it’s memory: The vmmon will then analyze the memory and present us with the statistics about which memory is used for heap, stack, data, etc. This can be seen on the picture below: Windows Architecture Let’s present a picture about Windows Architecture taken from [2]: On the picture above we can see the HAL (Hardware Abstraction Layer), which is the first abstraction layer that abstracts the hardware details from the operating system. The operating system can then call the same API functions and the HAL takes care of how they are actually executed on the underlying hardware. Every driver that is loaded in the kernel mode uses HAL to interact with the hardware components, so even the drivers don’t interact with hardware directly. The kernel drivers can interact with the hardware directly, but usually they don’t need to, since they can use HAL API to execute some action. The hardware abstraction layer’s API is provided with the hal.dll library file that is located in the C:\WINDOWS\system32\ directory as can be seen below: The rest of the system kernel components are provided by the following libraries and executables [3]:csrss.exe : manages user processes and threads win32k.sys : user and graphics device driver (GDI) kernel32.dll : access to resources like file system, devices, processes, threads and error handling in Windows systems advapi32.dll : access to windows registry, shutdown/restart the system, start/stop/create services, manage user accounts user32.dll : create and manage screen windows, buttons, scrollbars, receive mouse and keyboard input gdi32.dll : outputs graphical content to monitors, printers and other output devices comdlg32.dll : dialog boxes for opening and saving files, choosing color and font comctl32.dll : access to status bars, progress bars, tools, tabs shell32.dll : access the operating system shell netapi32.dll : access to networking functions The programs can use Windows API (Win 32 API) to implement the needed actions. But the WinAPI uses the described DLL libraries underneath. Right above the kernel mode is the user mode, where the most important library is ntdll.dll.Thatcan be used as an entry point into the kernel if some process needs services of the kernel. Conclusion We’ve seen how the user and kernel mode are separated and what each of those provide to the user. The kernel mode is used to provide services to the user mode applications. The kernel mode is capable of doing almost anything with the underlying system, but the most important thing is the existence of Win32 API that provides another abstraction layer over the underlying hardware components. If you’re interested in knowing all of the system libraries that a kernel uses, you can run the “lm n” command in Windbg, which will list all of the libraries used by the kernel mode.kd> lm nstart end module name7c900000 7c9b2000 ntdll ntdll.dll804d7000 806d0280 nt ntkrnlpa.exe806d1000 806e4d00 hal halacpi.dllbf000000 bf011600 dxg dxg.sysbf012000 bf028000 VBoxDisp VBoxDisp.dllbf800000 bf9c7e00 win32k win32k.sysf57cf000 f580fa80 HTTP HTTP.sysf5978000 f59cf600 srv srv.sysf5a20000 f5a4c180 mrxdav mrxdav.sysf5b0d000 f5b17000 secdrv secdrv.sysf5e79000 f5e7c900 ndisuio ndisuio.sysf6ee9000 f6f00900 dump_atapi dump_atapi.sysf6fa1000 f6fc6500 ipnat ipnat.sysf6fef000 f705e780 mrxsmb mrxsmb.sysf705f000 f7089e80 rdbss rdbss.sysf709c000 f70d9000 VBoxSF VBoxSF.sysf70d9000 f70fad00 afd afd.sysf70fb000 f7122c00 netbt netbt.sysf7123000 f717b480 tcpip tcpip.sysf717c000 f718e600 ipsec ipsec.sysf71cb000 f71cd900 Dxapi Dxapi.sysf71d7000 f7234f00 update update.sysf7235000 f7257700 ks ks.sysf7264000 f7266f80 mouhid mouhid.sysf7268000 f726a880 hidusb hidusb.sysf7280000 f72afe80 rdpdr rdpdr.sysf72b0000 f72c0e00 psched psched.sysf72c1000 f72d7580 ndiswan ndiswan.sysf72d8000 f72fb200 USBPORT USBPORT.SYSf72fc000 f730ff00 VIDEOPRT VIDEOPRT.SYSf7310000 f7334000 VBoxVideo VBoxVideo.sysf7334000 f7347900 parport parport.sysf7348000 f7362000 VBoxMouse VBoxMouse.sysf838d000 f838f280 rasacd rasacd.sysf83c1000 f83dab80 Mup Mup.sysf83db000 f8407980 NDIS NDIS.sysf8408000 f8494600 Ntfs Ntfs.sysf8495000 f84b4000 VBoxGuest VBoxGuest.sysf84b4000 f84cab00 KSecDD KSecDD.sysf84cb000 f84dcf00 sr sr.sysf84dd000 f84fcb00 fltMgr fltMgr.sysf84fd000 f8514900 atapi atapi.sysf8515000 f853a700 dmio dmio.sysf853b000 f8559880 ftdisk ftdisk.sysf855a000 f856aa80 pci pci.sysf856b000 f8598d80 ACPI ACPI.sysf869a000 f86a3180 isapnp isapnp.sysf86aa000 f86b4580 MountMgr MountMgr.sysf86ba000 f86c6c80 VolSnap VolSnap.sysf86ca000 f86d2e00 disk disk.sysf86da000 f86e6180 CLASSPNP CLASSPNP.SYSf872a000 f8736d00 i8042prt i8042prt.sysf873a000 f8749600 cdrom cdrom.sysf874a000 f8752a00 pcntpci5 pcntpci5.sysf875a000 f8766880 rasl2tp rasl2tp.sysf876a000 f8774200 raspppoe raspppoe.sysf877a000 f8785d00 raspptp raspptp.sysf878a000 f8792900 msgpc msgpc.sysf87da000 f87e3f00 termdd termdd.sysf87ea000 f87f3e80 NDProxy NDProxy.SYSf87fa000 f8808880 usbhub usbhub.sysf881a000 f8822780 netbios netbios.sysf885a000 f8864e00 Fips Fips.SYSf888a000 f8899900 Cdfs Cdfs.SYSf889a000 f88a2700 wanarp wanarp.sysf88aa000 f88b3000 HIDCLASS HIDCLASS.SYSf891a000 f8920180 PCIIDEX PCIIDEX.SYSf8922000 f8926d00 PartMgr PartMgr.sysf895a000 f8960000 kbdclass kbdclass.sysf8962000 f8967a00 mouclass mouclass.sysf896a000 f896e300 usbohci usbohci.sysf8972000 f8979600 usbehci usbehci.sysf897a000 f897ea80 TDI TDI.SYSf8982000 f8986580 ptilink ptilink.sysf898a000 f898e080 raspti raspti.sysf89b2000 f89b7200 vga vga.sysf89ba000 f89bea80 Msfs Msfs.SYSf89c2000 f89c9880 Npfs Npfs.SYSf89ca000 f89d0180 HIDPARSE HIDPARSE.SYSf89e2000 f89e6500 watchdog watchdog.sysf8aaa000 f8aad000 BOOTVID BOOTVID.dllf8aae000 f8ab0800 compbatt compbatt.sysf8ab2000 f8ab5780 BATTC BATTC.SYSf8b3e000 f8b41680 CmBatt CmBatt.sysf8b42000 f8b44780 ndistapi ndistapi.sysf8b7a000 f8b7dc80 mssmbios mssmbios.sysf8b9a000 f8b9bb80 kdcom kdcom.dllf8b9c000 f8b9d100 WMILIB WMILIB.SYSf8b9e000 f8b9f580 intelide intelide.sysf8ba0000 f8ba1700 dmload dmload.sysf8bca000 f8bcb100 swenum swenum.sysf8bcc000 f8bcd280 USBD USBD.SYSf8bce000 f8bcff00 Fs_Rec Fs_Rec.SYSf8bd0000 f8bd1080 Beep Beep.SYSf8bd2000 f8bd3080 mnmdd mnmdd.SYSf8bd4000 f8bd5080 RDPCDD RDPCDD.sysf8be4000 f8be5100 dump_WMILIB dump_WMILIB.SYSf8c00000 f8c01a80 ParVdm ParVdm.SYSf8ca7000 f8ca7d00 dxgthk dxgthk.sysf8d38000 f8d38c00 audstub audstub.sysf8de1000 f8de1b80 Null Null.SYSUnloaded modules:f884a000 f8855000 imapi.sysf883a000 f8849000 redbook.sysf882a000 f883a000 serial.sysf89aa000 f89af000 Cdaudio.SYSf8391000 f8394000 Sfloppy.SYSf89a2000 f89a7000 Flpydisk.SYSf899a000 f89a1000 Fdc.SYSWe can see that there are a lot of loaded libraries that kernel mode uses to provide services to the user application and to keep track of everything the operating system must do. References: [1] PankajGarg, Windows Memory Management, accessible at http://www.intellectualheaven.com/Articles/WinMM.pdf. [2] HanyBarakat’s Technical Blog, accessible at Deeper into Windows Architecture - Hany Barakat's Technical Blog - Site Home - MSDN Blogs. [3] Windows API, accessible at Windows API - Wikipedia, the free encyclopedia.Sursa: InfoSec Institute Resources – Windows Architecture and User/Kernel Mode Quote