
Controlador en modo kernel de Windows con cliente en modo usuario que expone lectura/escritura de memoria física y virtual basada en IOCTL, recorrido de tablas de páginas, escaneo de patrones y emulación de entrada para trampas en juegos.
██╗ ██╗████████╗██╗ ██╗██╗██╗ ██╗███╗ ███╗
██║ ██║╚══██╔══╝██║ ██║██║██║ ██║████╗ ████║
██║ ██║ ██║ ███████║██║██║ ██║██╔████╔██║
██║ ██║ ██║ ██╔══██║██║██║ ██║██║╚██╔╝██║
███████╗██║ ██║ ██║ ██║██║╚██████╔╝██║ ╚═╝ ██║
╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═════╝ ╚═╝ ╚═╝
Framework de controlador en modo kernel de Windows con cliente en modo usuario
[!IMPORTANT]
Obtén el proyecto completo
Los archivos de solución están disponibles a través del servidor de Discord.
¿Interesado en comprar el código fuente completo? Contáctame en Telegram o Discord: @tonythimself.
Lithium es un controlador en modo kernel de Windows (lithium-kernel) emparejado con un cliente en modo usuario (lithium-usermode). Se comunica mediante una interfaz IOCTL personalizada y expone primitivas de manipulación de memoria de bajo nivel, recorrido de tablas de páginas y control de dispositivos de entrada.
| Característica | Descripción |
|---|---|
| Lectura/Escritura de memoria física | Lectura/escritura directa de direcciones físicas mediante MmCopyMemory |
| Lectura/Escritura de memoria virtual | Acceso a memoria virtual entre procesos mediante MmCopyVirtualMemory |
| Resolución de DTB | Extracción de la base de la tabla de directorios mediante enumeración de la base de datos PFN |
| Recorrido de tablas de páginas | Traducción de direcciones lineales con caché de capas PML4/PDPT/PD/PT |
| Escaneo de patrones | Escaneo de firmas estilo IDA en la memoria del proceso |
| Asignación de memoria | ZwAllocateVirtualMemory en el contexto del proceso objetivo |
| Protección de memoria | ZwProtectVirtualMemory en el contexto del proceso objetivo |
| Emulación de ratón | Entrada de ratón a nivel de kernel mediante hook del callback del servicio MouClass |
| Ocultación de hilos | Suplantación de campos de ETHREAD (dirección de inicio, CID, hora de creación, etc.) |
| Desactivación de callbacks NMI | Supresión de callbacks NMI para evasión de depuradores |
| Limpieza de pool | Eliminación de entradas de la tabla de big pool del rastreador de pool del kernel |
lithium/
├── lithium-kernel/ # Kernel-mode driver (KMDF)
│ ├── entry.cpp # DriverEntry entry point
│ ├── core/
│ │ ├── dispatch/ # IOCTL dispatch and request routing
│ │ ├── requests/
│ │ │ ├── directory-table-base/ # DTB resolution & page table walk
│ │ │ ├── image-base/ # Process module base retrieval
│ │ │ ├── mouse/ # Mouse input emulation via MouClass
│ │ │ ├── read-write/ # Physical and virtual memory R/W
│ │ │ └── virtual-memory/ # Allocate, protect, query, pattern scan
│ │ └── utilities/
│ │ ├── kernel/ # Module enumeration, NMI, thread ops
│ │ └── ... # Pool cleaner, CRT shim
│ └── dependencies/
│ ├── additional/
│ │ ├── crt/ # Minimal CRT implementation
│ │ ├── security/ # skCrypter string encryption, oxorany
│ │ └── structures/ # Shared invoke data structures
│ └── includes.hpp # Master include header
│
└── lithium-usermode/ # User-mode client
├── entry.cpp # Client entry point
├── core/
│ └── driver/ # IOCTL communication layer
└── dependencies/
├── additional/
│ └── structs.hpp # Page table entry unions & helpers
└── includes.hpp
La comunicación se establece enganchando la rutina de despacho IOCTL de un controlador existente (ProcObsrvesx.sys). En tiempo de carga, el módulo del kernel localiza el controlador objetivo, busca su manejador de despacho IRP y lo sobrescribe con un trampolín hacia el propio hooked_ioctl de lithium. El cliente en modo usuario abre \\.\ProcObsrvesx y todos los IOCTL se redirigen de forma transparente a través del hook.
| Código | Estructura de entrada | Acción |
|---|---|---|
invoke_base | base_invoke { pid, handle } | Obtener la base de la imagen del proceso |
invoke_dtb | dtb_invoke { pid, dtb } | Resolver la base de la tabla de directorios |
invoke_read | read_invoke { pid, directory_table, address, buffer, size } | Leer memoria física |
invoke_write | write_invoke { pid, directory_table, address, buffer, size } | Escribir memoria física |
invoke_read_virtual | read_virtual_invoke { pid, address, buffer, size } | Leer memoria virtual |
invoke_write_virtual | write_virtual_invoke { pid, address, buffer, size } | Escribir memoria virtual |
invoke_allocate | allocate_invoke { pid, type, protection, address, size } | Asignar memoria virtual |
invoke_protect | protect_invoke { pid, protection, address, size } | Cambiar la protección de memoria |
invoke_virtual_query | query_virtual_invoke { pid, address, mbi } | Consultar información de memoria virtual |
invoke_pattern_scan | pattern_invoke { pid, signature, address, pattern_address } | Escanear patrones en memoria |
invoke_move_mouse | mouse_invoke { x, y, flags, button_flags } | Emular entrada de ratón |
El controlador itera sobre los rangos de memoria física devueltos por MmGetPhysicalMemoryRanges, recorre la base de datos PFN para localizar la entrada PML4 autorreferenciada y valida cada capa de la tabla de páginas para confirmar la base de la tabla de directorios correcta para un proceso dado.
La traducción de lineal a físico recorre la jerarquía de tablas de páginas x64 de cuatro niveles (PML4 → PDPT → PD → PT) con caché por nivel. La compatibilidad con páginas grandes (2MB / 1GB) se incluye en la medida de lo posible.
El controlador localiza los objetos de controlador MouClass y MouHID, resuelve el MouseClassServiceCallback desde la extensión del dispositivo HID e inyecta paquetes MOUSE_INPUT_DATA directamente en la cadena de callbacks.
Los campos clave de ETHREAD — hora de creación, dirección de inicio, dirección de inicio de Win32, pila del kernel, CID y estado de salida — se guardan y se reemplazan con valores benignos o nulos. Al desmontar, los valores originales se restauran antes de la terminación del hilo.
lithium.sln en Visual Studiolithium-kernel → lithium-kernel.syslithium-usermode → lithium-usermode.exeO mediante MSBuild:
msbuild lithium.sln /p:Configuration=Release /p:Platform=x64
#include <core/driver/driver.hpp>
g_driver->initialize_handle();
DWORD pid = g_driver->get_process_id(L"target.exe");
g_driver->attach(pid);
g_driver->image_base = g_driver->get_image_base(0);
g_driver->dtb = g_driver->resolve_directory_table_base();
auto value = g_driver->read<uintptr_t>(g_driver->image_base + 0xOFFSET);
g_driver->mouse_event(-10, -10, 0, 0);