#include "internal-hook.hpp" #include #include #include #include #include #include "hde/mhde_wrapper.hpp" #include "ex/exploit.hpp" struct FrameContext { ID3D12CommandAllocator* allocator = nullptr; D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle{}; ID3D12Resource* backbuffer = nullptr; }; struct Vertex { float x, y, z, u, v; }; struct original_prologue { uint64_t len; uint8_t bytes[32]; }; struct present_ipc { volatile bool lock = false; volatile bool active = false; volatile uint64_t func = 0; volatile uint64_t arg[8]{}; IDXGISwapChain* swapchain = 0; ID3D12CommandQueue* queue = 0; volatile uint64_t spoofhelper = 0; volatile uint64_t rbx = 0; volatile uint64_t r14 = 0; volatile uint64_t result = 0; volatile bool virtualfunc = false; volatile uint16_t index = false; volatile uint64_t rdx = 0; volatile uint64_t r8 = 0; volatile uint64_t prologue16b = 0; original_prologue orig_prologue{}; }; struct SyncBackEntry { void* dst; size_t size; size_t offset; }; template struct function_traits; template struct function_traits { using return_type = R; using argument_types = std::tuple; }; template struct function_traits { using return_type = R; using argument_types = std::tuple; }; template struct function_traits { using return_type = R; using argument_types = std::tuple; }; present_ipc* p_ipc = 0; template constexpr bool tuple_convertible() { if constexpr (sizeof...(Args) != std::tuple_size_v) { return false; } else { return ([](std::index_sequence) { return (std::is_convertible_v> && ...); })(std::make_index_sequence>{}); } } template constexpr uint64_t to_u64(T&& value) { if constexpr (std::is_integral_v> && sizeof(T) <= sizeof(uint64_t)) { return static_cast(value); } else { return reinterpret_cast(value); } } static inline void set_original_prologue(const uint8_t* p) { static std::unordered_map cache; if (auto it = cache.find(p); it != cache.end()) { p_ipc->func += it->second.len; p_ipc->orig_prologue = it->second; return; } cache[p] = {}; CMHDE mhde; auto len = mhde.Disassemble(p); while (len < 14) len += mhde.Disassemble(p + len); cache[p].len = len; memcpy(cache[p].bytes, p, len); *(uint32_t*)&cache[p].bytes[len] = 0x862ff41; p_ipc->func += len; p_ipc->orig_prologue = cache[p]; return; } // Displacement finder with caching static inline uint64_t find_valid_disp_cached(const uint8_t* p) { static std::unordered_map cache; if (auto it = cache.find(p); it != cache.end()) { return it->second; } for (size_t i = 0; i < 30; ++i) { //mov rax,QWORD PTR [rax+?32] if (i + 6 < 30 && p[i] == 0x48 && p[i + 1] == 0x8B && p[i + 2] == 0x80) { int32_t disp = *reinterpret_cast(p + i + 3); if (disp > 0 && disp % 8 == 0) { cache[p] = static_cast(disp); return disp; } } //mov rax,QWORD PTR [rax+?] if (i + 3 < 30 && p[i] == 0x48 && p[i + 1] == 0x8B && p[i + 2] == 0x40) { int8_t disp = static_cast(p[i + 3]); if (disp > 0 && disp % 8 == 0) { cache[p] = static_cast(disp); return disp; } } //jmp qword ptr [rax+?] if (i + 3 < 30 && p[i] == 0xFF && p[i + 1] == 0x60) { int8_t disp = static_cast(p[i + 2]); if (disp > 0 && disp % 8 == 0) { cache[p] = static_cast(disp); return disp; } } //jmp qword ptr [rax+?32] if (i + 6 < 30 && p[i] == 0xFF && p[i + 1] == 0xA0) { int32_t disp = *reinterpret_cast(&p[i + 2]); if (disp > 0 && disp % 8 == 0) { cache[p] = static_cast(disp); return disp; } } } cache[p] = 0; return 0; } template uint64_t ipc_call(CExploit& ex, Func fn, Args&&... args) { static_assert(sizeof...(Args) <= 8, "Too many arguments"); using Return = typename function_traits::return_type; constexpr bool is_struct_return = std::is_class_v && std::is_trivially_copyable_v && !std::is_void_v && !std::is_integral_v; // If a struct is returned, enforce that the last argument is Return* if constexpr (is_struct_return) { static_assert(sizeof...(Args) >= 1, "Missing struct return output pointer"); using LastArg = std::tuple_element_t...>>; static_assert(std::is_pointer_v, "Last argument must be a pointer to struct return type"); static_assert(std::is_same_v>, Return>, "Last argument must be a pointer to the return type struct"); } static std::vector sync_entries; sync_entries.clear(); size_t cursor = 0; if constexpr (std::is_member_function_pointer_v) { using expected_args = typename function_traits::argument_types; if constexpr (!is_struct_return) { static_assert(tuple_convertible(), "ipc_call: arguments not convertible to member function signature"); } static_assert(sizeof(fn) <= sizeof(uint64_t), "Member function pointer too large"); p_ipc->func = 0; p_ipc->virtualfunc = 1; auto b = *reinterpret_cast(&fn); p_ipc->index = find_valid_disp_cached(reinterpret_cast(b)); } else if constexpr (std::is_pointer_v) { using expected_args = typename function_traits::argument_types; static_assert(tuple_convertible(), "ipc_call: arguments not convertible to function signature"); p_ipc->virtualfunc = 0; p_ipc->func = std::bit_cast(fn); } else { static_assert([] { return false; }(), "Unsupported function type in ipc_call"); } uint64_t* dest = const_cast(p_ipc->arg); size_t i = 0; auto process_arg = [&](auto&& arg) { using T = std::decay_t; if constexpr (std::is_pointer_v) { using Pointee = std::remove_pointer_t; if constexpr (std::is_trivially_copyable_v) { size_t size = 0; if constexpr (std::is_same_v || std::is_same_v) { size = std::strlen(arg) + 1; } else if constexpr (std::is_same_v || std::is_same_v) { size = (std::wcslen(arg) + 1) * sizeof(wchar_t); } else if constexpr (std::is_same_v) { size = sizeof(Vertex) * 4; } else if constexpr (std::is_same_v) { size = sizeof(D3D11_INPUT_ELEMENT_DESC) * 2; } else { size = sizeof(Pointee); } uint8_t* local_base = reinterpret_cast(ex.get_LocalSharedMemory()) + PAD_DATA + cursor; uint8_t* remote_base = reinterpret_cast(ex.get_RemoteSharedMemory()) + PAD_DATA + cursor; std::memcpy(local_base, arg, size); dest[i++] = reinterpret_cast(remote_base); if constexpr (!std::is_const_v) { sync_entries.push_back(SyncBackEntry{ const_cast(static_cast(arg)), size, cursor }); } cursor += size; } else { dest[i++] = reinterpret_cast(arg); // non-trivial, pass raw pointer } } else if constexpr (std::is_lvalue_reference_v && std::is_trivially_copyable_v) { size_t size = sizeof(T); if constexpr (sizeof(T) <= 8) { auto dst = &dest[i++]; std::memset(dst, 0, 8); std::memcpy(dst, &arg, 8); } else { uint8_t* local_base = reinterpret_cast(ex.get_LocalSharedMemory()) + PAD_DATA + cursor; uint8_t* remote_base = reinterpret_cast(ex.get_RemoteSharedMemory()) + PAD_DATA + cursor; std::memcpy(local_base, &arg, size); dest[i++] = reinterpret_cast(remote_base); cursor += size; } } else { if constexpr (sizeof(std::forward(arg)) <= 8) { auto dst = &dest[i++]; std::memset(dst, 0, 8); std::memcpy(dst, &arg, 8); } else { dest[i++] = (uint64_t)(std::forward(arg)); } } }; (process_arg(std::forward(args)), ...); p_ipc->prologue16b = 0; p_ipc->active = 1; while (!p_ipc->prologue16b) { _mm_pause(); } if (*(uint16_t*)(p_ipc->func) != p_ipc->prologue16b) { printf("Hook detected at 0x%llx, jitting it\n", p_ipc->func); set_original_prologue((uint8_t*)p_ipc->func); p_ipc->prologue16b = 0xB00B; } else { p_ipc->prologue16b = 0xDEAD; } while (p_ipc->active) { _mm_pause(); } for (const auto& entry : sync_entries) { void* src = reinterpret_cast(ex.get_LocalSharedMemory()) + PAD_DATA + entry.offset; std::memcpy(entry.dst, src, entry.size); } return p_ipc->result; } uint32_t GetQueueIndexFromSwapchain() { WNDCLASSW wc = {}; wc.lpfnWndProc = DefWindowProcW; wc.hInstance = GetModuleHandleW(nullptr); wc.lpszClassName = L"_2"; RegisterClassW(&wc); HWND hwnd = CreateWindowW(wc.lpszClassName, L"_2", WS_OVERLAPPEDWINDOW, 0, 0, 1, 1, nullptr, nullptr, nullptr, nullptr); DXGI_SWAP_CHAIN_DESC1 sd = {}; sd.Width = 1; sd.Height = 1; sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.BufferCount = 2; sd.SampleDesc.Count = 1; sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; IDXGIFactory4* factory = nullptr; CreateDXGIFactory1(IID_PPV_ARGS(&factory)); ID3D12Device* device = nullptr; D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device)); D3D12_COMMAND_QUEUE_DESC cqDesc = {}; ID3D12CommandQueue* queue = nullptr; device->CreateCommandQueue(&cqDesc, IID_PPV_ARGS(&queue)); IDXGISwapChain1* swapChain1 = nullptr; factory->CreateSwapChainForHwnd(queue, hwnd, &sd, nullptr, nullptr, &swapChain1); IDXGISwapChain3* swapChain = nullptr; swapChain1->QueryInterface(IID_PPV_ARGS(&swapChain)); uint64_t val = (uint64_t)queue; uint64_t base = (uint64_t)swapChain; uint32_t index = 0; for (uint32_t i = 0; i < 0x40; ++i) { if (*(uint64_t*)(base + 8 * i) == val) { index = i; break; } } swapChain->Release(); swapChain1->Release(); queue->Release(); device->Release(); factory->Release(); DestroyWindow(hwnd); UnregisterClassW(wc.lpszClassName, wc.hInstance); return index; } void __attribute__((noinline)) shellcode_present_hook(void) { MAGIC_ASM __asm { movabs r10, 0xdeadbeefdeadbeef mov QWORD PTR[r10 + 0x50], rcx mov QWORD PTR[r10 + 0x88], rdx mov QWORD PTR[r10 + 0x90], r8 #ifdef DIRECTX12 add rcx, 0x138 mov rcx, QWORD PTR[rcx] mov QWORD PTR[r10 + 0x58], rcx #endif begin_lock : mov al, BYTE PTR[r10] cmp al, 0x1 jne short fin mov al, BYTE PTR[r10 + 0x1] cmp al, 0x1 jne short begin_lock sub rsp, 0x48 mov QWORD PTR[r10 + 0x68], rbx mov QWORD PTR[r10 + 0x70], r14 mov rcx, QWORD PTR[r10 + 0x10] mov rdx, QWORD PTR[r10 + 0x18] mov r8, QWORD PTR[r10 + 0x20] mov r9, QWORD PTR[r10 + 0x28] mov r11, QWORD PTR[r10 + 0x30] mov QWORD PTR[rsp + 0x20], r11 mov r11, QWORD PTR[r10 + 0x38] mov QWORD PTR[rsp + 0x28], r11 mov r11, QWORD PTR[r10 + 0x40] mov QWORD PTR[rsp + 0x30], r11 mov r11, QWORD PTR[r10 + 0x48] mov QWORD PTR[rsp + 0x38], r11 cmp BYTE PTR[r10 + 0x80], 0x1 je short vcall mov rbx, QWORD PTR[r10 + 0x8] mov r11w, WORD PTR[rbx] mov WORD PTR[r10 + 0x98], r11w wait : mov r11w, WORD PTR[r10 + 0x98] cmp r11w, 0xb00b je short jit cmp r11w, 0xdead jne short wait jmp short execute jit : lea rbx, [rip + jit_space] vmovups ymm0, YMMWORD PTR[r10 + 0xa8] vmovups YMMWORD PTR[rbx], ymm0 vzeroupper execute : lea r14, [rip + ret_addr] jmp QWORD PTR[r10 + 0x60] vcall : xor r11, r11 mov r11w, WORD PTR[r10 + 0x82] mov rbx, QWORD PTR[rcx] mov rbx, QWORD PTR[rbx + r11 * 1] mov QWORD PTR[r10 + 0x8], rbx mov r11w, WORD PTR[rbx] mov WORD PTR[r10 + 0x98], r11w jmp short wait ret_addr : pop rbx movabs r10, 0xdeadbeefdeadbeef mov rbx, QWORD PTR[r10 + 0x68] mov r14, QWORD PTR[r10 + 0x70] mov QWORD PTR[r10 + 0x78], rax mov BYTE PTR[r10 + 0x1], 0x0 add rsp, 0x48 jmp short begin_lock fin : mov rcx, QWORD PTR [r10 + 0x50] mov rdx, QWORD PTR [r10 + 0x88] mov r8, QWORD PTR [r10 + 0x90] .byte 0xE9 .byte 0x00 .byte 0x00 .byte 0x00 .byte 0x00 jit_space : } MAGIC_ASM MAGIC_ASM } size_t install_hook_present(CProcess& process, CExploit& exploit, int offset) { p_ipc = (present_ipc*)(exploit.get_LocalSharedMemory() + PAD_PRESENT_IPC); memset(p_ipc, 0, sizeof(*p_ipc)); auto shell = get_shell(&shellcode_present_hook); shellcode obfuscated_shellcode{}; obfuscated_shellcode.code = prepend_junk_ops(shell.code, shell.len, (std::rand() % 10) + 7, &obfuscated_shellcode.len); #ifdef DIRECTX12 auto index = GetQueueIndexFromSwapchain(); *(uint32_t*)(&obfuscated_shellcode.code[0x1c + 3 + (obfuscated_shellcode.len - shell.len)]) = index * 8; #endif for (size_t i = 0; i <= obfuscated_shellcode.len - 8; ) { if (*(uint64_t*)(obfuscated_shellcode.code + i) == 0xdeadbeefdeadbeef) { *(uint64_t*)(obfuscated_shellcode.code + i) = exploit.get_RemoteSharedMemory() + PAD_PRESENT_IPC; i += 8; } else ++i; } uintptr_t dh64_present = exploit.ReadU64(process.discord_base + process.present_tramp_offset); uintptr_t dh64_rwx = dh64_present & 0xFFFFFFFFFFFFF000; uint32_t distance_to_present_tramp = dh64_present - (dh64_rwx + offset + obfuscated_shellcode.len); if (distance_to_present_tramp < 0x10000) { memcpy(obfuscated_shellcode.code + obfuscated_shellcode.len - 4, &distance_to_present_tramp, sizeof(uint32_t)); exploit.WriteData(dh64_rwx + offset, obfuscated_shellcode.code, obfuscated_shellcode.len); exploit.WriteU64(process.discord_base + process.present_tramp_offset, dh64_rwx + offset); } while (!p_ipc->swapchain) { _mm_pause(); } p_ipc->spoofhelper = process.discord_base + process.spoofcall_offset; return obfuscated_shellcode.len; } #include #pragma comment(lib, "d3dcompiler.lib") #define BEGIN(id) \ LARGE_INTEGER _##id##_start, _##id##_freq; \ QueryPerformanceFrequency(&_##id##_freq); \ QueryPerformanceCounter(&_##id##_start); #define END(id) \ LARGE_INTEGER _##id##_end; \ QueryPerformanceCounter(&_##id##_end); \ double _##id##_time = double(_##id##_end.QuadPart - _##id##_start.QuadPart) / double(_##id##_freq.QuadPart); \ printf(#id " took %.6f ms\n", _##id##_time*1000); void RenderThread(CExploit& exploit,D2DSharedRenderer& renderer, const wchar_t* shared_tex_name, HANDLE begin_event, HANDLE done_event) { typedef void (WINAPI* RtlCopyMemory_t)(void* Destination, const void* Source, size_t Length); RtlCopyMemory_t RtlCopyMemory = (RtlCopyMemory_t)GetProcAddress(LoadLibraryA("ntdll.dll"), "RtlCopyMemory"); typedef HRESULT(WINAPI* D3DCreateBlob_t)(SIZE_T Size, ID3DBlob** ppBlob); D3DCreateBlob_t D3DCreateBlob = (D3DCreateBlob_t)GetProcAddress(LoadLibraryA("d3dcompiler_47.dll"), "D3DCreateBlob"); static struct dx12 { ID3D12Device* device = nullptr; ID3D12GraphicsCommandList* cmdList = nullptr; ID3D12RootSignature* rootSig = nullptr; ID3D12PipelineState* pso = nullptr; ID3D12DescriptorHeap* srvHeap = nullptr; ID3D12DescriptorHeap* rtvHeap = nullptr; ID3D12Resource* sharedTex = nullptr; HANDLE sharedHandle = nullptr; ID3D12Resource* vertexBuffer = nullptr; D3D12_VERTEX_BUFFER_VIEW vertexBufferView = {}; UINT rtvDescriptorSize = 0; UINT backbufferCount = 0; FrameContext* frames = nullptr; bool initialized = false; } dx12; static bool isDx11 = false; static struct dx11 { bool initialized = false; ID3D11Buffer* vertexBuffer = nullptr; ID3D11VertexShader* vs = nullptr; ID3D11PixelShader* ps = nullptr; ID3D11InputLayout* inputLayout = nullptr; ID3D11ShaderResourceView* srv = nullptr; ID3D11SamplerState* sampler = nullptr; ID3D11BlendState* blend = nullptr; ID3D11Texture2D* sharedTex = nullptr; ID3D11Device1* device = nullptr; ID3D11DeviceContext1* ctx = nullptr; } dx11; struct D3D11StateBackup { ID3D11RenderTargetView* rtv = nullptr; ID3D11BlendState* blend = nullptr; FLOAT blendFactor[4]{}; UINT sampleMask = 0; D3D11_VIEWPORT viewport{}; UINT numViewports = 1; ID3D11InputLayout* inputLayout = nullptr; ID3D11Buffer* vertexBuffer = nullptr; UINT stride = 0, offset = 0; D3D11_PRIMITIVE_TOPOLOGY topology{}; ID3D11VertexShader* vs = nullptr; ID3D11PixelShader* ps = nullptr; ID3D11ShaderResourceView* srv = nullptr; ID3D11SamplerState* sampler = nullptr; }; while (1) { WaitForSingleObject(begin_event, INFINITE); p_ipc->lock = 1; if (!isDx11) { if (dx12.initialized == false) { ipc_call(exploit, &IDXGISwapChain::GetDevice, p_ipc->swapchain, __uuidof(ID3D12Device), (void**)&dx12.device); if (!dx12.device) { isDx11 = true; p_ipc->lock = 0; SetEvent(done_event); Sleep(0); continue; } DXGI_SWAP_CHAIN_DESC desc = {}; ipc_call(exploit, &IDXGISwapChain::GetDesc, p_ipc->swapchain, &desc); dx12.backbufferCount = desc.BufferCount; dx12.frames = new FrameContext[dx12.backbufferCount]; ipc_call(exploit, &ID3D12Device::OpenSharedHandleByName, dx12.device, shared_tex_name, GENERIC_ALL, &dx12.sharedHandle); ipc_call(exploit, &ID3D12Device::OpenSharedHandle, dx12.device, dx12.sharedHandle, __uuidof(**(&dx12.sharedTex)), IID_PPV_ARGS_Helper(&dx12.sharedTex)); D3D12_RESOURCE_DESC texDesc{}; ipc_call(exploit, &ID3D12Resource::GetDesc, dx12.sharedTex, &texDesc); D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {}; srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; srvHeapDesc.NumDescriptors = 1; srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; ipc_call(exploit, &ID3D12Device::CreateDescriptorHeap, dx12.device, &srvHeapDesc, IID_PPV_ARGS(&dx12.srvHeap)); D3D12_CPU_DESCRIPTOR_HANDLE heap{}; ipc_call(exploit, &ID3D12DescriptorHeap::GetCPUDescriptorHandleForHeapStart, dx12.srvHeap, &heap); D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Format = texDesc.Format; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MipLevels = texDesc.MipLevels; ipc_call(exploit, &ID3D12Device::CreateShaderResourceView, dx12.device, dx12.sharedTex, &srvDesc, heap); D3D12_DESCRIPTOR_HEAP_DESC rtvDesc = {}; rtvDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; rtvDesc.NumDescriptors = dx12.backbufferCount; ipc_call(exploit, &ID3D12Device::CreateDescriptorHeap, dx12.device, &rtvDesc, IID_PPV_ARGS(&dx12.rtvHeap)); dx12.rtvDescriptorSize = ipc_call(exploit, &ID3D12Device::GetDescriptorHandleIncrementSize, dx12.device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV); D3D12_CPU_DESCRIPTOR_HANDLE rtvStart{}; ipc_call(exploit, &ID3D12DescriptorHeap::GetCPUDescriptorHandleForHeapStart, dx12.rtvHeap, &rtvStart); for (UINT i = 0; i < dx12.backbufferCount; i++) { FrameContext& ctx = dx12.frames[i]; ipc_call(exploit, &ID3D12Device::CreateCommandAllocator, dx12.device, D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&ctx.allocator)); ipc_call(exploit, &IDXGISwapChain::GetBuffer, p_ipc->swapchain, (uint64_t)i, IID_PPV_ARGS(&ctx.backbuffer)); ctx.rtvHandle = rtvStart; ipc_call(exploit, &ID3D12Device::CreateRenderTargetView, dx12.device, ctx.backbuffer, nullptr, ctx.rtvHandle); rtvStart.ptr += dx12.rtvDescriptorSize; } Vertex quad[] = { { -1.0f, -1.0f, 0.0f, 0.0f, 1.0f }, { -1.0f, 1.0f, 0.0f, 0.0f, 0.0f }, { 1.0f, -1.0f, 0.0f, 1.0f, 1.0f }, { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f }, }; D3D12_HEAP_PROPERTIES heapProps = { D3D12_HEAP_TYPE_UPLOAD }; D3D12_RESOURCE_DESC resDesc = {}; resDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; resDesc.Width = sizeof(quad); resDesc.Height = 1; resDesc.DepthOrArraySize = 1; resDesc.MipLevels = 1; resDesc.SampleDesc.Count = 1; resDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; ipc_call(exploit, &ID3D12Device::CreateCommittedResource, dx12.device, &heapProps, D3D12_HEAP_FLAG_NONE, &resDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&dx12.vertexBuffer)); void* p = 0; ipc_call(exploit, &ID3D12Resource::Map, dx12.vertexBuffer, 0, nullptr, &p); ipc_call(exploit, RtlCopyMemory, p, quad, sizeof(quad)); ipc_call(exploit, &ID3D12Resource::Unmap, dx12.vertexBuffer, 0, nullptr); memset((void*)&p_ipc->arg[0], 0, sizeof(p_ipc->arg)); dx12.vertexBufferView.BufferLocation = ipc_call(exploit, &ID3D12Resource::GetGPUVirtualAddress, dx12.vertexBuffer); dx12.vertexBufferView.StrideInBytes = sizeof(Vertex); dx12.vertexBufferView.SizeInBytes = sizeof(quad); const char* g_vsSrc = "struct VS_INPUT { float4 pos : POSITION; float2 tex : TEXCOORD0; };" "struct VS_OUTPUT { float4 pos : SV_POSITION; float2 tex : TEXCOORD0; };" "VS_OUTPUT main(VS_INPUT input) {" " VS_OUTPUT output;" " output.pos = input.pos;" " output.tex = input.tex;" " return output;" "}"; const char* g_psSrc = "Texture2D tex0 : register(t0);" "SamplerState samp0 : register(s0);" "struct VS_OUTPUT { float4 pos : SV_POSITION; float2 tex : TEXCOORD0; };" "float4 main(VS_OUTPUT input) : SV_Target {" "return tex0.Sample(samp0, input.tex);" "}"; ID3DBlob* local_vs = nullptr, * local_ps = nullptr, * local_sig = nullptr; ID3DBlob* vs = nullptr, * ps = nullptr, * sig = nullptr; D3DCompile(g_vsSrc, strlen(g_vsSrc), nullptr, nullptr, nullptr, "main", "vs_5_0", 0, 0, &local_vs, nullptr); D3DCompile(g_psSrc, strlen(g_psSrc), nullptr, nullptr, nullptr, "main", "ps_5_0", 0, 0, &local_ps, nullptr); ipc_call(exploit, D3DCreateBlob, local_vs->GetBufferSize(), &vs); memcpy((void*)(exploit.get_LocalSharedMemory() + PAD_DATA), local_vs->GetBufferPointer(), local_vs->GetBufferSize()); ipc_call(exploit, RtlCopyMemory, (void*)ipc_call(exploit, &ID3DBlob::GetBufferPointer, vs), (void*)(exploit.get_RemoteSharedMemory() + PAD_DATA), local_vs->GetBufferSize()); ipc_call(exploit, D3DCreateBlob, local_ps->GetBufferSize(), &ps); memcpy((void*)(exploit.get_LocalSharedMemory() + PAD_DATA), local_ps->GetBufferPointer(), local_ps->GetBufferSize()); ipc_call(exploit, RtlCopyMemory, (void*)ipc_call(exploit, &ID3DBlob::GetBufferPointer, ps), (void*)(exploit.get_RemoteSharedMemory() + PAD_DATA), local_ps->GetBufferSize()); D3D12_DESCRIPTOR_RANGE range = { D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0 }; D3D12_ROOT_PARAMETER param = {}; param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; param.DescriptorTable.NumDescriptorRanges = 1; param.DescriptorTable.pDescriptorRanges = ⦥ param.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; D3D12_STATIC_SAMPLER_DESC samp = {}; samp.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; samp.AddressU = samp.AddressV = samp.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; samp.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; samp.ShaderRegister = 0; D3D12_ROOT_SIGNATURE_DESC sigDesc = {}; sigDesc.NumParameters = 1; sigDesc.pParameters = ¶m; sigDesc.NumStaticSamplers = 1; sigDesc.pStaticSamplers = &samp; sigDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; D3D12SerializeRootSignature(&sigDesc, D3D_ROOT_SIGNATURE_VERSION_1, &local_sig, nullptr); ipc_call(exploit, D3DCreateBlob, local_sig->GetBufferSize(), &sig); memcpy((void*)(exploit.get_LocalSharedMemory() + PAD_DATA), local_sig->GetBufferPointer(), local_sig->GetBufferSize()); void* remote_sig_ptr = (void*)ipc_call(exploit, &ID3DBlob::GetBufferPointer, sig); ipc_call(exploit, RtlCopyMemory, remote_sig_ptr, (void*)(exploit.get_RemoteSharedMemory() + PAD_DATA), local_sig->GetBufferSize()); ipc_call(exploit, &ID3D12Device::CreateRootSignature, dx12.device, (uint64_t)0, remote_sig_ptr, local_sig->GetBufferSize(), IID_PPV_ARGS(&dx12.rootSig)); strcpy((char*)(exploit.get_LocalSharedMemory() + PAD_DATA + 0x300), "POSITION"); strcpy((char*)(exploit.get_LocalSharedMemory() + PAD_DATA + 0x300 + 9), "TEXCOORD"); D3D12_INPUT_ELEMENT_DESC layout[] = { { (char*)(exploit.get_RemoteSharedMemory() + PAD_DATA + 0x300), 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { (char*)(exploit.get_RemoteSharedMemory() + PAD_DATA + 0x309), 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, }; memcpy((void*)(exploit.get_LocalSharedMemory() + PAD_DATA + 0x312), layout, sizeof(layout)); D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.pRootSignature = dx12.rootSig; psoDesc.VS = { (void*)ipc_call(exploit, &ID3DBlob::GetBufferPointer, vs), local_vs->GetBufferSize() }; psoDesc.PS = { (void*)ipc_call(exploit, &ID3DBlob::GetBufferPointer, ps), local_ps->GetBufferSize() }; psoDesc.BlendState = {}; psoDesc.BlendState.AlphaToCoverageEnable = true; //psoDesc.BlendState.IndependentBlendEnable = true; psoDesc.BlendState.RenderTarget[0].BlendEnable = true; psoDesc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_ONE; psoDesc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA; psoDesc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; psoDesc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE; psoDesc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA; psoDesc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; psoDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; psoDesc.SampleMask = UINT_MAX; { D3D12_RASTERIZER_DESC& desc = psoDesc.RasterizerState; desc.FillMode = D3D12_FILL_MODE_SOLID; desc.CullMode = D3D12_CULL_MODE_NONE; desc.FrontCounterClockwise = FALSE; desc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS; desc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP; desc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; desc.DepthClipEnable = true; desc.MultisampleEnable = FALSE; desc.AntialiasedLineEnable = FALSE; desc.ForcedSampleCount = 0; desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; } { D3D12_DEPTH_STENCIL_DESC& desc = psoDesc.DepthStencilState; desc.DepthEnable = false; desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; desc.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS; desc.StencilEnable = false; desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP; desc.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS; desc.BackFace = desc.FrontFace; } psoDesc.InputLayout = { (D3D12_INPUT_ELEMENT_DESC*)(exploit.get_RemoteSharedMemory() + PAD_DATA + 0x312), _countof(layout) }; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_B8G8R8A8_UNORM; psoDesc.SampleDesc.Count = 1; psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; ipc_call(exploit, &ID3D12Device::CreateGraphicsPipelineState, dx12.device, &psoDesc, IID_PPV_ARGS(&dx12.pso)); ipc_call(exploit, &ID3DBlob::Release, vs); ipc_call(exploit, &ID3DBlob::Release, ps); ipc_call(exploit, &ID3DBlob::Release, sig); local_vs->Release(); local_ps->Release(); local_sig->Release(); ipc_call(exploit, &ID3D12Device::CreateCommandList, dx12.device, (uint64_t)0, D3D12_COMMAND_LIST_TYPE_DIRECT, dx12.frames[0].allocator, nullptr, IID_PPV_ARGS(&dx12.cmdList)); ipc_call(exploit, &ID3D12GraphicsCommandList::Close, dx12.cmdList); dx12.initialized = true; } UINT frameIdx = ipc_call(exploit, &IDXGISwapChain3::GetCurrentBackBufferIndex, (IDXGISwapChain3*)p_ipc->swapchain); FrameContext& ctx = dx12.frames[frameIdx]; ipc_call(exploit, &ID3D12CommandAllocator::Reset, ctx.allocator); ipc_call(exploit, &ID3D12GraphicsCommandList::Reset, dx12.cmdList, ctx.allocator, dx12.pso); D3D12_RESOURCE_BARRIER barrier = {}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Transition.pResource = ctx.backbuffer; barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; ipc_call(exploit, &ID3D12GraphicsCommandList::ResourceBarrier, dx12.cmdList, (uint64_t)1, &barrier); ipc_call(exploit, &ID3D12GraphicsCommandList::OMSetRenderTargets, dx12.cmdList, (uint64_t)1, &ctx.rtvHandle, (uint64_t)0, nullptr); DXGI_SWAP_CHAIN_DESC desc = {}; ipc_call(exploit, &IDXGISwapChain::GetDesc, p_ipc->swapchain, &desc); D3D12_VIEWPORT viewport = { 0, 0, (float)desc.BufferDesc.Width, (float)desc.BufferDesc.Height, 0.0f, 1.0f }; D3D12_RECT scissor = { 0, 0, (LONG)desc.BufferDesc.Width, (LONG)desc.BufferDesc.Height }; ipc_call(exploit, &ID3D12GraphicsCommandList::RSSetViewports, dx12.cmdList, (uint64_t)1, &viewport); ipc_call(exploit, &ID3D12GraphicsCommandList::RSSetScissorRects, dx12.cmdList, (uint64_t)1, &scissor); ipc_call(exploit, &ID3D12GraphicsCommandList::SetGraphicsRootSignature, dx12.cmdList, dx12.rootSig); ipc_call(exploit, &ID3D12GraphicsCommandList::SetPipelineState, dx12.cmdList, dx12.pso); ipc_call(exploit, &ID3D12GraphicsCommandList::SetDescriptorHeaps, dx12.cmdList, (uint64_t)1, &dx12.srvHeap); ipc_call(exploit, &ID3D12GraphicsCommandList::IASetPrimitiveTopology, dx12.cmdList, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); ipc_call(exploit, &ID3D12GraphicsCommandList::IASetVertexBuffers, dx12.cmdList, (uint64_t)0, (uint64_t)1, &dx12.vertexBufferView); D3D12_GPU_DESCRIPTOR_HANDLE gpuheap{}; ipc_call(exploit, &ID3D12DescriptorHeap::GetGPUDescriptorHandleForHeapStart, dx12.srvHeap, &gpuheap); ipc_call(exploit, &ID3D12GraphicsCommandList::SetGraphicsRootDescriptorTable, dx12.cmdList, (uint64_t)0, gpuheap); ipc_call(exploit, &ID3D12GraphicsCommandList::DrawInstanced, dx12.cmdList, (uint64_t)4, (uint64_t)1, (uint64_t)0, (uint64_t)0); barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; ipc_call(exploit, &ID3D12GraphicsCommandList::ResourceBarrier, dx12.cmdList, (uint64_t)1, &barrier); ipc_call(exploit, &ID3D12GraphicsCommandList::Close, dx12.cmdList); ipc_call(exploit, &ID3D12CommandQueue::ExecuteCommandLists, p_ipc->queue, (uint64_t)1, (ID3D12CommandList* const*)&dx12.cmdList); } else { if (dx11.initialized == false) { ipc_call(exploit, &IDXGISwapChain::GetDevice, p_ipc->swapchain, __uuidof(ID3D11Device1), (void**)&dx11.device); if (!dx11.device) { MessageBoxA(nullptr, "This is neither DX12 or DX11 game?", "Error", MB_OK); } // Quad vertices Vertex quad[] = { { -1.0f, -1.0f, 0.0f, 0.0f, 1.0f }, { -1.0f, 1.0f, 0.0f, 0.0f, 0.0f }, { 1.0f, -1.0f, 0.0f, 1.0f, 1.0f }, { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f }, }; D3D11_BUFFER_DESC vbDesc = {}; vbDesc.Usage = D3D11_USAGE_IMMUTABLE; vbDesc.ByteWidth = sizeof(quad); vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; memcpy((void*)(exploit.get_LocalSharedMemory() + PAD_DATA + 0x200), quad, sizeof(quad)); D3D11_SUBRESOURCE_DATA vbData = { (void*)(exploit.get_RemoteSharedMemory() + PAD_DATA + 0x200) }; ipc_call(exploit, &ID3D11Device1::CreateBuffer, dx11.device, &vbDesc, &vbData, &dx11.vertexBuffer); const char* vsSrc = "struct VS_INPUT { float4 pos : POSITION; float2 tex : TEXCOORD0; };" "struct VS_OUTPUT { float4 pos : SV_POSITION; float2 tex : TEXCOORD0; };" "VS_OUTPUT main(VS_INPUT input) {" " VS_OUTPUT output;" " output.pos = input.pos;" " output.tex = input.tex;" " return output;" "}"; // Pixel shader sampling from tex0 const char* psSrc = "Texture2D tex0 : register(t0);" "SamplerState samp0 : register(s0);" "struct VS_OUTPUT { float4 pos : SV_POSITION; float2 tex : TEXCOORD0; };" "float4 main(VS_OUTPUT input) : SV_Target {" " return tex0.Sample(samp0, input.tex);" "}"; ID3DBlob* local_vs = nullptr, * local_ps = nullptr; ID3DBlob* vs = nullptr, * ps = nullptr; D3DCompile(vsSrc, strlen(vsSrc), nullptr, nullptr, nullptr, "main", "vs_5_0", 0, 0, &local_vs, nullptr); D3DCompile(psSrc, strlen(psSrc), nullptr, nullptr, nullptr, "main", "ps_5_0", 0, 0, &local_ps, nullptr); ipc_call(exploit, D3DCreateBlob, local_vs->GetBufferSize(), &vs); memcpy((void*)(exploit.get_LocalSharedMemory() + PAD_DATA), local_vs->GetBufferPointer(), local_vs->GetBufferSize()); ipc_call(exploit, RtlCopyMemory, (void*)ipc_call(exploit, &ID3DBlob::GetBufferPointer, vs), (void*)(exploit.get_RemoteSharedMemory() + PAD_DATA), local_vs->GetBufferSize()); ipc_call(exploit, D3DCreateBlob, local_ps->GetBufferSize(), &ps); memcpy((void*)(exploit.get_LocalSharedMemory() + PAD_DATA), local_ps->GetBufferPointer(), local_ps->GetBufferSize()); ipc_call(exploit, RtlCopyMemory, (void*)ipc_call(exploit, &ID3DBlob::GetBufferPointer, ps), (void*)(exploit.get_RemoteSharedMemory() + PAD_DATA), local_ps->GetBufferSize()); strcpy((char*)(exploit.get_LocalSharedMemory() + PAD_DATA + 0x300), "POSITION"); strcpy((char*)(exploit.get_LocalSharedMemory() + PAD_DATA + 0x300 + 9), "TEXCOORD"); D3D11_INPUT_ELEMENT_DESC layout[] = { { (char*)(exploit.get_RemoteSharedMemory() + PAD_DATA + 0x300), 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { (char*)(exploit.get_RemoteSharedMemory() + PAD_DATA + 0x309), 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; memcpy((void*)(exploit.get_LocalSharedMemory() + PAD_DATA + 0x312), layout, sizeof(layout)); ipc_call(exploit, &ID3D11Device1::CreateInputLayout, dx11.device, layout, _countof(layout), (void*)ipc_call(exploit, &ID3DBlob::GetBufferPointer, vs), ipc_call(exploit, &ID3DBlob::GetBufferSize, vs), &dx11.inputLayout); ipc_call(exploit, &ID3D11Device1::CreateVertexShader, dx11.device, (void*)ipc_call(exploit, &ID3DBlob::GetBufferPointer, vs), ipc_call(exploit, &ID3DBlob::GetBufferSize, vs), nullptr, &dx11.vs); ipc_call(exploit, &ID3D11Device1::CreatePixelShader, dx11.device, (void*)ipc_call(exploit, &ID3DBlob::GetBufferPointer, ps), ipc_call(exploit, &ID3DBlob::GetBufferSize, ps), nullptr, &dx11.ps); ipc_call(exploit, &ID3D11Device1::OpenSharedResourceByName, dx11.device, L"Global\\BlueSharedTex", DXGI_SHARED_RESOURCE_READ, __uuidof(ID3D11Texture2D), (void**)&dx11.sharedTex); local_vs->Release(); local_ps->Release(); D3D11_TEXTURE2D_DESC texDesc = {}; ipc_call(exploit, &ID3D11Texture2D::GetDesc, dx11.sharedTex, &texDesc); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.Format = texDesc.Format; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MostDetailedMip = 0; srvDesc.Texture2D.MipLevels = texDesc.MipLevels; ipc_call(exploit, &ID3D11Device1::CreateShaderResourceView, dx11.device, dx11.sharedTex, &srvDesc, &dx11.srv); D3D11_SAMPLER_DESC samp = {}; samp.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; samp.AddressU = samp.AddressV = samp.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; ipc_call(exploit, &ID3D11Device1::CreateSamplerState, dx11.device, &samp, &dx11.sampler); // Alpha blending D3D11_BLEND_DESC b = {}; b.RenderTarget[0].BlendEnable = TRUE; b.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; b.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; b.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; b.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; b.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; b.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; b.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; ipc_call(exploit, &ID3D11Device1::CreateBlendState, dx11.device, &b, &dx11.blend); ipc_call(exploit, &ID3D11Device1::GetImmediateContext1, dx11.device, &dx11.ctx); dx11.initialized = true; } D3D11StateBackup s{}; { //ipc_call(exploit, &ID3D11DeviceContext1::OMGetRenderTargets, dx11.ctx, 1, &s.rtv, nullptr); //ipc_call(exploit, &ID3D11DeviceContext1::OMGetBlendState, dx11.ctx, &s.blend, s.blendFactor, &s.sampleMask); //ipc_call(exploit, &ID3D11DeviceContext1::RSGetViewports, dx11.ctx, &s.numViewports, &s.viewport); ipc_call(exploit, &ID3D11DeviceContext1::IAGetInputLayout, dx11.ctx, &s.inputLayout); ipc_call(exploit, &ID3D11DeviceContext1::IAGetVertexBuffers, dx11.ctx, 0, 1, &s.vertexBuffer, &s.stride, &s.offset); ipc_call(exploit, &ID3D11DeviceContext1::IAGetPrimitiveTopology, dx11.ctx, &s.topology); //ipc_call(exploit, &ID3D11DeviceContext1::VSGetShader, dx11.ctx, &s.vs, nullptr, nullptr); //ipc_call(exploit, &ID3D11DeviceContext1::PSGetShader, dx11.ctx, &s.ps, nullptr, nullptr); //ipc_call(exploit, &ID3D11DeviceContext1::PSGetShaderResources, dx11.ctx, 0, 1, &s.srv); //ipc_call(exploit, &ID3D11DeviceContext1::PSGetSamplers, dx11.ctx, 0, 1, &s.sampler); } ID3D11Texture2D* backbuffer = nullptr; ID3D11RenderTargetView* rtv = nullptr; ipc_call(exploit, &IDXGISwapChain::GetBuffer, p_ipc->swapchain, 0, IID_PPV_ARGS(&backbuffer)); ipc_call(exploit, &ID3D11Device1::CreateRenderTargetView, dx11.device, backbuffer, nullptr, &rtv); ipc_call(exploit, &ID3D11Texture2D::Release, backbuffer); float blendFactor[4] = { 0 }; D3D11_VIEWPORT vp = { 0, 0, (FLOAT)1920, (FLOAT)1080, 0.0f, 1.0f }; ipc_call(exploit, &ID3D11DeviceContext1::OMSetRenderTargets, dx11.ctx, 1, &rtv, nullptr); ipc_call(exploit, &ID3D11DeviceContext1::OMSetBlendState, dx11.ctx, dx11.blend, blendFactor, 0xFFFFFFFF); ipc_call(exploit, &ID3D11DeviceContext1::RSSetViewports, dx11.ctx, 1, &vp); UINT stride = sizeof(Vertex), offset = 0; ipc_call(exploit, &ID3D11DeviceContext1::IASetInputLayout, dx11.ctx, dx11.inputLayout); ipc_call(exploit, &ID3D11DeviceContext1::IASetVertexBuffers, dx11.ctx, (uint64_t)0, (uint64_t)1, &dx11.vertexBuffer, &stride, &offset); ipc_call(exploit, &ID3D11DeviceContext1::IASetPrimitiveTopology, dx11.ctx, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); ipc_call(exploit, &ID3D11DeviceContext1::VSSetShader, dx11.ctx, dx11.vs, nullptr, 0); ipc_call(exploit, &ID3D11DeviceContext1::PSSetShader, dx11.ctx, dx11.ps, nullptr, 0); ipc_call(exploit, &ID3D11DeviceContext1::PSSetShaderResources, dx11.ctx, 0, 1, &dx11.srv); ipc_call(exploit, &ID3D11DeviceContext1::PSSetSamplers, dx11.ctx, 0, 1, &dx11.sampler); ipc_call(exploit, &ID3D11DeviceContext1::Draw, dx11.ctx, 4, 0); ipc_call(exploit, &ID3D11RenderTargetView::Release, rtv); { // ipc_call(exploit, &ID3D11DeviceContext1::OMSetRenderTargets, dx11.ctx, 1, &s.rtv, nullptr); // ipc_call(exploit, &ID3D11DeviceContext1::OMSetBlendState, dx11.ctx, s.blend, s.blendFactor, s.sampleMask); // ipc_call(exploit, &ID3D11DeviceContext1::RSSetViewports, dx11.ctx, s.numViewports, &s.viewport); ipc_call(exploit, &ID3D11DeviceContext1::IASetInputLayout, dx11.ctx, s.inputLayout); ipc_call(exploit, &ID3D11DeviceContext1::IASetVertexBuffers, dx11.ctx, 0, 1, &s.vertexBuffer, &s.stride, &s.offset); ipc_call(exploit, &ID3D11DeviceContext1::IASetPrimitiveTopology, dx11.ctx, s.topology); // ipc_call(exploit, &ID3D11DeviceContext1::VSSetShader, dx11.ctx, s.vs, nullptr, 0); // ipc_call(exploit, &ID3D11DeviceContext1::PSSetShader, dx11.ctx, s.ps, nullptr, 0); // ipc_call(exploit, &ID3D11DeviceContext1::PSSetShaderResources, dx11.ctx, 0, 1, &s.srv); // ipc_call(exploit, &ID3D11DeviceContext1::PSSetSamplers, dx11.ctx, 0, 1, &s.sampler); } { if (s.rtv) ipc_call(exploit, &ID3D11RenderTargetView::Release, s.rtv); if (s.blend) ipc_call(exploit, &ID3D11BlendState::Release, s.blend); if (s.inputLayout) ipc_call(exploit, &ID3D11InputLayout::Release, s.inputLayout); if (s.vertexBuffer) ipc_call(exploit, &ID3D11Buffer::Release, s.vertexBuffer); if (s.vs) ipc_call(exploit, &ID3D11VertexShader::Release, s.vs); if (s.ps) ipc_call(exploit, &ID3D11PixelShader::Release, s.ps); if (s.srv) ipc_call(exploit, &ID3D11ShaderResourceView::Release, s.srv); if (s.sampler) ipc_call(exploit, &ID3D11SamplerState::Release, s.sampler); } } SetEvent(done_event); p_ipc->lock = 0; if (GetAsyncKeyState(VK_F1)) break; } }