Create old_variant_winmmabase_rop.cpp

An old variant that still works with some work.
This commit is contained in:
TALON SCHMELER
2025-11-26 11:51:46 +01:00
committed by GitHub
parent 090b260a67
commit ccc1330fcc

View File

@@ -0,0 +1,928 @@
#include <windows.h>
#include <stdio.h>
#include <psapi.h>
#include <shlobj.h>
#include <stdint.h>
#include <winternl.h>
#include <consoleapi.h>
#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_MMIO_STRUCT 0x200
#define SHARED_MEM_SHADOW_VMT 0x300
#define SHARED_MEM_COMMAND_BUFFER 0x700
#define SHARED_MEM_STACK_OFFSET 0x800
#define SHARED_MEM_STACK_PLACEHOLDER_OFFSET (SHARED_MEM_STACK_OFFSET - 8)
#pragma comment(lib, "ntdll.lib")
class CProcess
{
public:
DWORD ThreadID{};
DWORD ProcessID{};
HWND ProcessHwnd{};
uintptr_t peb{};
uintptr_t discord_base{};
uintptr_t discord_framebuffer{};
uintptr_t base{};
bool Initialize(const wchar_t* WindowName, const wchar_t* ClassName = 0)
{
ProcessHwnd = FindWindowW(ClassName, WindowName);
if (!ProcessHwnd) return false;
ThreadID = GetWindowThreadProcessId(ProcessHwnd, &ProcessID);
return ThreadID != 0;
}
};
class CExploit
{
private:
CProcess *ProcessData{};
HMODULE winmm{};
FARPROC mmio_rename{};
uint64_t SharedCount{};
uint64_t PopRCX{};
uint64_t PopRDX{};
uint64_t PopRAX{};
uint64_t PopRSP{};
uint64_t MovRax_RCX{};
uint64_t ReadRCX_RAX{};
uint64_t WriteRCX_RDX{};
uint64_t WriteRDX_RCX{};
uint64_t WriteRCX_RAX{};
uint64_t AddRSP_58{};
uint64_t AddRCX_RBP{};
uint64_t PushRAX_PopRSP{};
bool LegacyWin10;
uint32_t ShellCursor{};
const char* ModulesToCheck[114] = { "ntdll.dll", "kernel32.dll", "user32.dll", "ws2_32.dll", "shell32.dll", "dxgi.dll", "crypt32.dll", "advapi32.dll", "ole32.dll", "secur32.dll", "psapi.dll", "rasadhlp.dll", "msctf.dll", "ntasn1.dll", "SHCore.dll", "avifil32.dll", "cryptsp.dll", "wbemsvc.dll", "winmmbase.dll", "combase.dll", "dwmapi.dll", "powrprof.dll", "ncrypt.dll", "MMDevAPI.dll", "msvcp_win.dll", "propsys.dll", "CoreMessaging.dll", "cryptbase.dll", "IPHLPAPI.DLL", "drvstore.dll", "gdi32full.dll", "version.dll", "midimap.dll", "coloradapterclient.dll", "wininet.dll", "Windows.UI.dll", "cryptnet.dll", "wbemcomn.dll", "bcrypt.dll", "mscms.dll", "schannel.dll", "userenv.dll", "amsi.dll", "rsaenh.dll", "ucrtbase.dll", "msvfw32.dll", "d3d11.dll", "devobj.dll", "dhcpcsvc6.dll", "wintrust.dll", "xinput1_3.dll", "mswsock.dll", "wdmaud.drv", "sxs.dll", "bcryptprimitives.dll", "ncryptsslp.dll", "gdi32.dll", "normaliz.dll", "clbcatq.dll", "fastprox.dll", "profapi.dll", "win32u.dll", "avrt.dll", "NapiNSP.dll", "WinTypes.dll", "pnrpnsp.dll", "CoreUIComponents.dll", "D3DCompiler_43.dll", "umpdc.dll", "XAudio2_9.dll", "KernelBase.dll", "ntmarta.dll", "sspicli.dll", "kernel.appcore.dll", "dhcpcsvc.dll", "ksuser.dll", "InputHost.dll", "msvcrt.dll", "imm32.dll", "AudioSes.dll", "dnsapi.dll", "wshbth.dll", "mskeyprotect.dll", "msacm32.dll", "twinapi.appcore.dll", "wbemprox.dll", "oleaut32.dll", "msasn1.dll", "winrnr.dll", "hid.dll", "setupapi.dll", "dsound.dll", "windows.storage.dll", "dbghelp.dll", "WindowManagementAPI.dll", "nlaapi.dll", "ResourcePolicyClient.dll", "comctl32.dll", "msacm32.drv", "dbgcore.dll", "imagehlp.dll", "rpcrt4.dll", "FWPUCLNT.DLL", "DXCore.dll", "uxtheme.dll", "TextInputFramework.dll", "winmm.dll", "Windows.Internal.Graphics.Display.DisplayColorManagement.dll", "Wldap32.dll", "shlwapi.dll", "wldp.dll", "sechost.dll", "nsi.dll" };
bool FindSharedMemory(HANDLE hProcess, uint64_t* MemoryOut, uint64_t* SharedCountOut)
{
uint8_t* Address{};
MEMORY_BASIC_INFORMATION Mbi{};
bool found = false;
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;
else if (strstr(filename, "r5apex.exe"))
ProcessData->base = (uintptr_t)Address;
}
else if (Mbi.State == MEM_COMMIT && Mbi.Protect == PAGE_READWRITE && Mbi.RegionSize == 0x3201000 && Mbi.Type == MEM_MAPPED) {
ProcessData->discord_framebuffer = (uintptr_t)Address;
}
else if (!found && Mbi.State == MEM_COMMIT && Mbi.Protect == PAGE_READWRITE && Mbi.RegionSize == 0x1000 && Mbi.Type == MEM_MAPPED)
{
PSAPI_WORKING_SET_EX_INFORMATION WsInfo{};
WsInfo.VirtualAddress = Mbi.BaseAddress;
if (QueryWorkingSetEx(hProcess, &WsInfo, sizeof(WsInfo)))
{
if (hProcess == HANDLE(-1))
{
*MemoryOut = uint64_t(Mbi.BaseAddress);
*SharedCountOut = WsInfo.VirtualAttributes.ShareCount;
found = true;
}
else if (WsInfo.VirtualAttributes.ShareCount == *SharedCountOut)
{
*MemoryOut = uint64_t(Mbi.BaseAddress);
found = true;
}
}
}
Address += Mbi.RegionSize;
}
return found;
}
template<int SigLenT>
uint64_t FindROPSignatureInModule(const char* ModuleName, const char(&Signature)[SigLenT])
{
const int SigLen = SigLenT - 1;
uint64_t ModuleBase = uint64_t(GetModuleHandleA(ModuleName));
if (!ModuleBase)
{
ModuleBase = uint64_t(LoadLibraryA(ModuleName));
if (!ModuleBase)
{
printf("Failed to load module[%s]\n", ModuleName);
return 0;
}
}
PIMAGE_NT_HEADERS64 NtHdr = NTHEADER(ModuleBase);
PIMAGE_SECTION_HEADER SectionHdr = IMAGE_FIRST_SECTION(NtHdr);
for (int i = 0; i < NtHdr->FileHeader.NumberOfSections; i++, SectionHdr++)
{
if (SectionHdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
continue;
if (!(SectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE))
continue;
for (uint32_t u = 0; u < SectionHdr->Misc.VirtualSize - SigLen; u++)
{
uint64_t Addr = ModuleBase + SectionHdr->VirtualAddress + u;
if (memcmp((void*)Addr, Signature, SigLen) == 0)
{
return Addr;
}
}
}
return 0;
}
template<int SigLenT>
bool FindGadget(uint64_t* Out, const char* ModuleName, const char(&Signature)[SigLenT])
{
if (*Out)
return true;
*Out = FindROPSignatureInModule(ModuleName, Signature);
return *Out;
}
public:
uint64_t LocalSharedMemory{};
uint64_t RemoteSharedMemory{};
uint64_t RemoteProcessBase{};
void InsertChain(uint64_t Val1, uint64_t Val2, bool Need2 = true)
{
*(volatile uint64_t*)(LocalSharedMemory + ShellCursor) = Val1;
ShellCursor += 8;
if (Need2)
{
*(volatile uint64_t*)(LocalSharedMemory + ShellCursor) = Val2;
ShellCursor += 8;
}
}
void ResetCursor()
{
ShellCursor = SHARED_MEM_STACK_OFFSET;
}
void FixupControlFlow()
{
if (!LegacyWin10)
{
InsertChain(PopRCX, -0x71);
InsertChain(AddRCX_RBP, MovRax_RCX);
InsertChain(PushRAX_PopRSP, 0, false);
}
else
{
InsertChain(PopRAX, -0x71);
InsertChain(AddRCX_RBP, PushRAX_PopRSP);
}
}
void Hijack()
{
Sleep(0);
ShowWindow(ProcessData->ProcessHwnd, 0);
auto craftedinfo = (MMIOINFO*)(LocalSharedMemory + SHARED_MEM_MMIO_STRUCT);
memset(craftedinfo, 0, sizeof(*craftedinfo));
craftedinfo->dwFlags = 0x1000000;
craftedinfo->pIOProc = (LPMMIOPROC)(AddRSP_58);
craftedinfo->pchBuffer = (HPSTR)(PopRSP);
craftedinfo->pchNext = (HPSTR)(RemoteSharedMemory + SHARED_MEM_STACK_OFFSET);
auto hhook = SetWindowsHookExA(WH_SHELL, (HOOKPROC)(mmio_rename), winmm, ProcessData->ThreadID);
SendMessage(ProcessData->ProcessHwnd, WM_APPCOMMAND, 0, RemoteSharedMemory + SHARED_MEM_MMIO_STRUCT);
UnhookWindowsHookEx(hhook);
memset((void*)(LocalSharedMemory + SHARED_MEM_STACK_OFFSET), 0, 0x1000 - SHARED_MEM_STACK_OFFSET);
Sleep(0);
ShowWindow(ProcessData->ProcessHwnd, 1);
}
uint64_t ReadU64(uint64_t Address)
{
ResetCursor();
{
InsertChain(PopRCX, Address);
InsertChain(ReadRCX_RAX, 0, false);
InsertChain(PopRCX, RemoteSharedMemory + SHARED_MEM_STACK_PLACEHOLDER_OFFSET);
InsertChain(WriteRCX_RAX, 0, false);
}
FixupControlFlow();
Hijack();
return *(volatile uint64_t*)(LocalSharedMemory + SHARED_MEM_STACK_PLACEHOLDER_OFFSET);
}
void WriteU64(uint64_t Address, uint64_t Value)
{
ResetCursor();
{
InsertChain(PopRAX, Value);
InsertChain(PopRCX, Address);
InsertChain(WriteRCX_RAX, 0, false);
}
FixupControlFlow();
Hijack();
}
bool CloneAndReplaceVMT(uint64_t vtbl, size_t size) {
//Because of stack size issue and to be on the safe space, we don't allow Shadowing VMT bigger than 280 bytes.
if (size > 0x3f0)
return false;
auto orig_vtbl = ReadU64(vtbl);
if (!orig_vtbl)
return false;
if (orig_vtbl != RemoteSharedMemory + SHARED_MEM_SHADOW_VMT)
{
ResetCursor();
bool leftover = false;
for (int i = 0; i < size; i += 8) {
InsertChain(PopRCX, orig_vtbl + i);
InsertChain(ReadRCX_RAX, PopRCX);
InsertChain(RemoteSharedMemory + SHARED_MEM_SHADOW_VMT + i, WriteRCX_RAX);
leftover = true;
if (i && (i % 0x140 == 0)) {
FixupControlFlow();
Hijack();
Sleep(1);
ResetCursor();
leftover = false;
}
}
if (leftover) {
FixupControlFlow();
Hijack();
}
WriteU64(ProcessData->base + 0x16F1230, RemoteSharedMemory + SHARED_MEM_SHADOW_VMT);
return true;
}
return false;
}
// Every write 8 bytes uses 40 bytes of stack and we have 2000 bytes of stack to work with
// So we can at most write 400 bytes at once
void WriteData(uint64_t Address, BYTE* Data, size_t size)
{
if (size >= 400)
return;
ResetCursor();
for(int i = 0;i < size; i+= 8)
{
InsertChain(PopRAX, *(uint64_t*)(Data+i));
InsertChain(PopRCX, Address+i);
InsertChain(WriteRCX_RAX, 0, false);
}
FixupControlFlow();
Hijack();
}
bool Initialize(CProcess* Proc)
{
ProcessData = Proc;
winmm = LoadLibraryA("winmmbase.dll");
mmio_rename = GetProcAddress(winmm, "mmioRenameW");
// Load shared mem.
{
char Path[MAX_PATH];
SHGetFolderPathA(NULL, CSIDL_DESKTOP, NULL, SHGFP_TYPE_CURRENT, Path);
}
// Locate shared memory in our client.
if (!FindSharedMemory(HANDLE(-1), &LocalSharedMemory, &SharedCount))
{
printf("Failed to find shared memory in current process\n");
return false;
}
// Locate shared memory in target process.
{
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))
{
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);
}
// Find gadgets.
{
bool AllGadgetsFound = false;
uint16_t LoadBitMap = 0;
for (int i = 0; i < ARRAYSIZE(ModulesToCheck); i++)
{
const char* ModuleName = ModulesToCheck[i];
SET_BIT(LoadBitMap, 0, FindGadget(&PopRCX, ModuleName, "\x59\xC3"));
SET_BIT(LoadBitMap, 1, FindGadget(&PopRDX, ModuleName, "\x5A\xC3"));
SET_BIT(LoadBitMap, 2, FindGadget(&PopRAX, ModuleName, "\x58\xC3"));
SET_BIT(LoadBitMap, 3, FindGadget(&PopRSP, ModuleName, "\x5C\xC3"));
SET_BIT(LoadBitMap, 4, FindGadget(&WriteRCX_RDX, ModuleName, "\x48\x89\x11\xC3"));
SET_BIT(LoadBitMap, 5, FindGadget(&ReadRCX_RAX, ModuleName, "\x48\x8B\x01\xC3"));
SET_BIT(LoadBitMap, 6, FindGadget(&WriteRDX_RCX, ModuleName, "\x48\x89\x0A\xC3"));
SET_BIT(LoadBitMap, 7, FindGadget(&WriteRCX_RAX, ModuleName, "\x48\x89\x01\xC3"));
SET_BIT(LoadBitMap, 8, FindGadget(&AddRSP_58, ModuleName, "\x48\x83\xC4\x58\xC3"));
SET_BIT(LoadBitMap, 9, FindGadget(&AddRCX_RBP, ModuleName, "\x48\x01\xE9\xC3"));
if (!AddRCX_RBP)
{
SET_BIT(LoadBitMap, 9, FindGadget(&AddRCX_RBP, ModuleName, "\x48\x01\xE8\xC3"));
if (AddRCX_RBP)
LegacyWin10 = true;
}
SET_BIT(LoadBitMap, 10, FindGadget(&PushRAX_PopRSP, ModuleName, "\x50\x5C\xC3"));
SET_BIT(LoadBitMap, 11, FindGadget(&MovRax_RCX, ModuleName, "\x51\x58\xC3"));
if (LoadBitMap == 0xFFF)
{
AllGadgetsFound = true;
break;
}
}
if (!AllGadgetsFound)
{
printf("Failed to find some gadgets\n");
__debugbreak();
return false;
}
}
/*
if (ProcessData->peb)
ProcessData->base = ReadU64(ProcessData->peb + 0x10);
*/
return true;
}
};
#define READ 1
#define WRITE 2
class CIpc {
public:
struct command {
uint64_t lock{}; // 0
uint64_t operation{}; // 8
uint64_t val1{}; // 0x10 - READ : addr to read from | WRITE : value to write
uint64_t val2{}; // 0x18 - READ : where the read value goes | WRITE : address to write to
};
inline static command* cmd{};
static bool Setup(CProcess& proc, CExploit& exploit) {
/*
*
*
*
*
*/
/*
auto installed = exploit.CloneAndReplaceVMT(proc.base + 0x16F1230, 0x1B8);
if (installed) {
uintptr_t dh64_present_tramp = exploit.ReadU64(proc.discord_base + 0xE9090);
if (!dh64_present_tramp)
return false;
uintptr_t dh64_rwx = dh64_present_tramp & 0xFFFFFFFFFFFFF000;
BYTE ipc_shellcode[] = { 0x49, 0xBA, 0xAF, 0xFF, 0x7A, 0x1F, 0xBF, 0x01, 0x00, 0x00, 0xFF, 0xB0, 0xD8, 0x00, 0x00, 0x00, 0x41, 0x80, 0x3A, 0x00, 0x74, 0x2B, 0x41, 0x8A, 0x42, 0x08, 0x3C, 0x01, 0x75, 0x0D, 0x49, 0x8B, 0x42, 0x10, 0x48, 0x8B, 0x00, 0x49, 0x89, 0x42, 0x18, 0xEB, 0x0F, 0x3C, 0x02, 0x75, 0xE1, 0x49, 0x8B, 0x42, 0x10, 0x4D, 0x8B, 0x5A, 0x18, 0x49, 0x89, 0x03, 0x41, 0xC6, 0x42, 0x08, 0x00, 0xEB, 0xCF, 0xC3 };
uint64_t command_buffer = exploit.RemoteSharedMemory + SHARED_MEM_COMMAND_BUFFER;
cmd = (command*)(exploit.LocalSharedMemory + SHARED_MEM_COMMAND_BUFFER);
cmd->lock = 0;
cmd->operation = 0;
cmd->val1 = 0;
cmd->val2 = 0;
memcpy(ipc_shellcode + 2, &command_buffer, sizeof(uint64_t));
exploit.WriteData(dh64_rwx + 0x12, (BYTE*)ipc_shellcode, sizeof(ipc_shellcode));
*(uint64_t*)(exploit.LocalSharedMemory + SHARED_MEM_SHADOW_VMT + (27 * 8)) = *(uint64_t*)(exploit.LocalSharedMemory + SHARED_MEM_SHADOW_VMT + (25 * 8));
*(uint64_t*)(exploit.LocalSharedMemory + SHARED_MEM_SHADOW_VMT + (26 * 8)) = dh64_rwx + 0x12;
*(uint64_t*)(exploit.LocalSharedMemory + SHARED_MEM_SHADOW_VMT + (25 * 8)) = proc.base + 0x2feaab;
}
else {
cmd = (command*)(exploit.LocalSharedMemory + SHARED_MEM_COMMAND_BUFFER);
cmd->lock = 0;
cmd->operation = 0;
cmd->val1 = 0;
cmd->val2 = 0;
}
*/
uintptr_t dh64_present_tramp = exploit.ReadU64(proc.discord_base + 0xE9090);
if (!dh64_present_tramp)
return false;
uintptr_t dh64_rwx = dh64_present_tramp & 0xFFFFFFFFFFFFF000;
BYTE ipc_shellcode[] = {
0x49, 0xBA, 0xAF, 0xFF, 0x7A, 0x1F, 0xBF, 0x01,
0x00, 0x00, 0x49, 0x83, 0x3A, 0x00, 0x74, 0x36,
0x49, 0x8B, 0x42, 0x08, 0x48, 0x83, 0xF8, 0x01,
0x75, 0x0D, 0x49, 0x8B, 0x42, 0x10, 0x48, 0x8B,
0x00, 0x49, 0x89, 0x42, 0x18, 0xEB, 0x15, 0x49,
0x8B, 0x42, 0x08, 0x48, 0x83, 0xF8, 0x02, 0x75,
0xD9, 0x49, 0x8B, 0x42, 0x10, 0x4D, 0x8B, 0x5A,
0x18, 0x49, 0x89, 0x03, 0x49, 0xC7, 0x42, 0x08,
0x00, 0x00, 0x00, 0x00, 0xEB, 0xC4, 0xE9, 0x00,
0x00, 0x00, 0x00 };
uint64_t command_buffer = exploit.RemoteSharedMemory + SHARED_MEM_COMMAND_BUFFER;
uint32_t distance_to_present_tramp = dh64_present_tramp - (dh64_rwx + 0x12 + sizeof(ipc_shellcode));
cmd = (command*)(exploit.LocalSharedMemory + SHARED_MEM_COMMAND_BUFFER);
cmd->lock = 0;
cmd->operation = 0;
cmd->val1 = 0;
cmd->val2 = 0;
if (distance_to_present_tramp < 0x1000) { // If we relaunch, no need to overwrite it or it would crash because distance is going to be negative.
memcpy(ipc_shellcode + 2, &command_buffer, sizeof(uint64_t));
memcpy(ipc_shellcode + sizeof(ipc_shellcode) - 4, &distance_to_present_tramp, sizeof(uint32_t));
Sleep(10);
exploit.WriteData(dh64_rwx + 0x12, (BYTE*)ipc_shellcode, sizeof(ipc_shellcode));
Sleep(10);
exploit.WriteU64(proc.discord_base + 0xE9090, dh64_rwx + 0x12);
}
return true;
}
__forceinline static void LockFrame() {
cmd->operation = 0;
cmd->lock = 1;
}
__forceinline static void UnlockFrame() {
cmd->operation = 0;
cmd->lock = 0;
}
static uint64_t Read64(uintptr_t ptr) {
cmd->val2 = 0;
cmd->val1 = ptr;
cmd->operation = READ;
while (CIpc::cmd->operation == READ)
_mm_pause();
return cmd->val2;
}
static void Write64(uintptr_t ptr, uint64_t val) {
cmd->val2 = ptr;
cmd->val1 = val;
cmd->operation = WRITE;
while (CIpc::cmd->operation == WRITE)
_mm_pause();
return;
}
template <typename T>
static T Read(uintptr_t ptr) {
T ret{};
int size_of_T = sizeof(T);
int full_chunks = size_of_T / 8;
int remaining_bytes = size_of_T % 8;
for (int i = 0; i < full_chunks; i++) {
auto tmp = Read64(ptr + (i * 8));
memcpy(((char*)&ret) + (i * 8), &tmp, 8);
}
if (remaining_bytes > 0 || full_chunks == 0) {
auto tmp = Read64(ptr + (full_chunks * 8));
memcpy(((char*)&ret) + (full_chunks * 8), &tmp, remaining_bytes);
}
return ret;
}
static void Cleanup() {
if (cmd) {
UnlockFrame();
cmd->operation = 0;
cmd->val1 = 0;
cmd->val2 = 0;
}
}
};
#pragma pack(push, 1)
namespace DiscOverlay {
typedef struct _Header
{
UINT Magic; //0
uint64_t FrameCount; //4
UINT Width; //12
UINT Height; //16
} Header;
};
#pragma pack(pop,1)
BOOL WINAPI ConsoleHandler(DWORD signal) {
if (signal == CTRL_C_EVENT || signal == CTRL_CLOSE_EVENT)
CIpc::Cleanup();
return true;
}
void onExit() {
CIpc::Cleanup();
}
/*
1FA 4000
*/
#include <vector>
#include <unordered_set>
#include "C:\Users\Generic\python\font_glyphs.h"
class FrameBuffer {
private:
size_t width, height;
std::vector<uint32_t> buffer; // Buffer now uses uint32_t for each pixel
std::unordered_set<size_t> dirtyFlags;
std::unordered_set<size_t> previous_dirtyFlags;
public:
FrameBuffer(size_t w, size_t h) : width(w), height(h) {
size_t totalPixels = w * h;
buffer.resize(totalPixels, 0);
size_t chunkCount = (totalPixels * sizeof(uint32_t) + 7) / 8;
dirtyFlags.reserve(chunkCount);
previous_dirtyFlags.reserve(chunkCount);
clearBuffers();
}
void clearBuffers() {
std::fill(buffer.begin(), buffer.end(), 0);
dirtyFlags.clear();
previous_dirtyFlags.clear();
}
void SetPixel(size_t x, size_t y, uint32_t color) {
if (x >= width)
return;
if (y >= height)
return;
size_t index = y * width + x;
size_t chunkIndex = (index * sizeof(uint32_t)) / 8;
buffer[index] = color;
dirtyFlags.insert(chunkIndex);
}
void UpdateDirtyFlags() {
for (auto &i : previous_dirtyFlags)
dirtyFlags.insert(i);
}
void Flush(CProcess& proc) {
uintptr_t baseAddress = proc.discord_framebuffer + 20;
UpdateDirtyFlags();
previous_dirtyFlags.clear();
uint64_t* currentBuffer = reinterpret_cast<uint64_t*>(buffer.data());
int b = 0;
for (auto &i : dirtyFlags) {
size_t byteOffset = i * 8;
CIpc::Write64(baseAddress + byteOffset, currentBuffer[i]);
if (currentBuffer[i])
previous_dirtyFlags.insert(i);
currentBuffer[i] = 0;
b++;
}
dirtyFlags.clear();
}
bool resize(size_t newWidth, size_t newHeight) {
if (width != newWidth || height != newHeight) {
width = newWidth;
height = newHeight;
size_t totalPixels = newWidth * newHeight;
buffer.resize(totalPixels);
size_t chunkCount = (totalPixels * sizeof(uint32_t) + 7) / 8;
dirtyFlags.reserve(chunkCount);
previous_dirtyFlags.reserve(chunkCount);
clearBuffers();
return true;
}
return false;
}
inline void DrawTexts(UINT x, UINT y, const char* text, uint32_t color, int drawOutline = 1) {
UINT startX = x;
int baselineY = y; // Set to where you want the text baseline
for (size_t i = 0; text[i] != '\0'; i++) {
char c = text[i];
if (c < 32 || c > 126) continue;
const Glyph* glyph = &glyphs[c - 32];
const unsigned char* bitmap = glyph->data;
int glyphX = startX + glyph->offset_x;
int glyphY = baselineY + glyph->offset_y; // Adjust to place baseline correctly
if (drawOutline) {
uint32_t outlineColor = 0x000000; // Assuming black color for the outline
// Draw outline by setting pixels around each character pixel
for (int row = 0; row < glyph->height; row++) {
for (int col = 0; col < glyph->width; col++) {
int bit = (bitmap[row * ((glyph->width + 7) / 8) + col / 8] >> (7 - (col % 8))) & 1;
if (bit) {
for (int dy = -1; dy <= 1; dy++) {
for (int dx = -1; dx <= 1; dx++) {
if (dx != 0 || dy != 0) { // Avoid the center pixel
SetPixel(glyphX + col + dx, glyphY + row + dy, outlineColor + 0xFF000000);
}
}
}
}
}
}
}
// Draw the actual character
for (int row = 0; row < glyph->height; row++) {
for (int col = 0; col < glyph->width; col++) {
int bit = (bitmap[row * ((glyph->width + 7) / 8) + col / 8] >> (7 - (col % 8))) & 1;
if (bit) {
SetPixel(glyphX + col, glyphY + row, color);
}
}
}
startX += glyph->width; // Advance to the start of the next character
}
}
inline void DrawLine(UINT x1, UINT y1, UINT x2, UINT y2, uint32_t color)
{
int dx = abs(static_cast<int>(x2 - x1)), sx = x1 < x2 ? 1 : -1;
int dy = -abs(static_cast<int>(y2 - y1)), sy = y1 < y2 ? 1 : -1;
int err = dx + dy, e2;
while (true)
{
SetPixel(x1, y1, color);
if (x1 == x2 && y1 == y2)
break;
e2 = 2 * err;
if (e2 >= dy) { err += dy; x1 += sx; }
if (e2 <= dx) { err += dx; y1 += sy; }
}
}
inline void DrawRectangle(UINT x1, UINT y1, UINT width, UINT height, uint32_t color)
{
for (UINT x = x1; x < x1 + width; x++)
{
SetPixel(x, y1, color);
SetPixel(x, y1 + height - 1, color);
}
for (UINT y = y1; y < y1 + height; y++)
{
SetPixel(x1, y, color);
SetPixel(x1 + width - 1, y, color);
}
}
inline void DrawCircle(UINT x0, UINT y0, UINT radius, uint32_t color)
{
int x = radius;
int y = 0;
int radiusError = 1 - x;
while (x >= y)
{
SetPixel(x0 + x, y0 + y, color);
SetPixel(x0 - x, y0 + y, color);
SetPixel(x0 - x, y0 - y, color);
SetPixel(x0 + x, y0 - y, color);
SetPixel(x0 + y, y0 + x, color);
SetPixel(x0 - y, y0 + x, color);
SetPixel(x0 - y, y0 - x, color);
SetPixel(x0 + y, y0 - x, color);
y++;
if (radiusError < 0)
{
radiusError += 2 * y + 1;
}
else
{
x--;
radiusError += 2 * (y - x + 1);
}
}
}
};
namespace Offset {
};
#pragma comment(lib, "winmm.lib")
int main()
{
// Init
{
SetConsoleCtrlHandler(ConsoleHandler, TRUE);
atexit(onExit);
}
CProcess ApexProcess{};
CExploit Exploit{};
if (!ApexProcess.Initialize(L"Apex Legends", L"Respawn001"))
{
printf("Apex is not running\n");
// Sleep(5000);
// return -1;
}
if (!Exploit.Initialize(&ApexProcess))
{
printf("Failed to load exploit\n");
Sleep(5000);
return -1;
}
if (!ApexProcess.discord_base) {
printf("Discord overlay not enabled\n");
Sleep(5000);
return -1;
}
if (!ApexProcess.discord_framebuffer) {
printf("ESP can't be enabled, no discord overlay found\n");
Sleep(5000);
return -1;
}
if (!CIpc::Setup(ApexProcess, Exploit)) {
printf("Failed IPC setup\n");
Sleep(5000);
return -1;
}
Sleep(10);
printf("starting...\n");
FrameBuffer* fb = new FrameBuffer(1920, 1080);
LARGE_INTEGER frequency;
LARGE_INTEGER start;
LARGE_INTEGER end;
QueryPerformanceFrequency(&frequency);
while (1) {
/*
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&start);
*/
QueryPerformanceCounter(&start);
CIpc::LockFrame();
auto overlay_header = CIpc::Read<DiscOverlay::Header>(ApexProcess.discord_framebuffer);
overlay_header.FrameCount++;
CIpc::Write64(ApexProcess.discord_framebuffer + 4, overlay_header.FrameCount);
if (fb->resize(overlay_header.Width, overlay_header.Height))
fb->Flush(ApexProcess);
else {
fb->DrawTexts(400, 400, "Just drawing with 0 handle or detection vector", 0xFFFFFFFF);
fb->DrawCircle(500, 500, 5, 0xFFFFFFFF);
fb->Flush(ApexProcess);
}
CIpc::UnlockFrame();
QueryPerformanceCounter(&end);
double duration = (end.QuadPart - start.QuadPart) * 1.0e3 / frequency.QuadPart;
// Print the duration in milliseconds with four-digit accuracy using printf
printf("Time taken: %.4f ms\n", duration);
Sleep(0);
}
return 0;
}