Hi. Work has me writing drivers and utilizing the Windows kernel, so I figured I would write about it. It is quite interesting and perhaps you may find it interesting as well.
What makes kernel-mode so special?
Firstly you should understand that there are 2 “modes” within a Windows machine: user-mode and kernel-mode. These 2 modes denote positions of privilege and lie within a set of “rings” called protection rings, where the outer rings have fewer privileges than the inner rings, and in the center lies the kernel. There are 4 rings, user-mode (the mode you are operating on right now whilst reading this post) is ring 3. Since drivers are in direct contact with hardware, they require more privileges and thus need a more privileged ring.
As you can see, the kernel lies within ring 0, which essentially means that the kernel has permissions to access to everything. If you’re familiar with Linux, think of it like how the root user has access to every file and folder in a system.
Kernel-level programs have access to physical memory, hardware, low-level system functions, and can even provide services for user-level programs.
If you’ve ever deal with MSVC++, you might be aware of NTDLL, which interfaces kernel-level functionality and provides it to user-mode programs. This is an example of a kernel-mode program providing an user-mode DLL with services, namely exported functions.
Why bother learning about the Windows kernel?
The thing about having unfettered access to every part of a computer is that it is, well, powerful. Should an attacker discover an exploit that leverages ring 0 access to execute malicious software on a machine, you might need to know how the kernel works so that you can mitigate and prevent damage from the malicious program.
Secondly, very few people know and understand kernel functionality. Knowledge is so scarce that Microsoft doesn’t even have documentation on it. Think of how good it would look on your resume.
I’ll tell you an insider secret, there are only really 3 main ways exploit development works nowadays, and they piggyback off of each other. Most other methods are moot.
Phishing
Kind of obvious, but social engineering is the most prevalent method of hacking/breaching a system. There aren’t enough YARA rules on the planet to prevent Mary from HR from downloading the wrong Excel file.
Physical Access
Once someone has physical access to a machine, there really isn’t anything you can do about it. And I don’t mean a snoopy individual finding their way into your server room, I mean someone downloading your software and discovering exploits within it. This can range from finding poorly written code (see most crypto exploits) to ripping physical memory off of the PCIe board for read-only exploits (called Direct Memory Access or DMA).
Kernel Privilege
If you are able to achieve ring 0 access with, you then have access to everything, and can thus alter other programs that might have had user-level protections in them. At this point, the exploit is unstoppable. The term for this is privilege escalation.
Now that the reasoning and basics have been established. I can now explain to you some lower level concepts.
System Architecture
Processes
If you’ve read me for a bit, you should know what processes are. They are containers that hold modules. Within these modules are the code that is executed. Processes are assigned a unique Process ID (PID).
Threads
Processes don’t “run”. Threads are what “runs” within a program. Thread usage is implemented in DLL Injection and Shellcode Injection. You can have multiple threads running within a single process at the same time.
Virtual Memory
Ever wondered how, when you allocate a block of memory, it is always one, uninterrupted, concurrent block? This is the magic of virtual memory. I could write an entire post on virtual memory, but I’ll keep it as brief as possible. For every program that exists on a machine, it is given a dedicated virtual address space for it to operate in. This memory space is managed by the OS, and it also improves program security by managing the RWX of the memory space so that data cannot be read from, written to, or executed without explicit permission. Lastly, virtual memory can be utilized to extend the capabilities of RAM so that programs can continue to run even if the machine is out of RAM by using physical disk space as a memory buffer.
I/O System
I/O or input/output is what handles things that involve input, and… get this… output. This is commonly the disk, but references anything like keyboard, mouse, screen, etc. I/O also manages how drivers are handled, since drivers usually communicate with hardware. An important handler of this driver-handling feature is Windows Management Instrumentation or WMI. We actually used WMI in the Shellcode Injection post. Did you miss it? Look again! Lastly, there’s Plug and Play or PnP which happens automatically when you plug in a new mouse or microphone where drivers are automatically installed and resources are allocated for the device.
Several upcoming posts of mine will involve the Windows kernel as my current job is a dance between red-team exploit development and blue-team systems programming. I wear 2 hats. They’ve started me on kernel work recently so I will transcribe what I’m learning here! This will involve writing some drivers, so if you want to follow along, you’ll need to install the Windows Driver Kit and set up a VM for kernel debugging (good luck with that) since, if a driver errors out, you blue screen your machine.
That’s all for this post; a small introduction to the Windows kernel and some concepts that will be touched on in the future. There will still be other posts on other concepts, but the kernel will be relatively frequent, so be on the lookout.
Go!
-BowTiedCrawfish
Thank you ser, great read!
I haven't thought of ring 0 in a long time, but it brought me back to memory lane, when DOS had a 640k barrier, and everything ran in real mode. When NT arrived, I had to learn the Rings and write assembler for a scsi driver once. Nice read. Cheers.