#pragma warning( disable: 4100 4101 4103 4189)


#include "IOPLDispatcher.h"
#include "DBKFunc.h"
#include "DBKDrvr.h"


#include "memscan.h"

#include "deepkernel.h"

#include "processlist.h"
#include "threads.h"

#include "interruptHook.h"
#include "debugger.h"

#include "vmxhelper.h"
#include "vmxoffload.h"
#include "ultimap.h"
#include "ultimap2.h"


UINT64 PhysicalMemoryRanges=0; //initialized once, and used thereafter. If the user adds/removes ram at runtime, screw him and make him the reload the driver
UINT64 PhysicalMemoryRangesListSize=0;

#if (NTDDI_VERSION >= NTDDI_VISTA)
PVOID DRMHandle = NULL;
PEPROCESS DRMProcess = NULL;
PEPROCESS DRMProcess2 = NULL;
#endif

typedef PCHAR (*GET_PROCESS_IMAGE_NAME) (PEPROCESS Process); 
GET_PROCESS_IMAGE_NAME PsGetProcessImageFileName; 


/*
typedef struct
{
	int listcount;
	char cpunrs[255];
} CPULISTFILLSTRUCT, *PCPULISTFILLSTRUCT;

VOID GetCPUIDS_all(PCPULISTFILLSTRUCT p)
{
	DbgPrint("GetCPUIDS_all(for cpu %d)\n", cpunr());
	if (p->listcount<255)
	{
		p->cpunrs[p->listcount]=cpunr();
		p->listcount++;
	}
}
*/

NTSYSAPI NTSTATUS NTAPI ZwQueryInformationProcess(IN HANDLE ProcessHandle, IN PROCESSINFOCLASS ProcessInformationClass, OUT PVOID ProcessInformation, IN ULONG ProcessInformationLength, OUT PULONG ReturnLength OPTIONAL);



void mykapc2(PKAPC Apc, PKNORMAL_ROUTINE NormalRoutine, PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2)
{
	ULONG_PTR iswow64;
	ExFreePool(Apc);
	DbgPrint("My second kernelmode apc!!!!\n");
	DbgPrint("SystemArgument1=%x\n",*(PULONG)SystemArgument1);
	DbgPrint("SystemArgument2=%x\n", *(PULONG)SystemArgument2);

	if (ZwQueryInformationProcess(ZwCurrentProcess(), ProcessWow64Information, &iswow64, sizeof(iswow64), NULL) == STATUS_SUCCESS)
	{
#if (NTDDI_VERSION >= NTDDI_VISTA)	
		if (iswow64)
		{
			DbgPrint("WOW64 apc");
			PsWrapApcWow64Thread(NormalContext, (PVOID*)NormalRoutine);
		}
#endif
	}

}

void nothing2(PVOID arg1, PVOID arg2, PVOID arg3)
{
	
	return;
}

void mykapc(PKAPC Apc, PKNORMAL_ROUTINE NormalRoutine, PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2)
{
	//kernelmode apc, always gets executed
	PKAPC      kApc;
	LARGE_INTEGER Timeout;

	kApc = ExAllocatePool(NonPagedPool, sizeof(KAPC));

	ExFreePool(Apc);

	DbgPrint("My kernelmode apc!!!!(irql=%d)\n", KeGetCurrentIrql());
	
	DbgPrint("NormalRoutine=%p\n",*(PUINT_PTR)NormalRoutine);
	DbgPrint("NormalContext=%p\n",*(PUINT_PTR)NormalContext);
	DbgPrint("SystemArgument1=%p\n",*(PUINT_PTR)SystemArgument1);
	DbgPrint("SystemArgument2=%p\n",*(PUINT_PTR)SystemArgument2);
	
	
	
	KeInitializeApc(kApc,
		            (PKTHREAD)PsGetCurrentThread(),
                    0,
                    (PKKERNEL_ROUTINE)mykapc2,
                    NULL,
                    (PKNORMAL_ROUTINE)*(PUINT_PTR)SystemArgument1,
                    UserMode,
                    (PVOID)*(PUINT_PTR)NormalContext
                    );

	KeInsertQueueApc (kApc, (PVOID)*(PUINT_PTR)SystemArgument1, (PVOID)*(PUINT_PTR)SystemArgument2, 0);


	//wait in usermode (so interruptable by a usermode apc)
	Timeout.QuadPart = 0;
	KeDelayExecutionThread(UserMode, TRUE, &Timeout);

	return;
}

void nothing(PVOID arg1, PVOID arg2, PVOID arg3)
{
	return;
}


void CreateRemoteAPC(ULONG threadid,PVOID addresstoexecute)
{
	
	PKTHREAD   kThread;
	PKAPC      kApc;

	kApc = ExAllocatePool(NonPagedPool, sizeof(KAPC));

	kThread=(PKTHREAD)getPEThread(threadid);
	DbgPrint("(PVOID)KThread=%p\n",kThread);
	DbgPrint("addresstoexecute=%p\n", addresstoexecute);
	
   
	KeInitializeApc(kApc,
		            kThread,
                    0,
                    (PKKERNEL_ROUTINE)mykapc,
                    NULL,
                    (PKNORMAL_ROUTINE)nothing,
                    KernelMode,
                    0
                    );

	KeInsertQueueApc (kApc, addresstoexecute, addresstoexecute, 0);
}

#define PROCESS_TERMINATE                  (0x0001)  
#define PROCESS_CREATE_THREAD              (0x0002)  
#define PROCESS_SET_SESSIONID              (0x0004)  
#define PROCESS_VM_OPERATION               (0x0008)  
#define PROCESS_VM_READ                    (0x0010)  
#define PROCESS_VM_WRITE                   (0x0020)  
#define PROCESS_DUP_HANDLE                 (0x0040)  
#define PROCESS_CREATE_PROCESS             (0x0080)  
#define PROCESS_SET_QUOTA                  (0x0100)  
#define PROCESS_SET_INFORMATION            (0x0200)  
#define PROCESS_QUERY_INFORMATION          (0x0400)  
#define PROCESS_SUSPEND_RESUME             (0x0800)  
#define PROCESS_QUERY_LIMITED_INFORMATION  (0x1000)  


#if (NTDDI_VERSION >= NTDDI_VISTA)
OB_PREOP_CALLBACK_STATUS ThreadPreCallback(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION OperationInformation)
{		
	if (DRMProcess == NULL)
		return OB_PREOP_SUCCESS;

	if (PsGetCurrentProcess() == DRMProcess)
		return OB_PREOP_SUCCESS;

	if (OperationInformation->ObjectType == *PsThreadType)
	{		
		if ((PsGetProcessId(DRMProcess) == PsGetThreadProcessId(OperationInformation->Object)) || ((DRMProcess2) && (PsGetProcessId(DRMProcess2) == PsGetThreadProcessId(OperationInformation->Object))))
		{
			//probably block it

			if (OperationInformation->Operation == OB_OPERATION_HANDLE_CREATE)
			{
				//create handle			

				ACCESS_MASK da = OperationInformation->Parameters->CreateHandleInformation.DesiredAccess;

				DbgPrint("PID %d opened a handle to the a CE thread with access mask %x", PsGetCurrentProcessId(), da);

				da = da & (THREAD_SET_LIMITED_INFORMATION | THREAD_QUERY_LIMITED_INFORMATION);

				OperationInformation->Parameters->CreateHandleInformation.DesiredAccess = 0;// da;
			}
			else if (OperationInformation->Operation == OB_OPERATION_HANDLE_DUPLICATE)
			{
				//duplicate handle
				ACCESS_MASK da = OperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess;

				DbgPrint("PID %d duplicated a handle to a CE thread with access mask %x", PsGetCurrentProcessId(), da);

				da = da & (THREAD_SET_LIMITED_INFORMATION | THREAD_QUERY_LIMITED_INFORMATION);
				OperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess = 0;// da;
			}
		}
	}
	return OB_PREOP_SUCCESS;
}


VOID ThreadPostCallback(PVOID RegistrationContext, POB_POST_OPERATION_INFORMATION OperationInformation)
{
	//DbgPrint("ProcessPostCallback");
}


OB_PREOP_CALLBACK_STATUS ProcessPreCallback(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION OperationInformation)
{
	if (DRMProcess == NULL)
		return OB_PREOP_SUCCESS;

	//if (PsGetCurrentProcess() == DRMProcess)
	//	return OB_PREOP_SUCCESS;

	if (OperationInformation->ObjectType == *PsProcessType)
	{
		if ((OperationInformation->Object == DRMProcess) || (OperationInformation->Object == DRMProcess2))
		{
			//probably block it

			if (OperationInformation->Operation == OB_OPERATION_HANDLE_CREATE)
			{
				//create handle			
				
				ACCESS_MASK da = OperationInformation->Parameters->CreateHandleInformation.DesiredAccess;

				DbgPrint("PID %d(%p) opened a handle to the CE process(%p) with access mask %x", PsGetCurrentProcessId(), PsGetCurrentProcess(), DRMProcess, da);

				da = da & (PROCESS_TERMINATE | PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_SUSPEND_RESUME);

				//da = da & PROCESS_SUSPEND_RESUME;

				OperationInformation->Parameters->CreateHandleInformation.DesiredAccess = 0;// da;
			}
			else if (OperationInformation->Operation == OB_OPERATION_HANDLE_DUPLICATE)
			{
				//duplicate handle
				ACCESS_MASK da = OperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess;

				DbgPrint("PID %d(%p) opened a handle to the CE process(%p) with access mask %x", PsGetCurrentProcessId(), PsGetCurrentProcess(), DRMProcess, da);


				da = da & (PROCESS_TERMINATE | PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_SUSPEND_RESUME);

				//da = da & PROCESS_SUSPEND_RESUME;

				OperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess = 0;// da;
			}
		}
	}
	return OB_PREOP_SUCCESS;
}


VOID ProcessPostCallback(PVOID RegistrationContext, POB_POST_OPERATION_INFORMATION OperationInformation)
{
	//DbgPrint("ProcessPostCallback");
}
#endif


BOOL DispatchIoctlDBVM(IN PDEVICE_OBJECT DeviceObject, ULONG IoControlCode, PVOID lpInBuffer, DWORD nInBufferSize, PVOID lpOutBuffer, DWORD nOutBufferSize, PDWORD lpBytesReturned)
/*
Called if dbvm has loaded the driver. Use this to setup a fake irp
*/
{
	//allocate a in and out buffer
	//setup a fake IRP
	IRP FakeIRP;
	BOOL r;
	PVOID buffer;
	buffer=ExAllocatePool(PagedPool, max(nInBufferSize, nOutBufferSize));
	RtlCopyMemory(buffer, lpInBuffer, nInBufferSize);	


	DbgPrint("DispatchIoctlDBVM\n");

	FakeIRP.AssociatedIrp.SystemBuffer=buffer;
	FakeIRP.Flags=IoControlCode; //(ab)using an unused element

	r=DispatchIoctl(DeviceObject, &FakeIRP)==STATUS_SUCCESS;


	RtlCopyMemory(lpOutBuffer, buffer, nOutBufferSize);

	ExFreePool(buffer);

	return r;
}

EXTERN_C BOOL IsCeCtl(ULONG32 ctl_id)
{
	return (
		ctl_id == IOCTL_CE_READMEMORY	||
		ctl_id == IOCTL_CE_WRITEMEMORY ||
		ctl_id == IOCTL_CE_OPENPROCESS ||
		ctl_id == IOCTL_CE_QUERY_VIRTUAL_MEMORY ||
		ctl_id == IOCTL_CE_TEST ||
		ctl_id == IOCTL_CE_GETPEPROCESS ||
		ctl_id == IOCTL_CE_READPHYSICALMEMORY ||
		ctl_id == IOCTL_CE_WRITEPHYSICALMEMORY ||
		ctl_id == IOCTL_CE_GETPHYSICALADDRESS ||
		ctl_id == IOCTL_CE_GETCR3 ||
		ctl_id == IOCTL_CE_SETCR3 ||
		ctl_id == IOCTL_CE_GETSDT ||
		ctl_id == IOCTL_CE_INITIALIZE ||
		ctl_id == IOCTL_CE_DONTPROTECTME ||
		ctl_id == IOCTL_CE_GETIDT ||
		ctl_id == IOCTL_CE_HOOKINTS ||
		ctl_id == IOCTL_CE_DEBUGPROCESS ||
		ctl_id == IOCTL_CE_STARTPROCESSWATCH ||
		ctl_id == IOCTL_CE_GETPROCESSEVENTS ||
		ctl_id == IOCTL_CE_GETTHREADEVENTS ||
		ctl_id == IOCTL_CE_GETVERSION ||
		ctl_id == IOCTL_CE_GETCR4 ||
		ctl_id == IOCTL_CE_OPENTHREAD ||
		ctl_id == IOCTL_CE_MAKEWRITABLE ||
		ctl_id == IOCTL_CE_STOPDEBUGGING ||
		ctl_id == IOCTL_CE_ALLOCATEMEM ||
		ctl_id == IOCTL_CE_CREATEAPC ||
		ctl_id == IOCTL_CE_GETPETHREAD ||
		ctl_id == IOCTL_CE_SUSPENDTHREAD ||
		ctl_id == IOCTL_CE_RESUMETHREAD ||
		ctl_id == IOCTL_CE_SUSPENDPROCESS ||
		ctl_id == IOCTL_CE_RESUMEPROCESS ||
		ctl_id == IOCTL_CE_ALLOCATEMEM_NONPAGED ||
		ctl_id == IOCTL_CE_GETPROCADDRESS ||
		ctl_id == IOCTL_CE_GETSDTADDRESS ||
		ctl_id == IOCTL_CE_GETGDT ||
		ctl_id == IOCTL_CE_SETCR4 ||
		ctl_id == IOCTL_CE_GETTR ||
		ctl_id == IOCTL_CE_VMXCONFIG ||
		ctl_id == IOCTL_CE_GETCR0 ||
		ctl_id == IOCTL_CE_USERDEFINEDINTERRUPTHOOK ||
		ctl_id == IOCTL_CE_SETGLOBALDEBUGSTATE ||
		ctl_id == IOCTL_CE_CONTINUEDEBUGEVENT ||
		ctl_id == IOCTL_CE_WAITFORDEBUGEVENT ||
		ctl_id == IOCTL_CE_GETDEBUGGERSTATE ||
		ctl_id == IOCTL_CE_SETDEBUGGERSTATE ||
		ctl_id == IOCTL_CE_GD_SETBREAKPOINT ||
		ctl_id == IOCTL_CE_TOUCHDEBUGREGISTER ||
		ctl_id == IOCTL_CE_LAUNCHDBVM ||
		ctl_id == IOCTL_CE_UNHOOKALLINTERRUPTS ||
		ctl_id == IOCTL_CE_EXECUTE_CODE ||
		ctl_id == IOCTL_CE_GETPROCESSNAMEADDRESS ||
		ctl_id == IOCTL_CE_SETKERNELSTEPABILITY ||
		ctl_id == IOCTL_CE_READMSR ||
		ctl_id == IOCTL_CE_WRITEMSR ||
		ctl_id == IOCTL_CE_SETSTORELBR ||
		ctl_id == IOCTL_CE_ULTIMAP ||
		ctl_id == IOCTL_CE_ULTIMAP_DISABLE ||
		ctl_id == IOCTL_CE_ULTIMAP_WAITFORDATA ||
		ctl_id == IOCTL_CE_ULTIMAP_CONTINUE ||
		ctl_id == IOCTL_CE_ULTIMAP_FLUSH ||
		ctl_id == IOCTL_CE_GETMEMORYRANGES ||
		ctl_id == IOCTL_CE_STARTACCESMONITOR ||
		ctl_id == IOCTL_CE_ENUMACCESSEDMEMORY ||
		ctl_id == IOCTL_CE_GETACCESSEDMEMORYLIST ||
		ctl_id == IOCTL_CE_WRITESIGNOREWP ||
		ctl_id == IOCTL_CE_FREE_NONPAGED ||
		ctl_id == IOCTL_CE_MAP_MEMORY ||
		ctl_id == IOCTL_CE_UNMAP_MEMORY ||
		ctl_id == IOCTL_CE_ULTIMAP2 ||
		ctl_id == IOCTL_CE_DISABLEULTIMAP2 ||
		ctl_id == IOCTL_CE_ULTIMAP2_WAITFORDATA ||
		ctl_id == IOCTL_CE_ULTIMAP2_CONTINUE ||
		ctl_id == IOCTL_CE_ULTIMAP2_FLUSH ||
		ctl_id == IOCTL_CE_ULTIMAP2_PAUSE ||
		ctl_id == IOCTL_CE_ULTIMAP2_RESUME ||
		ctl_id == IOCTL_CE_ULTIMAP2_LOCKFILE ||
		ctl_id == IOCTL_CE_ULTIMAP2_RELEASEFILE ||
		ctl_id == IOCTL_CE_ULTIMAP_PAUSE ||
		ctl_id == IOCTL_CE_ULTIMAP_RESUME ||
		ctl_id == IOCTL_CE_ULTIMAP2_GETTRACESIZE ||
		ctl_id == IOCTL_CE_ULTIMAP2_RESETTRACESIZE ||
		ctl_id == IOCTL_CE_ENABLE_DRM ||
		ctl_id == IOCTL_CE_GET_PEB ||
		ctl_id == IOCTL_CE_QUERYINFORMATIONPROCESS ||
		ctl_id == IOCTL_CE_NTPROTECTVIRTUALMEMORY ||
		ctl_id == IOCTL_CE_LOCK_MEMORY ||
		ctl_id == IOCTL_CE_UNLOCK_MEMORY ||
		ctl_id == IOCTL_CE_ALLOCATE_MEMORY_FOR_DBVM
		);
}

EXTERN_C NTSTATUS DispatchIoctl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;

	PIO_STACK_LOCATION     irpStack = NULL;
	LUID sedebugprivUID;
	ULONG IoControlCode;

	//if (!loadedbydbvm)
	//{
	//	irpStack=IoGetCurrentIrpStackLocation(Irp);
	//	IoControlCode=irpStack->Parameters.DeviceIoControl.IoControlCode;
	//}
	//else
	//	IoControlCode=Irp->Flags;

	IoControlCode = Irp->Flags;

	//DbgPrint("DispatchIoctl. IoControlCode=%x\n", IoControlCode);
#ifdef TOBESIGNED
	sedebugprivUID.LowPart = SE_DEBUG_PRIVILEGE;
	sedebugprivUID.HighPart = 0;

	if (SeSinglePrivilegeCheck(sedebugprivUID, UserMode) == FALSE)
	{
		DbgPrint("DispatchIoctl called by a process without SeDebugPrivilege");
		return STATUS_UNSUCCESSFUL;
	}
#endif



	switch (IoControlCode)
	{

		case IOCTL_CE_READMEMORY:
			__try
			{
				struct input
				{
					UINT64 processid;
					UINT64 startaddress;
					WORD bytestoread;
				} *pinp;

				pinp = Irp->AssociatedIrp.SystemBuffer;

				ntStatus = ReadProcessMemory((DWORD)pinp->processid, NULL, (PVOID)(UINT_PTR)pinp->startaddress, pinp->bytestoread, pinp) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
			}
			__except (1)
			{
				ntStatus = STATUS_UNSUCCESSFUL;
			};

			break;


		case IOCTL_CE_WRITEMEMORY:
			__try
			{
				struct input
				{
					UINT64 processid;
					UINT64 startaddress;
					WORD bytestowrite;
				} *pinp, inp;

				DbgPrint("sizeof(inp)=%d\n", sizeof(inp));
				pinp = Irp->AssociatedIrp.SystemBuffer;
				ntStatus = WriteProcessMemory((DWORD)pinp->processid, NULL, (PVOID)(UINT_PTR)pinp->startaddress, pinp->bytestowrite, (PVOID)((UINT_PTR)pinp + sizeof(inp))) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
			}
			__except (1)
			{
				//something went wrong and I don't know what
				ntStatus = STATUS_UNSUCCESSFUL;
			};



			break;


		case IOCTL_CE_OPENPROCESS:
		{
			PEPROCESS selectedprocess = NULL;
			ULONG processid = *(PULONG)Irp->AssociatedIrp.SystemBuffer;
			HANDLE ProcessHandle = GetHandleForProcessID((HANDLE)processid);
			struct out
			{
				UINT64 h;
				BYTE   Special;
			} *POutput = Irp->AssociatedIrp.SystemBuffer;


			ntStatus = STATUS_SUCCESS;
			if (ProcessHandle == 0)
			{
				POutput->Special = 0;
				__try
				{
					ProcessHandle = 0;

					if (PsLookupProcessByProcessId((PVOID)(UINT_PTR)(processid), &selectedprocess) == STATUS_SUCCESS)
					{

						//DbgPrint("Calling ObOpenObjectByPointer\n");
						ntStatus = ObOpenObjectByPointer(
							selectedprocess,
							0,
							NULL,
							PROCESS_ALL_ACCESS,
							*PsProcessType,
							KernelMode, //UserMode,
							&ProcessHandle);

						//DbgPrint("ntStatus=%x",ntStatus);
					}
				}
				__except (1)
				{
					ntStatus = STATUS_UNSUCCESSFUL;
				}
			}
			else
			{
				//DbgPrint("ProcessHandle=%x", (int)ProcessHandle);
				POutput->Special = 1;
			}

			if (selectedprocess)
			{
				ObDereferenceObject(selectedprocess);
			}

			POutput->h = (UINT64)ProcessHandle;
			break;
		}


		case IOCTL_CE_OPENTHREAD:
		{
			HANDLE ThreadHandle;
			CLIENT_ID ClientID;
			OBJECT_ATTRIBUTES ObjectAttributes;

			RtlZeroMemory(&ObjectAttributes, sizeof(OBJECT_ATTRIBUTES));

			ntStatus = STATUS_SUCCESS;

			ClientID.UniqueProcess = 0;
			ClientID.UniqueThread = (HANDLE)(UINT_PTR) * (PULONG)Irp->AssociatedIrp.SystemBuffer;
			ThreadHandle = 0;

			__try
			{
				ThreadHandle = 0;
				ntStatus = ZwOpenThread(&ThreadHandle, PROCESS_ALL_ACCESS, &ObjectAttributes, &ClientID);
			}
			__except (1)
			{
				ntStatus = STATUS_UNSUCCESSFUL;
			}

			*(PUINT64)Irp->AssociatedIrp.SystemBuffer = (UINT64)ThreadHandle;


			break;
		}


		case IOCTL_CE_MAKEWRITABLE:
		{
#ifdef AMD64
			//untill I know how win64 handles paging, not implemented
#else
			struct InputBuf
			{
				UINT64 StartAddress;
				ULONG Size;
				BYTE CopyOnWrite;
			} *PInputBuf;

			PInputBuf = Irp->AssociatedIrp.SystemBuffer;

			ntStatus = MakeWritable((PVOID)(UINT_PTR)PInputBuf->StartAddress, PInputBuf->Size, (PInputBuf->CopyOnWrite == 1)) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
#endif
			break;
		}



		case IOCTL_CE_QUERY_VIRTUAL_MEMORY:
		{
			struct InputBuf
			{
				UINT64 ProcessID;
				UINT64 StartAddress;
			} *PInputBuf;

			struct OutputBuf
			{
				UINT64 length;
				DWORD protection;
			} *POutputBuf;



			UINT_PTR BaseAddress;
			UINT_PTR length;
			BOOL ShowResult = 0;


			ntStatus = STATUS_SUCCESS;
			PInputBuf = Irp->AssociatedIrp.SystemBuffer;
			POutputBuf = Irp->AssociatedIrp.SystemBuffer;


			if (PInputBuf->StartAddress == (UINT64)0x12000)
				ShowResult = 1;


			__try
			{
				ntStatus = GetMemoryRegionData((DWORD)PInputBuf->ProcessID, NULL, (PVOID)(UINT_PTR)(PInputBuf->StartAddress), &(POutputBuf->protection), &length, &BaseAddress);
			}
			__except (1)
			{
				DbgPrint("GetMemoryRegionData error");
				ntStatus = STATUS_UNSUCCESSFUL;
				break;
			}

			POutputBuf->length = (UINT64)length;

			if (ShowResult)
			{
				DbgPrint("GetMemoryRegionData returned %x\n", ntStatus);
				DbgPrint("protection=%x\n", POutputBuf->protection);
				DbgPrint("length=%p\n", POutputBuf->length);
				DbgPrint("BaseAddress=%p\n", BaseAddress);
			}



			break;
		}


		case IOCTL_CE_TEST: //just a test to see it's working
		{
			UNICODE_STRING test;
			PVOID x;
			QWORD a, b;

			_disable();
			a = __rdtsc();
			b = __rdtsc();

			_enable();


			DbgPrint("%d\n", (int)(b - a));
			break;
		}

		case IOCTL_CE_GETPETHREAD:
		{

			*(PUINT64)Irp->AssociatedIrp.SystemBuffer = (UINT64)getPEThread((UINT_PTR) * (PULONG)Irp->AssociatedIrp.SystemBuffer);
			ntStatus = STATUS_SUCCESS;
			break;
		}


		case IOCTL_CE_GETPEPROCESS:
		{
			DWORD processid = *(PDWORD)Irp->AssociatedIrp.SystemBuffer;
			PEPROCESS selectedprocess;


			if (processid == 0)
			{
				ntStatus = STATUS_UNSUCCESSFUL;
			}
			else
			{
				if (PsLookupProcessByProcessId((PVOID)(UINT_PTR)(processid), &selectedprocess) == STATUS_SUCCESS)
				{
#ifdef AMD64
					*(PUINT64)Irp->AssociatedIrp.SystemBuffer = (UINT64)selectedprocess;
#else
					*(PUINT64)Irp->AssociatedIrp.SystemBuffer = (DWORD)selectedprocess;
#endif
					//DbgPrint("PEProcess=%llx\n", *(PUINT64)Irp->AssociatedIrp.SystemBuffer);
					ObDereferenceObject(selectedprocess);

				}
				else
					*(PUINT64)Irp->AssociatedIrp.SystemBuffer = 0;
			}

			ntStatus = STATUS_SUCCESS;
			break;
		}


		case IOCTL_CE_READPHYSICALMEMORY:
		{
			struct input
			{
				UINT64 startaddress;
				UINT64 bytestoread;
			} *pinp;
			pinp = Irp->AssociatedIrp.SystemBuffer;

			DbgPrint("IOCTL_CE_READPHYSICALMEMORY:pinp->startaddress=%x, pinp->bytestoread=%d", pinp->startaddress, pinp->bytestoread);


			ntStatus = ReadPhysicalMemory((PVOID)(UINT_PTR)pinp->startaddress, (UINT_PTR)pinp->bytestoread, pinp);
			break;



		}

		case IOCTL_CE_WRITEPHYSICALMEMORY:
		{
			HANDLE			physmem;
			UNICODE_STRING	physmemString;
			OBJECT_ATTRIBUTES attributes;
			WCHAR			physmemName[] = L"\\device\\physicalmemory";
			UCHAR *memoryview;

			RtlInitUnicodeString(&physmemString, physmemName);

			InitializeObjectAttributes(&attributes, &physmemString, OBJ_CASE_INSENSITIVE, NULL, NULL);
			ntStatus = ZwOpenSection(&physmem, SECTION_ALL_ACCESS, &attributes);
			if (ntStatus == STATUS_SUCCESS)
			{
				//hey look, it didn't kill it
				struct input
				{
					UINT64 startaddress;
					UINT64 bytestoread;
				} *pinp;

				UCHAR *pinp2;

				SIZE_T length;
				PHYSICAL_ADDRESS	viewBase;
				UINT_PTR offset;
				UINT_PTR toread;


				pinp = Irp->AssociatedIrp.SystemBuffer;
				pinp2 = (UCHAR *)pinp;
				viewBase.QuadPart = (ULONGLONG)(pinp->startaddress);

				length = 0x2000;//pinp->bytestoread;
				toread = (UINT_PTR)pinp->bytestoread;

				memoryview = NULL;
				ntStatus = ZwMapViewOfSection(
					physmem,  //sectionhandle
					NtCurrentProcess(), //processhandle
					&memoryview, //BaseAddress
					0L, //ZeroBits
					length, //CommitSize
					&viewBase, //SectionOffset
					&length, //ViewSize
					ViewShare,
					0,
					PAGE_READWRITE);

				if (ntStatus == STATUS_SUCCESS)
				{
					offset = (UINT_PTR)(pinp->startaddress) - (UINT_PTR)viewBase.QuadPart;
					RtlCopyMemory(&memoryview[offset], &pinp2[16], toread);

					ZwUnmapViewOfSection(
						NtCurrentProcess(), //processhandle
						memoryview);
				}

				ZwClose(physmem);
			}

			break;
		}



		case IOCTL_CE_GETPHYSICALADDRESS:
		{
			struct input
			{
				UINT64  ProcessID;
				UINT64 BaseAddress;
			} *pinp;

			PEPROCESS selectedprocess;
			PHYSICAL_ADDRESS physical;
			physical.QuadPart = 0;

			ntStatus = STATUS_SUCCESS;
			pinp = Irp->AssociatedIrp.SystemBuffer;

			//DbgPrint("IOCTL_CE_GETPHYSICALADDRESS. ProcessID(%p)=%x BaseAddress(%p)=%x\n",&pinp->ProcessID, pinp->ProcessID, &pinp->BaseAddress, pinp->BaseAddress);

			__try
			{
				//switch to the selected process
				if (PsLookupProcessByProcessId((PVOID)(UINT_PTR)(pinp->ProcessID), &selectedprocess) == STATUS_SUCCESS)
				{
					KAPC_STATE apc_state;
					RtlZeroMemory(&apc_state, sizeof(apc_state));
					KeStackAttachProcess((PVOID)selectedprocess, &apc_state);

					__try
					{
						physical = MmGetPhysicalAddress((PVOID)(UINT_PTR)pinp->BaseAddress);
					}
					__finally
					{
						KeUnstackDetachProcess(&apc_state);
					}


					ObDereferenceObject(selectedprocess);

				}
			}
			__except (1)
			{
				ntStatus = STATUS_UNSUCCESSFUL;
			}

			if (ntStatus == STATUS_SUCCESS)
			{
				//DbgPrint("physical.LowPart=%x",physical.LowPart);
				RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, &physical.QuadPart, 8);

			}


			break;
		}

		case IOCTL_CE_GETMEMORYRANGES:
		{

			struct output
			{
				UINT64 address;
				UINT64 size;
			} *poutp = Irp->AssociatedIrp.SystemBuffer;

			DbgPrint("IOCTL_CE_GETMEMORYRANGES\n");


			if (PhysicalMemoryRanges == 0)
			{
				__try
				{
					PPHYSICAL_MEMORY_RANGE mr = MmGetPhysicalMemoryRanges();

					if (mr)
					{
						//find the end
						int i;
						PhysicalMemoryRanges = (UINT64)mr;
						for (i = 0; mr[i].NumberOfBytes.QuadPart || mr[i].BaseAddress.QuadPart; i++);

						PhysicalMemoryRangesListSize = (UINT64)(&mr[i]) - (UINT64)(&mr[0]);
					}



				}
				__except (1)
				{
					//just in case this function decides to bug out in the future
				}
			}

			poutp->address = PhysicalMemoryRanges;
			poutp->size = PhysicalMemoryRangesListSize;

			ntStatus = STATUS_SUCCESS;

			break;
		}

		case IOCTL_CE_GETSDTADDRESS:
		{
			DbgPrint("Obsolete\n");
			ntStatus = STATUS_UNSUCCESSFUL;
			break;
		}


		case IOCTL_CE_GETCR0:
		{
			*(UINT64 *)Irp->AssociatedIrp.SystemBuffer = getCR0();
			ntStatus = STATUS_SUCCESS;

			break;
		}


		case IOCTL_CE_GETCR4:
		{
			//seems CR4 isn't seen as a register...
			*(UINT64 *)Irp->AssociatedIrp.SystemBuffer = (UINT64)getCR4();
			ntStatus = STATUS_SUCCESS;

			break;
		}


		case IOCTL_CE_SETCR4:
		{
			//seems CR4 isn't seen as a register...
			ULONG cr4reg = *(ULONG *)Irp->AssociatedIrp.SystemBuffer;
			setCR4((UINT64)cr4reg);
			ntStatus = STATUS_SUCCESS;
			break;
		}


		case IOCTL_CE_GETCR3:
		{
			UINT_PTR cr3reg = 0;
			PEPROCESS selectedprocess;


			ntStatus = STATUS_SUCCESS;

			//switch context to the selected process.  (processid is stored in the systembuffer)
			if (PsLookupProcessByProcessId((PVOID)(UINT_PTR)(*(ULONG *)Irp->AssociatedIrp.SystemBuffer), &selectedprocess) == STATUS_SUCCESS)
			{
				__try
				{
					KAPC_STATE apc_state;
					RtlZeroMemory(&apc_state, sizeof(apc_state));
					KeStackAttachProcess((PVOID)selectedprocess, &apc_state);

					__try
					{
						cr3reg = (UINT_PTR)getCR3();

					}
					__finally
					{
						KeUnstackDetachProcess(&apc_state);
					}

				}
				__except (1)
				{
					ntStatus = STATUS_UNSUCCESSFUL;
					break;
				}

				ObDereferenceObject(selectedprocess);

			}

			DbgPrint("cr3reg=%p\n", cr3reg);

			*(UINT64 *)Irp->AssociatedIrp.SystemBuffer = cr3reg;

			break;
		}



		case IOCTL_CE_GETSDT:
		{
			//returns the address of KeServiceDescriptorTable
			ntStatus = STATUS_UNSUCCESSFUL;
			break;
		}



		case IOCTL_CE_GETIDT:
		{
			//returns the address of the IDT of the current CPU
			IDT idt;
			RtlZeroMemory(&idt, sizeof(IDT));
			GetIDT(&idt);
			RtlZeroMemory(Irp->AssociatedIrp.SystemBuffer, 2 + 8); //so that the 32-bit version doesn't have to deal with garbage at the end
			RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, &idt, sizeof(IDT)); //copy idt
			ntStatus = STATUS_SUCCESS;

			break;
		}

		case IOCTL_CE_GETGDT:
		{
			//returns the address of the IDT of the current CPU
			GDT gdt;
			RtlZeroMemory(&gdt, sizeof(GDT));
			GetGDT(&gdt);
			RtlZeroMemory(Irp->AssociatedIrp.SystemBuffer, 2 + 8);
			RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, &gdt, sizeof(GDT)); //copy gdt
			ntStatus = STATUS_SUCCESS;

			break;
		}

		case IOCTL_CE_LAUNCHDBVM:
		{
			struct intput
			{
				UINT64 dbvmimgpath;
				DWORD32 cpuid;
			} *pinp;
			pinp = Irp->AssociatedIrp.SystemBuffer;
			DbgPrint("IOCTL_CE_LAUNCHDBVM\n");

			initializeDBVM((PCWSTR)(UINT_PTR)pinp->dbvmimgpath);

			if (pinp->cpuid == 0xffffffff) {
				forEachCpu(vmxoffload_dpc, NULL, NULL, NULL, vmxoffload_override);
				cleanupDBVM();
			}
			else
				forOneCpu((CCHAR)pinp->cpuid, vmxoffload_dpc, NULL, NULL, NULL, vmxoffload_override);

			DbgPrint("Returned from vmxoffload()\n");
			break;
		}


		case IOCTL_CE_HOOKINTS: //hooks the DEBUG interrupts
		{
			DbgPrint("IOCTL_CE_HOOKINTS\n");
			forEachCpu(debugger_initHookForCurrentCPU_DPC, NULL, NULL, NULL, NULL);
			ntStatus = STATUS_SUCCESS;

			/*
			DbgPrint("IOCTL_CE_HOOKINTS for cpu %d\n", cpunr());
			if (debugger_initHookForCurrentCPU())
				ntStatus=STATUS_SUCCESS;
			else
				ntStatus=STATUS_UNSUCCESSFUL;*/

			break;
		}

		case IOCTL_CE_USERDEFINEDINTERRUPTHOOK:
		{
			struct intput
			{
				UINT64 interruptnumber;
				UINT64 newCS;
				UINT64 newRIP;
				UINT64 addressofjumpback;
			} *pinp;
			DbgPrint("IOCTL_CE_USERDEFINEDINTERRUPTHOOK\n");

			pinp = Irp->AssociatedIrp.SystemBuffer;

			inthook_HookInterrupt((unsigned char)(pinp->interruptnumber), (int)pinp->newCS, (ULONG_PTR)pinp->newRIP, (PJUMPBACK)(UINT_PTR)(pinp->addressofjumpback));
			DbgPrint("After the hook\n");
			ntStatus = STATUS_SUCCESS;
			break;
		}


		case IOCTL_CE_UNHOOKALLINTERRUPTS:
		{
			int i;
			DbgPrint("IOCTL_CE_UNHOOKALLINTERRUPTS for cpu %d\n", cpunr());
			for (i = 0; i < 256; i++)
				inthook_UnhookInterrupt((unsigned char)i);

			ntStatus = STATUS_SUCCESS;
			break;
		}

		case IOCTL_CE_SETGLOBALDEBUGSTATE:
		{
			struct intput
			{
				BOOL newstate;
			} *pinp;
			pinp = Irp->AssociatedIrp.SystemBuffer;
			debugger_setGlobalDebugState(pinp->newstate);
			ntStatus = STATUS_SUCCESS;
			break;
		}

		case IOCTL_CE_DEBUGPROCESS:
		{
			struct input
			{
				DWORD	ProcessID;
			} *pinp;

			DbgPrint("IOCTL_CE_DEBUGPROCESS\n");
			pinp = Irp->AssociatedIrp.SystemBuffer;

			debugger_startDebugging(pinp->ProcessID);

			ntStatus = STATUS_SUCCESS;

			break;

		}

		case IOCTL_CE_STOPDEBUGGING:
		{
			debugger_stopDebugging();
			ntStatus = STATUS_SUCCESS;
			break;
		}





		case IOCTL_CE_STARTPROCESSWATCH:
		{
			NTSTATUS r = STATUS_SUCCESS;
			DbgPrint("IOCTL_CE_STARTPROCESSWATCH\n");

			ProcessWatcherOpensHandles = *(char *)Irp->AssociatedIrp.SystemBuffer != 0;

			if (CreateProcessNotifyRoutineEnabled && WatcherProcess)
			{
				ntStatus = STATUS_UNSUCCESSFUL;
				break;
			}

			//still here
			ExAcquireResourceExclusiveLite(&ProcesslistR, TRUE);
			ProcessEventCount = 0;
			ExReleaseResourceLite(&ProcesslistR);

			//DbgPrint("IOCTL_CE_STARTPROCESSWATCH\n");

			CleanProcessList();



			if ((r == STATUS_SUCCESS) && (CreateProcessNotifyRoutineEnabled == FALSE))
			{

				DbgPrint("calling PsSetCreateProcessNotifyRoutine\n");


#if (NTDDI_VERSION >= NTDDI_VISTASP1) 
				r = PsSetCreateProcessNotifyRoutineEx(CreateProcessNotifyRoutineEx, FALSE);
				CreateProcessNotifyRoutineEnabled = r == STATUS_SUCCESS;
#else
				CreateProcessNotifyRoutineEnabled = (PsSetCreateProcessNotifyRoutine(CreateProcessNotifyRoutine, FALSE) == STATUS_SUCCESS);
#endif
				if (CreateProcessNotifyRoutineEnabled)
					CreateThreadNotifyRoutineEnabled = (PsSetCreateThreadNotifyRoutine(CreateThreadNotifyRoutine) == STATUS_SUCCESS);
			}

			ntStatus = (CreateProcessNotifyRoutineEnabled) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;

			if (ntStatus == STATUS_SUCCESS)
				DbgPrint("CreateProcessNotifyRoutineEnabled worked\n");
			else
				DbgPrint("CreateProcessNotifyRoutineEnabled failed (r=%x)\n", r);


			break;
		}



		case IOCTL_CE_GETPROCESSEVENTS:
		{

			ExAcquireResourceExclusiveLite(&ProcesslistR, TRUE);

			*(PUCHAR)Irp->AssociatedIrp.SystemBuffer = ProcessEventCount;
			RtlCopyMemory((PVOID)((UINT_PTR)Irp->AssociatedIrp.SystemBuffer + 1), &ProcessEventdata[0], ProcessEventCount * sizeof(ProcessEventdta));
			ProcessEventCount = 0; //there's room for new events

			ExReleaseResourceLite(&ProcesslistR);

			ntStatus = STATUS_SUCCESS;
			break;
		}


		case IOCTL_CE_GETTHREADEVENTS:
		{
			ExAcquireResourceExclusiveLite(&ProcesslistR, TRUE);

			*(PUCHAR)Irp->AssociatedIrp.SystemBuffer = ThreadEventCount;
			RtlCopyMemory((PVOID)((UINT_PTR)Irp->AssociatedIrp.SystemBuffer + 1), &ThreadEventData[0], ThreadEventCount * sizeof(ThreadEventDta));
			ThreadEventCount = 0; //there's room for new events

			ExReleaseResourceLite(&ProcesslistR);

			ntStatus = STATUS_SUCCESS;
			break;
		}



		case IOCTL_CE_CREATEAPC:
		{
			struct input
			{
				UINT64 threadid;
				UINT64 addresstoexecute;
			} *inp;
			inp = Irp->AssociatedIrp.SystemBuffer;

			CreateRemoteAPC((ULONG)inp->threadid, (PVOID)(UINT_PTR)inp->addresstoexecute);
			ntStatus = STATUS_SUCCESS;
			break;
		}


		case IOCTL_CE_SUSPENDTHREAD:
		{
			struct input
			{
				ULONG threadid;
			} *inp;
			inp = Irp->AssociatedIrp.SystemBuffer;

			DbgPrint("CE_SUSPENDTHREAD\n");

			DBKSuspendThread(inp->threadid);
			ntStatus = STATUS_SUCCESS;
			break;
		}

		case IOCTL_CE_RESUMETHREAD:
		{
			struct input
			{
				ULONG threadid;
			} *inp;
			inp = Irp->AssociatedIrp.SystemBuffer;

			DbgPrint("CE_RESUMETHREAD\n");

			DBKResumeThread(inp->threadid);
			ntStatus = STATUS_SUCCESS;
			break;
		}


		case IOCTL_CE_SUSPENDPROCESS:
		{
			struct input
			{
				ULONG processid;
			} *inp;
			inp = Irp->AssociatedIrp.SystemBuffer;



			DbgPrint("IOCTL_CE_SUSPENDPROCESS\n");

			if (PsSuspendProcess)
			{
				PEPROCESS selectedprocess;
				if (PsLookupProcessByProcessId((PVOID)(UINT_PTR)(inp->processid), &selectedprocess) == STATUS_SUCCESS)
				{
					ntStatus = PsSuspendProcess(selectedprocess);
					ObDereferenceObject(selectedprocess);
				}
				else
					ntStatus = STATUS_NOT_FOUND;
			}
			else
				ntStatus = STATUS_NOT_IMPLEMENTED;

			break;
		}


		case IOCTL_CE_RESUMEPROCESS:
		{
			struct input
			{
				ULONG processid;
			} *inp;
			inp = Irp->AssociatedIrp.SystemBuffer;



			DbgPrint("IOCTL_CE_RESUMEPROCESS\n");

			if (PsResumeProcess)
			{
				PEPROCESS selectedprocess;
				if (PsLookupProcessByProcessId((PVOID)(UINT_PTR)(inp->processid), &selectedprocess) == STATUS_SUCCESS)
				{
					ntStatus = PsResumeProcess(selectedprocess);
					ObDereferenceObject(selectedprocess);
				}
				else
					ntStatus = STATUS_NOT_FOUND;
			}
			else
				ntStatus = STATUS_NOT_IMPLEMENTED;

			break;
		}

		case IOCTL_CE_ALLOCATEMEM:
		{
			struct input
			{
				UINT64 ProcessID;
				UINT64 BaseAddress;
				UINT64 Size;
				UINT64 AllocationType;
				UINT64 Protect;
			} *inp;
			PEPROCESS selectedprocess;

			PVOID BaseAddress;
			SIZE_T RegionSize;


			inp = Irp->AssociatedIrp.SystemBuffer;
			BaseAddress = (PVOID)(UINT_PTR)inp->BaseAddress;
			RegionSize = (SIZE_T)(inp->Size);


			if (PsLookupProcessByProcessId((PVOID)(UINT_PTR)(inp->ProcessID), &selectedprocess) == STATUS_SUCCESS)
			{
				__try
				{
					KAPC_STATE apc_state;
					RtlZeroMemory(&apc_state, sizeof(apc_state));
					KeAttachProcess((PVOID)selectedprocess); //local process is much more fun!!!!

					DbgPrint("Switched Process\n");
					__try
					{
						DbgPrint("Calling ZwAllocateVirtualMemory\n");
						DbgPrint("Before call: BaseAddress=%p\n", BaseAddress);
						DbgPrint("Before call: RegionSize=%x\n", RegionSize);

						ntStatus = ZwAllocateVirtualMemory((HANDLE)-1, &BaseAddress, 0, &RegionSize, (ULONG)inp->AllocationType, (ULONG)inp->Protect);

						if ((ntStatus == STATUS_SUCCESS) && (HiddenDriver))
						{
							//initialize the memory with crap so it becomes paged
							int i;
							char *x;
							x = BaseAddress;
							for (i = 0; i < (int)RegionSize; i++)
								x[i] = (unsigned char)i;
						}

						DbgPrint("ntStatus=%x\n", ntStatus);
						DbgPrint("BaseAddress=%p\n", BaseAddress);
						DbgPrint("RegionSize=%x\n", RegionSize);
						*(PUINT64)Irp->AssociatedIrp.SystemBuffer = 0;
						*(PUINT_PTR)Irp->AssociatedIrp.SystemBuffer = (UINT_PTR)BaseAddress;

					}
					__finally
					{
						KeDetachProcess();
					}

				}
				__except (1)
				{
					ntStatus = STATUS_UNSUCCESSFUL;
					break;
				}


				ObDereferenceObject(selectedprocess);
			}

			break;
		}


		case IOCTL_CE_ALLOCATEMEM_NONPAGED:
		{
			struct input
			{
				ULONG Size;
			} *inp;
			PVOID address;
			int size;

			inp = Irp->AssociatedIrp.SystemBuffer;
			size = inp->Size;

			address = ExAllocatePool(NonPagedPool, size);
			*(PUINT64)Irp->AssociatedIrp.SystemBuffer = 0;
			*(PUINT_PTR)Irp->AssociatedIrp.SystemBuffer = (UINT_PTR)address;


			if (address == 0)
				ntStatus = STATUS_UNSUCCESSFUL;
			else
			{
				DbgPrint("Alloc success. Cleaning memory... (size=%d)\n", size);

				DbgPrint("address=%p\n", address);
				RtlZeroMemory(address, size);

				ntStatus = STATUS_SUCCESS;
			}

			break;
		}

		case IOCTL_CE_FREE_NONPAGED:
		{
			struct input
			{
				UINT64 Address;
			} *inp;

			inp = Irp->AssociatedIrp.SystemBuffer;

			ExFreePool((PVOID)(UINT_PTR)inp->Address);

			ntStatus = STATUS_SUCCESS;

			break;
		}


		case IOCTL_CE_MAP_MEMORY:
		{
			struct input
			{
				UINT64 FromPID;
				UINT64 ToPID;
				UINT64 address;
				DWORD size;
			} *inp;

			struct output
			{
				UINT64 FromMDL;
				UINT64 Address;
			} *outp;

			KAPC_STATE apc_state;
			PEPROCESS selectedprocess;
			PMDL FromMDL = NULL;

			inp = Irp->AssociatedIrp.SystemBuffer;
			outp = Irp->AssociatedIrp.SystemBuffer;

			DbgPrint("IOCTL_CE_MAP_MEMORY\n");
			DbgPrint("address %x size %d\n", inp->address, inp->size);
			ntStatus = STATUS_UNSUCCESSFUL;

			if (inp->FromPID)
			{
				//switch
				DbgPrint("From PID %d\n", inp->FromPID);
				if (PsLookupProcessByProcessId((PVOID)(UINT_PTR)(inp->FromPID), &selectedprocess) == STATUS_SUCCESS)
				{
					__try
					{
						RtlZeroMemory(&apc_state, sizeof(apc_state));
						KeStackAttachProcess((PVOID)selectedprocess, &apc_state);

						__try
						{
							FromMDL = IoAllocateMdl((PVOID)(UINT_PTR)inp->address, inp->size, FALSE, FALSE, NULL);
							if (FromMDL)
								MmProbeAndLockPages(FromMDL, KernelMode, IoReadAccess);
						}
						__finally
						{
							KeUnstackDetachProcess(&apc_state);
						}

					}
					__except (1)
					{
						DbgPrint("Exception\n");
						ntStatus = STATUS_UNSUCCESSFUL;
						break;
					}

					ObDereferenceObject(selectedprocess);
				}
			}
			else
			{
				DbgPrint("From kernel or self\n", inp->FromPID);
				__try
				{
					FromMDL = IoAllocateMdl((PVOID)(UINT_PTR)inp->address, inp->size, FALSE, FALSE, NULL);
					if (FromMDL)
					{
						DbgPrint("IoAllocateMdl success\n");
						MmProbeAndLockPages(FromMDL, KernelMode, IoReadAccess);
					}
				}
				__except (1)
				{
					DbgPrint("Exception\n");

					if (FromMDL)
					{
						IoFreeMdl(FromMDL);
						FromMDL = NULL;
					}
				}
			}

			if (FromMDL)
			{
				DbgPrint("FromMDL is valid\n");

				if (inp->ToPID)
				{
					//switch
					DbgPrint("To PID %d\n", inp->ToPID);
					if (PsLookupProcessByProcessId((PVOID)(UINT_PTR)(inp->ToPID), &selectedprocess) == STATUS_SUCCESS)
					{
						__try
						{
							RtlZeroMemory(&apc_state, sizeof(apc_state));
							KeStackAttachProcess((PVOID)selectedprocess, &apc_state);

							__try
							{
								outp->Address = (UINT64)MmMapLockedPagesSpecifyCache(FromMDL, UserMode, MmWriteCombined, NULL, FALSE, NormalPagePriority);
								outp->FromMDL = (UINT64)FromMDL;
								ntStatus = STATUS_SUCCESS;
							}
							__finally
							{
								KeUnstackDetachProcess(&apc_state);
							}

						}
						__except (1)
						{
							DbgPrint("Exception part 2\n");
							ntStatus = STATUS_UNSUCCESSFUL;
							break;
						}

						ObDereferenceObject(selectedprocess);
					}
				}
				else
				{
					DbgPrint("To kernel or self\n", inp->FromPID);

					__try
					{
						outp->Address = (UINT64)MmMapLockedPagesSpecifyCache(FromMDL, UserMode, MmWriteCombined, NULL, FALSE, NormalPagePriority);
						outp->FromMDL = (UINT64)FromMDL;
						ntStatus = STATUS_SUCCESS;
					}
					__except (1)
					{
						DbgPrint("Exception part 2\n");
					}
				}





			}
			else
				DbgPrint("FromMDL==NULL\n");



			break;
		}

		case IOCTL_CE_UNMAP_MEMORY:
		{
			struct output
			{
				UINT64 FromMDL;
				UINT64 Address;
			} *inp;

			PMDL mdl;

			inp = Irp->AssociatedIrp.SystemBuffer;
			mdl = (PMDL)(UINT_PTR)inp->FromMDL;

			MmUnmapLockedPages((PMDL)(UINT_PTR)inp->Address, mdl);
			MmUnlockPages(mdl);
			IoFreeMdl(mdl);

			ntStatus = STATUS_SUCCESS; //no BSOD means success ;)

			break;
		}

		case IOCTL_CE_LOCK_MEMORY:
		{
			struct
			{
				UINT64 ProcessID;
				UINT64 address;
				UINT64 size;
			} *inp;

			struct
			{
				UINT64 mdl;
			} *outp;
			KAPC_STATE apc_state;
			PEPROCESS selectedprocess;

			DbgPrint("IOCTL_CE_LOCK_MEMORY");
			inp = Irp->AssociatedIrp.SystemBuffer;
			outp = Irp->AssociatedIrp.SystemBuffer;



			if (PsLookupProcessByProcessId((PVOID)(UINT_PTR)(inp->ProcessID), &selectedprocess) == STATUS_SUCCESS)
			{
				PMDL mdl = NULL;
				KeStackAttachProcess(selectedprocess, &apc_state);

				__try
				{
					mdl = IoAllocateMdl((PVOID)(UINT_PTR)inp->address, (ULONG)inp->size, FALSE, FALSE, NULL);
					if (mdl)
					{
						__try
						{
							MmProbeAndLockPages(mdl, UserMode, IoReadAccess);

							DbgPrint("MmProbeAndLockPages succeeded");
						}
						__except (1)
						{
							DbgPrint("MmProbeAndLockPages failed");
							IoFreeMdl(mdl);
							ntStatus = STATUS_UNSUCCESSFUL;
							break;
						}

					}
				}
				__finally
				{
					KeUnstackDetachProcess(&apc_state);
				}

				outp->mdl = (UINT_PTR)mdl;


				DbgPrint("Locked the page\n");
				ntStatus = STATUS_SUCCESS;
			}

			break;
		}

		case IOCTL_CE_UNLOCK_MEMORY:
		{
			struct
			{
				UINT64 mdl;
			} *inp;
			DbgPrint("IOCTL_CE_UNLOCK_MEMORY");
			inp = Irp->AssociatedIrp.SystemBuffer;

			MmUnlockPages((PMDL)(UINT_PTR)inp->mdl);
			IoFreeMdl((PMDL)(UINT_PTR)inp->mdl);
			break;
		}

		case IOCTL_CE_GETPROCADDRESS:
		{
			struct input
			{
				UINT64 s;
			} *inp;
			UNICODE_STRING y;
			UINT64 result;
			PVOID x;



			inp = Irp->AssociatedIrp.SystemBuffer;

			RtlInitUnicodeString(&y, (PCWSTR)(UINT_PTR)(inp->s));
			x = MmGetSystemRoutineAddress(&y);
			result = (UINT64)x;


			RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, &result, 8);
			ntStatus = STATUS_SUCCESS;

			break;
		}

		case IOCTL_CE_GETPROCESSNAMEADDRESS:
		{
			struct input
			{
				UINT64 PEPROCESS;
			} *inp;

			struct output
			{
				UINT64 Address;
			} *outp;

			UNICODE_STRING temp;

			inp = Irp->AssociatedIrp.SystemBuffer;
			outp = Irp->AssociatedIrp.SystemBuffer;

			RtlInitUnicodeString(&temp, L"PsGetProcessImageFileName");
			PsGetProcessImageFileName = (GET_PROCESS_IMAGE_NAME)MmGetSystemRoutineAddress(&temp);
			if (PsGetProcessImageFileName != NULL)
			{
				outp->Address = (UINT_PTR)PsGetProcessImageFileName((PEPROCESS)((UINT_PTR)(inp->PEPROCESS)));
				ntStatus = STATUS_SUCCESS;
			}
			else
			{
				DbgPrint("PsGetProcessImageFileName==NULL");
				ntStatus = STATUS_UNSUCCESSFUL;
			}


			break;
		}
		/*x
				case IOCTL_CE_MAKEKERNELCOPY:
					{
						struct input
						{
							ULONG Base;
							ULONG KernelSize;
						} *inp;
						DbgPrint("IOCTL_CE_MAKEKERNELCOPY");
						inp=Irp->AssociatedIrp.SystemBuffer;
						ntStatus=makeKernelCopy(inp->Base, inp->KernelSize);
						break;
					}
		*/


		case IOCTL_CE_CONTINUEDEBUGEVENT:
		{
			struct input
			{
				BOOL handled;
			} *inp = Irp->AssociatedIrp.SystemBuffer;

			DbgPrint("IOCTL_CE_CONTINUEDEBUGEVENT\n");
			ntStatus = debugger_continueDebugEvent(inp->handled);
			break;

		}

		case IOCTL_CE_WAITFORDEBUGEVENT:
		{
			struct input
			{
				ULONG timeout;
			} *inp = Irp->AssociatedIrp.SystemBuffer;

			ntStatus = debugger_waitForDebugEvent(inp->timeout);

			break;

		}

		case IOCTL_CE_GETDEBUGGERSTATE:
		{
			DbgPrint("IOCTL_CE_GETDEBUGGERSTATE\n");
			__try
			{
				ntStatus = debugger_getDebuggerState((PDebugStackState)(Irp->AssociatedIrp.SystemBuffer));
			}
			__except (1)
			{
				DbgPrint("Exception happened\n");
				ntStatus = STATUS_UNSUCCESSFUL;
			}

			DbgPrint("ntStatus=%x rax=%x\n", ntStatus, ((PDebugStackState)(Irp->AssociatedIrp.SystemBuffer))->rax);
			break;
		}

		case IOCTL_CE_SETDEBUGGERSTATE:
		{
			DbgPrint("IOCTL_CE_SETDEBUGGERSTATE: state->rax=%x\n", ((PDebugStackState)(Irp->AssociatedIrp.SystemBuffer))->rax);
			__try
			{
				ntStatus = debugger_setDebuggerState((PDebugStackState)Irp->AssociatedIrp.SystemBuffer);
			}
			__except (1)
			{
				DbgPrint("Exception happened\n");
				ntStatus = STATUS_UNSUCCESSFUL;
			}
			break;
		}

		case IOCTL_CE_SETKERNELSTEPABILITY:
		{
			struct input
			{
				int state;

			} *inp = Irp->AssociatedIrp.SystemBuffer;
			KernelCodeStepping = inp->state;
			ntStatus = STATUS_SUCCESS;
			break;
		}

		case IOCTL_CE_WRITESIGNOREWP:
		{
			KernelWritesIgnoreWP = *(BYTE *)Irp->AssociatedIrp.SystemBuffer;
			ntStatus = STATUS_SUCCESS;
			break;
		}


		case IOCTL_CE_GD_SETBREAKPOINT:
		{
			struct input
			{
				BOOL active;
				int debugregspot;
				UINT64 address;
				DWORD breakType;
				DWORD breakLength;
			} *inp = Irp->AssociatedIrp.SystemBuffer;

			DbgPrint("sizeof(struct input)=%d\n", sizeof(struct input));
			//DbgPrint("address=%llx breakType=%d breakLength=%d\n",inp->address, inp->breakType,inp->breakLength);

			if (inp->active)
			{
				DbgPrint("activating breapoint %d\n", inp->debugregspot);
				ntStatus = debugger_setGDBreakpoint(inp->debugregspot, (UINT_PTR)inp->address, (BreakType)inp->breakType, (BreakLength)inp->breakLength);
			}
			else
			{
				DbgPrint("Deactivating breakpoint :%d\n", inp->debugregspot);
				ntStatus = debugger_unsetGDBreakpoint(inp->debugregspot);
			}
			break;
		}

		case IOCTL_CE_TOUCHDEBUGREGISTER: //used after setting a global debug breakpoint
		{
			debugger_touchDebugRegister(0);
			ntStatus = STATUS_SUCCESS;
			break;
		}

		case IOCTL_CE_SETSTORELBR:
		{
			BOOL newstate = *(PBOOL)Irp->AssociatedIrp.SystemBuffer;

			DbgPrint("Calling debugger_setStoreLBR(%d)\n", newstate);
			debugger_setStoreLBR(newstate);
			ntStatus = STATUS_SUCCESS;
			break;
		}


		case IOCTL_CE_EXECUTE_CODE:
		{
			typedef NTSTATUS(*PARAMETERLESSFUNCTION)(UINT64 parameters);
			PARAMETERLESSFUNCTION functiontocall;

			struct input
			{
				UINT64	functionaddress; //function address to call
				UINT64	parameters;
			} *inp = Irp->AssociatedIrp.SystemBuffer;
			DbgPrint("IOCTL_CE_EXECUTE_CODE\n");

			functiontocall = (PARAMETERLESSFUNCTION)(UINT_PTR)(inp->functionaddress);

			__try
			{
				ntStatus = functiontocall(inp->parameters);
				DbgPrint("Still alive\n");
				ntStatus = STATUS_SUCCESS;
			}
			__except (1)
			{
				DbgPrint("Exception occured\n");
				ntStatus = STATUS_UNSUCCESSFUL;
			}

			break;
		}


		case IOCTL_CE_GETVERSION:
		{
			DbgPrint("IOCTL_CE_GETVERSION. Version=%d\n", dbkversion);
			*(PULONG)Irp->AssociatedIrp.SystemBuffer = dbkversion;
			ntStatus = STATUS_SUCCESS;
			break;
		}

		case IOCTL_CE_READMSR:
		{
			DWORD msr = *(PDWORD)Irp->AssociatedIrp.SystemBuffer;

			//DbgPrint("IOCTL_CE_READMSR: msr=%x\n", msr);

			__try
			{
				*(PUINT64)Irp->AssociatedIrp.SystemBuffer = __readmsr(msr);
				//DbgPrint("Output: %llx\n",*(PUINT64)Irp->AssociatedIrp.SystemBuffer); 

				ntStatus = STATUS_SUCCESS;
			}
			__except (1)
			{
				ntStatus = STATUS_UNSUCCESSFUL;
			}

			break;
		}

		case IOCTL_CE_WRITEMSR:
		{
			struct input
			{
				UINT64 msr;
				UINT64 value;
			} *inp = Irp->AssociatedIrp.SystemBuffer;

			DbgPrint("IOCTL_CE_WRITEMSR:\n");
			DbgPrint("msr=%llx\n", inp->msr);
			DbgPrint("value=%llx\n", inp->value);

			__try
			{
				__writemsr(inp->msr, inp->value);
				ntStatus = STATUS_SUCCESS;
			}
			__except (1)
			{
				DbgPrint("Error while writing value\n");
				ntStatus = STATUS_UNSUCCESSFUL;
			}
			break;
		}

		case IOCTL_CE_ULTIMAP2:
		{
			struct input
			{
				UINT32 PID;
				UINT32 Size;
				UINT32 RangeCount;
				UINT32 NoPMI;
				UINT32 UserMode;
				UINT32 KernelMode;
				URANGE Ranges[8];
				WCHAR OutputPath[200];
			} *inp = Irp->AssociatedIrp.SystemBuffer;
			int i;

			DbgPrint("IOCTL_CE_ULTIMAP2");
			for (i = 0; i < (int)(inp->RangeCount); i++)
				DbgPrint("%d=%p -> %p", i, (PVOID)(UINT_PTR)inp->Ranges[i].StartAddress, (PVOID)(UINT_PTR)inp->Ranges[i].EndAddress);

			SetupUltimap2(inp->PID, inp->Size, inp->OutputPath, inp->RangeCount, inp->Ranges, inp->NoPMI, inp->UserMode, inp->KernelMode);

			ntStatus = STATUS_SUCCESS;
			break;
		}

		case IOCTL_CE_ULTIMAP2_WAITFORDATA:
		{

			ULONG timeout = *(ULONG *)Irp->AssociatedIrp.SystemBuffer;
			PULTIMAP2DATAEVENT output = Irp->AssociatedIrp.SystemBuffer;
			output->Address = 0;

			ntStatus = ultimap2_waitForData(timeout, output);

			break;
		}

		case IOCTL_CE_ULTIMAP2_LOCKFILE:
		{
			int cpunr = *(int *)Irp->AssociatedIrp.SystemBuffer;
			ultimap2_LockFile(cpunr);

			ntStatus = STATUS_SUCCESS;
			break;
		}

		case IOCTL_CE_ULTIMAP2_RELEASEFILE:
		{
			int cpunr = *(int *)Irp->AssociatedIrp.SystemBuffer;
			ultimap2_ReleaseFile(cpunr);

			ntStatus = STATUS_SUCCESS;
			break;
		}

		case IOCTL_CE_ULTIMAP2_GETTRACESIZE:
		{
			*(UINT64 *)Irp->AssociatedIrp.SystemBuffer = ultimap2_GetTraceFileSize();
			ntStatus = STATUS_SUCCESS;
			break;
		}

		case IOCTL_CE_ULTIMAP2_RESETTRACESIZE:
		{
			ultimap2_ResetTraceFileSize();
			ntStatus = STATUS_SUCCESS;
			break;
		}


		case IOCTL_CE_ULTIMAP2_CONTINUE:
		{
			int cpunr = *(int *)Irp->AssociatedIrp.SystemBuffer;
			ntStatus = ultimap2_continue(cpunr);

			break;
		}

		case IOCTL_CE_ULTIMAP2_FLUSH:
		{
			ntStatus = ultimap2_flushBuffers();
			break;
		}

		case IOCTL_CE_ULTIMAP2_PAUSE:
		{
			ntStatus = ultimap2_pause();
			break;
		}

		case IOCTL_CE_ULTIMAP2_RESUME:
		{
			ntStatus = ultimap2_resume();
			break;
		}

		case IOCTL_CE_DISABLEULTIMAP2:
		{
			DisableUltimap2();
			break;
		}

		case IOCTL_CE_ULTIMAP:
		{
#pragma pack(1)
			struct input
			{
				UINT64 targetCR3;
				UINT64 dbgctl;
				UINT64 dsareasize;
				BOOL savetofile;
				int HandlerCount;
				WCHAR filename[200];
			} *inp = Irp->AssociatedIrp.SystemBuffer;
#pragma pack()


			DbgPrint("IOCTL_CE_ULTIMAP:\n");
			DbgPrint("ultimap(%I64x, %I64x, %d):\n", (UINT64)inp->targetCR3, (UINT64)inp->dbgctl, inp->dsareasize);

			if (inp->savetofile)
				DbgPrint("filename=%S\n", &inp->filename[0]);

			ntStatus = ultimap(inp->targetCR3, inp->dbgctl, (int)inp->dsareasize, inp->savetofile, &inp->filename[0], inp->HandlerCount);



			break;
		}

		case IOCTL_CE_ULTIMAP_DISABLE:
		{
			ultimap_disable();
			ntStatus = STATUS_SUCCESS;
			break;
		}

		case IOCTL_CE_ULTIMAP_WAITFORDATA:
		{

			ULONG timeout = *(ULONG *)Irp->AssociatedIrp.SystemBuffer;
			PULTIMAPDATAEVENT output = Irp->AssociatedIrp.SystemBuffer;
			ntStatus = ultimap_waitForData(timeout, output);

			break;
		}

		case IOCTL_CE_ULTIMAP_CONTINUE:
		{
			PULTIMAPDATAEVENT input = Irp->AssociatedIrp.SystemBuffer;
			ntStatus = ultimap_continue(input);

			break;
		}

		case IOCTL_CE_ULTIMAP_FLUSH:
		{
			ultimap_flushBuffers();
			ntStatus = STATUS_SUCCESS;
			break;
		}

		case IOCTL_CE_ULTIMAP_PAUSE:
		{
			ultimap_pause();
			ntStatus = STATUS_SUCCESS;
			break;
		}

		case IOCTL_CE_ULTIMAP_RESUME:
		{
			ultimap_resume();
			ntStatus = STATUS_SUCCESS;
			break;
		}

		/*
	case IOCTL_CE_GETCPUIDS:
		{
			CPULISTFILLSTRUCT x;

			forEachCpuPassive(GetCPUIDS_all,&x);
		}*/

		case IOCTL_CE_STARTACCESMONITOR:
		{
			//this is used instead of writeProcessMemory for speed reasons (the reading out is still done with readProcessMemory because of easier memory management)
			struct input
			{
				UINT64 ProcessID;
			} *inp;
			PEPROCESS selectedprocess;

			PVOID BaseAddress;
			SIZE_T RegionSize;

			inp = Irp->AssociatedIrp.SystemBuffer;
			DbgPrint("IOCTL_CE_STARTACCESMONITOR(%d)\n", inp->ProcessID);


			ntStatus = STATUS_UNSUCCESSFUL;

			if (PsLookupProcessByProcessId((PVOID)(UINT_PTR)(inp->ProcessID), &selectedprocess) == STATUS_SUCCESS)
			{
				ntStatus = markAllPagesAsNeverAccessed(selectedprocess);
				ObDereferenceObject(selectedprocess);
			}

			break;
		}

		case IOCTL_CE_ENUMACCESSEDMEMORY:
		{
			struct input
			{
				UINT64 ProcessID;
			} *inp;
			PEPROCESS selectedprocess;

			PVOID BaseAddress;
			SIZE_T RegionSize;

			inp = Irp->AssociatedIrp.SystemBuffer;
			DbgPrint("IOCTL_CE_ENUMACCESSEDMEMORY(%d)\n", inp->ProcessID);


			ntStatus = STATUS_UNSUCCESSFUL;

			if (PsLookupProcessByProcessId((PVOID)(UINT_PTR)(inp->ProcessID), &selectedprocess) == STATUS_SUCCESS)
			{
				*(int *)Irp->AssociatedIrp.SystemBuffer = enumAllAccessedPages(selectedprocess);
				ObDereferenceObject(selectedprocess);
			}

			ntStatus = STATUS_SUCCESS;
			break;
		}

		case IOCTL_CE_GETACCESSEDMEMORYLIST:
		{
			int ListSizeInBytes = *(int *)Irp->AssociatedIrp.SystemBuffer;
			PPRANGE List = (PPRANGE)Irp->AssociatedIrp.SystemBuffer;

			DbgPrint("IOCTL_CE_GETACCESSEDMEMORYLIST\n");

			getAccessedPageList(List, ListSizeInBytes);

			DbgPrint("return from IOCTL_CE_GETACCESSEDMEMORYLIST\n");
			ntStatus = STATUS_SUCCESS;
			break;
		}

		case IOCTL_CE_INITIALIZE:
		{
			//find the KeServiceDescriptorTableShadow 
			struct input
			{
				UINT64 AddressOfWin32K;
				UINT64 SizeOfWin32K;
				UINT64 NtUserBuildHwndList_callnumber;
				UINT64 NtUserQueryWindow_callnumber;
				UINT64 NtUserFindWindowEx_callnumber;
				UINT64 NtUserGetForegroundWindow_callnumber;
				UINT64 ActiveLinkOffset;
				UINT64 ProcessNameOffset;
				UINT64 DebugportOffset;
				UINT64 ProcessEvent;
				UINT64 ThreadEvent;
			} *pinp;

			DbgPrint("IOCTL_CE_INITIALIZE\n");
			pinp = Irp->AssociatedIrp.SystemBuffer;
			ntStatus = STATUS_SUCCESS;

			//referencing event handles to objects

			ObReferenceObjectByHandle((HANDLE)(UINT_PTR)pinp->ProcessEvent, EVENT_ALL_ACCESS, NULL, KernelMode, &ProcessEvent, NULL);
			ObReferenceObjectByHandle((HANDLE)(UINT_PTR)pinp->ThreadEvent, EVENT_ALL_ACCESS, NULL, KernelMode, &ThreadEvent, NULL);

			*(UINT_PTR *)Irp->AssociatedIrp.SystemBuffer = (UINT_PTR)0;
			break;
		}


		case IOCTL_CE_VMXCONFIG:
		{
#pragma pack(1)
			struct input
			{
				ULONG Virtualization_Enabled;
				QWORD Password1;
				ULONG Password2;
				QWORD Password3;
			} *pinp;
#pragma pack()


			DbgPrint("IOCTL_CE_VMXCONFIG called\n");
			ntStatus = STATUS_SUCCESS;

			pinp = Irp->AssociatedIrp.SystemBuffer;

			if (pinp->Virtualization_Enabled)
			{
				vmx_password1 = pinp->Password1;
				vmx_password2 = pinp->Password2;
				vmx_password3 = pinp->Password3;

				DbgPrint("new passwords are: %p-%x-%p\n", (void *)vmx_password1, vmx_password2, (void *)vmx_password3);

				__try
				{
					vmx_version = vmx_getversion();
					DbgPrint("Still here, so vmx is loaded. vmx_version=%x\n", vmx_version);
					vmxusable = 1;
				}
				__except (1)
				{
					DbgPrint("Exception happened. This means no vmx installed, or one of the passwords is wrong\n");
					ntStatus = STATUS_UNSUCCESSFUL;

					vmxusable = 0;
				};
			}
			else
			{
				DbgPrint("Virtualization_Enabled=0\n");
				vmxusable = 0;
			}

			break;
		}


		case IOCTL_CE_ENABLE_DRM:
		{
#if (NTDDI_VERSION >= NTDDI_VISTA)				
			struct
			{
				QWORD PreferedAltitude;
				QWORD ProtectedProcess;
			} *inp = Irp->AssociatedIrp.SystemBuffer;



			DbgPrint("inp->PreferedAltitude=%p", inp->PreferedAltitude);
			DbgPrint("inp->PreferedAltitude=%p", inp->ProtectedProcess);


			if (DRMProcess)
			{
				//check if this process has been terminated
				LARGE_INTEGER timeout;

				timeout.QuadPart = -500000;
				ntStatus = KeWaitForSingleObject(DRMProcess, UserRequest, UserMode, FALSE, &timeout);

				if (ntStatus != STATUS_SUCCESS)
					break;
			}

			DRMProcess = PsGetCurrentProcess();

			if (inp->ProtectedProcess)
			{
				if (DRMProcess != (PEPROCESS)((UINT_PTR)inp->ProtectedProcess))
					DRMProcess2 = (PEPROCESS)((UINT_PTR)inp->ProtectedProcess);
			}

			DbgPrint("DRMProcess=%p", DRMProcess);
			DbgPrint("DRMProcess2=%p", DRMProcess2);

			if (DRMHandle == NULL)
			{
				WCHAR wcAltitude[10];
				UNICODE_STRING usAltitude;
				OB_CALLBACK_REGISTRATION r;
				LARGE_INTEGER tc;
				OB_OPERATION_REGISTRATION obr[2];
				int RandomVal = (int)(inp->PreferedAltitude);
				int trycount = 0;

				if (RandomVal == 0)
				{
					tc.QuadPart = 0;
					KeQueryTickCount(&tc);
					RandomVal = 1000 + (tc.QuadPart % 50000);
				}

				DbgPrint("Activating CE's super advanced DRM"); //yeah right....

				DbgPrint("RandomVal=%d", RandomVal);
				RtlStringCbPrintfW(wcAltitude, sizeof(wcAltitude) - 2, L"%d", RandomVal);

				DbgPrint("wcAltitude=%S", wcAltitude);
				RtlInitUnicodeString(&usAltitude, wcAltitude);

				r.Version = OB_FLT_REGISTRATION_VERSION;
				r.Altitude = usAltitude;
				r.RegistrationContext = NULL;


				obr[0].ObjectType = PsProcessType;
				obr[0].Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
				obr[0].PreOperation = ProcessPreCallback;
				obr[0].PostOperation = ProcessPostCallback;

				obr[1].ObjectType = PsThreadType;
				obr[1].Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
				obr[1].PreOperation = ThreadPreCallback;
				obr[1].PostOperation = ThreadPostCallback;

				r.OperationRegistration = obr;
				r.OperationRegistrationCount = 2;

				ntStatus = ObRegisterCallbacks(&r, &DRMHandle);

				while ((ntStatus == STATUS_FLT_INSTANCE_ALTITUDE_COLLISION) && (trycount < 10))
				{
					RandomVal++;
					RtlStringCbPrintfW(wcAltitude, sizeof(wcAltitude) - 2, L"%d", RandomVal);
					RtlInitUnicodeString(&usAltitude, wcAltitude);
					r.Altitude = usAltitude;

					trycount++;

					ntStatus = ObRegisterCallbacks(&r, &DRMHandle);
				}

				DbgPrint("ntStatus=%X", ntStatus);
			}
			else
				ntStatus = STATUS_SUCCESS;
#else
			ntStatus = STATUS_NOT_IMPLEMENTED;
#endif				
			break;
		}

		case IOCTL_CE_GET_PEB:
		{
			KAPC_STATE oldstate;
			PEPROCESS ep = *(PEPROCESS *)Irp->AssociatedIrp.SystemBuffer;


			//DbgPrint("IOCTL_CE_GET_PEB");
			KeStackAttachProcess((PKPROCESS)ep, &oldstate);
			__try
			{
				ULONG r;
				PROCESS_BASIC_INFORMATION pbi;
				//DbgPrint("Calling ZwQueryInformationProcess");
				ntStatus = ZwQueryInformationProcess(ZwCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), &r);
				if (ntStatus == STATUS_SUCCESS)
				{
					//DbgPrint("pbi.UniqueProcessId=%x\n", (int)pbi.UniqueProcessId);
					//DbgPrint("pbi.PebBaseAddress=%p\n", (PVOID)pbi.PebBaseAddress);					
					*(QWORD *)Irp->AssociatedIrp.SystemBuffer = (QWORD)(pbi.PebBaseAddress);
				}
				else
					DbgPrint("ZwQueryInformationProcess failed");
			}
			__finally
			{
				KeUnstackDetachProcess(&oldstate);
			}


			break;
		}

		case IOCTL_CE_QUERYINFORMATIONPROCESS:
		{
			struct
			{
				QWORD processid;
				QWORD ProcessInformationAddress;
				QWORD ProcessInformationClass;
				QWORD ProcessInformationLength;
			}  *inp = Irp->AssociatedIrp.SystemBuffer;

			struct
			{
				QWORD result;
				QWORD returnLength;
				char data;
			} *outp = Irp->AssociatedIrp.SystemBuffer;

			PEPROCESS selectedprocess;
			DbgPrint("IOCTL_CE_QUERYINFORMATIONPROCESS");

			if (inp->processid == 0)
			{
				DbgPrint("Still works\n");
				ntStatus = STATUS_SUCCESS;
				break;
			}
			__try
			{

				if (PsLookupProcessByProcessId((HANDLE)(UINT_PTR)inp->processid, &selectedprocess) == STATUS_SUCCESS)
				{
					KAPC_STATE oldstate;
					KeStackAttachProcess((PKPROCESS)selectedprocess, &oldstate);
					__try
					{
						ULONG returnLength;

						if (inp->ProcessInformationAddress == 0)
						{
							DbgPrint("NULL ProcessInformationAddress");
							outp->result = ZwQueryInformationProcess(NtCurrentProcess(), inp->ProcessInformationClass, NULL, (ULONG)inp->ProcessInformationLength, &returnLength);
						}
						else
							outp->result = ZwQueryInformationProcess(NtCurrentProcess(), inp->ProcessInformationClass, &(outp->data), (ULONG)inp->ProcessInformationLength, &returnLength);

						DbgPrint("outp->result=%x", outp->result);

						outp->returnLength = returnLength;
						DbgPrint("outp->returnLength=%x", outp->returnLength);

						ntStatus = STATUS_SUCCESS;
					}
					__finally
					{
						KeUnstackDetachProcess(&oldstate);
					}

					ObDereferenceObject(selectedprocess);
				}
				else
				{
					DbgPrint("Failed to find pid %x", inp->processid);
					ntStatus = STATUS_EXPIRED_HANDLE;
				}
			}
			__except (1)
			{
				DbgPrint("Exception");
				ntStatus = STATUS_EXPIRED_HANDLE;
			}
			break;
		}

		case IOCTL_CE_NTPROTECTVIRTUALMEMORY:
		{


			break;
		}

		case IOCTL_CE_ALLOCATE_MEMORY_FOR_DBVM:
		{
			PHYSICAL_ADDRESS LowAddress, HighAddress, SkipBytes;
			PMDL mdl;
			QWORD pagecount = *(QWORD *)Irp->AssociatedIrp.SystemBuffer;
			PFN_NUMBER *pfnlist;
			DbgPrint("IOCTL_CE_ALLOCATE_MEMORY_FOR_DBVM(%d)\n", pagecount);

			if (!vmxusable)
			{
				DbgPrint("This only works when DBVM is present\n");
				ntStatus = STATUS_INVALID_DEVICE_STATE;
				break;
			}

			LowAddress.QuadPart = 0;
			HighAddress.QuadPart = 0xffffffffffffffffI64;
			SkipBytes.QuadPart = 0;
			mdl = MmAllocatePagesForMdlEx(LowAddress, HighAddress, SkipBytes, (SIZE_T)pagecount * 4096, MmCached, MM_ALLOCATE_REQUIRE_CONTIGUOUS_CHUNKS | MM_ALLOCATE_FULLY_REQUIRED); //do not free this, EVER
			if (mdl)
			{
				int i;
				PDBVMOffloadMemInfo mi;

				pagecount = MmGetMdlByteCount(mdl) / 4096;
				DbgPrint("Allocated %d pages\n", pagecount);

				pfnlist = MmGetMdlPfnArray(mdl);

				if (pfnlist)
				{
					//convert the pfnlist to a list dbvm understands, and go in blocks of 32
					mi = ExAllocatePool(PagedPool, sizeof(DBVMOffloadMemInfo));
					if (mi)
					{
						mi->List = ExAllocatePool(PagedPool, sizeof(UINT64) * 32);
						if (mi->List)
						{
							mi->Count = 0;
							for (i = 0; i < pagecount; i++)
							{
								mi->List[mi->Count] = pfnlist[i] << 12;
								mi->Count++;

								if (mi->Count == 32)
								{
									int j;
									int r = vmx_add_memory(mi->List, mi->Count);


									DbgPrint("vmx_add_memory for %d pages returned %d\n", mi->Count, r);

									for (j = 0; j < mi->Count; j++)
									{
										DbgPrint("%d : %p\n", j, (void *)((UINT_PTR)mi->List[j]));
									}


									mi->Count = 0;
								}
							}

							if (mi->Count)
							{
								int r = vmx_add_memory(mi->List, mi->Count);
								DbgPrint("vmx_add_memory for %d pages returned %d\n", mi->Count, r);
							}
							ExFreePool(mi->List);
						}
						else
							DbgPrint("Failure allocating mi->List");
						ExFreePool(mi);
					}
					else
						DbgPrint("Failure allocting mi");

				}
				else
					DbgPrint("Failure getting pfn list");
				ExFreePool(mdl); //only free the mdl, the rest belongs to dbvm now

				ntStatus = STATUS_SUCCESS;
			}
			else
			{
				DbgPrint("Failure allocating MDL");
				ntStatus = STATUS_MEMORY_NOT_ALLOCATED;
			}


			break;
		}

		default:
			DbgPrint("Unhandled IO request: %x\n", IoControlCode);
			break;
	}


	Irp->IoStatus.Status = ntStatus;

	// Set # of bytes to copy back to user-mode...
	if (irpStack) //only NULL when loaded by dbvm
	{
		if (ntStatus == STATUS_SUCCESS)
			Irp->IoStatus.Information = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
		else
			Irp->IoStatus.Information = 0;

		IoCompleteRequest(Irp, IO_NO_INCREMENT);
	}


	return ntStatus;
}