Simple Rendering x64
Well, shit ton of people keep asking me how to create an internal hack because external hacks get annoying at a point. So let's begin, also this method works for x86 as long as you have the correct classes for it.
First we must hook the game's Present function, now in order to do so, we require the IDXGISwapChain pointer which leads us to the VTable itself. This pointer can be found and utilized from the game as well. The class that holds this is ScreenInfo which is held by DxRenderer:
Now all we need to do is to swap the vtable and initialize. The VTable function, can be easily found or made by yourself as well.
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.
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 here. NOW we can initialize. Also we're going to want to disable PB SS or else we'll get banned. Now in order to do that you can just simply null out the game's SS module as that is what PB uses to take screenshots. This will just result in a blank screen when uploaded, this can also occur naturally if there are issues with the user's graphics card which is why PB doesn't ban for this. If you wan't to get a clean screenshot, load up the ss module class in ReClass and analyze what happens when a SS is taken, from there it's pretty much common sense.
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.
First we must hook the game's Present function, now in order to do so, we require the IDXGISwapChain pointer which leads us to the VTable itself. This pointer can be found and utilized from the game as well. The class that holds this is ScreenInfo which is held by DxRenderer:
Code:
const DWORD64 OFFSET_DXRENDERER = 0x142540BF0;
class ScreenInfo
{
public:
BYTE pad00[0x58]; //0x00
unsigned int m_Width; //0x58
unsigned int m_Height; //0x5C
unsigned int m_WindowWidth; //0x60
unsigned int m_WindowHeight; //0x64
BYTE pad01[0x88]; //0x68
IDXGISwapChain* m_pSwapChain; //0xF0
};
class DxRenderer
{
public:
char pad_0x00[0x38]; // 0x00
ScreenInfo* m_pScreen; // 0x38
char pad_0x40[0xC0]; // 0x40
ID3D11Device* m_pDevice; // 0x100
ID3D11DeviceContext* m_pContext; // 0x108
static DxRenderer* Singleton()
{
return *(DxRenderer**)OFFSET_DXRENDERER;
}
};
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;
}
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);
}
};
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;
}
