Slight update.. I don't feel like making a D3D hook thread atm..
http://i.imgur.com/v3jlME2.pnghttp://i.imgur.com/YhhRANM.pngThe below code is injected into the game. I didn't get around to making the game "load" it instead of injecting. It's faster to test stuff via injection rather than loading SMART or placing modules in the bin folder. Simple VTable hook really.
Models hooks are pretty much (almost) complete.. I dumped everything into one file to make the post shorter.. Doesn't look like a lot but it uses all the code from the github so yeah..:
#include <windows.h>
#include <iostream>
#include <d3d9.h>
#include <d3dx9.h>
#include <detours.h>
#include <thread>
#include <cstdint>
#include <memory>
#include <fstream>
#include "Graphics.hxx"
#pragma comment(lib, "WS2_32.lib")
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#pragma comment(lib, "detours.lib")
enum D3D9_vTable
{
QUERYINTERFACE,
ADDREF,
RELEASE,
TESTCOOPERATIVELEVEL,
GETAVAILABLETEXTUREMEM,
EVICTMANAGEDRESOURCES,
GETDIRECT3D,
GET_DEVICE_CAPS,
GETDISPLAYMODE,
GETCREATIONPARAMETERS,
SETCURSORPROPERTIES,
SETCURSORPOSITION,
SHOW_CURSOR,
CREATEADDITIONALSWAPCHAIN,
GETSWAPCHAIN,
GETNUMBEROFSWAPCHAINS,
RESET,
PRESENT,
GETBACKBUFFER,
GETRASTERSTATUS,
SETDIALOGBOXMODE,
GETGAMMARAMP,
SETGAMMARAMP,
CREATETEXTURE,
CREATEVOLUMETEXTURE,
CREATECUBETEXTURE,
CREATEVERTEXBUFFER,
CREATEINDEXBUFFER,
CREATERENDERTARGET,
CREATEDEPTHSTENCILSURFACE,
UPDATESURFACE,
UPDATETEXTURE,
GETRENDERTARGETDATA,
GETFRONTBUFFERDATA,
STRETCHRECT,
COLORFILL,
CREATEOFFSCREENPLAINSURFACE,
SETRENDERTARGET,
GETRENDERTARGET,
SETDEPTHSTENCILSURFACE,
GETDEPTHSTENCILSURFACE,
BEGINSCENE,
ENDSCENE,
CLEAR,
SETTRANSFORM,
GETTRANSFORM,
MULTIPLYTRANSFORM,
SETVIEWPORT,
GETVIEWPORT,
SETMATERIAL,
GETMATERIAL,
SETLIGHT,
GETLIGHT,
LIGHTENABLE,
GETLIGHTENABLE,
SETCLIPPLANE,
GETCLIPPLANE,
SETRENDERSTATE,
GETRENDERSTATE,
CREATESTATEBLOCK,
BEGINSTATEBLOCK,
ENDSTATEBLOCK,
SETCLIPSTATUS,
GETCLIPSTATUS,
GETTEXTURE,
SETTEXTURE,
GETTEXTURESTAGESTATE,
SETTEXTURESTAGESTATE,
GETSAMPLERSTATE,
SETSAMPLERSTATE,
VALIDATEDEVICE,
SET_PALETTE_ENTRIES,
GET_PALETTE_ENTRIES,
SETCURRENTTEXTUREPALETTE,
GETCURRENTTEXTUREPALETTE,
SETSCISSORRECT,
GETSCISSORRECT,
SETSOFTWAREVERTEXPROCESSING,
GETSOFTWAREVERTEXPROCESSING,
SETNPATCHMODE,
GETNPATCHMODE,
DRAWPRIMITIVE,
DRAWINDEXEDPRIMITIVE,
DRAWPRIMITIVEUP,
DRAWINDEXEDPRIMITIVEUP,
PROCESSVERTICES,
CREATEVERTEXDECLARATION,
SETVERTEXDECLARATION,
GETVERTEXDECLARATION,
SETFVF,
GETFVF,
CREATEVERTEXSHADER,
SETVERTEXSHADER,
GETVERTEXSHADER,
SETVERTEXSHADERCONSTANTF,
GETVERTEXSHADERCONSTANTF,
SETVERTEXSHADERCONSTANTI,
GETVERTEXSHADERCONSTANTI,
SETVERTEXSHADERCONSTANTB,
GETVERTEXSHADERCONSTANTB,
SETSTREAMSOURCE,
GETSTREAMSOURCE,
SETSTREAMSOURCEFREQ,
GETSTREAMSOURCEFREQ,
SETINDICES,
GETINDICES,
CREATEPIXELSHADER,
SETPIXELSHADER,
GETPIXELSHADER,
SETPIXELSHADERCONSTANTF,
GETPIXELSHADERCONSTANTF,
SETPIXELSHADERCONSTANTI,
GETPIXELSHADERCONSTANTI,
SETPIXELSHADERCONSTANTB,
GETPIXELSHADERCONSTANTB,
DRAWRECTPATCH,
DRAWTRIPATCH,
DELETEPATCH,
CREATEQUERY,
};
typedef HRESULT(__stdcall *EndScene_t)(LPDIRECT3DDEVICE9 pDevice);
typedef HRESULT(__stdcall *BeginScene_t)(LPDIRECT3DDEVICE9 pDevice);
typedef HRESULT(__stdcall *Reset_t)(LPDIRECT3DDEVICE9 pDevice, D3DPRESENT_PARAMETERS *pPresentationParameters);
typedef HRESULT(__stdcall *DrawPrimitive_t)(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount);
typedef HRESULT(__stdcall *DrawIndexedPrimitive_t)(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE PrimitiveType, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount);
typedef HRESULT(__stdcall *DrawPrimitiveUP_t)(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, CONST void* pVertexStreamZeroData, UINT VertexStreamZeroStride);
typedef HRESULT(__stdcall *DrawIndexedPrimitiveUP_t)(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices, UINT PrimitiveCount, CONST void* pIndexData, D3DFORMAT IndexDataFormat, CONST void* pVertexStreamZeroData, UINT VertexStreamZeroStride);
typedef HRESULT(__stdcall *SetTexture_t)(LPDIRECT3DDEVICE9 pDevice, DWORD Sampler, IDirect3DBaseTexture9 *pTexture);
BeginScene_t o_BeginScene;
EndScene_t o_EndScene;
Reset_t o_Reset;
DrawPrimitive_t o_DrawPrimitive;
DrawIndexedPrimitive_t o_DrawIndexedPrimitive;
DrawPrimitiveUP_t o_DrawPrimitiveUP;
DrawIndexedPrimitiveUP_t o_DrawIndexedPrimitiveUP;
SetTexture_t o_SetTexture;
Font* font = NULL;
HRESULT __stdcall DXI_BeginScene(LPDIRECT3DDEVICE9 pDevice)
{
static bool init = false;
if (!init)
{
init = true;
font = new Font(pDevice, "Arial", 8);
}
return o_BeginScene(pDevice);
}
HRESULT __stdcall DXI_EndScene(LPDIRECT3DDEVICE9 pDevice)
{
if (font)
font->Draw(50, 50, "HELLO");
return o_EndScene(pDevice);
}
//When the application is minimised, resources are destroyed and rebuilt automatically. It's how d3d works.
HRESULT __stdcall DXI_Reset(LPDIRECT3DDEVICE9 pDevice, D3DPRESENT_PARAMETERS *pPresentationParameters)
{
if (font)
font->OnLostDevice();
HRESULT res = o_Reset(pDevice, pPresentationParameters);
if (font)
font->OnResetDevice();
return res;
}
HRESULT __stdcall DXI_DrawPrimitive(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount)
{
IDirect3DBaseTexture9* tex = nullptr;
if (SUCCEEDED(pDevice->GetTexture(0, &tex)))
{
LPDIRECT3DTEXTURE9 _tex = (LPDIRECT3DTEXTURE9)tex;
D3DSURFACE_DESC desc;
if (SUCCEEDED(_tex->GetLevelDesc(0, &desc)))
{
if (desc.Width && desc.Height) //51 x 51 = mini-map compass. Better to check on the Simba side. 512 x 512 = map.
{
D3DXMATRIX WVP;
if (SUCCEEDED(pDevice->GetVertexShaderConstantF(0, (float*)&WVP, 4)))
{
D3DXMatrixTranspose(&WVP, &WVP);
D3DXVECTOR3 out;
D3DXVECTOR3 in(0, 0, 0);
D3DXVec3TransformCoord(&out, &in, &WVP);
D3DVIEWPORT9 viewport;
pDevice->GetViewport(&viewport);
out.x = (out.x + 1.0f) * viewport.Width * 0.5f + viewport.X;
out.y = (1.0f - out.y) * viewport.Height * 0.5f + viewport.Y;
if (font)
font->Draw(out.x, out.y, "Compass(%, %)", desc.Width, desc.Height);
}
}
}
tex->Release();
}
return o_DrawPrimitive(pDevice, PrimitiveType, StartVertex, PrimitiveCount);
}
//function in which both textures AND models are drawn. Textures have a primCount of 2 and NumVertices of 4. Basically 2 triangles make up one square/rectangular texture.
//models otherwise..
HRESULT __stdcall DXI_DrawIndexedPrimitive(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE PrimitiveType, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount)
{
DWORD ID = GenerateID(pDevice, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
D3DXVECTOR3 out = WorldToScreen(pDevice); //Get the base center point of the model.. For more advanced accuracy, you can use ProcessVerts to get each and every vertex of said model (fingers, eyes, etc..)
static bool debug = false;
if (GetAsyncKeyState(VK_END) & 1)
debug = !debug;
if (font && debug)
font->Draw(out.x, out.y, 0xFFFF0000, "%", ID);
return o_DrawIndexedPrimitive(pDevice, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
}
HRESULT __stdcall DXI_DrawPrimitiveUP(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, CONST void* pVertexStreamZeroData, UINT VertexStreamZeroStride)
{
return o_DrawPrimitiveUP(pDevice, PrimitiveType, PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
}
HRESULT __stdcall DXI_DrawIndexedPrimitiveUP(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices, UINT PrimitiveCount, CONST void* pIndexData, D3DFORMAT IndexDataFormat, CONST void* pVertexStreamZeroData, UINT VertexStreamZeroStride)
{
return o_DrawIndexedPrimitiveUP(pDevice, PrimitiveType, MinVertexIndex, NumVertices, PrimitiveCount, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
}
HRESULT __stdcall DXI_SetTexture(LPDIRECT3DDEVICE9 pDevice, DWORD Sampler, IDirect3DBaseTexture9 *pTexture)
{
return o_SetTexture(pDevice, Sampler, pTexture);
}
DWORD __stdcall InitialiseHooks(void* param);
bool __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hinstDLL);
CreateThread(NULL, 0, InitialiseHooks, NULL, 0, 0);
return true;
case DLL_PROCESS_DETACH:
break;
default:
break;
}
return true;
}
DWORD FindPattern(DWORD dwAddress, DWORD dwLen, BYTE *bMask, const char* szMask)
{
auto bCompare = [](const BYTE* pData, const BYTE* bMask, const char* szMask) -> bool
{
for (; *szMask; ++szMask, ++pData, ++bMask)
if (*szMask == 'x' && *pData != *bMask)
return 0;
return (*szMask) == 0;
};
for (DWORD i = 0; i < dwLen; ++i)
if (bCompare(reinterpret_cast<std::uint8_t*>(dwAddress + i), bMask, szMask))
return static_cast<DWORD>(dwAddress + i);
return 0;
}
template<typename T, typename U>
void DetourFunction(T &OriginalFunction, U HookFunction)
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&reinterpret_cast<void*&>(OriginalFunction), reinterpret_cast<void*>(HookFunction));
DetourTransactionCommit();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
}
DWORD WINAPI VTableRepatch(void* param)
{
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
DetourFunction(o_BeginScene, DXI_BeginScene);
DetourFunction(o_EndScene, DXI_EndScene);
DetourFunction(o_Reset, DXI_Reset);
DetourFunction(o_DrawPrimitive, DXI_DrawPrimitive);
DetourFunction(o_DrawIndexedPrimitive, DXI_DrawIndexedPrimitive);
DetourFunction(o_DrawPrimitiveUP, DXI_DrawPrimitiveUP);
DetourFunction(o_DrawIndexedPrimitiveUP, DXI_DrawIndexedPrimitiveUP);
DetourFunction(o_SetTexture, DXI_SetTexture);
}
return 0;
}
DWORD __stdcall InitialiseHooks(void* param)
{
while (!GetModuleHandle("d3d9.dll"))
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
DWORD* VTable = nullptr;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
static std::uint8_t bMask[] = { 0xC7, 0x06, 0x00, 0x00, 0x00, 0x00, 0x89, 0x86, 0x00, 0x00, 0x00, 0x00, 0x89, 0x86 };
DWORD Address = FindPattern(reinterpret_cast<DWORD>(GetModuleHandle("d3d9.dll")), 0x128000, bMask, "xx????xx????xx");
memcpy(&VTable, reinterpret_cast<void*>(Address + 2), 4);
o_BeginScene = reinterpret_cast<BeginScene_t>(VTable[BEGINSCENE]);
o_EndScene = reinterpret_cast<EndScene_t>(VTable[ENDSCENE]);
o_Reset = reinterpret_cast<Reset_t>(VTable[RESET]);
o_DrawPrimitive = reinterpret_cast<DrawPrimitive_t>(VTable[DRAWPRIMITIVE]);
o_DrawIndexedPrimitive = reinterpret_cast<DrawIndexedPrimitive_t>(VTable[DRAWINDEXEDPRIMITIVE]);
o_DrawPrimitiveUP = reinterpret_cast<DrawPrimitiveUP_t>(VTable[DRAWPRIMITIVEUP]);
o_DrawIndexedPrimitiveUP = reinterpret_cast<DrawIndexedPrimitiveUP_t>(VTable[DRAWINDEXEDPRIMITIVEUP]);
o_SetTexture = reinterpret_cast<SetTexture_t>(VTable[SETTEXTURE]);
DetourFunction(o_BeginScene, DXI_BeginScene);
DetourFunction(o_EndScene, DXI_EndScene);
DetourFunction(o_Reset, DXI_Reset);
DetourFunction(o_DrawPrimitive, DXI_DrawPrimitive);
DetourFunction(o_DrawIndexedPrimitive, DXI_DrawIndexedPrimitive);
DetourFunction(o_DrawPrimitiveUP, DXI_DrawPrimitiveUP);
DetourFunction(o_DrawIndexedPrimitiveUP, DXI_DrawIndexedPrimitiveUP);
DetourFunction(o_SetTexture, DXI_SetTexture);
CreateThread(NULL, 0, VTableRepatch, NULL, 0, 0);
return 0;
}
With this, the FPS is at 50. FPS drops a bit when drawing the ID's on screen but when you run a script you won't be drawing them on screen anyway so that doesn't matter. What matters is the FPS while the script is running or while you are playing and that itself is at 50-53 (I haven't seen lower). Drawing the ID's with D3DXFont is extremely slow ={ I will speed it up later by drawing them manually. Memory usage is nice too. I haven't noticed any lag. There's no leaks. I tested only the above. I got Kasi to test it. He didn't test FPS but it was running very nicely.
I took a look at hooking textures. I have to find a way to save textures to the disk and to generate ID's in memory (my current code for saving and generating crashes because the textures aren't stored in ram.. I might have to wrap IDirect3DTexture9). Will take some time to figure out. I just finally got an OKAY debugger to help me.. Before everything was just assembly..
I dumped shaders such as below:
// Parameters:
//
// float4 DistanceFogPlane;
// float4 HeightFogPlane;
// float4x2 TexCoordMatrix;
// float4x4 WVPMatrix;
//
//
// Registers:
//
// Name Reg Size
// ---------------- ----- ----
// WVPMatrix c0 4
// TexCoordMatrix c4 2
// DistanceFogPlane c6 1
// HeightFogPlane c7 1
//
vs_2_0
def c8, 0, 1, 0, 0
dcl_position v0
dcl_texcoord v1
dcl_color v2
dp4 oPos.x, v0, c0
dp4 oPos.y, v0, c1
dp4 oPos.z, v0, c2
dp4 oPos.w, v0, c3
dp4 oT0.x, v1, c4
dp4 oT0.y, v1, c5
dp4 r0.x, v0, c7
max r0.x, r0.x, c8.x
min oT4.x, r0.x, c8.y
dp4 r0.x, v0, c6
max r0.x, r0.x, c8.x
min oT4.y, r0.x, c8.y
mov oD0, v2
mov oT0.zw, c8.x
mov oT1.xyz, c8.x
mov oT2.xyz, c8.y
mov oT3.xyz, c8.x
mov oT5, c8.x
mov oT6.xyz, c8.x
mov oT7, c8.x
// approximately 20 instruction slots used
// Parameters:
//
// sampler2D SpriteSampler;
//
//
// Registers:
//
// Name Reg Size
// ------------- ----- ----
// SpriteSampler s0 1
//
ps_2_0
dcl t0.xy
dcl v0
dcl_2d s0
texld r0, t0, s0
mul r0, r0, v0
mov oC0, r0
// approximately 3 instruction slots used (1 texture, 2 arithmetic)
// Parameters:
//
// sampler2D DiffuseSampler;
// float3 DistanceFogColour;
// float3 HeightFogColour;
//
//
// Registers:
//
// Name Reg Size
// ----------------- ----- ----
// DistanceFogColour c0 1
// HeightFogColour c1 1
// DiffuseSampler s0 1
//
ps_2_0
def c2, 0, 0, 0, 0
dcl v0
dcl t0.xy
dcl t2.xyz
dcl t4.xy
dcl_2d s0
texld r0, t0, s0
mul r0.xyz, r0, v0
mul r1.xyz, r0, t2
mad r0.xyz, r0, -t2, c1
mov r1.w, v0.w
mov r0.w, c2.x
mad r0, t4.x, r0, r1
add r1.xyz, -r0, c0
mov r1.w, c2.x
mad r0, t4.y, r1, r0
mov oC0, r0
// approximately 11 instruction slots used (1 texture, 10 arithmetic)
//...
vs_2_0
dcl_position v0
dcl_texcoord v1
dcl_color v2
mov oPos, v0
mov oT0.xy, v1
mov oD0, v2
// approximately 3 instruction slots used
// Parameters:
//
// float4x2 TexCoordMatrix;
// float4x4 WVPMatrix;
//
//
// Registers:
//
// Name Reg Size
// -------------- ----- ----
// WVPMatrix c0 4
// TexCoordMatrix c4 2
//
vs_2_0
def c6, 0, 0, 0, 0
dcl_position v0
dcl_color v1
dcl_texcoord v2
dp4 oPos.x, v0, c0
dp4 oPos.y, v0, c1
dp4 oPos.z, v0, c2
dp4 oPos.w, v0, c3
dp4 oT0.x, v2, c4
dp4 oT0.y, v2, c5
mov oD0, v1
mov oT1.x, c6.x
// approximately 8 instruction slots used
It's pretty annoying having to go through these things.. It's a lot harder than OpenGL by far :l There's not really any good debuggers for d3d. PIX (a Microsoft Direct-X debugger) is detected by Jaclib and automatically terminates the process.. You can't just debug RS just like that. It detects it -_-

It detects it because PIX and Olly-Dbg because they start the game process rather than injecting to it during run-time. Olly-Dbg has the phantom plugin but you can't really use Olly-Dbg for Direct-X.
So yeah.. It's hard ={ I'll get it done but I got other things to do as well.. Just thought you guys could see how things are done and if you know anything you can contrib..