Hey all, this is me once again with another interesting niche topic related to Windows internals. Again, I couldn’t find any blog posts other than the documentation from MSDN, so guess what? I wrote one. I can hear you screaming, ‘Dude, what the heck? Where is he getting these blog ideas from?’ Well, it was quite random, honestly. I was watching an OffByOneSecurity stream where Connor McGarr was mentioning IRQLs. I googled it, and guess what? I landed on a four-year-old Stack Overflow page where someone was complaining that they were having hard time understanding DPCs and IRQLs. That’s when I started reading about them, and here’s the post based on what I’ve learned.
DPCs are a mechanism that allows code running at a high interrupt request level (IRQL) to defer execution of lower-priority work until the processor returns to a lower IRQL. This helps ensure that interrupt handling remains fast and does not block other crucial system tasks.
DPCs run at IRQL DISPATCH_LEVEL
, which is above normal thread execution but below hardware interrupts. This means that once a DPC is scheduled, it preempts normal thread execution but still allows hardware interrupts to occur.
LOL, I know you didn’t get the above definition. You could see I’ve used the terms “IRQL” & “Interupt Handling” which you might not aware of.. so let’s talk about them first. Once you get those then understanding DPCs would be easy.
IRQLs (Interrupt Request Levels) determine the priority of operations in Windows. When the processor runs at a specific IRQL, only higher-priority tasks can interrupt it. This ensures critical system functions aren’t disrupted by less important tasks.
Windows has multiple IRQL levels, starting from PASSIVE_LEVEL, where regular threads run, up to HIGH_LEVEL, reserved for critical system events. If you still didn’t get it, Think of IRQLs like a priority system for handling tasks on the processor.
For example, let’s say a system processing user input while also handling hardware interrupts (For now, just ignore those levels rather focus on the flow):
This prevents low-priority tasks from delaying time-sensitive operations. Hope it makes sense now.
Interrupt handling as the name says, is the process by which a CPU temporarily stops executing its current task to respond to an event that needs immediate attention. These events, called interrupts, can come from hardware (e.g., a keyboard press, network packet arrival) or software (e.g., system calls, exceptions).
How It Works:
A best example (according to me) would be,
Now, go to the top and read the DPC’s introduction once again, you might get that this time. BTW, If you are curious about those IRQL levels then follow along. If you aren’t interested in their details then skip to the next part.
Windows defines several IRQL levels, ranging from PASSIVE_LEVEL
, where normal thread execution occurs, to HIGH_LEVEL
, which is used for critical system events. The key IRQLs are:
PASSIVE_LEVEL
.DIRQL
, preventing lower-priority operations from interrupting them. Device drivers must ensure minimal execution time in ISRs and defer work using DPCs.I’ve wrote this part using ChatGPT (bcoz, I don’t know these either at the time of writing). I mean, It’s better to know about them but speaking in general, this would be useful if you are into windows driver development. Honestly, if you are just doing security research, you don’t really need to care about this.
DPCs execute via the following mechanism:
DISPATCH_LEVEL
and executes them.DIRQL
, it cannot call functions that require PASSIVE_LEVEL
.DISPATCH_LEVEL
and performs the deferred processing.PASSIVE_LEVEL
, the DPC can offload work to a worker thread.DPCs execute at DISPATCH_LEVEL
IRQL, meaning they have direct kernel access and run with high privileges. This makes them an attractive target for attackers. Some of the vectors that you could focus (These are the usecases that I am aware of. There can be multiple other usecases too. If you know any other ways, please let me know, I can modify this part) are:
DISPATCH_LEVEL
, meaning they can access kernel memory, which could be exploited to manipulate system structures.If an attacker can manipulate a queued DPC entry to point to their shellcode/attacker controlled memory region, they can execute arbitrary code in kernel mode. This could lead to privilege escalation.
Vulnerable drivers may register a DPC routine using _KeInsertQueueDpc_
. If an attacker can overwrite this function pointer, they can redirect execution to arbitrary code. The sample flow might look like this,
DISPATCH_LEVEL
IRQL.Afaik, If your target is implemented with PatchGuard or SMEP or HVCI in general, this won’t work. There might be work bypasses for this but I don’t know (atleast for now!!!)
BTW, the above mentioned flow was based on CVE-2021–28314. So, for detailed analysis, please read the root cause analysis of that bug.
As I always mention in my posts, there may be many other primitives beyond this. I’m far from calling myself a vulnerability researcher , I still have a lot to learn and explore. These are just some of the primitives I came across while reading other blogs, and I’m always grateful to the authors who take the time to document the root cause analysis of the bugs they discover.
That’s all for now! Hope you guys find this post interesting and useful. Follow me on LinkedIn, Medium, X.
PEACE!
A Look at Modern Windows Kernel Exploitation/Hacking Stream -> https://www.youtube.com/live/nauAlHXrkIk?feature=shared
flylib.com](https://flylib.com/books/en/2.14.1.26/1/?source=post_page-----ecd138292883---------------------------------------)
en.wikipedia.org](https://en.wikipedia.org/wiki/Deferred_Procedure_Call?source=post_page-----ecd138292883---------------------------------------)
www.osr.com](https://www.osr.com/nt-insider/2009-issue1/deferred-procedure-call-details/?source=post_page-----ecd138292883---------------------------------------)