Seguita la lezione precedente, non dovrebbe essere troppo difficile riuscire a capire il seguente codice per enumerare i driver, pertanto si eviteranno inutili lungaggini o ripetizioni fornendo semplicemente il codice commentato.
// Simile a struttura LDR_DATA_TABLE_ENTRY vista in lezione precedente (si veda [1]) ma // presenta info su moduli caricati in kernel space (driver, DLL speciali e Ntsokrnl.exe naturalmente) typedef struct _KLDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderLinks; PVOID ExceptionTable; ULONG ExceptionTableSize; ULONG pad1; PVOID GpValue; PVOID NonPagedDebugInfo; PVOID DllBase; PVOID EntryPoint; ULONG SizeOfImage; ULONG pad2; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; USHORT LoadCount; USHORT pad3; PVOID SectionPointer; ULONG CheckSum; ULONG CoverageSectionSize; PVOID CoverageSection; PVOID LoadedImports; PVOID Spare; ULONG SizeOfImageNotRounded; ULONG TimeDateStamp; } KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY; VOID EnumDriver(PDRIVER_OBJECT pDriverObject) { // Campo DriverSection di DRIVER_OBJECT è un puntatore ad una Head di una // lista doppiamente collegata i cui elementi sono di tipo KLDR_DATA_TABLE_ENTRY. // Simile a caso visto in lezione precedente: si veda [1] PKLDR_DATA_TABLE_ENTRY entry = (PKLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection; PKLDR_DATA_TABLE_ENTRY firstentry; firstentry = entry; while ((PKLDR_DATA_TABLE_ENTRY)entry->InLoadOrderLinks.Flink != firstentry) { DbgPrint("BASE=%p\tPATH=%wZ", entry->DllBase, entry->FullDllName); entry = (PKLDR_DATA_TABLE_ENTRY)entry->InLoadOrderLinks.Flink; } }
Per quanto riguarda la creazione del thread di sistema e l'impostazione della routine da fargli eseguire, anche in questo caso la cosa non presenta particolari difficoltà.
// Valori negativi per tempo relativo (rispetto a timer di sistema), // considerati come numero di intervalli di 100 nanosecondi. // Valori positivi per tempo assoluto (sempre considerando timer di sistema ed intervalli di 100 nanosecondi). #define DELAY_ONE_MICROSECOND (-10) #define DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000) // Evento su cui mettersi in attesa KEVENT kEvent; VOID CreateThreadTest() { HANDLE hThread; UNICODE_STRING ustrTest = RTL_CONSTANT_STRING(L"This is a string for test!"); NTSTATUS status; // KeInitializeEvent inizializza un oggetto evento impostandone il tipo e lo stato iniziale. // Per il tipo le opzioni sono due: // - NotificationEvent: Usato per risvegliare più thread in attesa sullo stesso oggetto // evento. Una volta segnalato l'oggetto evento resta in questo stato fino a non si chiama // esplicitamente KeResetEvent o KeClearEvent su tale oggetto evento. // - SynchronizationEvent: Usato per risvegliare un singolo thread in attesa sull'oggetto // evento. Tale oggetto viene riportato automaticamente allo stato non segnalato una volta // che l'attesa è soddisfatta. // Per lo stato iniziale: FALSE indica non segnalato. KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE); // PsCreateSystemThread crea un thread di sistema che eseguira la funzione il cui indirizzo // è passato come penultimo parametro passandogli un argomento il cui indirizzo è passato // come ultimo parametro. // Il primo parametro è un puntatore che riceverà l'indirizzo dell'handle al thread di sistema creato. status = PsCreateSystemThread(&hThread, 0, NULL, NULL, NULL, MyThreadFunc, (PVOID)&ustrTest); if (!NT_SUCCESS(status)) { DbgPrint("PsCreateSystemThread failed!"); return; } // Chiude l'handle al thread di sistema poichè non serve in questo caso. // Nota: Tale operazione non termina il thread. Decrementa solo il // numero di riferimenti al thread. ZwClose(hThread); // Resta in attesa sull'oggetto evento finché questo non viene segnalato. // Si veda la documentazione ufficiale per maggiori dettagli sugli altri parametri (non rilevanti al momento). KeWaitForSingleObject(&kEvent, Executive, KernelMode, FALSE, NULL); DbgPrint("CreateThreadTest OVER!\n"); }
VOID MyThreadFunc(IN PVOID context) { PUNICODE_STRING str = (PUNICODE_STRING)context; DbgPrint("Kernel thread running: %wZ\n", str); DbgPrint("Wait 3s!\n"); MySleep(3000); DbgPrint("Kernel thread exit!\n"); // KeSetEvent imposta allo stato segnalato l'oggetto evento passato come primo parametro. // Gli altri due parametri non sono importanti al momento; si veda la documentazione ufficiale per maggiori dettagli. KeSetEvent(&kEvent, 0, TRUE); // PsTerminateSystemThread termina il thread di sistema corrente passando lo stato con cui // si vuole terminare tale thread come primo parametro. PsTerminateSystemThread(STATUS_SUCCESS); }
VOID MySleep(LONG msec) { LARGE_INTEGER my_interval; my_interval.QuadPart = DELAY_ONE_MILLISECOND; my_interval.QuadPart *= msec; // KeDelayExecutionThread mette in attesa il thread corrente per il tempo passato come ultimo parametro. // In kernel mode primo e secondo parametro normalemente KernelMode e 0, rispettivamente. KeDelayExecutionThread(KernelMode, 0, &my_interval); }
Insieme a DriverEntry ed il codice di supporto viene fornita anche una funzione che richiede il tempo di sistema e converte il risultato stampandolo in un formato adatto ad essere letto. Verificare, confrontare o semplicemente salvare il tempo di sistema può rivelarsi un'operazione utile in più di una occasione.
/*typedef struct TIME_FIELDS { CSHORT Year; CSHORT Month; CSHORT Day; CSHORT Hour; CSHORT Minute; CSHORT Second; CSHORT Milliseconds; CSHORT Weekday; } TIME_FIELDS;*/ VOID MyGetCurrentTime() { LARGE_INTEGER CurrentTime; LARGE_INTEGER LocalTime; TIME_FIELDS TimeFiled; // Quello che si ottiene qui è in realtà Greenwich Mean Time (GMT+0). KeQuerySystemTime(&CurrentTime); // Converte in tempo locale ExSystemTimeToLocalTime(&CurrentTime, &LocalTime); // Converte in un formato facile da utilizzare RtlTimeToTimeFields(&LocalTime, &TimeFiled); DbgPrint("[TimeTest] NowTime : %4d-%2d-%2d %2d:%2d:%2d", TimeFiled.Year, TimeFiled.Month, TimeFiled.Day, TimeFiled.Hour, TimeFiled.Minute, TimeFiled.Second); } VOID DriverUnload(PDRIVER_OBJECT pDriverObj) { UNREFERENCED_PARAMETER(pDriverObj); } NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString) { UNREFERENCED_PARAMETER(pRegistryString); pDriverObj->DriverUnload = DriverUnload; EnumDriver(pDriverObj); MyGetCurrentTime(); CreateThreadTest(); return STATUS_SUCCESS; }
Codice sorgente:
EnumDriversDriver.zip
Riferimenti:
[1] 13 - Kernel API: Altre funzioni (Processi, Thread e DLL)
[2] https://github.com/andylau004/LookDrvCode/blob/master/WIN64驱动编程基础教程/代码/%5B2-8%5DOtherFunction/MyDriver.h
Nessun commento:
Posta un commento