✍️
Red Teaming Experiments
  • What is this iRed.team?
  • Pinned
    • Pentesting Cheatsheets
      • SQL Injection & XSS Playground
    • Active Directory & Kerberos Abuse
      • From Domain Admin to Enterprise Admin
      • Kerberoasting
      • Kerberos: Golden Tickets
      • Kerberos: Silver Tickets
      • AS-REP Roasting
      • Kerberoasting: Requesting RC4 Encrypted TGS when AES is Enabled
      • Kerberos Unconstrained Delegation
      • Kerberos Constrained Delegation
      • Kerberos Resource-based Constrained Delegation: Computer Object Take Over
      • Domain Compromise via DC Print Server and Kerberos Delegation
      • DCShadow - Becoming a Rogue Domain Controller
      • DCSync: Dump Password Hashes from Domain Controller
      • PowerView: Active Directory Enumeration
      • Abusing Active Directory ACLs/ACEs
      • Privileged Accounts and Token Privileges
      • From DnsAdmins to SYSTEM to Domain Compromise
      • Pass the Hash with Machine$ Accounts
      • BloodHound with Kali Linux: 101
      • Backdooring AdminSDHolder for Persistence
      • Active Directory Enumeration with AD Module without RSAT or Admin Privileges
      • Enumerating AD Object Permissions with dsacls
      • Active Directory Password Spraying
  • offensive security
    • Red Team Infrastructure
      • HTTP Forwarders / Relays
      • SMTP Forwarders / Relays
      • Phishing with Modlishka Reverse HTTP Proxy
      • Automating Red Team Infrastructure with Terraform
      • Cobalt Strike 101
      • Powershell Empire 101
      • Spiderfoot 101 with Kali using Docker
    • Initial Access
      • Password Spraying Outlook Web Access: Remote Shell
      • Phishing with MS Office
        • Phishing: XLM / Macro 4.0
        • T1173: Phishing - DDE
        • T1137: Phishing - Office Macros
        • Phishing: OLE + LNK
        • Phishing: Embedded Internet Explorer
        • Phishing: .SLK Excel
        • Phishing: Replacing Embedded Video with Bogus Payload
        • Inject Macros from a Remote Dotm Template
        • Bypassing Parent Child / Ancestry Detections
        • Phishing: Embedded HTML Forms
      • Phishing with GoPhish and DigitalOcean
      • Forced Authentication
      • NetNTLMv2 hash stealing using Outlook
    • Code Execution
      • T1117: regsvr32
      • T1170: MSHTA
      • T1196: Control Panel Item
      • Executing Code as a Control Panel Item through an Exported Cplapplet Function
      • Code Execution through Control Panel Add-ins
      • T1191: CMSTP
      • T1118: InstallUtil
      • Using MSBuild to Execute Shellcode in C#
      • T1202: Forfiles Indirect Command Execution
      • Application Whitelisting Bypass with WMIC and XSL
      • Powershell Without Powershell.exe
      • Powershell Constrained Language Mode ByPass
      • Forcing Iexplore.exe to Load a Malicious DLL via COM Abuse
      • T1216: pubprn.vbs Signed Script Code Execution
    • Code & Process Injection
      • CreateRemoteThread Shellcode Injection
      • DLL Injection
      • Reflective DLL Injection
      • Shellcode Reflective DLL Injection
      • Process Doppelganging
      • Loading and Executing Shellcode From PE Resources
      • Process Hollowing and Portable Executable Relocations
      • APC Queue Code Injection
      • Early Bird APC Queue Code Injection
      • Shellcode Execution in a Local Process with QueueUserAPC and NtTestAlert
      • Shellcode Execution through Fibers
      • Shellcode Execution via CreateThreadpoolWait
      • Local Shellcode Execution without Windows APIs
      • Injecting to Remote Process via Thread Hijacking
      • SetWindowHookEx Code Injection
      • Finding Kernel32 Base and Function Addresses in Shellcode
      • Executing Shellcode with Inline Assembly in C/C++
      • Writing Custom Shellcode Encoders and Decoders
      • Backdooring PE Files with Shellcode
      • NtCreateSection + NtMapViewOfSection Code Injection
      • AddressOfEntryPoint Code Injection without VirtualAllocEx RWX
      • Module Stomping for Shellcode Injection
      • PE Injection: Executing PEs inside Remote Processes
      • API Monitoring and Hooking for Offensive Tooling
      • Windows API Hooking
      • Import Adress Table (IAT) Hooking
      • DLL Injection via a Custom .NET Garbage Collector
      • Writing and Compiling Shellcode in C
      • Injecting .NET Assembly to an Unmanaged Process
    • Defense Evasion
      • AV Bypass with Metasploit Templates and Custom Binaries
      • Evading Windows Defender with 1 Byte Change
      • Bypassing Windows Defender: One TCP Socket Away From Meterpreter and Beacon Sessions
      • Bypassing Cylance and other AVs/EDRs by Unhooking Windows APIs
      • Windows API Hashing in Malware
      • Detecting Hooked Syscalls
      • Calling Syscalls Directly from Visual Studio to Bypass AVs/EDRs
      • Retrieving ntdll Syscall Stubs from Disk at Run-time
      • Full DLL Unhooking with C++
      • Enumerating RWX Protected Memory Regions for Code Injection
      • Disabling Windows Event Logs by Suspending EventLog Service Threads
      • T1027: Obfuscated Powershell Invocations
      • Masquerading Processes in Userland via _PEB
      • Commandline Obfusaction
      • File Smuggling with HTML and JavaScript
      • T1099: Timestomping
      • T1096: Alternate Data Streams
      • T1158: Hidden Files
      • T1140: Encode/Decode Data with Certutil
      • Downloading Files with Certutil
      • T1045: Packed Binaries
      • Unloading Sysmon Driver
      • Bypassing IDS Signatures with Simple Reverse Shells
      • Preventing 3rd Party DLLs from Injecting into your Malware
      • ProcessDynamicCodePolicy: Arbitrary Code Guard (ACG)
      • Parent Process ID (PPID) Spoofing
      • Executing C# Assemblies from Jscript and wscript with DotNetToJscript
    • Enumeration and Discovery
      • Windows Event IDs and Others for Situational Awareness
      • Enumerating COM Objects and their Methods
      • Enumerating Users without net, Services without sc and Scheduled Tasks without schtasks
      • Enumerating Windows Domains with rpcclient through SocksProxy == Bypassing Command Line Logging
      • Dump GAL from OWA
      • T1010: Application Window Discovery
      • T1087: Account Discovery & Enumeration
      • Using COM to Enumerate Hostname, Username, Domain, Network Drives
      • Detecting Sysmon on the Victim Host
    • Privilege Escalation
      • T1134: Primary Access Token Manipulation
      • Windows NamedPipes 101 + Privilege Escalation
      • T1038: DLL Hijacking
      • T1108: WebShells
      • T1183: Image File Execution Options Injection
      • Unquoted Service Paths
      • Pass The Hash: Privilege Escalation with Invoke-WMIExec
      • Environment Variable $Path Interception
      • Weak Service Permissions
    • Credential Access & Dumping
      • Dumping Credentials from Lsass Process Memory with Mimikatz
      • Dumping Lsass Without Mimikatz
      • Dumping Lsass without Mimikatz with MiniDumpWriteDump
      • Dumping Hashes from SAM via Registry
      • Dumping SAM via esentutl.exe
      • Dumping LSA Secrets
      • Dumping and Cracking mscash - Cached Domain Credentials
      • Dumping Domain Controller Hashes Locally and Remotely
      • Dumping Domain Controller Hashes via wmic and Vssadmin Shadow Copy
      • Network vs Interactive Logons
      • Reading DPAPI Encrypted Secrets with Mimikatz and C++
      • T1214: Credentials in Registry
      • T1174: Password Filter
      • Forcing WDigest to Store Credentials in Plaintext
      • Dumping Delegated Default Kerberos and NTLM Credentials w/o Touching Lsass
      • Intercepting Logon Credentials via Custom Security Support Provider and Authentication Packages
      • Pulling Web Application Passwords by Hooking HTML Input Fields
      • Intercepting Logon Credentials by Hooking msv1_0!SpAcceptCredentials
      • Credentials Collection via CredUIPromptForCredentials
    • Lateral Movement
      • T1028: WinRM for Lateral Movement
      • WinRS for Lateral Movement
      • T1047: WMI for Lateral Movement
      • T1076: RDP Hijacking for Lateral Movement with tscon
      • T1051: Shared Webroot
      • T1175: Lateral Movement via DCOM
      • WMI + MSI Lateral Movement
      • Lateral Movement via Service Configuration Manager
      • Lateral Movement via SMB Relaying
      • WMI + NewScheduledTaskAction Lateral Movement
      • WMI + PowerShell Desired State Configuration Lateral Movement
      • Simple TCP Relaying with NetCat
      • Empire Shells with NetNLTMv2 Relaying
      • Lateral Movement with Psexec
      • From Beacon to Interactive RDP Session
      • SSH Tunnelling / Port Forwarding
      • Lateral Movement via WMI Event Subscription
      • Lateral Movement via DLL Hijacking
      • Lateral Movement over headless RDP with SharpRDP
      • ShadowMove: Lateral Movement by Duplicating Existing Sockets
    • Persistence
      • DLL Proxying for Persistence
      • T1053: Schtask
      • T1035: Service Execution
      • T1015: Sticky Keys
      • T1136: Create Account
      • T1013: AddMonitor()
      • T1128: NetSh Helper DLL
      • T1084: Abusing Windows Managent Instrumentation
        • WMI as a Data Storage
      • Windows Logon Helper
      • Hijacking Default File Extension
      • Persisting in svchost.exe with a Service DLL
      • Modifying .lnk Shortcuts
      • T1180: Screensaver Hijack
      • T1138: Application Shimming
      • T1197: BITS Jobs
      • T1122: COM Hijacking
      • T1198: SIP & Trust Provider Hijacking
      • T1209: Hijacking Time Providers
      • T1130: Installing Root Certificate
      • Powershell Profile Persistence
      • RID Hijacking
      • Word Library Add-Ins
      • Office Templates
    • Exfiltration
      • Powershell Payload Delivery via DNS using Invoke-PowerCloud
  • reversing, forensics & misc
    • Windows Internals
      • Configuring Kernel Debugging Environment with kdnet and WinDBG Preview
      • Compiling a Simple Kernel Driver, DbgPrint, DbgView
      • Loading Windows Kernel Driver for Debugging
      • Subscribing to Process Creation, Thread Creation and Image Load Notifications from a Kernel Driver
      • Listing Open Handles and Finding Kernel Object Addresses
      • Sending Commands From Your Userland Program to Your Kernel Driver using IOCTL
      • Windows Kernel Drivers 101
      • x64 Calling Convention: Stack Frame
      • System Service Descriptor Table - SSDT
      • Interrupt Descriptor Table - IDT
      • Token Abuse for Privilege Escalation in Kernel
      • Manipulating ActiveProcessLinks to Hide Processes in Userland
      • ETW: Event Tracing for Windows 101
      • Exploring Injected Threads
      • Parsing PE File Headers with C++
      • Instrumenting Windows APIs with Frida
      • Exploring Process Environment Block
    • Cloud
      • AWS Accounts, Users, Groups, Roles, Policies
    • Neo4j
    • Dump Virtual Box Memory
    • AES Encryption Using Crypto++ .lib in Visual Studio C++
    • Reversing Password Checking Routine
Powered by GitBook
On this page
  • At a Glance
  • IDT Location
  • Dumping IDT
  • IDT Entry
  • IDT Entry for the Keyboard Interrupt 0xa0
  • ISR for the Keyboard Interrupt a0
  • _KINTERRUPT
  • Finding _KINTERRUPT
  • References

Was this helpful?

  1. reversing, forensics & misc
  2. Windows Internals

Interrupt Descriptor Table - IDT

PreviousSystem Service Descriptor Table - SSDTNextToken Abuse for Privilege Escalation in Kernel

Last updated 4 years ago

Was this helpful?

At a Glance

  • Interrupts could be thought of as notifications to the CPU that tells it that some event happened on the system. Classic examples of interrupts are hardware interrupts such as mouse button or keyboard key presses, network packet activity and hardware generated exceptions such as a division by zero or a breakpoint - interrupts 0x00 and 0x03 respectively

  • Once the CPU gets interrupted, it stops doing what it was doing and responds to the new interrupt

  • CPU knows how to respond and what kernel routines to execute for the newly received interrupt by looking up Interrupt Service Routines (ISR) that are found in the Interrupt Descriptor Table (IDT)

  • IDT is a list of IDT descriptor entries which are 8 or 16 bytes in size depending on the architecture

  • Pointer to IDT is stored in an IDTR register for each physical processor or in other words, each processor has its own IDTR register pointing to its own Interrupt Descriptor Table

Offsets across different screenshots and windbg output may differ due to the fact that I rebooted the debugee a couple of times during the time these notes were taken.

The notes are based on debugging a kernel of a 64 bit Windows, running in a VM with 1 CPU.

IDT Location

We can check where the Interrupt Descriptor Table is located in kernel by reading the register IDTR:

r idtr

As noted later, the command !idt allows us to dump the Interrupt Descriptor Table contents and it also confirms that the IDT is located at fffff803`536dda00 as shown below:

Dumping IDT

We can dump the IDT and see addresses of Interrupt Service Routines for a given interrupt. Below is a snippet of the Interrupt Descriptor Table:

kd> !idt

Dumping IDT: fffff80091456000

00:    fffff8008f37e100 nt!KiDivideErrorFaultShadow
01:    fffff8008f37e180 nt!KiDebugTrapOrFaultShadow    Stack = 0xFFFFF8009145A9E0
02:    fffff8008f37e200 nt!KiNmiInterruptShadow    Stack = 0xFFFFF8009145A7E0
03:    fffff8008f37e280 nt!KiBreakpointTrapShadow
...
90:    fffff8008f37f680 i8042prt!I8042MouseInterruptService (KINTERRUPT ffffd4816353e8c0)
a0:    fffff8008f37f700 i8042prt!I8042KeyboardInterruptService (KINTERRUPT ffffd4816353ea00)
...

Below shows the IDT dumping and ISR code execution in action:

  • IDT table is dumped with !idt

  • IRS entry point for the interrupt a0 is located at fffff8008f37f700

    • This is the routine that gets executed first inside the kernel when a keyboard event such as a keypress is registered on the OS

    • Eventually, the routine i8042prt!I8042KeyboardInterruptService (inside the actual keyboard driver) is hit once the code at fffff8008f37f700 is finished

  • Putting a breakpoint on

    i8042prt!I8042KeyboardInterruptService

  • Once the breakpoint is set, a key is pressed on the OS login prompt and our breakpoint is hit, confirming that

    i8042prt!I8042KeyboardInterruptService indeed handles keyboard interrupts

Below is a heavily simplified diagram illustrating all of the above events taking place:

  • the keyboard interrupt 0xa0 occurs

  • after some hoops, the code is eventually redirected to the keyboard driver where the interrupt gets handled in i8042prt!I8042KeyboardInterruptService

IDT Entry

IDT is made up of IDT entries _KIDTENTRY64 which is a kernel memory structure and is defined like so:

kd> dt nt!_KIDTENTRY64
   +0x000 OffsetLow        : Uint2B
   +0x002 Selector         : Uint2B
   +0x004 IstIndex         : Pos 0, 3 Bits
   +0x004 Reserved0        : Pos 3, 5 Bits
   +0x004 Type             : Pos 8, 5 Bits
   +0x004 Dpl              : Pos 13, 2 Bits
   +0x004 Present          : Pos 15, 1 Bit
   +0x006 OffsetMiddle     : Uint2B
   +0x008 OffsetHigh       : Uint4B
   +0x00c Reserved1        : Uint4B
   +0x000 Alignment        : Uint8B

Members OffsetLow, OffsetMiddle and OffsetHigh at offsets 0x000, 0x006 and 0x008 make up the virtual address in the kernel and it's where the code execution will be transferred to by the CPU once that particular interrupt takes place - in other words - this is the Interrupt Service Routine's (ISR) entry point.

IDT Entry for the Keyboard Interrupt 0xa0

As an example, let's inspect the IDT entry for the keyboard interrupt which is located at index a0 in the IDT table as discovered earlier:

!idt a0

From earlier, we also know that the IDT resides at fffff803536dd000:

kd> r idtr
idtr=fffff803536dd000

We can get the location of the a0 IDT entry by adding 0xa0*0x10 (interrupt index a0 times 0x10 since a descriptor entry is 16 bytes in size) to the IDT table address fffff803536dd000, which gives us fffff803`536dda00:

kd> dq idtr + (0xa0*0x10) L2
fffff803`536dda00  51568e00`0010e700 00000000`fffff803

With the above information, we can overlay the a0 interrupt descriptor entry with _KIDTENTRY64 and inspect a0 IDT entry's content:

kd> dt _kidtentry64 (idtr + (0xa0*0x10))
ntdll!_KIDTENTRY64
   +0x000 OffsetLow        : 0xe700
   +0x002 Selector         : 0x10
   +0x004 IstIndex         : 0y000
   +0x004 Reserved0        : 0y00000 (0)
   +0x004 Type             : 0y01110 (0xe)
   +0x004 Dpl              : 0y00
   +0x004 Present          : 0y1
   +0x006 OffsetMiddle     : 0x5156
   +0x008 OffsetHigh       : 0xfffff803
   +0x00c Reserved1        : 0
   +0x000 Alignment        : 0x51568e00`0010e700

ISR for the Keyboard Interrupt a0

Below shows the instructions at fffff803`5156e700 (ISR entry point) to be executed by the CPU once interrupt a0 is triggered:

  • FFFFFFFFFFFFFFA0 will be pushed on the stack

  • jump to fffff803`5156ea40 will happen

...and eventually, the i8042prt!I8042KeyboardInterruptService will be hit and below confirms it - firstly, the breakpoint is hit for fffff803`5156e700 and i8042prt!I8042KeyboardInterruptService is hit immediately after:

_KINTERRUPT

_KINTERRUPT is a kernel memory structure that holds information about an interrupt. The key member of this structure for this lab is the member located at offset 0x18 - it's a pointer to the ServiceRoutine - the routine (inside the associated driver) that is responsible for actually handling the interrupt:

dt nt!_KINTERRUPT
   +0x000 Type             : Int2B
   +0x002 Size             : Int2B
   +0x008 InterruptListEntry : _LIST_ENTRY
   +0x018 ServiceRoutine   : Ptr64     unsigned char 
   ...
   +0x0f8 Padding          : [8] UChar

As an example - from earlier, we know that the ISR for keyboard interrupts is located at ffffd4816353ea00, therefore we can inspect the _KINTERRUPT structure of that our interrupt by overlaying it with memory contents at ffffd4816353ea00:

dt nt!_KINTERRUPT ffffd4816353ea00

This allows us to confirm that the ServiceRoutine is again pointing correctly to i8042prt!I8042KeyboardInterruptService inside the keyboard driver:

Finding _KINTERRUPT

In order to manually find the location of _KINTERRUPT for a given interrupt, we need to leverage the following memory locations and structures.

Process Control Region or PCR (_KPCR memory structure in kernel) stores information about a given processor:

kd> dt _KPCR
ntdll!_KPCR
   +0x000 NtTib            : _NT_TIB
   +0x000 GdtBase          : Ptr64 _KGDTENTRY64
   +0x008 TssBase          : Ptr64 _KTSS64
   +0x010 UserRsp          : Uint8B
   +0x018 Self             : Ptr64 _KPCR
   +0x020 CurrentPrcb      : Ptr64 _KPRCB
   +0x028 LockArray        : Ptr64 _KSPIN_LOCK_QUEUE
   +0x030 Used_Self        : Ptr64 Void
   +0x038 IdtBase          : Ptr64 _KIDTENTRY64
   +0x040 Unused           : [2] Uint8B
   +0x050 Irql             : UChar
   +0x051 SecondLevelCacheAssociativity : UChar
   +0x052 ObsoleteNumber   : UChar
   +0x053 Fill0            : UChar
   +0x054 Unused0          : [3] Uint4B
   +0x060 MajorVersion     : Uint2B
   +0x062 MinorVersion     : Uint2B
   +0x064 StallScaleFactor : Uint4B
   +0x068 Unused1          : [3] Ptr64 Void
   +0x080 KernelReserved   : [15] Uint4B
   +0x0bc SecondLevelCacheSize : Uint4B
   +0x0c0 HalReserved      : [16] Uint4B
   +0x100 Unused2          : Uint4B
   +0x108 KdVersionBlock   : Ptr64 Void
   +0x110 Unused3          : Ptr64 Void
   +0x118 PcrAlign1        : [24] Uint4B
   +0x180 Prcb             : _KPRCB

_KPCR location can be found like this:

kd> ? @$pcr
Evaluate expression: -8781847822336 = fffff803`51148000

kd> !pcr
KPCR for Processor 0 at fffff80351148000:
    Major 1 Minor 1
    NtTib.ExceptionList: fffff803536dffb0
        NtTib.StackBase: fffff803536de000
       NtTib.StackLimit: 0000000000000000
...snip...

Inside the _KPCR, at offset 0x180 there is a member that points to a Process Control Block memory structure _KPRCB which contains information about the state of a processor.

The key member we're interested when trying to find the _KINTERRUPT memory location for a given interrupt is InterruptObject as it contains a list of pointers to a list of _KINTERRUPT objects. InterrupObject is located at offset 0x2e80 as shown below:

kd> dt _KPRCB
ntdll!_KPRCB
   +0x000 MxCsr            : Uint4B
   +0x004 LegacyNumber     : UChar
   +0x005 ReservedMustBeZero : UChar
   ....
   +0x2e80 InterruptObject  : [256] Ptr64 Void //256 pointers max as noted earlier
   ....

With the above knowledge, we can now find the _KINTERRUPT location for the keyboard interrupt a0:

dt @$pcr nt!_KPCR Prcb.InterruptObject[a0]

Below confirms that the _KINTERRUPT for the interrupt a0 we found manually matches that given by the !idt command:

References

IDT table using index 0x0a is looked up () and the and code jumps to it

Based on the above IDT entry for the keyboard interrupt, the below that the combination of Offset(High|Middle|Low) form the virtual address of the Interrupt Service Routine (ISR) entry point - the code that will be executed when a0 interrupt is triggered by the keyboard:

IDT address + 0xa0 * 0x10
ISR Entry Point is resolved
re-enforces
Code Injection and API Hooking TechniquesSecurityXploded Blog
Logo
Kernel Interrupt Overview - Linux.comLinux.com
Kernel Interrupt Overview - Linux.comLinux.com
Interrupt handlerWikipedia
Hooking Series PART II: Interrupt Descriptor Table HookingReLearEx
Logo
Interrupt Descriptor Table - OSDev Wiki
Logo
CodeMachine - Interrupt Dispatching Internals
Logo
Logo
Fooling Windows about its internal CPU - Sina & Shahriar's BlogSina & Shahriar's Blog
Hooking IDT - Infosec ResourcesInfosec Resources
Logo
Logo
Logo
idtr register contains the same value seen when dumping IDT with !idt
Logo