News

Ein Blick auf moderne Forschung zu User-Mode-Anti-Cheat-Bypasses

Moderne Anti-Cheat-Systeme sind längst keine einfachen Erkennungsschichten mehr. Sie sind verteilte Vertrauenssysteme aus Kernel-Treibern, User-Mode-Komponenten und…

Vom Elocarry Team · 26. Januar 2026

13 Min. Lesezeit
Kurze Antwort
Dies ist ein Forschungsbericht auf hoher Abstraktionsebene darüber, wie moderne Anti-Cheat-Systeme Vertrauen auf Kernel-Treiber, User-Mode-Komponenten und externe Validierungsdienste verteilen. Er bleibt konzeptionell und untersucht, wo die Vertrauensgrenzen im User-Mode liegen, wie der Ausführungskontext validiert wird und welche Annahmen diese Systeme treffen, statt Schritt-für-Schritt-Anleitungen zu liefern. Die Kernaussage: Der User-Mode bleibt eine relevante Angriffsfläche, weil dort auf die Absicht des Spielers geschlossen wird, auch wenn die Durchsetzung im Kernel passiert.

Moderne Anti-Cheat-Systeme sind längst keine einfachen Erkennungsschichten mehr. Sie sind verteilte Vertrauenssysteme aus Kernel-Treibern, User-Mode-Komponenten und externen Validierungsdiensten. Zwar ist die Durchsetzung im Kernel strenger geworden, doch der User-Mode spielt weiterhin eine entscheidende Rolle dabei, wie Informationen gesammelt, validiert und verarbeitet werden.

Bei meiner Forschung zu User-Mode-Bypass-Frameworks geht es nicht darum, einer Erkennung zu entgehen, sondern darum zu verstehen, wo Vertrauen angesetzt wird, wie der Ausführungskontext validiert wird und welche Annahmen über das Verhalten im User-Mode getroffen werden.

Dieser Beitrag geht die technischen Ideen hinter dieser Forschung durch und verweist dabei auf Architekturmuster und Codestrukturen statt auf Anleitungen.

Warum der User-Mode immer noch eine relevante Angriffsfläche ist

Selbst in Anti-Cheat-Designs mit starkem Kernel-Fokus ist der User-Mode zuständig für:

  • Die erste Datenaufbereitung (Render-Status, Entity-Daten, Eingabekontext)
  • Die Kommunikation mit Kernel-Komponenten
  • Das Auslösen von Erkennungsheuristiken und Eskalationspfaden

Viele Systeme gehen davon aus, dass die Durchsetzung im Kernel allein ausreicht. In der Praxis ist der User-Mode der Ort, an dem auf die Absicht geschlossen wird, nicht der Ort, an dem sie durchgesetzt wird. Dieser Unterschied ist wichtig.

Framework-Architektur: Was ich untersucht habe

Grob gesagt untersucht das Framework drei Kernideen:

  1. Kontrollierter Ausführungskontext im User-Mode
  2. Manuelle Kontrolle über Modul-Layout und Sichtbarkeit
  3. Weniger vom Kernel beobachtbare Anomalien, ohne mit dem Kernel zu interagieren

Das spiegelt sich im Aufbau der Codebasis wider: nicht als monolithischer Exploit, sondern als trennbare Komponenten, die jeweils eine bestimmte Annahme testen.

Manual Mapping als Test einer Vertrauensgrenze

Eine der zentralen Forschungskomponenten dreht sich um manuelles PE-Mapping.

Statt sich auf den Loader des Betriebssystems zu verlassen, um:

  • Module zu registrieren
  • die verketteten Listen des Loaders zu befüllen
  • Instrumentation-Callbacks zu benachrichtigen

…rekonstruiert der Forschungscode nur den minimalen Laufzeitzustand, der für die Ausführung nötig ist, und lässt Registrierungsartefakte höherer Ebene bewusst weg.

Aus Sicht der Verteidigung wirft das eine wichtige Frage auf:

Hängt die Erkennung am Verhalten oder am Vorhandensein der erwarteten Loader-Metadaten?

Wenn sich Systeme stark auf den Loader-Status verlassen (PEB-Einträge, Modullisten, Image-Benachrichtigungen), lassen sie sich mit Code testen, der ausgeführt wird, ohne an diesen Mechanismen teilzunehmen, und aus Sicht der CPU trotzdem gültig bleibt.

Quellen

exploit.cpp

#include "exploit.hpp"
#include "utils.hpp"
#include <psapi.h>
#include <stdio.h>
#include <Windows.h>
#include <shlobj.h>
#include <stdint.h>
#include <winternl.h>
#include <mmsystem.h>
#include <time.h>
#include <shlwapi.h>
#include <unordered_set>
#include "pe_mapper.hpp"

#define NTHEADER(ImgBase) PIMAGE_NT_HEADERS64(PIMAGE_DOS_HEADER(ImgBase)->e_lfanew + uint64_t(ImgBase))
#define SET_BIT(Val, Num, Up) \
 { \
 if (Up) \
 { \
 Val |= (1 << Num); \
 } \
 else \
 { \
 Val &= ~(1 << Num); \
 } \
 }
#define IS_BIT_SET(Val, Num) (Val & (1 << Num))

#define SHARED_MEM_WPARAM_STRUCT 0x800




unsigned char* make_fake_pe() {
 unsigned char* p = (unsigned char*)malloc(0x200);
 if (!p) return NULL;
 memset(p, 0, 0x200);
 *(unsigned short*)(p + 0x0) = 0x5A4D;
 *(unsigned int*)(p + 0x3C) = 0x40;
 *(unsigned int*)(p + 0x40) = 0x00004550;
 *(unsigned short*)(p + 0x44) = 0x8664;
 *(unsigned short*)(p + 0x46) = 1;
 *(unsigned short*)(p + 0x54) = 0xF0;
 *(unsigned short*)(p + 0x58) = 0x20B;
 *(unsigned int*)(p + 0x58 + 0x10) = 0x0;
 size_t sec = 0x148;
 memcpy(p + sec + 0x0, ".data\0\0\0", 8);
 *(unsigned int*)(p + sec + 0x8) = 0x1000;
 *(unsigned int*)(p + sec + 0xC) = 0x100000 - 0x1000; //offset
 *(unsigned int*)(p + sec + 0x10) = 0x1000; //size
 *(unsigned int*)(p + sec + 0x14) = 0x200;
 *(unsigned int*)(p + sec + 0x24) = 0x60000000u; //permission
 return p;
}


OBFUSCATE void CExploit::ChangeProtection(uint64_t Address, size_t size, DWORD protection) {
 ShowWindow(ProcessData->ProcessHwnd, 0);
 Sleep(0);


 struct wparam {
 uint64_t memcpy{};
 uint64_t arg2{};
 uint64_t function_ptr{};
 uint64_t arg1{};
 uint64_t lock{};
 UNICODE_STRING dst{}; // 0x28
 UNICODE_STRING src{}; // 0x38
 uint64_t val{}; // 0x48

 };

 wparam* a = (wparam*)(LocalSharedMemory + SHARED_MEM_WPARAM_STRUCT);

 memset(a, 0, sizeof(wparam));
 a->arg1 = PAGE_READWRITE;
 a->arg2 = rand()*rand();
 a->memcpy = set_mrprot;
 a->function_ptr = t;
 a->lock = 0;


 auto hhook = SetWindowsHookExA(WH_SHELL, (HOOKPROC)w, ddll, ProcessData->ThreadID);
 if (!hhook) {
 printf("Failed critical %08x - process has crashed!\n", GetLastError());
 Sleep(5000);
 ExitProcess(0);
 }
 Sleep(0);

 SendMessageA(ProcessData->ProcessHwnd, WM_APPCOMMAND, (WPARAM)RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT, rand() * rand());

 a->dst.Length = 8;
 a->dst.MaximumLength = 8;
 a->dst.Buffer = (PWSTR)(mr_data_addr_ptr);
 a->src.Length = 8;
 a->src.MaximumLength = 8;
 a->src.Buffer = (PWSTR)(RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x48);
 a->arg1 = RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x28;
 a->arg2 = RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x38;
 a->memcpy = write_fn;
 a->function_ptr = t;
 a->val = Address;
 a->lock = 0;
 SendMessageA(ProcessData->ProcessHwnd, WM_APPCOMMAND, (WPARAM)RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT, rand()* rand());

 a->dst.Length = 8;
 a->dst.MaximumLength = 8;
 a->dst.Buffer = (PWSTR)(mr_data_size_ptr);
 a->src.Length = 8;
 a->src.MaximumLength = 8;
 a->src.Buffer = (PWSTR)(RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x48);
 a->arg1 = RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x28;
 a->arg2 = RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x38;
 a->memcpy = write_fn;
 a->function_ptr = t;
 a->val = size;
 a->lock = 0;
 SendMessageA(ProcessData->ProcessHwnd, WM_APPCOMMAND, (WPARAM)RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT, rand()* rand());

 a->arg1 = protection;
 a->arg2 = rand() * rand();
 a->memcpy = set_mrprot;
 a->function_ptr = t;
 a->lock = 0;

 SendMessageA(ProcessData->ProcessHwnd, WM_APPCOMMAND, (WPARAM)RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT, rand()* rand());


 a->dst.Length = 8;
 a->dst.MaximumLength = 8;
 a->dst.Buffer = (PWSTR)(mr_data_addr_ptr);
 a->src.Length = 8;
 a->src.MaximumLength = 8;
 a->src.Buffer = (PWSTR)(RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x48);
 a->arg1 = RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x28;
 a->arg2 = RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x38;
 a->memcpy = write_fn;
 a->function_ptr = t;
 a->val = mr_data_addr_orig;
 a->lock = 0;
 SendMessageA(ProcessData->ProcessHwnd, WM_APPCOMMAND, (WPARAM)RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT, rand()* rand());

 a->dst.Length = 8;
 a->dst.MaximumLength = 8;
 a->dst.Buffer = (PWSTR)(mr_data_size_ptr);
 a->src.Length = 8;
 a->src.MaximumLength = 8;
 a->src.Buffer = (PWSTR)(RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x48);
 a->arg1 = RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x28;
 a->arg2 = RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x38;
 a->memcpy = write_fn;
 a->function_ptr = t;
 a->val = mr_data_size_orig;
 a->lock = 0;
 SendMessageA(ProcessData->ProcessHwnd, WM_APPCOMMAND, (WPARAM)RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT, rand()* rand());

 a->arg1 = PAGE_READONLY;
 a->arg2 = rand() * rand();
 a->memcpy = set_mrprot;
 a->function_ptr = t;
 a->lock = 0;
 SendMessageA(ProcessData->ProcessHwnd, WM_APPCOMMAND, (WPARAM)RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT, rand()* rand());

 UnhookWindowsHookEx(hhook);
 Sleep(0);

 ShowWindow(ProcessData->ProcessHwnd, 1);
 return;

}
uint64_t CExploit::MapPEHeader(uint64_t Address)
{
 ShowWindow(ProcessData->ProcessHwnd, 0);
 Sleep(0);


 struct wparam {
 uint64_t memcpy{};
 uint64_t arg2{};
 uint64_t function_ptr{};
 uint64_t arg1{};
 uint64_t lock{};
 UNICODE_STRING dst{}; // 0x28
 UNICODE_STRING src{}; // 0x38
 uint64_t val{}; // 0x48

 };

 wparam* a = (wparam*)(LocalSharedMemory + SHARED_MEM_WPARAM_STRUCT);


 memset(a, 0, sizeof(wparam));
 a->arg1 = Address;
 a->arg2 = 0xFFFFFFFFFFFFFFFF;
 a->memcpy = set_protect;
 a->function_ptr = t;
 a->lock = 0;


 auto hhook = SetWindowsHookExA(WH_SHELL, (HOOKPROC)w, ddll, ProcessData->ThreadID);
 if (!hhook) {
 printf("Failed critical %08x - process has crashed!\n", GetLastError());
 Sleep(5000);
 ExitProcess(0);
 }
 Sleep(0);

 SendMessageA(ProcessData->ProcessHwnd, WM_APPCOMMAND, (WPARAM)RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT, rand() * rand());

 UnhookWindowsHookEx(hhook);
 Sleep(0);

 ShowWindow(ProcessData->ProcessHwnd, 1);
 return 0;
}


uint64_t CExploit::AllocateRX(BYTE* data, size_t size)
{
 ShowWindow(ProcessData->ProcessHwnd, 0);
 Sleep(0);


 struct wparam {
 uint64_t memcpy{};
 uint64_t arg2{};
 uint64_t function_ptr{};
 uint64_t arg1{};
 uint64_t lock{};
 UNICODE_STRING dst{}; // 0x28
 UNICODE_STRING src{}; // 0x38
 uint64_t val{}; // 0x48

 };

 wparam* a = (wparam*)(LocalSharedMemory + SHARED_MEM_WPARAM_STRUCT);


 memset(a, 0, sizeof(wparam));
 a->arg1 = 0x100000;
 a->arg2 = rand() * rand();
 a->memcpy = (uintptr_t)GetProcAddress(LoadLibraryA("msvcrt.dll"), "malloc");
 a->function_ptr = t;
 a->lock = 0;

 std::unordered_set<uintptr_t> existing_mem;
 HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, ProcessData->ProcessID);
 if (hProcess == INVALID_HANDLE_VALUE)
 {
 printf("Failed to open process[%d] error[%d]\n", ProcessData->ProcessID, GetLastError());
 return false;
 }


 uint8_t* Address{};
 MEMORY_BASIC_INFORMATION Mbi{};
 while (true)
 {
 if (!VirtualQueryEx(hProcess, Address, &Mbi, sizeof(Mbi)))
 break;


 if (Mbi.State == MEM_COMMIT && Mbi.Protect == PAGE_READWRITE && Mbi.RegionSize == 0x101000 && Mbi.Type == MEM_PRIVATE)
 {
 existing_mem.insert((uintptr_t)Mbi.BaseAddress);
 }

 Address += Mbi.RegionSize;
 }
 ShowWindow(ProcessData->ProcessHwnd, 0);
 Sleep(0);
 auto hhook = SetWindowsHookExA(WH_SHELL, (HOOKPROC)w, ddll, ProcessData->ThreadID);
 if (!hhook) {
 printf("Failed critical %08x - process has crashed!\n", GetLastError());
 Sleep(5000);
 ExitProcess(0);
 }
 Sleep(0);

 SendMessageA(ProcessData->ProcessHwnd, WM_APPCOMMAND, (WPARAM)RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT, rand() * rand());

 UnhookWindowsHookEx(hhook);
 Sleep(0);

 ShowWindow(ProcessData->ProcessHwnd, 1);
 Address = 0;
 uintptr_t found_addr = 0;
 while (true)
 {

 if (!VirtualQueryEx(hProcess, Address, &Mbi, sizeof(Mbi)))
 break;

 // printf("%llx - %llx - %d - %d - %d\n", Address, Mbi.RegionSize, Mbi.Type, Mbi.Protect, Mbi.State);
 if (Mbi.State == MEM_COMMIT && Mbi.Protect == PAGE_READWRITE && Mbi.RegionSize == 0x101000 && Mbi.Type == MEM_PRIVATE)
 {
 if (!existing_mem.contains((uintptr_t)Mbi.BaseAddress)) {
 found_addr = (uintptr_t)Mbi.BaseAddress;
 break;
 }
 }

 Address += Mbi.RegionSize;
 }
 CloseHandle(hProcess);
 if (found_addr) {
 auto x = make_fake_pe();
 unsigned char empty[0x200]{};
 WriteData(found_addr, (BYTE*)x, 0x200);
 WriteData(found_addr + 0x100000 - 0x1000, data, size);
 MapPEHeader(found_addr);
 WriteData(found_addr, (BYTE*)empty, 0x200);
 free(x);
 return found_addr + 0x100000 - 0x1000;

 }
 return 0;
}


uint64_t CExploit::ReadU64(uint64_t Address)
{
 ShowWindow(ProcessData->ProcessHwnd, 0);
 Sleep(0);


 struct wparam {
 uint64_t memcpy{}; //0
 uint64_t arg2{}; //8
 uint64_t function_ptr{}; //0x10
 uint64_t arg1{}; // 0x18
 uint64_t lock{}; // 0x20
 UNICODE_STRING dst{}; // 0x28
 UNICODE_STRING src{}; // 0x38
 uint64_t val{}; // 0x48
 };

 wparam* a = (wparam*)(LocalSharedMemory + SHARED_MEM_WPARAM_STRUCT);


 memset(a, 0, sizeof(wparam));

 a->dst.Length = 8;
 a->dst.MaximumLength = 8;
 a->dst.Buffer = (PWSTR)(RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x48);
 a->src.Length = 8;
 a->src.MaximumLength = 8;
 a->src.Buffer = (PWSTR)(Address);
 a->arg1 = RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x28;
 a->arg2 = RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x38;
 a->memcpy = write_fn;
 a->function_ptr = t;
 a->lock = 0;


 auto hhook = SetWindowsHookExA(WH_SHELL, (HOOKPROC)w, ddll, ProcessData->ThreadID);
 if (!hhook) {
 printf("Failed critical %08x - process has crashed!\n", GetLastError());
 Sleep(5000);
 ExitProcess(0);
 }
 Sleep(0);

 SendMessageA(ProcessData->ProcessHwnd, WM_APPCOMMAND, (WPARAM)RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT, rand() % 0xFFFFFFFFFFFFFFFF);

 UnhookWindowsHookEx(hhook);
 Sleep(0);

 ShowWindow(ProcessData->ProcessHwnd, 1);

 return a->val;
}


void CExploit::ReadData(uint64_t Address, BYTE* Data, size_t size)
{
 if (size > 0x700) {
 printf("Read is too big\n");
 __debugbreak();
 }

 ShowWindow(ProcessData->ProcessHwnd, 0);
 Sleep(0);


 struct wparam {
 uint64_t memcpy{}; //0
 uint64_t arg2{}; //8
 uint64_t function_ptr{}; //0x10
 uint64_t arg1{}; // 0x18
 uint64_t lock{}; // 0x20
 UNICODE_STRING dst{}; // 0x28
 UNICODE_STRING src{}; // 0x38
 uint64_t val{}; // 0x48
 };

 wparam* a = (wparam*)(LocalSharedMemory + SHARED_MEM_WPARAM_STRUCT);


 memset(a, 0, sizeof(wparam));

 a->dst.Length = size;
 a->dst.MaximumLength = size;
 a->dst.Buffer = (PWSTR)(RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x48);
 a->src.Length = size;
 a->src.MaximumLength = size;
 a->src.Buffer = (PWSTR)(Address);
 a->arg1 = RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x28;
 a->arg2 = RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x38;
 a->memcpy = write_fn;
 a->function_ptr = t;
 a->lock = 0;


 auto hhook = SetWindowsHookExA(WH_SHELL, (HOOKPROC)w, ddll, ProcessData->ThreadID);
 if (!hhook) {
 printf("Failed critical %08x - process has crashed!\n", GetLastError());
 Sleep(5000);
 ExitProcess(0);
 }
 Sleep(0);

 SendMessageA(ProcessData->ProcessHwnd, WM_APPCOMMAND, (WPARAM)RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT, rand() % 0xFFFFFFFFFFFFFFFF);

 UnhookWindowsHookEx(hhook);
 Sleep(0);

 ShowWindow(ProcessData->ProcessHwnd, 1);

 memcpy(Data, &a->val, size);

}

void CExploit::WriteU64(uint64_t Address, uint64_t Value)
{
 ShowWindow(ProcessData->ProcessHwnd, 0);
 Sleep(0);


 struct wparam {
 uint64_t memcpy{}; //0
 uint64_t arg2{}; //8
 uint64_t function_ptr{}; //0x10
 uint64_t arg1{}; // 0x18
 uint64_t lock{}; // 0x20
 UNICODE_STRING dst{}; // 0x28
 UNICODE_STRING src{}; // 0x38
 uint64_t val{}; // 0x48
 };

 wparam* a = (wparam*)(LocalSharedMemory + SHARED_MEM_WPARAM_STRUCT);


 memset(a, 0, sizeof(wparam));

 a->dst.Length = 8;
 a->dst.MaximumLength = 8;
 a->dst.Buffer = (PWSTR)(Address);
 a->src.Length = 8;
 a->src.MaximumLength = 8;
 a->src.Buffer = (PWSTR)(RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x48);
 a->arg1 = RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x28;
 a->arg2 = RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x38;
 a->memcpy = write_fn;
 a->function_ptr = t;
 a->val = Value;
 a->lock = 0;


 auto hhook = SetWindowsHookExA(WH_SHELL, (HOOKPROC)w, ddll, ProcessData->ThreadID);
 if (!hhook) {
 printf("Failed critical %08x - process has crashed!\n", GetLastError());
 Sleep(5000);
 ExitProcess(0);
 }
 Sleep(0);

 SendMessageA(ProcessData->ProcessHwnd, WM_APPCOMMAND, (WPARAM)RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT, rand() % 0xFFFFFFFFFFFFFFFF);

 UnhookWindowsHookEx(hhook);
 Sleep(0);

 ShowWindow(ProcessData->ProcessHwnd, 1);

 return;


}

void CExploit::WriteData(uint64_t Address, BYTE* Data, size_t size)
{

 struct wparam {
 uint64_t memcpy{}; //0
 uint64_t arg2{}; //8
 uint64_t function_ptr{}; //0x10
 uint64_t arg1{}; // 0x18
 uint64_t lock{}; // 0x20
 UNICODE_STRING dst{}; // 0x28
 UNICODE_STRING src{}; // 0x38
 uint64_t val{}; // 0x48
 };

 wparam* a = (wparam*)(LocalSharedMemory + SHARED_MEM_WPARAM_STRUCT);
 size_t max_size = 0x50;
 if (size > max_size) {
 size_t chunks = (size + max_size - 1) / max_size;
 for (size_t i = 0; i < chunks; ++i) {
 size_t remainder = size % max_size;
 size_t chunk_size = (i == chunks - 1) ? ((remainder == 0) ? max_size : remainder) : max_size;
 WriteData(Address + i * max_size, Data + i * max_size, chunk_size);
 }
 return;
 }

 ShowWindow(ProcessData->ProcessHwnd, 0);
 Sleep(0);

 memset(a, 0, sizeof(wparam));

 a->dst.Length = size;
 a->dst.MaximumLength = size;
 a->dst.Buffer = (PWSTR)(Address);
 a->src.Length = size;
 a->src.MaximumLength = size;
 a->src.Buffer = (PWSTR)(RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x48);
 a->arg1 = RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x28;
 a->arg2 = RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT + 0x38;
 a->memcpy = write_fn;
 a->function_ptr = t;

 a->lock = 0;

 memcpy(&a->val, Data, size);

 auto hhook = SetWindowsHookExA(WH_SHELL, (HOOKPROC)w, ddll, ProcessData->ThreadID);
 if (!hhook) {
 printf("Failed critical %08x - process has crashed!\n", GetLastError());
 Sleep(5000);
 ExitProcess(0);
 }
 Sleep(0);

 SendMessageA(ProcessData->ProcessHwnd, WM_APPCOMMAND, (WPARAM)RemoteSharedMemory + SHARED_MEM_WPARAM_STRUCT, rand() % 0xFFFFFFFFFFFFFFFF);

 UnhookWindowsHookEx(hhook);
 Sleep(0);

 ShowWindow(ProcessData->ProcessHwnd, 1);

 return;
}

bool CExploit::Initialize(CProcess* Proc)
{
 srand(GetTickCount());
 ProcessData = Proc;
 nt = LoadLibraryA("ntdll.dll");
 sh = LoadLibraryA("shell32.dll");
 ddll = LoadLibraryA("uxtheme.dll");

 // Locate shared memory in our client.
 if (!FindSharedMemory(HANDLE(-1), &LocalSharedMemory, &SharedCount, (char*)"randomfuckingnameyougotnoidea.exe"))
 {
 printf("Failed to find shared memory in current process\n");
 return false;
 }


 {
 HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, ProcessData->ProcessID);
 if (hProcess == INVALID_HANDLE_VALUE)
 {
 printf("Failed to open process[%d] error[%d]\n", ProcessData->ProcessID, GetLastError());
 return false;
 }

 if (!FindSharedMemory(hProcess, &RemoteSharedMemory, &SharedCount, ProcessData->exe_name))
 {
 CloseHandle(hProcess);
 printf("Failed to find shared memory in target process\n");
 return false;
 }


 PROCESS_BASIC_INFORMATION pbi{};
 NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), 0);
 ProcessData->peb = (uintptr_t)pbi.PebBaseAddress;
 CloseHandle(hProcess);

 if ((*(uint32_t*)0x7FFE0260) >= 26100)
 {


 typedef struct _THREAD_BASIC_INFORMATION {
 NTSTATUS ExitStatus;
 PVOID TebBaseAddress;
 CLIENT_ID ClientId;
 KAFFINITY AffinityMask;
 KPRIORITY Priority;
 KPRIORITY BasePriority;
 } THREAD_BASIC_INFORMATION;

 HANDLE hThread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, false, ProcessData->ThreadID);
 THREAD_BASIC_INFORMATION x{};
 ULONG retlen{};
 NtQueryInformationThread(hThread, (THREADINFOCLASS)0, &x, sizeof(x), &retlen);
 CloseHandle(hThread);
 PVOID attack_addr = (PVOID)((uint64_t)x.TebBaseAddress + 0x1850);
 ShowWindow(ProcessData->ProcessHwnd, SW_HIDE); //wtf man
 auto hhook = SetWindowsHookExA(WH_SHELL, (HOOKPROC)GetProcAddress(nt, "RtlOpenCrossProcessEmulatorWorkConnection"), ddll, ProcessData->ThreadID);
 Sleep(0);
 SendMessageA(ProcessData->ProcessHwnd, WM_APPCOMMAND, (WPARAM)attack_addr, (LPARAM)attack_addr);

 UnhookWindowsHookEx(hhook);
 ShowWindow(ProcessData->ProcessHwnd, SW_SHOW); //wtf man
 printf("Fixup applied\n");
 }
 }
 /*
 if (!ProcessData->discord_path)
 {
 printf("Failed to find discord path\n");
 return false;
 }
 */
 /* Map and get discord rwx */

 {


 const char* writeGadgetPattern = "?? 89 ?? ?? 08 57 ?? 83 ?? 20 ?? 8d ?? 20 ?? 8b ?? e8";

 w = (uintptr_t)PatternScan(nt, writeGadgetPattern);
 if (!w) {
 printf("Failed to find W\n");
 return false;
 }

 const char* trampPattern = "48 83 ec ?? 48 8b da 48 85 d2 74 ?? 83 7a ?? ?? 75 ?? 83 7a ?? ?? 75 ??";

 t = (uintptr_t)PatternScan(sh, trampPattern);
 if (!t) {
 printf("Failed to find t\n");
 return false;
 }
 t = t & 0xFFFFFFFFFFFFFFF0;

 const char* setProtectPattern = "48 8b e9 48 8b d1 41 8d 48 03";
 set_protect = (uintptr_t)PatternScan(nt, setProtectPattern);
 if (!set_protect) {
 printf("Failed to find set_protect\n");
 return false;
 }

 while (*(unsigned char*)set_protect != 0xCC) set_protect--;
 set_protect++;


 const char* mrDataPattern = "48 8B 05 ?? ?? ?? ?? 4C 8D 44 24 ?? 48 89 44 24";
 set_mrprot = (uintptr_t)PatternScan(nt, mrDataPattern);
 
 if (!set_mrprot) {
 printf("Failed to find set_mrprot\n");
 return false;
 }
 mr_data_addr_ptr = set_mrprot + *(int32_t*)(set_mrprot + 3) + 7;
 mr_data_size_ptr = set_mrprot + *(int32_t*)(set_mrprot + 3) + 7 - 0x10;

 mr_data_addr_orig = *(uintptr_t*)mr_data_addr_ptr;
 mr_data_size_orig = *(uintptr_t*)mr_data_size_ptr;
 
 while (*(unsigned char*)set_mrprot != 0xCC) set_mrprot--;
 set_mrprot++;


 write_fn = (uint64_t)GetProcAddress(nt, "RtlCopyString");


 }
 return true;
}

uint64_t CExploit::get_LocalSharedMemory()
{
 return LocalSharedMemory;
}

uint64_t CExploit::get_RemoteSharedMemory()
{
 return RemoteSharedMemory;
}

uint64_t CExploit::get_RemoteBase()
{
 return RemoteProcessBase;
}


bool CExploit::FindSharedMemory(HANDLE hProcess, uint64_t* MemoryOut, uint64_t* SharedCountOut, char* exe_name)
{
 if (hProcess == (HANDLE)-1)
 {
 uint8_t* Address{};
 MEMORY_BASIC_INFORMATION Mbi{};
 bool found_it = false;
 while (true)
 {
 if (!VirtualQueryEx(hProcess, Address, &Mbi, sizeof(Mbi)))
 break;
 if (Mbi.State == MEM_COMMIT && Mbi.Protect == PAGE_READWRITE && Mbi.RegionSize == 0x1000 && Mbi.Type == MEM_MAPPED)
 {
 //scan inside SHCore.dll to see if this address is inside data
 auto shcore = LoadLibraryA("SHCore.dll");
 uint8_t* Address2 = (uint8_t*)shcore;
 MEMORY_BASIC_INFORMATION Mbi2{};
 int i = 0;
 while (VirtualQuery(Address2, &Mbi2, sizeof(Mbi2)))
 {
 if (i >= 9)
 break;
 if (Mbi2.Type == MEM_IMAGE && Mbi2.Protect == PAGE_READWRITE)
 {
 for (int ii = 0; ii < Mbi2.RegionSize; ii += 0x8)
 {
 if (*(uintptr_t*)&Address2[ii] == (uintptr_t)Mbi.BaseAddress)
 {
 found_it = true;
 *MemoryOut = (uintptr_t)Mbi.BaseAddress;
 break;
 }
 }
 }
 if (found_it)
 break;

 i++;
 Address2 += Mbi2.RegionSize;
 }
 }
 if (found_it)
 break;
 Address += Mbi.RegionSize;
 }


 /* HANDLE h_map;

 h_map = OpenFileMappingA(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, "windows_shell_global_counters");
 if (h_map == nullptr)
 return false;

 uintptr_t frame_buffer = (uintptr_t)MapViewOfFile(h_map, FILE_MAP_ALL_ACCESS, 0, 0, 0);
 CloseHandle(h_map);
 if (!frame_buffer)
 return false;
 printf("FrameBuffer: %llx\n", frame_buffer);
 *MemoryOut = frame_buffer;*/
 return found_it;
 }


 bool found = false;

 uint8_t* Address{};
 MEMORY_BASIC_INFORMATION Mbi{};
 while (true)
 {
 if (!VirtualQueryEx(hProcess, Address, &Mbi, sizeof(Mbi)))
 break;

 if (hProcess != GetCurrentProcess() && Mbi.State == MEM_COMMIT && Mbi.Protect == PAGE_READONLY && Mbi.RegionSize == 0x1000 && Mbi.Type == MEM_IMAGE)
 {
 char filename[1024]{};
 K32GetMappedFileNameA(hProcess, Mbi.BaseAddress, filename, sizeof(filename));
 if (strstr(filename, "DiscordHook64"))
 {
 ProcessData->discord_base = (uintptr_t)Address;
 char dos_path[1024]{};
 utils::DevicePathToDosPath(filename, dos_path, sizeof(dos_path));
 ProcessData->discord_path = _strdup(dos_path);
 }
 else if (strstr(filename, "shell32.dll") || strstr(filename, "Shell32.dll") || strstr(filename, "SHELL32.dll"))
 {
 if ((uintptr_t)sh != (uintptr_t)Address) {
 uintptr_t delta = (uintptr_t)Address - (uintptr_t)sh;
 t += delta; 
 }

 }
 else if (strstr(filename, exe_name))
 {
 ProcessData->base = (uintptr_t)Address;
 }
 }
 else if (!found && Mbi.State == MEM_COMMIT && Mbi.Protect == PAGE_READWRITE && Mbi.RegionSize == 0x1000 && Mbi.Type == MEM_MAPPED)
 {
 *(SHORT*)((this->LocalSharedMemory) + 0xF00) = 0x00;


 auto hhook = SetWindowsHookExA(WH_SHELL, (HOOKPROC)GetProcAddress(nt, "RtlGetIntegerAtom"), ddll, ProcessData->ThreadID);
 ShowWindow(ProcessData->ProcessHwnd, SW_HIDE);
 Sleep(1);
 auto result = SendMessage(ProcessData->ProcessHwnd, WM_APPCOMMAND, (uintptr_t)Address + 0xF00, (uintptr_t)Address + 0xF00);

 Sleep(1);
 auto unhook = UnhookWindowsHookEx(hhook);
 ShowWindow(ProcessData->ProcessHwnd, SW_SHOW);
 if (*(SHORT*)((this->LocalSharedMemory) + 0xF00)) {
 *MemoryOut = (uintptr_t)Address;
 found = true;
 }
 }
 else if (Mbi.State == MEM_COMMIT && Mbi.Protect == PAGE_READWRITE && Mbi.RegionSize == 0x3201000 && Mbi.Type == MEM_MAPPED)
 {
 ProcessData->discord_framebuffer = (uintptr_t)Address;
 }

 Address += Mbi.RegionSize;
 }

 return found;
}

std::uint8_t* CExploit::PatternScan(void* module, const char* signature)
{
 static auto pattern_to_byte = [](const char* pattern)
 {
 auto bytes = std::vector<int>{};
 auto start = const_cast<char*>(pattern);
 auto end = const_cast<char*>(pattern) + strlen(pattern);

 for (auto current = start; current < end; ++current)
 {
 if (*current == '?')
 {
 ++current;
 if (*current == '?')
 ++current;
 bytes.push_back(-1);
 }
 else
 {
 bytes.push_back(strtoul(current, &current, 16));
 }
 }
 return bytes;
 };

 auto dosHeader = (PIMAGE_DOS_HEADER)module;
 auto ntHeaders = (PIMAGE_NT_HEADERS)((std::uint8_t*)module + dosHeader->e_lfanew);

 auto sizeOfImage = ntHeaders->OptionalHeader.SizeOfImage;
 auto patternBytes = pattern_to_byte(signature);
 auto scanBytes = reinterpret_cast<std::uint8_t*>(module);

 auto s = patternBytes.size();
 auto d = patternBytes.data();

 for (auto i = 0ul; i < sizeOfImage - s; ++i)
 {
 bool found = true;
 for (auto j = 0ul; j < s; ++j)
 {
 if (scanBytes[i + j] != d[j] && d[j] != -1)
 {
 found = false;
 break;
 }
 }
 if (found)
 {
 return &scanBytes[i];
 }
 }
 return nullptr;
}

void CExploit::SetupRW()
{

}

bool CProcess::Initialize(const wchar_t* WindowName, const wchar_t* ClassName, char* exe_name, HWND target_window)
{
 if (!target_window)
 {
 ProcessHwnd = FindWindowW(ClassName, WindowName);
 }
 else
 {
 ProcessHwnd = target_window;
 }
 this->exe_name = exe_name;
 if (!ProcessHwnd)
 return false;
 ThreadID = GetWindowThreadProcessId(ProcessHwnd, &ProcessID);
 return ThreadID != 0;
}