Code:
PBYTE SwapVTable(PDWORD64* pVTable, PBYTE pHook, size_t iIndex)
{
DWORD dwOld = 0;
VirtualProtect((PVOID)((*pVTable) + iIndex), sizeof(PDWORD64), PAGE_EXECUTE_READWRITE, &dwOld);
PBYTE pOrig = ((PBYTE)(*pVTable)[iIndex]);
(*pVTable)[iIndex] = (DWORD64)pHook;
VirtualProtect((PVOID)((*pVTable) + iIndex), sizeof(PDWORD64), dwOld, &dwOld);
return pOrig;
}
Now if the vtable is analyzed you will know that the index of Present is 8. (Not going to go in depth as that is for another time and will take too long to explain.) So all we need to do now is to figure out how to render once hooked. The class DebugRenderer will help us achieve this.
Code:
const DWORD64 OFFSET_DEBUGRENDERER = 0x140616630;
const DWORD64 OFFSET_DRAWTEXT = 0x140617BD0;
const DWORD64 OFFSET_DRAWLINE = 0x1406177A0;
const DWORD64 OFFSET_DRAWLINERECT2D = 0x140617810;
const DWORD64 OFFSET_DRAWFILLRECT = 0x1406179A0;
class DebugRenderer2
{
public:
static DebugRenderer2* Singleton()
{
typedef EngineD3D::DebugRenderer2* (__stdcall* EngineD3D__DebugRenderManager_getThreadContext_t)(void);
EngineD3D__DebugRenderManager_getThreadContext_t EngineD3D__DebugRenderManager_getThreadContext = (EngineD3D__DebugRenderManager_getThreadContext_t)OFFSET_DEBUGRENDERER;
return EngineD3D__DebugRenderManager_getThreadContext();
}
void RenderEngineText(int x, int y, Color32 color, char* text, float scale)
{
typedef void(__thiscall *tdrawText)(EngineD3D::DebugRenderer2*, int, int, char*, Color32, float);
tdrawText mdrawText = (tdrawText)OFFSET_DRAWTEXT;
mdrawText(this, x, y, text, color, scale);
}
void RenderEngineTextCentered(int x, int y, Color32 color, char* text, float scale)
{
typedef void(__thiscall *tdrawText)(EngineD3D::DebugRenderer2*, int, int, char *, Color32, float);
tdrawText mdrawText = (tdrawText)OFFSET_DRAWTEXT;
mdrawText(this, x - static_cast<int>((strlen(text)) * 4.4), y, text, color, scale);
}
void RenderEngine2DLine(float x1, float y1, float x2, float y2, Color32 color)
{
Tuple2< float > minpos = Tuple2< float >(x1, y1);
Tuple2< float > maxpos = Tuple2< float >(x2, y2);
typedef void(__thiscall *tdrawLine2d)(EngineD3D::DebugRenderer2*, Tuple2<float>*, Tuple2<float>*, Color32);
tdrawLine2d mdrawLine2d = (tdrawLine2d)OFFSET_DRAWLINE;
mdrawLine2d(this, &minpos, &maxpos, color);
}
void RenderEngine2DLineRect(float x1, float y1, float x2, float y2, Color32 color)
{
Tuple2< float > minpos = Tuple2< float >(x1, y1);
Tuple2< float > maxpos = Tuple2< float >(x2, y2);
typedef void(__thiscall *tdrawLineRect2d)(EngineD3D::DebugRenderer2*, Tuple2<float>*, Tuple2<float>*, Color32);
tdrawLineRect2d mdrawLineRect2d = (tdrawLineRect2d)OFFSET_DRAWLINERECT2D;
mdrawLineRect2d(this, &minpos, &maxpos, color);
}
void RenderEngine2DRect(float x1, float y1, float x2, float y2, Color32 color)
{
Tuple2< float > minpos = Tuple2< float >(x1, y1);
Tuple2< float > maxpos = Tuple2< float >(x2, y2);
typedef void(__thiscall *tdrawRect2d)(EngineD3D::DebugRenderer2*, Tuple2<float>*, Tuple2<float>*, Color32);
tdrawRect2d mdrawRect2d = (tdrawRect2d)OFFSET_DRAWFILLRECT;
mdrawRect2d(this, &minpos, &maxpos, color);
}
};
Luckily we can just use the game's functions to render text, lines, shaders, etc. All that good shit, now if you want to create your own font, you can use the FW1FontWrapper whose use can be found
Code:
typedef HRESULT(__stdcall *D3D11PresentHook) (IDXGISwapChain* This, UINT SyncInterval, UINT Flags);
D3D11PresentHook oPresent = 0;
HRESULT __stdcall Present(IDXGISwapChain* This, UINT SyncInterval, UINT Flags)
{
const DWORD64 OFFSET_PBSSMODULE = 0x142546278;
*reinterpret_cast<PDWORD64*>(OFFSET_PBSSMODULE) = nullptr; //nulls out screenshot module
EngineD3D::DebugRenderer2::Singleton()->RenderEngineText(100, 100, EngineD3D::Color32(255, 0, 0, 255), "EHRMAGERD RENDERED", 1.0f);
return oPresent(This, SyncInterval, Flags);
}
bool _HookPresent()
{
oPresent = reinterpret_cast<D3D11PresentHook>(SwapVTable(reinterpret_cast<PDWORD64*>(DxRenderer::Singleton()->m_pScreen->m_pSwapChain), reinterpret_cast<PBYTE>(&Present), 8));
return true;
}
Last but not least, set the platform to x64 as well as a x64 injector. If you guys have any questions, feel free to ask. I'll probably post how to achieve entity iteration (player, weapon, vehicle, explosives, etc) if people ask for it.