Guida Windows Kernel Debugging come debuggare Windows

DispatchCode

Moderatore
24 Maggio 2016
500
14
377
249
Ultima modifica da un moderatore:

Windows kernel debugging: debuggare Windows​


1651563290506.png


In un precedente articolo sulla traduzione degli indirizzi virtuali in indirizzi fisici, ho riportato alcun output dove si vedevano informazioni su registri (come CR3), strutture interne, e altro ancora. Ho pensato di fare un passo indietro e riportare anche i passaggi per avere un ambiente sul quale è possibile effettuare il debugging.



1    Introduzione



Debuggare il kernel (o un driver) non è come debuggare un'applicazione utente. Quando si debugga un'applicazione utente utilizzando un debugger (GCC, OllyDbg, ImmunityDebugger, Windbg,...) il sistema continua ad eseguire le sue operazioni, solo l'applicazione in questione verrà interrotta; la stessa cosa non avviene quando si attacca un debugger a Windows. Collegando un debugger il sistema viene immediatamente freezato, non sarà più possibile eseguire alcuna operazione fintanto che non si comunichi tramite il debugger di riprendere l'esecuzione.

Per questo motivo il kernel debugging non si esegue sul medesimo OS. Ci sono tre alternative:
  • utilizzare un altro computer fisico
  • utilizzare una VM
  • utilizzare LiveKD
La terza strada è limitante, in quanto LiveKD è uno strumento (sviluppato da Russinovich) che consente di eseguire windbg sulla macchina locale così ad esempio da verificare un crash dump; sfortunatamente non sarà possibile eseguire altri comandi e si avrà una visione molto limitata. Per questo motivo l'unica strada comoda e a portata di tutti è utilizzare una VM.
Deciso questo, ora ci si trova di fronte a un'altra scelta:
  • debuggare tramite porta COM
  • debuggare usando la rete
In realtà la scelta è semplice: sceglieremo la rete, in quanto tramite porta COM il debug risulterà davvero molto lento. Inoltre potrà stupirvi, ma una volta tanto, la comunicazione tra host e target (la VM) non sarà così complicata da stabilire.

2    Strumenti


~ Virtual Machine ~​

La prima cosa che dovrete decidere è quale VM utilizzare. Io ho scelto VMWare Player in quanto è gratuito e fa bene il suo lavoro (inoltre mi trovo comodo); allo scopo penso che un'alternativa valga l'altra. Tuttavia non so quali configurazioni saranno necessarie sulle altre VM, quindi dovrete cercare in rete.

~ Windows 10 ISO ~​

La seconda cosa importante a questo punto è procurarsi Windows 10. Sino a qualche mese fa era disponibile un'immagine da importare per ciascuna VM più utilizzata (VMWare, VirtualBox, Hyper-V), ma sfortunatamente... trovrete solo Windows 11. Quindi vi consiglio di scaricare la ISO direttamente dal Media Creation Tool. Prestate attenzione all'architettura: io darò per scontato che host e target saranno Windows 10 x64.

~ Windows Debugging ~​

A questo punto scaricate l'SDK dal sito Microsoft, Windows 10 SDK, e avviate l'applicazione. Vi troverete di fronte ad una schermata analoga:

winsdk1.png


dovrete deselezionare tutto, lasciando la spunta solo sulla voce Debugging Tools for Windows.

~ Debugger ~​

Io ho scelto WinDbg Preview, lo trovere sullo store Microsoft. E' in sostanza una GUI su Windbg.

3    Avviamo il target (VM)



A questo punto avrete scaricato la VM con Win 10 x64. Riservatele quante risorse volete. Nella tab dedicata alla rete (Network), va benissimo quello che dovreste avere di default, ovvero:

vm_net_setup.png


Una volta avviata la VM è necessario abilitare il debug. Avviate il prompt dei comandi come amministratore e digitate:

Codice:
bcdedit /debug on

fatto questo dovrete riavviare la VM.
Se non lo avete fatto, installate anche i Tools di VMWare, vi saranno utili (per il copy & paste, specialmente).

Per essere sicuri che host e target comunicano, aprite il terminale sull'host e digitate ipconfig. Nel mio caso ho questo output:
Codice:
Configurazione IP di Windows


Scheda Ethernet vEthernet (Default Switch):

   Suffisso DNS specifico per connessione:
   Indirizzo IPv6 locale rispetto al collegamento . : fe80::d9fe:ed04:a53d:3c42%32
   Indirizzo IPv4. . . . . . . . . . . . : 172.24.128.1
   Subnet mask . . . . . . . . . . . . . : 255.255.240.0
   Gateway predefinito . . . . . . . . . :

Scheda Ethernet Ethernet 2:

   Stato supporto. . . . . . . . . . . . : Supporto disconnesso
   Suffisso DNS specifico per connessione: fritz.box

Scheda LAN wireless Connessione alla rete locale (LAN)* 1:

   Stato supporto. . . . . . . . . . . . : Supporto disconnesso
   Suffisso DNS specifico per connessione:

Scheda LAN wireless Connessione alla rete locale (LAN)* 10:

   Stato supporto. . . . . . . . . . . . : Supporto disconnesso
   Suffisso DNS specifico per connessione:

Scheda Ethernet VMware Network Adapter VMnet1:

   Suffisso DNS specifico per connessione:
   Indirizzo IPv6 locale rispetto al collegamento . : fe80::59c4:d251:c7e8:e2f4%8
   Indirizzo IPv4. . . . . . . . . . . . : 192.168.74.1
   Subnet mask . . . . . . . . . . . . . : 255.255.255.0
   Gateway predefinito . . . . . . . . . :

Scheda Ethernet VMware Network Adapter VMnet8:

   Suffisso DNS specifico per connessione:
   Indirizzo IPv6 locale rispetto al collegamento . : fe80::9a3:7317:1038:dc61%6
   Indirizzo IPv4. . . . . . . . . . . . : 192.168.21.1
   Subnet mask . . . . . . . . . . . . . : 255.255.255.0
   Gateway predefinito . . . . . . . . . :

Scheda LAN wireless Wi-Fi:

   Suffisso DNS specifico per connessione:
   Indirizzo IPv6 . . . . . . . . . . . . . . . . . : fde7:ea6f:4237:0:700c:da42:4003:3b70
   Indirizzo IPv6 temporaneo. . . . . . . . . . . . : fde7:ea6f:4237:0:acb6:fa49:4afe:2bf2
   Indirizzo IPv6 locale rispetto al collegamento . : fe80::700c:da42:4003:3b70%19
   Indirizzo IPv4. . . . . . . . . . . . : 192.168.1.129
   Subnet mask . . . . . . . . . . . . . : 255.255.255.0
   Gateway predefinito . . . . . . . . . : 192.168.1.1

Scheda Ethernet vEthernet (WSL):

   Suffisso DNS specifico per connessione:
   Indirizzo IPv6 locale rispetto al collegamento . : fe80::249f:31f4:b1fe:13f6%50
   Indirizzo IPv4. . . . . . . . . . . . : 172.26.32.1
   Subnet mask . . . . . . . . . . . . . : 255.255.240.0

Voi avrete probabilmente meno interfacce, ma dipende ad esempio se avete abilitato WSL oppure no etc etc.
L'IP che dovrete annotare è quello alla voce Ethernet VMWare Network Adapter, nel mio caso: 192.168.74.1.

Andate sulla VM, aprite un prompt come amministratori e digitate:
Codice:
ping -4 <vostro-ip>

se i pacchetti raggiungeranno il destinatario, allora la comunicazione tra host e target è stabilita.
Ora tornate sull'host e recatevi nella cartella in cui avete installato i tools per il debugging. Il percorso dovrebbe essere questo:

Codice:
C:\Program Files (x86)\Windows Kits\10\Debuggers\x64

dovrete copiare 2 files, chiamati VerifiedNICList.xml e kdnet.exe, e incollarli sul desktop della VM (o dove preferite).

Se non avete più una finestra del prompt aperta da amministratore (sulla VM), lanciatela. Andate nella cartella in cui avete incollato kdnet e lanciatelo passandogli l'IP visto in precedenza, e una porta [50000, 50039].
Di seguito vedrete il mio input, e l'output di kdnet:

Codice:
C:\Users\DispatchCode\Desktop>kdnet 192.168.74.1 50010

Enabling network debugging on Intel(R) 82574L Gigabit Network Connection.

To debug this machine, run the following command on your debugger host machine.
windbg -k net:port=50010,key=27vh8lqc6awhx.303bt4zycitsc.1duw3o5kopk8o.21cwx8lsfqdi2

Then reboot this machine by running shutdown -r -t 0 from this command prompt.

Qui l'output dà per scontato che utilizziamo windbg, mai in realtà nel nostro caso - nel mio almeno - abbiamo Windbg Preview. Annotatevi il suo output per intero (incollatelo ad esempio su notepad, sull'host).

4    Connessione tramite debugger



A questo punto ci siamo. Aprite il debugger e riportate le informazioni; sotto il mio screen:

windbg_preview_file.png


Premete OK. Nella finestra di output sul debugger dovreste vedere qualcosa di analogo:

Codice:
Microsoft (R) Windows Debugger Version 10.0.22549.1000 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.

Using NET for debugging
Opened WinSock 2.0
Waiting to reconnect...
Connected to target 192.168.1.129 on port 50005 on local IP 192.168.1.129.
You can get the target MAC address by running .kdtargetmac command.
Connected to Windows 10 19041 x64 target at (Sat Apr 30 18:10:16.792 2022 (UTC + 2:00)), ptr64 TRUE
Kernel Debugger connection established.

************* Path validation summary **************
Response                         Time (ms)     Location
Deferred                                       SRV*c:\Symbols*http://msdl.microsoft.com/download/symbols
Symbol search path is: SRV*c:\Symbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
Windows 10 Kernel Version 19041 MP (4 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Edition build lab: 19041.1.amd64fre.vb_release.191206-1406
Machine Name:
Kernel base = 0xfffff807`4ec00000 PsLoadedModuleList = 0xfffff807`4f82a270
Debug session time: Sat Apr 30 18:10:16.866 2022 (UTC + 2:00)
System Uptime: 0 days 0:01:18.402
Break instruction exception - code 80000003 (first chance)
*******************************************************************************
*                                                                             *
*   You are seeing this message because you pressed either                    *
*       CTRL+C (if you run console kernel debugger) or,                       *
*       CTRL+BREAK (if you run GUI kernel debugger),                          *
*   on your debugger machine's keyboard.                                      *
*                                                                             *
*                   THIS IS NOT A BUG OR A SYSTEM CRASH                       *
*                                                                             *
* If you did not intend to break into the debugger, press the "g" key, then   *
* press the "Enter" key now.  This message might immediately reappear.  If it *
* does, press "g" and "Enter" again.                                          *
*                                                                             *
*******************************************************************************
nt!DbgBreakPointWithStatus:
fffff807`4efff050 cc              int     3

Microsoft (R) Windows Debugger Version 10.0.22549.1000 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.

Using NET for debugging
Opened WinSock 2.0
Waiting to reconnect...

a questo punto, sul terminale che avrete ancora aperto sulla VM, lanciate shutdown -r -t 0.

Una volta riavviato l'OS target, il debugger mi segnala una connessione:

Codice:
Connected to target 192.168.74.1 on port 50010 on local IP 192.168.74.1.
You can get the target MAC address by running .kdtargetmac command.
Connected to Windows 10 19041 x64 target at (Sat Apr 30 19:32:15.489 2022 (UTC + 2:00)), ptr64 TRUE
Kernel Debugger connection established.

************* Path validation summary **************
Response                         Time (ms)     Location
Deferred                                       SRV*c:\Symbols*http://msdl.microsoft.com/download/symbols
Symbol search path is: SRV*c:\Symbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
Windows 10 Kernel Version 19041 MP (1 procs) Free x64
Edition build lab: 19041.1.amd64fre.vb_release.191206-1406
Machine Name:
Kernel base = 0xfffff802`3e800000 PsLoadedModuleList = 0xfffff802`3f42a230
System Uptime: 0 days 0:00:00.961
minio\security\base\lsa\security\driver\asyncsspi.cxx - SspiInitAsyncInterface
IOINIT: Built-in driver \Driver\hwpolicy failed to initialize with status - 0xC000025E
KDTARGET: Refreshing KD connection

Arrivati a questo punto, vedrete nella casella di input dei comandi (0: kd>) la scritta "Debugger is running...". Dal menu in alto premete Break:

Codice:
Break instruction exception - code 80000003 (first chance)
*******************************************************************************
*                                                                             *
*   You are seeing this message because you pressed either                    *
*       CTRL+C (if you run console kernel debugger) or,                       *
*       CTRL+BREAK (if you run GUI kernel debugger),                          *
*   on your debugger machine's keyboard.                                      *
*                                                                             *
*                   THIS IS NOT A BUG OR A SYSTEM CRASH                       *
*                                                                             *
* If you did not intend to break into the debugger, press the "g" key, then   *
* press the "Enter" key now.  This message might immediately reappear.  If it *
* does, press "g" and "Enter" again.                                          *
*                                                                             *
*******************************************************************************
nt!DbgBreakPointWithStatus:
fffff802`3ebff740 cc              int     3

nell'output vedrete questo.

5    Kernel debugging



Prima di iniziare, clickate su File > Settings e inserite nel campo di testo "Symbol Path" il percorso SRV*c:\Symbols*http://msdl.microsoft.com/download/symbols, poi premete Ok; create sull'host la cartella Symbols in C:\. Potete scegliere anche un altro percorso, l'importante è che andrete poi a modificare il percorso inserito in windbg.
A questo punto come input al debugger date .reload /f. Questo forzerà il reload dei simboli; questi consentono di vedere i nomi delle funzioni e contengono altre informazioni.

Tutto il necessario è installato. Ora iniziamo a giocare: premete Go, lasciando continuare l'esecuzione. Andate sul target e aprite Notepad, poi tornate sul debugger, e premete Break; noterete tutto freezato sul target. Elencate i processi in esecuzione con:

Codice:
!process 0 0 Notepad.exe

nel mio caso:

Codice:
PROCESS ffffc8033c98e080
    SessionId: 1  Cid: 21bc    Peb: 41c271c000  ParentCid: 1230
    DirBase: 11c4a9002  ObjectTable: ffffdd8edf3e8d00  HandleCount: 244.
    Image: notepad.exe

la struttura che rappresenta un processo in Windows si chiama EPROCESS; potete vedere i campi che la compongono con dt nt!_EPROCESS e potete vedere quella che rappresenta il processo in questione con dt nt!_EPROCESS ffffc8033c98e080 (l'indirizzo è preso dall'output sopra).
Bene, a questo punto, andiamo a guardare anche l'header di questa immagine, per farlo ci serve l'image base address ; dall'output precedente, clickate sul PEB. A questo punto vedrete un campo chiamato ImageBaseAddress: copiatene l'indirizzo.

Codice:
0: kd> !dh 00007ff7105f0000

File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
    8664 machine (X64)
       7 number of sections
4178AED3 time date stamp Fri Oct 22 08:55:15 2004

       0 file pointer to symbol table
       0 number of symbols
      F0 size of optional header
      22 characteristics
            Executable
            App can handle >2gb addresses

OPTIONAL HEADER VALUES
     20B magic #
   14.20 linker version
   24A00 size of code
    E000 size of initialized data
       0 size of uninitialized data
   24050 address of entry point
    1000 base of code
         ----- new -----
00007ff7105f0000 image base
    1000 section alignment
     200 file alignment
       2 subsystem (Windows GUI)
   10.00 operating system version
   10.00 image version
   10.00 subsystem version
   38000 size of image
     400 size of headers
   37B81 checksum
0000000000080000 size of stack reserve
0000000000011000 size of stack commit
0000000000100000 size of heap reserve
0000000000001000 size of heap commit
    C160  DLL characteristics
            High entropy VA supported
            Dynamic base
            NX compatible
            Guard
            Terminal server aware
       0 [       0] address [size] of Export Directory
   2D0A8 [     244] address [size] of Import Directory
   36000 [     BD8] address [size] of Resource Directory
   33000 [    10EC] address [size] of Exception Directory
       0 [       0] address [size] of Security Directory
   37000 [     2D4] address [size] of Base Relocation Directory
   2AC20 [      54] address [size] of Debug Directory
       0 [       0] address [size] of Description Directory
       0 [       0] address [size] of Special Directory
       0 [       0] address [size] of Thread Storage Directory
   266D0 [     118] address [size] of Load Configuration Directory
       0 [       0] address [size] of Bound Import Directory
   267E8 [     900] address [size] of Import Address Table Directory
   2C9C0 [      E0] address [size] of Delay Import Directory
       0 [       0] address [size] of COR20 Header Directory
       0 [       0] address [size] of Reserved Directory


SECTION HEADER #1
   .text name
   2490F virtual size
    1000 virtual address
   24A00 size of raw data
     400 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
60000020 flags
         Code
         (no align specified)
         Execute Read

SECTION HEADER #2
  .rdata name
    9268 virtual size
   26000 virtual address
    9400 size of raw data
   24E00 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
40000040 flags
         Initialized Data
         (no align specified)
         Read Only


Debug Directories(3)
    Type       Size     Address  Pointer
    cv           24       2b4e4    2a2e4    Format: RSDS, guid, 1, notepad.pdb
    (   13)     43c       2b508    2a308
    (   16)      24       2b944    2a744

SECTION HEADER #3
   .data name
    2738 virtual size
   30000 virtual address
     E00 size of raw data
   2E200 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
C0000040 flags
         Initialized Data
         (no align specified)
         Read Write

SECTION HEADER #4
  .pdata name
    10EC virtual size
   33000 virtual address
    1200 size of raw data
   2F000 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
40000040 flags
         Initialized Data
         (no align specified)
         Read Only

SECTION HEADER #5
  .didat name
     178 virtual size
   35000 virtual address
     200 size of raw data
   30200 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
C0000040 flags
         Initialized Data
         (no align specified)
         Read Write

SECTION HEADER #6
   .rsrc name
     BD8 virtual size
   36000 virtual address
     C00 size of raw data
   30400 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
40000040 flags
         Initialized Data
         (no align specified)
         Read Only

SECTION HEADER #7
  .reloc name
     2D4 virtual size
   37000 virtual address
     400 size of raw data
   31000 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
42000040 flags
         Initialized Data
         Discardable
         (no align specified)
         Read Only

E' anche possibile visualizzare la Interrupt Dispatch Table utilizzando !idt:

Codice:
0: kd> !idt

Dumping IDT: fffff8073a862000

00:    fffff80737812100 nt!KiDivideErrorFaultShadow
01:    fffff80737812180 nt!KiDebugTrapOrFaultShadow    Stack = 0xFFFFF8073A8669D0
02:    fffff80737812240 nt!KiNmiInterruptShadow    Stack = 0xFFFFF8073A8667D0
03:    fffff807378122c0 nt!KiBreakpointTrapShadow
04:    fffff80737812340 nt!KiOverflowTrapShadow
05:    fffff807378123c0 nt!KiBoundFaultShadow
06:    fffff80737812440 nt!KiInvalidOpcodeFaultShadow
07:    fffff807378124c0 nt!KiNpxNotAvailableFaultShadow
08:    fffff80737812540 nt!KiDoubleFaultAbortShadow    Stack = 0xFFFFF8073A8663D0
09:    fffff807378125c0 nt!KiNpxSegmentOverrunAbortShadow
0a:    fffff80737812640 nt!KiInvalidTssFaultShadow
0b:    fffff807378126c0 nt!KiSegmentNotPresentFaultShadow
0c:    fffff80737812740 nt!KiStackFaultShadow
0d:    fffff807378127c0 nt!KiGeneralProtectionFaultShadow
0e:    fffff80737812840 nt!KiPageFaultShadow
10:    fffff807378128c0 nt!KiFloatingErrorFaultShadow
11:    fffff80737812940 nt!KiAlignmentFaultShadow
12:    fffff807378129c0 nt!KiMcheckAbortShadow    Stack = 0xFFFFF8073A8665D0
13:    fffff80737812ac0 nt!KiXmmExceptionShadow
14:    fffff80737812b40 nt!KiVirtualizationExceptionShadow
15:    fffff80737812bc0 nt!KiControlProtectionFaultShadow
1f:    fffff80737812c40 nt!KiApcInterruptShadow
20:    fffff80737812cc0 nt!KiSwInterruptShadow
29:    fffff80737812d40 nt!KiRaiseSecurityCheckFailureShadow
2c:    fffff80737812dc0 nt!KiRaiseAssertionShadow
2d:    fffff80737812e40 nt!KiDebugServiceTrapShadow
2f:    fffff80737812f40 nt!KiDpcInterruptShadow
30:    fffff80737812fc0 nt!KiHvInterruptShadow
31:    fffff80737813040 nt!KiVmbusInterrupt0Shadow
32:    fffff807378130c0 nt!KiVmbusInterrupt1Shadow
33:    fffff80737813140 nt!KiVmbusInterrupt2Shadow
34:    fffff807378131c0 nt!KiVmbusInterrupt3Shadow
35:    fffff80737813468 nt!HalpInterruptCmciService (KINTERRUPT fffff80737af2f40)

36:    fffff80737813470 nt!HalpInterruptCmciService (KINTERRUPT fffff80737af3180)

50:    fffff80737813540 pci!ExpressRootPortMessageRoutine (KINTERRUPT ffff89017ef0b3c0)

51:    fffff80737813548 pci!ExpressRootPortMessageRoutine (KINTERRUPT ffff89017ef0b500)

52:    fffff80737813550 stornvme!NVMeHwMSIInterrupt (STORPORT) (KINTERRUPT ffff89017f53aa00)

53:    fffff80737813558 HDAudBus!HdaController::Isr (KINTERRUPT ffff89017ef64b40)

60:    fffff807378135c0 serial!SerialCIsrSw (KINTERRUPT ffff89017f53a8c0)

61:    fffff807378135c8 pci!ExpressRootPortMessageRoutine (KINTERRUPT ffff89017ef0b640)

62:    fffff807378135d0 stornvme!NVMeHwMSIInterrupt (STORPORT) (KINTERRUPT ffff89017f53ab40)

63:    fffff807378135d8 USBPORT!USBPORT_InterruptService (KINTERRUPT ffff89017f53a3c0)

                     dxgkrnl!DpiFdoLineInterruptRoutine (KINTERRUPT ffff89017ef64a00)

70:    fffff80737813640 i8042prt!I8042MouseInterruptService (KINTERRUPT ffff89017f53a640)

71:    fffff80737813648 pci!ExpressRootPortMessageRoutine (KINTERRUPT ffff89017ef0b780)

72:    fffff80737813650 storahci!AhciHwMSIInterrupt (STORPORT) (KINTERRUPT ffff89017f53ac80)

73:    fffff80737813658 USBXHCI!Interrupter_WdfEvtInterruptIsr (KMDF) (KINTERRUPT ffff89017ef64c80)

80:    fffff807378136c0 i8042prt!I8042KeyboardInterruptService (KINTERRUPT ffff89017f53a780)

81:    fffff807378136c8 pci!ExpressRootPortMessageRoutine (KINTERRUPT ffff89017ef0b8c0)

82:    fffff807378136d0 vmci!DllInitialize+0x1c10 (KINTERRUPT ffff89017ef0b140)

83:    fffff807378136d8 USBXHCI!Interrupter_WdfEvtInterruptIsr (KMDF) (KINTERRUPT ffff89017ef64dc0)

91:    fffff80737813748 pci!ExpressRootPortMessageRoutine (KINTERRUPT ffff89017ef0ba00)

92:    fffff80737813750 vmci!DllInitialize+0x1c10 (KINTERRUPT ffff89017ef0b280)

93:    fffff80737813758 USBXHCI!Interrupter_WdfEvtInterruptIsr (KMDF) (KINTERRUPT ffff89017f53a000)

a1:    fffff807378137c8 pci!ExpressRootPortMessageRoutine (KINTERRUPT ffff89017ef0bb40)

a2:    fffff807378137d0 ataport!IdePortInterrupt (KINTERRUPT ffff89017f53adc0)

a3:    fffff807378137d8 USBXHCI!Interrupter_WdfEvtInterruptIsr (KMDF) (KINTERRUPT ffff89017f53a140)

b0:    fffff80737813840 ACPI!ACPIInterruptServiceRoutine (KINTERRUPT ffff89017ef0bdc0)

b1:    fffff80737813848 pci!ExpressRootPortMessageRoutine (KINTERRUPT ffff89017ef0bc80)

b2:    fffff80737813850 ataport!IdePortInterrupt (KINTERRUPT ffff89017ef0b000)

b3:    fffff80737813858 USBXHCI!Interrupter_WdfEvtInterruptIsr (KMDF) (KINTERRUPT ffff89017f53a280)

b4:    fffff80737813860 USBPORT!USBPORT_InterruptService (KINTERRUPT ffff89017f53a500)

ce:    fffff80737813930 nt!HalpIommuInterruptRoutine (KINTERRUPT fffff80737af3ba0)

d1:    fffff80737813948 nt!HalpTimerClockInterrupt (KINTERRUPT fffff80737af3960)

d2:    fffff80737813950 nt!HalpTimerClockIpiRoutine (KINTERRUPT fffff80737af3840)

d7:    fffff80737813978 nt!HalpInterruptRebootService (KINTERRUPT fffff80737af3600)

d8:    fffff80737813980 nt!HalpInterruptStubService (KINTERRUPT fffff80737af33c0)

df:    fffff807378139b8 nt!HalpInterruptSpuriousService (KINTERRUPT fffff80737af32a0)

e1:    fffff80737813240 nt!KiIpiInterruptShadow
e2:    fffff807378139d0 nt!HalpInterruptLocalErrorService (KINTERRUPT fffff80737af34e0)

e3:    fffff807378139d8 nt!HalpInterruptDeferredRecoveryService (KINTERRUPT fffff80737af3060)

fd:    fffff80737813aa8 nt!HalpTimerProfileInterrupt (KINTERRUPT fffff80737af3a80)

fe:    fffff80737813ab0 nt!HalpPerfInterrupt (KINTERRUPT fffff80737af3720)

Questa tabella viene utilizzata per la gestione di eccezioni, interrupt software e interrupt hardware. Il puntatore alla struttura base è mantenuto in un registro chiamato idt, che possiamo ovviamente leggere:
Codice:
0: kd> r @idtr
idtr=fffff8073a862000

Ho preso come esempio l'interrupt della tastiera (i8042prt); come nel caso dei processi, è possibile guardare questa struttura (KINTERRUPT):
Codice:
0: kd> dt nt!_KINTERRUPT ffff89017f53a780
   +0x000 Type             : 0n22
   +0x002 Size             : 0n288
   +0x008 InterruptListEntry : _LIST_ENTRY [ 0x00000000`00000000 - 0x00000000`00000000 ]
   +0x018 ServiceRoutine   : 0xfffff807`3c586790     unsigned char  i8042prt!I8042KeyboardInterruptService+0
   +0x020 MessageServiceRoutine : (null)
   +0x028 MessageIndex     : 0
   +0x030 ServiceContext   : 0xffffb388`4ccd7780 Void
   +0x038 SpinLock         : 0
   +0x040 TickCount        : 0
   +0x048 ActualLock       : 0xffffb388`4ccd78e0  -> 0
   +0x050 DispatchAddress  : 0xfffff807`371f9360     void  nt!KiInterruptDispatch+0
   +0x058 Vector           : 0x80
   +0x05c Irql             : 0x8 ''
   +0x05d SynchronizeIrql  : 0x8 ''
   +0x05e FloatingSave     : 0 ''
   +0x05f Connected        : 0x1 ''
   +0x060 Number           : 0
   +0x064 ShareVector      : 0 ''
   +0x065 EmulateActiveBoth : 0 ''
   +0x066 ActiveCount      : 0
   +0x068 InternalState    : 0n0
   +0x06c Mode             : 1 ( Latched )
   +0x070 Polarity         : 0 ( InterruptPolarityUnknown )
   +0x074 ServiceCount     : 0
   +0x078 DispatchCount    : 0
   +0x080 PassiveEvent     : (null)
   +0x088 TrapFrame        : 0xffff810e`a75a1b00 _KTRAP_FRAME
   +0x090 DisconnectData   : (null)
   +0x098 ServiceThread    : (null)
   +0x0a0 ConnectionData   : 0xffffb388`4cd52d60 _INTERRUPT_CONNECTION_DATA
   +0x0a8 IntTrackEntry    : 0xffffb388`4cd1b920 Void
   +0x0b0 IsrDpcStats      : _ISRDPCSTATS
   +0x110 RedirectObject   : (null)
   +0x118 PhysicalDeviceObject : (null)

Possiamo anche fare riferimento a una singola entry della tabella (ho considerato sempre la tastiera, che si trova all'indice 0x80):

Codice:
0: kd> dt @idtr + @@c++(0x80 * sizeof(nt!_KIDTENTRY64)) nt!_KIDTENTRY64
   +0x000 OffsetLow        : 0x36c0
   +0x002 Selector         : 0x10
   +0x004 IstIndex         : 0y000
   +0x004 Reserved0        : 0y00000 (0)
   +0x004 Type             : 0y01110 (0xe)
   +0x004 Dpl              : 0y00
   +0x004 Present          : 0y1
   +0x006 OffsetMiddle     : 0x3781
   +0x008 OffsetHigh       : 0xfffff807
   +0x00c Reserved1        : 0
   +0x000 Alignment        : 0x37818e00`001036c0

L'indirizzo che verrà invocato si compone dei 3 indici Low, Middle e Hight 0xfffff807378136c0; disassemblando il codice a quell'indirizzo, si trova:

Codice:
0: kd> u 0xfffff807378136c0
nt!KiIsrThunkShadow+0x400:
fffff807`378136c0 6a80            push    0FFFFFFFFFFFFFF80h
fffff807`378136c2 e939040000      jmp     nt!KxIsrLinkageShadow (fffff807`37813b00)
fffff807`378136c7 cc              int     3
fffff807`378136c8 6a81            push    0FFFFFFFFFFFFFF81h
fffff807`378136ca e931040000      jmp     nt!KxIsrLinkageShadow (fffff807`37813b00)
fffff807`378136cf cc              int     3
fffff807`378136d0 6a82            push    0FFFFFFFFFFFFFF82h
fffff807`378136d2 e929040000      jmp     nt!KxIsrLinkageShadow (fffff807`37813b00)

la presenza di questa funzione chiamata Shadow, è dovuta al fix di Meltdown (KVA Shadow mitigating meltdown on Windows).

6    Conclusione



In conclusione vi lascio alcuni link, in primis la debugger reference, che contiene i vari comandi per interagire con windbg e tante altre info. Come seconda risorsa un approfondimento sulla IDT e sulle interrupt software: Interrupt Dispatching e Windows Kernel, che tratta anche le system call e la IDT (e faccio notare che lavora in Offensive Security).
 

Allegati

  • 1651563171589.png
    1651563171589.png
    318.4 KB · Visualizzazioni: 5
  • 1651563235800.png
    1651563235800.png
    399.3 KB · Visualizzazioni: 4

Windows kernel debugging: debuggare Windows​



In un precedente articolo sulla traduzione degli indirizzi virtuali in indirizzi fisici, ho riportato alcun output dove si vedevano informazioni su registri (come CR3), strutture interne, e altro ancora. Ho pensato di fare un passo indietro e riportare anche i passaggi per avere un ambiente sul quale è possibile effettuare il debugging.



1    Introduzione



Debuggare il kernel (o un driver) non è come debuggare un'applicazione utente. Quando si debugga un'applicazione utente utilizzando un debugger (GCC, OllyDbg, ImmunityDebugger, Windbg,...) il sistema continua ad eseguire le sue operazioni, solo l'applicazione in questione verrà interrotta; la stessa cosa non avviene quando si attacca un debugger a Windows. Collegando un debugger il sistema viene immediatamente freezato, non sarà più possibile eseguire alcuna operazione fintanto che non si comunichi tramite il debugger di riprendere l'esecuzione.

Per questo motivo il kernel debugging non si esegue sul medesimo OS. Ci sono tre alternative:
  • utilizzare un altro computer fisico
  • utilizzare una VM
  • utilizzare LiveKD
La terza strada è limitante, in quanto LiveKD è uno strumento (sviluppato da Russinovich) che consente di eseguire windbg sulla macchina locale così ad esempio da verificare un crash dump; sfortunatamente non sarà possibile eseguire altri comandi e si avrà una visione molto limitata. Per questo motivo l'unica strada comoda e a portata di tutti è utilizzare una VM.
Deciso questo, ora ci si trova di fronte a un'altra scelta:
  • debuggare tramite porta COM
  • debuggare usando la rete
In realtà la scelta è semplice: sceglieremo la rete, in quanto tramite porta COM il debug risulterà davvero molto lento. Inoltre potrà stupirvi, ma una volta tanto, la comunicazione tra host e target (la VM) non sarà così complicata da stabilire.

2    Strumenti


~ Virtual Machine ~​

La prima cosa che dovrete decidere è quale VM utilizzare. Io ho scelto VMWare Player in quanto è gratuito e fa bene il suo lavoro (inoltre mi trovo comodo); allo scopo penso che un'alternativa valga l'altra. Tuttavia non so quali configurazioni saranno necessarie sulle altre VM, quindi dovrete cercare in rete.

~ Windows 10 ISO ~​

La seconda cosa importante a questo punto è procurarsi Windows 10. Sino a qualche mese fa era disponibile un'immagine da importare per ciascuna VM più utilizzata (VMWare, VirtualBox, Hyper-V), ma sfortunatamente... trovrete solo Windows 11. Quindi vi consiglio di scaricare la ISO direttamente dal Media Creation Tool. Prestate attenzione all'architettura: io darò per scontato che host e target saranno Windows 10 x64.

~ Windows Debugging ~​

A questo punto scaricate l'SDK dal sito Microsoft, Windows 10 SDK, e avviate l'applicazione. Vi troverete di fronte ad una schermata analoga:

Visualizza allegato 62253

dovrete deselezionare tutto, lasciando la spunta solo sulla voce Debugging Tools for Windows.

~ Debugger ~​

Io ho scelto WinDbg Preview, lo trovere sullo store Microsoft. E' in sostanza una GUI su Windbg.

3    Avviamo il target (VM)



A questo punto avrete scaricato la VM con Win 10 x64. Riservatele quante risorse volete. Nella tab dedicata alla rete (Network), va benissimo quello che dovreste avere di default, ovvero:

Visualizza allegato 62254

Una volta avviata la VM è necessario abilitare il debug. Avviate il prompt dei comandi come amministratore e digitate:

Codice:
bcdedit /debug on

fatto questo dovrete riavviare la VM.
Se non lo avete fatto, installate anche i Tools di VMWare, vi saranno utili (per il copy & paste, specialmente).

Per essere sicuri che host e target comunicano, aprite il terminale sull'host e digitate ipconfig. Nel mio caso ho questo output:
Codice:
Configurazione IP di Windows


Scheda Ethernet vEthernet (Default Switch):

   Suffisso DNS specifico per connessione:
   Indirizzo IPv6 locale rispetto al collegamento . : fe80::d9fe:ed04:a53d:3c42%32
   Indirizzo IPv4. . . . . . . . . . . . : 172.24.128.1
   Subnet mask . . . . . . . . . . . . . : 255.255.240.0
   Gateway predefinito . . . . . . . . . :

Scheda Ethernet Ethernet 2:

   Stato supporto. . . . . . . . . . . . : Supporto disconnesso
   Suffisso DNS specifico per connessione: fritz.box

Scheda LAN wireless Connessione alla rete locale (LAN)* 1:

   Stato supporto. . . . . . . . . . . . : Supporto disconnesso
   Suffisso DNS specifico per connessione:

Scheda LAN wireless Connessione alla rete locale (LAN)* 10:

   Stato supporto. . . . . . . . . . . . : Supporto disconnesso
   Suffisso DNS specifico per connessione:

Scheda Ethernet VMware Network Adapter VMnet1:

   Suffisso DNS specifico per connessione:
   Indirizzo IPv6 locale rispetto al collegamento . : fe80::59c4:d251:c7e8:e2f4%8
   Indirizzo IPv4. . . . . . . . . . . . : 192.168.74.1
   Subnet mask . . . . . . . . . . . . . : 255.255.255.0
   Gateway predefinito . . . . . . . . . :

Scheda Ethernet VMware Network Adapter VMnet8:

   Suffisso DNS specifico per connessione:
   Indirizzo IPv6 locale rispetto al collegamento . : fe80::9a3:7317:1038:dc61%6
   Indirizzo IPv4. . . . . . . . . . . . : 192.168.21.1
   Subnet mask . . . . . . . . . . . . . : 255.255.255.0
   Gateway predefinito . . . . . . . . . :

Scheda LAN wireless Wi-Fi:

   Suffisso DNS specifico per connessione:
   Indirizzo IPv6 . . . . . . . . . . . . . . . . . : fde7:ea6f:4237:0:700c:da42:4003:3b70
   Indirizzo IPv6 temporaneo. . . . . . . . . . . . : fde7:ea6f:4237:0:acb6:fa49:4afe:2bf2
   Indirizzo IPv6 locale rispetto al collegamento . : fe80::700c:da42:4003:3b70%19
   Indirizzo IPv4. . . . . . . . . . . . : 192.168.1.129
   Subnet mask . . . . . . . . . . . . . : 255.255.255.0
   Gateway predefinito . . . . . . . . . : 192.168.1.1

Scheda Ethernet vEthernet (WSL):

   Suffisso DNS specifico per connessione:
   Indirizzo IPv6 locale rispetto al collegamento . : fe80::249f:31f4:b1fe:13f6%50
   Indirizzo IPv4. . . . . . . . . . . . : 172.26.32.1
   Subnet mask . . . . . . . . . . . . . : 255.255.240.0

Voi avrete probabilmente meno interfacce, ma dipende ad esempio se avete abilitato WSL oppure no etc etc.
L'IP che dovrete annotare è quello alla voce Ethernet VMWare Network Adapter, nel mio caso: 192.168.74.1.

Andate sulla VM, aprite un prompt come amministratori e digitate:
Codice:
ping -4 <vostro-ip>

se i pacchetti raggiungeranno il destinatario, allora la comunicazione tra host e target è stabilita.
Ora tornate sull'host e recatevi nella cartella in cui avete installato i tools per il debugging. Il percorso dovrebbe essere questo:

Codice:
C:\Program Files (x86)\Windows Kits\10\Debuggers\x64

dovrete copiare 2 files, chiamati VerifiedNICList.xml e kdnet.exe, e incollarli sul desktop della VM (o dove preferite).

Se non avete più una finestra del prompt aperta da amministratore (sulla VM), lanciatela. Andate nella cartella in cui avete incollato kdnet e lanciatelo passandogli l'IP visto in precedenza, e una porta [50000, 50039].
Di seguito vedrete il mio input, e l'output di kdnet:

Codice:
C:\Users\DispatchCode\Desktop>kdnet 192.168.74.1 50010

Enabling network debugging on Intel(R) 82574L Gigabit Network Connection.

To debug this machine, run the following command on your debugger host machine.
windbg -k net:port=50010,key=27vh8lqc6awhx.303bt4zycitsc.1duw3o5kopk8o.21cwx8lsfqdi2

Then reboot this machine by running shutdown -r -t 0 from this command prompt.

Qui l'output dà per scontato che utilizziamo windbg, mai in realtà nel nostro caso - nel mio almeno - abbiamo Windbg Preview. Annotatevi il suo output per intero (incollatelo ad esempio su notepad, sull'host).

4    Connessione tramite debugger



A questo punto ci siamo. Aprite il debugger e riportate le informazioni; sotto il mio screen:

Visualizza allegato 62255

Premete OK. Nella finestra di output sul debugger dovreste vedere qualcosa di analogo:

Codice:
Microsoft (R) Windows Debugger Version 10.0.22549.1000 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.

Using NET for debugging
Opened WinSock 2.0
Waiting to reconnect...
Connected to target 192.168.1.129 on port 50005 on local IP 192.168.1.129.
You can get the target MAC address by running .kdtargetmac command.
Connected to Windows 10 19041 x64 target at (Sat Apr 30 18:10:16.792 2022 (UTC + 2:00)), ptr64 TRUE
Kernel Debugger connection established.

************* Path validation summary **************
Response                         Time (ms)     Location
Deferred                                       SRV*c:\Symbols*http://msdl.microsoft.com/download/symbols
Symbol search path is: SRV*c:\Symbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
Windows 10 Kernel Version 19041 MP (4 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Edition build lab: 19041.1.amd64fre.vb_release.191206-1406
Machine Name:
Kernel base = 0xfffff807`4ec00000 PsLoadedModuleList = 0xfffff807`4f82a270
Debug session time: Sat Apr 30 18:10:16.866 2022 (UTC + 2:00)
System Uptime: 0 days 0:01:18.402
Break instruction exception - code 80000003 (first chance)
*******************************************************************************
*                                                                             *
*   You are seeing this message because you pressed either                    *
*       CTRL+C (if you run console kernel debugger) or,                       *
*       CTRL+BREAK (if you run GUI kernel debugger),                          *
*   on your debugger machine's keyboard.                                      *
*                                                                             *
*                   THIS IS NOT A BUG OR A SYSTEM CRASH                       *
*                                                                             *
* If you did not intend to break into the debugger, press the "g" key, then   *
* press the "Enter" key now.  This message might immediately reappear.  If it *
* does, press "g" and "Enter" again.                                          *
*                                                                             *
*******************************************************************************
nt!DbgBreakPointWithStatus:
fffff807`4efff050 cc              int     3

Microsoft (R) Windows Debugger Version 10.0.22549.1000 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.

Using NET for debugging
Opened WinSock 2.0
Waiting to reconnect...

a questo punto, sul terminale che avrete ancora aperto sulla VM, lanciate shutdown -r -t 0.

Una volta riavviato l'OS target, il debugger mi segnala una connessione:

Codice:
Connected to target 192.168.74.1 on port 50010 on local IP 192.168.74.1.
You can get the target MAC address by running .kdtargetmac command.
Connected to Windows 10 19041 x64 target at (Sat Apr 30 19:32:15.489 2022 (UTC + 2:00)), ptr64 TRUE
Kernel Debugger connection established.

************* Path validation summary **************
Response                         Time (ms)     Location
Deferred                                       SRV*c:\Symbols*http://msdl.microsoft.com/download/symbols
Symbol search path is: SRV*c:\Symbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
Windows 10 Kernel Version 19041 MP (1 procs) Free x64
Edition build lab: 19041.1.amd64fre.vb_release.191206-1406
Machine Name:
Kernel base = 0xfffff802`3e800000 PsLoadedModuleList = 0xfffff802`3f42a230
System Uptime: 0 days 0:00:00.961
minio\security\base\lsa\security\driver\asyncsspi.cxx - SspiInitAsyncInterface
IOINIT: Built-in driver \Driver\hwpolicy failed to initialize with status - 0xC000025E
KDTARGET: Refreshing KD connection

Arrivati a questo punto, vedrete nella casella di input dei comandi (0: kd>) la scritta "Debugger is running...". Dal menu in alto premete Break:

Codice:
Break instruction exception - code 80000003 (first chance)
*******************************************************************************
*                                                                             *
*   You are seeing this message because you pressed either                    *
*       CTRL+C (if you run console kernel debugger) or,                       *
*       CTRL+BREAK (if you run GUI kernel debugger),                          *
*   on your debugger machine's keyboard.                                      *
*                                                                             *
*                   THIS IS NOT A BUG OR A SYSTEM CRASH                       *
*                                                                             *
* If you did not intend to break into the debugger, press the "g" key, then   *
* press the "Enter" key now.  This message might immediately reappear.  If it *
* does, press "g" and "Enter" again.                                          *
*                                                                             *
*******************************************************************************
nt!DbgBreakPointWithStatus:
fffff802`3ebff740 cc              int     3

nell'output vedrete questo.

5    Kernel debugging



Prima di iniziare, clickate su File > Settings e inserite nel campo di testo "Symbol Path" il percorso SRV*c:\Symbols*http://msdl.microsoft.com/download/symbols, poi premete Ok; create sull'host la cartella Symbols in C:\. Potete scegliere anche un altro percorso, l'importante è che andrete poi a modificare il percorso inserito in windbg.
A questo punto come input al debugger date .reload /f. Questo forzerà il reload dei simboli; questi consentono di vedere i nomi delle funzioni e contengono altre informazioni.

Tutto il necessario è installato. Ora iniziamo a giocare: premete Go, lasciando continuare l'esecuzione. Andate sul target e aprite Notepad, poi tornate sul debugger, e premete Break; noterete tutto freezato sul target. Elencate i processi in esecuzione con:

Codice:
!process 0 0 Notepad.exe

nel mio caso:

Codice:
PROCESS ffffc8033c98e080
    SessionId: 1  Cid: 21bc    Peb: 41c271c000  ParentCid: 1230
    DirBase: 11c4a9002  ObjectTable: ffffdd8edf3e8d00  HandleCount: 244.
    Image: notepad.exe

la struttura che rappresenta un processo in Windows si chiama EPROCESS; potete vedere i campi che la compongono con dt nt!_EPROCESS e potete vedere quella che rappresenta il processo in questione con dt nt!_EPROCESS ffffc8033c98e080 (l'indirizzo è preso dall'output sopra).
Bene, a questo punto, andiamo a guardare anche l'header di questa immagine, per farlo ci serve l'image base address ; dall'output precedente, clickate sul PEB. A questo punto vedrete un campo chiamato ImageBaseAddress: copiatene l'indirizzo.

Codice:
0: kd> !dh 00007ff7105f0000

File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
    8664 machine (X64)
       7 number of sections
4178AED3 time date stamp Fri Oct 22 08:55:15 2004

       0 file pointer to symbol table
       0 number of symbols
      F0 size of optional header
      22 characteristics
            Executable
            App can handle >2gb addresses

OPTIONAL HEADER VALUES
     20B magic #
   14.20 linker version
   24A00 size of code
    E000 size of initialized data
       0 size of uninitialized data
   24050 address of entry point
    1000 base of code
         ----- new -----
00007ff7105f0000 image base
    1000 section alignment
     200 file alignment
       2 subsystem (Windows GUI)
   10.00 operating system version
   10.00 image version
   10.00 subsystem version
   38000 size of image
     400 size of headers
   37B81 checksum
0000000000080000 size of stack reserve
0000000000011000 size of stack commit
0000000000100000 size of heap reserve
0000000000001000 size of heap commit
    C160  DLL characteristics
            High entropy VA supported
            Dynamic base
            NX compatible
            Guard
            Terminal server aware
       0 [       0] address [size] of Export Directory
   2D0A8 [     244] address [size] of Import Directory
   36000 [     BD8] address [size] of Resource Directory
   33000 [    10EC] address [size] of Exception Directory
       0 [       0] address [size] of Security Directory
   37000 [     2D4] address [size] of Base Relocation Directory
   2AC20 [      54] address [size] of Debug Directory
       0 [       0] address [size] of Description Directory
       0 [       0] address [size] of Special Directory
       0 [       0] address [size] of Thread Storage Directory
   266D0 [     118] address [size] of Load Configuration Directory
       0 [       0] address [size] of Bound Import Directory
   267E8 [     900] address [size] of Import Address Table Directory
   2C9C0 [      E0] address [size] of Delay Import Directory
       0 [       0] address [size] of COR20 Header Directory
       0 [       0] address [size] of Reserved Directory


SECTION HEADER #1
   .text name
   2490F virtual size
    1000 virtual address
   24A00 size of raw data
     400 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
60000020 flags
         Code
         (no align specified)
         Execute Read

SECTION HEADER #2
  .rdata name
    9268 virtual size
   26000 virtual address
    9400 size of raw data
   24E00 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
40000040 flags
         Initialized Data
         (no align specified)
         Read Only


Debug Directories(3)
    Type       Size     Address  Pointer
    cv           24       2b4e4    2a2e4    Format: RSDS, guid, 1, notepad.pdb
    (   13)     43c       2b508    2a308
    (   16)      24       2b944    2a744

SECTION HEADER #3
   .data name
    2738 virtual size
   30000 virtual address
     E00 size of raw data
   2E200 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
C0000040 flags
         Initialized Data
         (no align specified)
         Read Write

SECTION HEADER #4
  .pdata name
    10EC virtual size
   33000 virtual address
    1200 size of raw data
   2F000 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
40000040 flags
         Initialized Data
         (no align specified)
         Read Only

SECTION HEADER #5
  .didat name
     178 virtual size
   35000 virtual address
     200 size of raw data
   30200 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
C0000040 flags
         Initialized Data
         (no align specified)
         Read Write

SECTION HEADER #6
   .rsrc name
     BD8 virtual size
   36000 virtual address
     C00 size of raw data
   30400 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
40000040 flags
         Initialized Data
         (no align specified)
         Read Only

SECTION HEADER #7
  .reloc name
     2D4 virtual size
   37000 virtual address
     400 size of raw data
   31000 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
42000040 flags
         Initialized Data
         Discardable
         (no align specified)
         Read Only

E' anche possibile visualizzare la Interrupt Dispatch Table utilizzando !idt:

Codice:
0: kd> !idt

Dumping IDT: fffff8073a862000

00:    fffff80737812100 nt!KiDivideErrorFaultShadow
01:    fffff80737812180 nt!KiDebugTrapOrFaultShadow    Stack = 0xFFFFF8073A8669D0
02:    fffff80737812240 nt!KiNmiInterruptShadow    Stack = 0xFFFFF8073A8667D0
03:    fffff807378122c0 nt!KiBreakpointTrapShadow
04:    fffff80737812340 nt!KiOverflowTrapShadow
05:    fffff807378123c0 nt!KiBoundFaultShadow
06:    fffff80737812440 nt!KiInvalidOpcodeFaultShadow
07:    fffff807378124c0 nt!KiNpxNotAvailableFaultShadow
08:    fffff80737812540 nt!KiDoubleFaultAbortShadow    Stack = 0xFFFFF8073A8663D0
09:    fffff807378125c0 nt!KiNpxSegmentOverrunAbortShadow
0a:    fffff80737812640 nt!KiInvalidTssFaultShadow
0b:    fffff807378126c0 nt!KiSegmentNotPresentFaultShadow
0c:    fffff80737812740 nt!KiStackFaultShadow
0d:    fffff807378127c0 nt!KiGeneralProtectionFaultShadow
0e:    fffff80737812840 nt!KiPageFaultShadow
10:    fffff807378128c0 nt!KiFloatingErrorFaultShadow
11:    fffff80737812940 nt!KiAlignmentFaultShadow
12:    fffff807378129c0 nt!KiMcheckAbortShadow    Stack = 0xFFFFF8073A8665D0
13:    fffff80737812ac0 nt!KiXmmExceptionShadow
14:    fffff80737812b40 nt!KiVirtualizationExceptionShadow
15:    fffff80737812bc0 nt!KiControlProtectionFaultShadow
1f:    fffff80737812c40 nt!KiApcInterruptShadow
20:    fffff80737812cc0 nt!KiSwInterruptShadow
29:    fffff80737812d40 nt!KiRaiseSecurityCheckFailureShadow
2c:    fffff80737812dc0 nt!KiRaiseAssertionShadow
2d:    fffff80737812e40 nt!KiDebugServiceTrapShadow
2f:    fffff80737812f40 nt!KiDpcInterruptShadow
30:    fffff80737812fc0 nt!KiHvInterruptShadow
31:    fffff80737813040 nt!KiVmbusInterrupt0Shadow
32:    fffff807378130c0 nt!KiVmbusInterrupt1Shadow
33:    fffff80737813140 nt!KiVmbusInterrupt2Shadow
34:    fffff807378131c0 nt!KiVmbusInterrupt3Shadow
35:    fffff80737813468 nt!HalpInterruptCmciService (KINTERRUPT fffff80737af2f40)

36:    fffff80737813470 nt!HalpInterruptCmciService (KINTERRUPT fffff80737af3180)

50:    fffff80737813540 pci!ExpressRootPortMessageRoutine (KINTERRUPT ffff89017ef0b3c0)

51:    fffff80737813548 pci!ExpressRootPortMessageRoutine (KINTERRUPT ffff89017ef0b500)

52:    fffff80737813550 stornvme!NVMeHwMSIInterrupt (STORPORT) (KINTERRUPT ffff89017f53aa00)

53:    fffff80737813558 HDAudBus!HdaController::Isr (KINTERRUPT ffff89017ef64b40)

60:    fffff807378135c0 serial!SerialCIsrSw (KINTERRUPT ffff89017f53a8c0)

61:    fffff807378135c8 pci!ExpressRootPortMessageRoutine (KINTERRUPT ffff89017ef0b640)

62:    fffff807378135d0 stornvme!NVMeHwMSIInterrupt (STORPORT) (KINTERRUPT ffff89017f53ab40)

63:    fffff807378135d8 USBPORT!USBPORT_InterruptService (KINTERRUPT ffff89017f53a3c0)

                     dxgkrnl!DpiFdoLineInterruptRoutine (KINTERRUPT ffff89017ef64a00)

70:    fffff80737813640 i8042prt!I8042MouseInterruptService (KINTERRUPT ffff89017f53a640)

71:    fffff80737813648 pci!ExpressRootPortMessageRoutine (KINTERRUPT ffff89017ef0b780)

72:    fffff80737813650 storahci!AhciHwMSIInterrupt (STORPORT) (KINTERRUPT ffff89017f53ac80)

73:    fffff80737813658 USBXHCI!Interrupter_WdfEvtInterruptIsr (KMDF) (KINTERRUPT ffff89017ef64c80)

80:    fffff807378136c0 i8042prt!I8042KeyboardInterruptService (KINTERRUPT ffff89017f53a780)

81:    fffff807378136c8 pci!ExpressRootPortMessageRoutine (KINTERRUPT ffff89017ef0b8c0)

82:    fffff807378136d0 vmci!DllInitialize+0x1c10 (KINTERRUPT ffff89017ef0b140)

83:    fffff807378136d8 USBXHCI!Interrupter_WdfEvtInterruptIsr (KMDF) (KINTERRUPT ffff89017ef64dc0)

91:    fffff80737813748 pci!ExpressRootPortMessageRoutine (KINTERRUPT ffff89017ef0ba00)

92:    fffff80737813750 vmci!DllInitialize+0x1c10 (KINTERRUPT ffff89017ef0b280)

93:    fffff80737813758 USBXHCI!Interrupter_WdfEvtInterruptIsr (KMDF) (KINTERRUPT ffff89017f53a000)

a1:    fffff807378137c8 pci!ExpressRootPortMessageRoutine (KINTERRUPT ffff89017ef0bb40)

a2:    fffff807378137d0 ataport!IdePortInterrupt (KINTERRUPT ffff89017f53adc0)

a3:    fffff807378137d8 USBXHCI!Interrupter_WdfEvtInterruptIsr (KMDF) (KINTERRUPT ffff89017f53a140)

b0:    fffff80737813840 ACPI!ACPIInterruptServiceRoutine (KINTERRUPT ffff89017ef0bdc0)

b1:    fffff80737813848 pci!ExpressRootPortMessageRoutine (KINTERRUPT ffff89017ef0bc80)

b2:    fffff80737813850 ataport!IdePortInterrupt (KINTERRUPT ffff89017ef0b000)

b3:    fffff80737813858 USBXHCI!Interrupter_WdfEvtInterruptIsr (KMDF) (KINTERRUPT ffff89017f53a280)

b4:    fffff80737813860 USBPORT!USBPORT_InterruptService (KINTERRUPT ffff89017f53a500)

ce:    fffff80737813930 nt!HalpIommuInterruptRoutine (KINTERRUPT fffff80737af3ba0)

d1:    fffff80737813948 nt!HalpTimerClockInterrupt (KINTERRUPT fffff80737af3960)

d2:    fffff80737813950 nt!HalpTimerClockIpiRoutine (KINTERRUPT fffff80737af3840)

d7:    fffff80737813978 nt!HalpInterruptRebootService (KINTERRUPT fffff80737af3600)

d8:    fffff80737813980 nt!HalpInterruptStubService (KINTERRUPT fffff80737af33c0)

df:    fffff807378139b8 nt!HalpInterruptSpuriousService (KINTERRUPT fffff80737af32a0)

e1:    fffff80737813240 nt!KiIpiInterruptShadow
e2:    fffff807378139d0 nt!HalpInterruptLocalErrorService (KINTERRUPT fffff80737af34e0)

e3:    fffff807378139d8 nt!HalpInterruptDeferredRecoveryService (KINTERRUPT fffff80737af3060)

fd:    fffff80737813aa8 nt!HalpTimerProfileInterrupt (KINTERRUPT fffff80737af3a80)

fe:    fffff80737813ab0 nt!HalpPerfInterrupt (KINTERRUPT fffff80737af3720)

Questa tabella viene utilizzata per la gestione di eccezioni, interrupt software e interrupt hardware. Il puntatore alla struttura base è mantenuto in un registro chiamato idt, che possiamo ovviamente leggere:
Codice:
0: kd> r @idtr
idtr=fffff8073a862000

Ho preso come esempio l'interrupt della tastiera (i8042prt); come nel caso dei processi, è possibile guardare questa struttura (KINTERRUPT):
Codice:
0: kd> dt nt!_KINTERRUPT ffff89017f53a780
   +0x000 Type             : 0n22
   +0x002 Size             : 0n288
   +0x008 InterruptListEntry : _LIST_ENTRY [ 0x00000000`00000000 - 0x00000000`00000000 ]
   +0x018 ServiceRoutine   : 0xfffff807`3c586790     unsigned char  i8042prt!I8042KeyboardInterruptService+0
   +0x020 MessageServiceRoutine : (null)
   +0x028 MessageIndex     : 0
   +0x030 ServiceContext   : 0xffffb388`4ccd7780 Void
   +0x038 SpinLock         : 0
   +0x040 TickCount        : 0
   +0x048 ActualLock       : 0xffffb388`4ccd78e0  -> 0
   +0x050 DispatchAddress  : 0xfffff807`371f9360     void  nt!KiInterruptDispatch+0
   +0x058 Vector           : 0x80
   +0x05c Irql             : 0x8 ''
   +0x05d SynchronizeIrql  : 0x8 ''
   +0x05e FloatingSave     : 0 ''
   +0x05f Connected        : 0x1 ''
   +0x060 Number           : 0
   +0x064 ShareVector      : 0 ''
   +0x065 EmulateActiveBoth : 0 ''
   +0x066 ActiveCount      : 0
   +0x068 InternalState    : 0n0
   +0x06c Mode             : 1 ( Latched )
   +0x070 Polarity         : 0 ( InterruptPolarityUnknown )
   +0x074 ServiceCount     : 0
   +0x078 DispatchCount    : 0
   +0x080 PassiveEvent     : (null)
   +0x088 TrapFrame        : 0xffff810e`a75a1b00 _KTRAP_FRAME
   +0x090 DisconnectData   : (null)
   +0x098 ServiceThread    : (null)
   +0x0a0 ConnectionData   : 0xffffb388`4cd52d60 _INTERRUPT_CONNECTION_DATA
   +0x0a8 IntTrackEntry    : 0xffffb388`4cd1b920 Void
   +0x0b0 IsrDpcStats      : _ISRDPCSTATS
   +0x110 RedirectObject   : (null)
   +0x118 PhysicalDeviceObject : (null)

Possiamo anche fare riferimento a una singola entry della tabella (ho considerato sempre la tastiera, che si trova all'indice 0x80):

Codice:
0: kd> dt @idtr + @@c++(0x80 * sizeof(nt!_KIDTENTRY64)) nt!_KIDTENTRY64
   +0x000 OffsetLow        : 0x36c0
   +0x002 Selector         : 0x10
   +0x004 IstIndex         : 0y000
   +0x004 Reserved0        : 0y00000 (0)
   +0x004 Type             : 0y01110 (0xe)
   +0x004 Dpl              : 0y00
   +0x004 Present          : 0y1
   +0x006 OffsetMiddle     : 0x3781
   +0x008 OffsetHigh       : 0xfffff807
   +0x00c Reserved1        : 0
   +0x000 Alignment        : 0x37818e00`001036c0

L'indirizzo che verrà invocato si compone dei 3 indici Low, Middle e Hight 0xfffff807378136c0; disassemblando il codice a quell'indirizzo, si trova:

Codice:
0: kd> u 0xfffff807378136c0
nt!KiIsrThunkShadow+0x400:
fffff807`378136c0 6a80            push    0FFFFFFFFFFFFFF80h
fffff807`378136c2 e939040000      jmp     nt!KxIsrLinkageShadow (fffff807`37813b00)
fffff807`378136c7 cc              int     3
fffff807`378136c8 6a81            push    0FFFFFFFFFFFFFF81h
fffff807`378136ca e931040000      jmp     nt!KxIsrLinkageShadow (fffff807`37813b00)
fffff807`378136cf cc              int     3
fffff807`378136d0 6a82            push    0FFFFFFFFFFFFFF82h
fffff807`378136d2 e929040000      jmp     nt!KxIsrLinkageShadow (fffff807`37813b00)

la presenza di questa funzione chiamata Shadow, è dovuta al fix di Meltdown (KVA Shadow mitigating meltdown on Windows).

6    Conclusione



In conclusione vi lascio alcuni link, in primis la debugger reference, che contiene i vari comandi per interagire con windbg e tante altre info. Come seconda risorsa un approfondimento sulla IDT e sulle interrupt software: Interrupt Dispatching e Windows Kernel, che tratta anche le system call e la IDT (e faccio notare che lavora in Offensive Security).
Fantastico! Ottima risorsa, grazie mille per queste utilissime informazioni!
 
  • Love
Reazioni: DispatchCode