#include <windows.h>
#include <tchar.h>

//
// driver stuff
//

#ifndef NTSTATUS
typedef LONG NTSTATUS;
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#define STATUS_SUCCESS      ((NTSTATUS)0x00000000L)
#endif 

BOOL OpenDevice(IN LPCTSTR DriverName, HANDLE * lphDevice);

#define FILE_DEVICE_ANTIMIDA 0x8000

#define CODE_RESTORE_INFO	CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x800, \
	METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_READ_MEM		CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x801, \
	METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_QUERY_MEM		CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x802, \
	METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_WRITE_MEM		CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x803, \
	METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_ALLOC_MEM		CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x804, \
	METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_CREATE_THREAD	CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x805, \
	METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_DBG_CONTINUE	CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x806, \
	METHOD_BUFFERED, FILE_ANY_ACCESS)

//
// ZwReadVirtualMemory stuff
// 

typedef struct _Input_ZwReadVirtualMemory
{
	HANDLE  ProcessHandle;
	PVOID  BaseAddress;
	PVOID  Buffer;
	ULONG  BufferLength;
	PULONG  ReturnLength;
} Input_ZwReadVirtualMemory;

extern "C" __declspec(dllexport) 
BOOL WINAPI FakeReadProcessMemory(HANDLE hProcess,	
								  LPCVOID lpBaseAddress,
								  LPVOID lpBuffer,	DWORD nSize,
								  LPDWORD lpNumberOfBytesRead)
{
	HANDLE hDevice;

	if (OpenDevice(_T("antimida"), &hDevice) == FALSE)
		return FALSE;

	Input_ZwReadVirtualMemory Input;

	Input.ProcessHandle = hProcess;
	Input.BaseAddress = (PVOID) lpBaseAddress;
	Input.Buffer = (PVOID) lpBuffer;
	Input.BufferLength = (ULONG) nSize;
	Input.ReturnLength = (PULONG) lpNumberOfBytesRead;

	DWORD RetBytes;

	if (!DeviceIoControl(hDevice, CODE_READ_MEM, 
		&Input, sizeof (Input_ZwReadVirtualMemory), NULL, 0, &RetBytes, NULL))
	{
		CloseHandle(hDevice);
		return FALSE;
	}

	CloseHandle(hDevice);

	return TRUE;
}

//
// ZwQueryVirtualMemory stuff
//

typedef enum _MEMORY_INFORMATION_CLASS {
	MemoryBasicInformation,
	MemoryWorkingSetList,
	MemorySectionName,
	MemoryBasicVlmInformation
} MEMORY_INFORMATION_CLASS;

typedef struct _Input_ZwQueryVirtualMemory
{
	HANDLE ProcessHandle;
	PVOID  BaseAddress;
	MEMORY_INFORMATION_CLASS  MemoryInformationClass;
	ULONG  MemoryInformationLength;
	PVOID  MemoryInformation;
	PULONG  ReturnLength;
} Input_ZwQueryVirtualMemory;

extern "C" __declspec(dllexport) 
SIZE_T WINAPI FakeVirtualQueryEx(IN HANDLE hProcess,
								 IN LPCVOID lpAddress,
								 OUT PMEMORY_BASIC_INFORMATION lpBuffer,
								 IN SIZE_T dwLength)
{
	Input_ZwQueryVirtualMemory Input;
	ULONG ReturnLength;

	Input.ProcessHandle = hProcess;
	Input.BaseAddress = (PVOID) lpAddress;
	Input.MemoryInformationClass = MemoryBasicInformation;
	Input.MemoryInformationLength = (ULONG) dwLength;
	Input.MemoryInformation = (PVOID) lpBuffer;
	Input.ReturnLength = &ReturnLength;

	HANDLE hDevice;

	if (OpenDevice(_T("antimida"), &hDevice) == FALSE)
		return FALSE;

	DWORD RetBytes;

	if (!DeviceIoControl(hDevice, CODE_QUERY_MEM, 
		&Input, sizeof (Input_ZwQueryVirtualMemory), 
		NULL, 0, &RetBytes, NULL))
	{
		CloseHandle(hDevice);
		return 0;
	}

	CloseHandle(hDevice);

	return (SIZE_T) ReturnLength;
}

//
// ZwReadVirtualMemory stuff
// 

typedef struct _Input_ZwWriteVirtualMemory
{
	HANDLE  ProcessHandle;
	PVOID  BaseAddress;
	PVOID  Buffer;
	ULONG  BufferLength;
	PULONG  ReturnLength;
} Input_ZwWriteVirtualMemory;

extern "C" __declspec(dllexport) 
BOOL WINAPI FakeWriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress,
								   LPVOID lpBuffer, DWORD nSize, 
								   LPDWORD lpNumberOfBytesWritten)
{
	HANDLE hDevice;

	if (OpenDevice(_T("antimida"), &hDevice) == FALSE)
		return FALSE;

	//
	// change memory protection
	//

	DWORD dwOldProtection;

	if (!VirtualProtectEx(hProcess, lpBaseAddress, nSize, 
		PAGE_EXECUTE_READWRITE, &dwOldProtection))
	{
		CloseHandle(hDevice);
		return FALSE;
	}

	Input_ZwWriteVirtualMemory Input;

	Input.ProcessHandle = hProcess;
	Input.BaseAddress = (PVOID) lpBaseAddress;
	Input.Buffer = (PVOID) lpBuffer;
	Input.BufferLength = (ULONG) nSize;
	Input.ReturnLength = (PULONG) lpNumberOfBytesWritten;

	DWORD RetBytes;
	BOOL bRet;

	if (!DeviceIoControl(hDevice, CODE_WRITE_MEM, 
		&Input, sizeof (Input_ZwWriteVirtualMemory), NULL, 0, &RetBytes, NULL))
	{
		bRet = FALSE;
	}

	CloseHandle(hDevice);

	//
	// restore memory protection
	//

	VirtualProtectEx(hProcess, lpBaseAddress, nSize, 
		dwOldProtection, &dwOldProtection);

	return TRUE;
}

//
// ZwAllocateVirtualMemory stuff
//

typedef struct _Input_ZwAllocateVirtualMemory
{
	HANDLE ProcessHandle;
	PVOID *BaseAddress;
	ULONG_PTR ZeroBits;
	PSIZE_T RegionSize;
	ULONG AllocationType;
	ULONG Protect;
} Input_ZwAllocateVirtualMemory;

extern "C" __declspec(dllexport)
NTSTATUS NTAPI FakeNtAllocateVirtualMemory(IN HANDLE ProcessHandle,
										   IN OUT PVOID *BaseAddress,
										   IN ULONG_PTR ZeroBits,
										   IN OUT PSIZE_T RegionSize,
										   IN ULONG AllocationType,
										   IN ULONG Protect)
{
	Input_ZwAllocateVirtualMemory Input;

	Input.ProcessHandle = ProcessHandle;
	Input.BaseAddress = BaseAddress;
	Input.ZeroBits = ZeroBits;
	Input.RegionSize = RegionSize;
	Input.AllocationType = AllocationType;
	Input.Protect = Protect;

	HANDLE hDevice;

	if (OpenDevice(_T("antimida"), &hDevice) == FALSE)
		return FALSE;

	DWORD RetBytes;

	if (!DeviceIoControl(hDevice, CODE_ALLOC_MEM, 
		&Input, sizeof (Input_ZwAllocateVirtualMemory), 
		NULL, 0, &RetBytes, NULL))
	{
		CloseHandle(hDevice);

		// who cares? (invalid parameter)
		return ((NTSTATUS)0xC000000DL); 
	}

	CloseHandle(hDevice);

	return STATUS_SUCCESS;
}

//
// ZwCreateThread stuff
//

typedef struct _Input_ZwCreateThread
{
	PHANDLE  ThreadHandle;
	ACCESS_MASK  DesiredAccess;
	PVOID  ObjectAttributes;
	HANDLE  ProcessHandle;
	PVOID  ClientId;
	PCONTEXT  ThreadContext;
	PVOID  UserStack;
	BOOLEAN  CreateSuspended;
} Input_ZwCreateThread;

extern "C" __declspec(dllexport)
NTSTATUS NTAPI FakeNtCreateThread(OUT PHANDLE  ThreadHandle,
								  IN ACCESS_MASK  DesiredAccess,
								  IN PVOID  ObjectAttributes,
								  IN HANDLE  ProcessHandle,
								  OUT PVOID  ClientId,
								  IN PCONTEXT  ThreadContext,
								  IN PVOID  UserStack,
								  IN BOOLEAN  CreateSuspended)
{
	Input_ZwCreateThread Input;

	Input.ThreadHandle = ThreadHandle;
	Input.DesiredAccess = DesiredAccess;
	Input.ObjectAttributes = ObjectAttributes;
	Input.ProcessHandle = ProcessHandle;
	Input.ClientId = ClientId;
	Input.ThreadContext = ThreadContext;
	Input.UserStack = UserStack;
	Input.CreateSuspended = CreateSuspended;

	HANDLE hDevice;

	if (OpenDevice(_T("antimida"), &hDevice) == FALSE)
		return FALSE;

	DWORD RetBytes;

	if (!DeviceIoControl(hDevice, CODE_CREATE_THREAD, 
		&Input, sizeof (Input_ZwCreateThread), 
		NULL, 0, &RetBytes, NULL))
	{
		CloseHandle(hDevice);

		// who cares? (invalid parameter)
		return ((NTSTATUS)0xC000000DL); 
	}

	CloseHandle(hDevice);

	return STATUS_SUCCESS;
}

//
// ZwDebugContinue stuff
//

typedef struct _Input_ZwDebugContinue
{
	PVOID *A;
	PVOID *B;
	PVOID *C;
} Input_ZwDebugContinue;


extern "C" __declspec(dllexport)
NTSTATUS NTAPI FakeZwDebugContinue(PVOID *A, PVOID *B, PVOID *C)
{
	Input_ZwDebugContinue Input;

	Input.A = A;
	Input.B = B;
	Input.C = C;

	HANDLE hDevice;

	if (OpenDevice(_T("antimida"), &hDevice) == FALSE)
		return FALSE;

	DWORD RetBytes;

	if (!DeviceIoControl(hDevice, CODE_DBG_CONTINUE, 
		&Input, sizeof (Input_ZwDebugContinue), 
		NULL, 0, &RetBytes, NULL))
	{
		CloseHandle(hDevice);

		// who cares? (invalid parameter)
		return ((NTSTATUS)0xC000000DL); 
	}

	CloseHandle(hDevice);

	return STATUS_SUCCESS;
}

BOOL OpenDevice(IN LPCTSTR DriverName, HANDLE * lphDevice)
{
	TCHAR    completeDeviceName[64];
	HANDLE   hDevice;

	/*if ( (GetVersion() & 0xFF) >= 5 ) {

		wsprintf(completeDeviceName, TEXT("\\\\.\\Global\\%s"), DriverName);

	} else {*/

		wsprintf(completeDeviceName, TEXT("\\\\.\\%s"), DriverName);
	//}

	hDevice = CreateFile(completeDeviceName, GENERIC_READ | GENERIC_WRITE, 0,
		NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	if (hDevice == ((HANDLE)-1))
		return FALSE;

	if (lphDevice)
		*lphDevice = hDevice;
	else
		CloseHandle(hDevice);

	return TRUE;
}

BOOL APIENTRY DllMain(HANDLE hModule, DWORD  Reason, LPVOID lpReserved)
{
	switch (Reason)
	{
	case DLL_PROCESS_ATTACH:
		{	
			DisableThreadLibraryCalls((HMODULE) hModule);
			break;
		}

	case DLL_PROCESS_DETACH:
		{
			return TRUE;
		}

	default:
		{
			return FALSE;
		}
	}

	return TRUE;
}