Skip to content
KitploitKITPLOIT
StrumentiExploitsBlog
Log in
Invia
StrumentiExploitsBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
BYOVD-DriverKiller — Reverse ed Exploitation di Driver | Kitploit
Strumenti/GitHubGitHub/alex3o/byovd-driverkiller
ExploitReverse EngineeringPost-ExploitAnalisi di BinariApprendimento e FormazioneRed Teaming
GitHubalex3o/byovd-driverkiller

BYOVD-DriverKiller

Reverse ed Exploitation di Driver

Vedi Repository
8314101 anno faRevisionato da Kitploit

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

BYOVD-DriverKiller

⚠️ Avvertenza : Questo progetto è strettamente educativo e dimostrativo. Non è destinato a essere utilizzato in un contesto dannoso. L'obiettivo è apprendere la metodologia del reverse engineering e le fasi di exploitation di un driver Windows.


Qui spiego l'approccio che ho seguito per risolvere l'esercizio proposto da d1rk(SaadAhla) https://github.com/SaadAhla, che consiste nell'effettuare reverse engineering ed exploitation su un driver legittimo, firmato e non presente nelle blocklist (HVCI, LOLBIN...). È disponibile un programma C in grado di terminare qualsiasi processo attivo sul sistema tramite questo driver in kernel-mode; ne descrivo il funzionamento più avanti.

POC-BYOD

📃 Uso : DriverKiller.exe <nome_processo.exe> [-d]

Opzione -d : consente di eliminare il servizio e il driver dal sistema dopo l'exploitation.

La modalità testsigning deve essere attivata sulla macchina target perché il certificato del driver è scaduto.


Parte 1 - Reverse engineering :

L'esercizio fornisce un file .sys, denominato con il suo hash SHA-256. Il primo passo consiste nell'aprire il file con IDA.
IDA è disponibile gratuitamente. Basta andare sul sito di Hex-Rays per generare una licenza e scaricare il software.

Si inizia elencando la IAT (Import Address Table) del driver e cercando la chiamata all'API che ci interessa : ZwTerminateProcess.

screen1-git

Facendo doppio clic su ZwTerminateProcess, IDA ci reindirizza al codice compilato di questa funzione. Selezionando la voce e visualizzando i cross-reference, si ottiene l'elenco delle funzioni del driver che la chiamano.

screen2-git

Si osserva che è la funzione sub_12EF4, all'offset 1CE, a utilizzare ZwTerminateProcess. Dopo un doppio clic, IDA mostra il suo codice compilato.

screen11-git

Il codice decompilato rivela le chiamate a ZwOpenProcess (che apre un handle verso il processo target) e a ZwTerminateProcess (che termina il processo tramite tale handle).

Consultando la documentazione di ZwOpenProcess (https://learn.microsoft.com/fr-fr/windows-hardware/drivers/ddi/ntddk/nf-ntddk-zwopenprocess), si nota che il parametro ClientID corrisponde a un puntatore che indica il PID del processo interessato.

Sulla riga sopra, ClientId.UniqueProcess viene inizializzato con la variabile v22. Quest'ultima è definita poco sopra :

v22 = (void )((_QWORD *)i + 10);

Per comprendere questa assegnazione, bisogna identificare la variabile i e il campo +10.

screen3-git

Più sopra in questa funzione, si osserva una chiamata a ZwQuerySystemInformation con il parametro SYSTEM_PROCESS_INFORMATION. Si comprende inoltre che i è l'iteratore sulle voci di questa struttura insieme alla variabile v6.

Secondo la documentazione di ZwQuerySystemInformation : (https://learn.microsoft.com/en-us/windows/win32/sysinfo/zwquerysysteminformation), questa funzione restituisce un array contenente una voce per ogni processo attivo sul sistema.

La struttura SYSTEM_PROCESS_INFORMATION è descritta qui : https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation

typedef struct _SYSTEM_PROCESS_INFORMATION {
    ULONG NextEntryOffset;
    ULONG NumberOfThreads;
    BYTE Reserved1[48];
    UNICODE_STRING ImageName;
    KPRIORITY BasePriority;
    HANDLE UniqueProcessId;
    PVOID Reserved2;
    ULONG HandleCount;
    ULONG SessionId;
    PVOID Reserved3;
    SIZE_T PeakVirtualSize;
    SIZE_T VirtualSize;
    ULONG Reserved4;
    SIZE_T PeakWorkingSetSize;
    SIZE_T WorkingSetSize;
    PVOID Reserved5;
    SIZE_T QuotaPagedPoolUsage;
    PVOID Reserved6;
    SIZE_T QuotaNonPagedPoolUsage;
    SIZE_T PagefileUsage;
    SIZE_T PeakPagefileUsage;
    SIZE_T PrivatePageCount;
    LARGE_INTEGER Reserved7[6];
} SYSTEM_PROCESS_INFORMATION;

Promemoria : dimensioni di alcuni tipi su Windows x64

  • ULONG = 4 byte
  • USHORT = 2 byte
  • HANDLE = 8 byte
  • PWSTR = 8 byte
  • KPRIORITY (typedef di un LONG) = 4 byte
  • UNICODE_STRING = 16 byte perché la sua struttura è la seguente :
  typedef struct _UNICODE_STRING {
    USHORT Length;        -> 2      
    USHORT MaximumLength; -> + 2 = 4
    PWSTR  Buffer;        -> + 8 = 12 (12 non è un multiplo di 8 quindi padding di 4 aggiunto prima di Buffer) = 16
} UNICODE_STRING;

Calcolo dell'offset di UniqueProcessId :

    ULONG NextEntryOffset;        -> 4
    ULONG NumberOfThreads;        -> + 4 = 8
    BYTE Reserved1[48];           -> + 48 = 56
    UNICODE_STRING ImageName;     -> + 16 = 72
    KPRIORITY BasePriority;       -> + 4 = 76 (76 non è un multiplo di 8 quindi padding di 4 aggiunto) = 80
    HANDLE UniqueProcessId;       -> + 8 = 88

Il membro UniqueProcessId si trova quindi all'offset 0x50 (80 decimale).

Osservando l'assegnazione della nostra variabile v22, si nota che i viene convertito (cast) in un puntatore QWORD (8 byte)

v22 = (void )((_QWORD *)i + 10);
Quindi v22 corrisponde all'indirizzo di i + 10 * 8 = 80 byte. Questa variabile contiene quindi il PID recuperato dalla struttura SYSTEM_PROCESS_INFORMATION.

Per sapere quale PID verrà passato a ZwTerminateProcess, bisogna analizzare la condizione che circonda questa assegnazione.

screen4-git

Si nota che il nome dell'immagine del processo viene prima recuperato :

v9 = (wchar_t )((_QWORD *)i + 8);
Perché v9 = indirizzo di i + 8 × 8 = 64 byte. Ciò corrisponde al Buffer del membro ImageName, dato che tale membro si trova all'offset 56 + 2 (USHORT) + 2 (USHORT) + 4 (padding) = 64

Viste le manipolazioni e i loop qui sotto, si può ipotizzare che venga effettuato un confronto tra il nome del processo passato come argomento (a2) e i processi attivi sul sistema v9/String.

sub_1C078(String, v9, (int)v13);
v17 = strupr(a2);
v18 = strupr(String);

È quindi il parametro a2 a dover contenere il nome del processo da terminare tramite ZwTerminateProcess. Si nota che a2 è un parametro della funzione sub_12EF4. Per andare oltre, bisogna esaminare i riferimenti di questa funzione (l'ho rinominata ZwTerminateProcessCaller per una migliore leggibilità).

screen5-git
Scarica lo strumento