In this Topic i will teach beginner how to make a very easy CSGO esp.
If I have time someday i will post a thread teah beginner how to inject into process
The source code and Esp Demo is on the bottom of the topic.
Foreword :why using d3d HOOK? Many PC games use D3D drawing ,so hook D3D is a very easy way to Change the drawing of the game as we wish.
1.where to hook:
Most D3D9 base games use DrawIndexedPrimitive() Function to draw,and CSGO is no exception.let`s use Depends.exe Open the C:\Windows\System32\d3d9.dll file.
but we didn`t find the DrawIndexedPrimitive() Function we want ,why? Let us see the definition of this function on MSDN:
DrawIndexedPrimitive is in the class IDirect3DDevice9 (actually in its virtual table),So it's tricky to find the address of DrawIndexedPrimitive, but we can find another way : write a D3D9 program and call DrawIndexedPrimitive ourselves:
Code:
IDirect3DDevice9* Device = 0;
_d3d9->CreateDevice(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
vp,
&d3dpp,
&Device
); //<-----------let`s Create an instance of IDirect3DDevice9
Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0,0,5,0,1);// <-------Use disassembly to view this line of C++ code
Code:
PVOID *FuncAddr = (PVOID *)Device;
PVOID VTTable = (PVOID )(*FuncAddr);
DWORD RealAddr = *(DWORD *)((char *)VTTable+0x148);//<----get the function address by VTTable+0x148
DWORD DxLibAddr =(DWORD) LoadLibraryA("d3d9.dll");
Device->Release();
g_offset = (RealAddr - DxLibAddr);//<---function address minus lib base address to obtain function offset
we can see disassembly code edx+0x148 ,This means that the relative virtual table offset of the DrawIndexedPrimitive function is 0x148.then We can easily get DrawIndexedPrimitive address by the code above.
2.How to inject into CSGO and Start hook:
(1)How to inject:
There are many ways to inject the process,you can use CreateThreadEx and loadlibrary ,or Using tool injection.Many injection tools can be downloaded from the forum,I will not explain the injection technology in depth here.
(2)how to start hook DrawIndexedPrimitive() function:
First we look at the disassembly of the function,it`s a very standard function header,we are going to hook the Five bytes of function header and Replaced with our code: E9 XXXXXXXX , XXXXXXXX is the offset of the function header from our MyDrawIndexedPrimitive() function.
Code:
ULONG_PTR address = GetDramIndexedPrimitiveAddress(offset);// <---Use DramIndexedPrimitive Function offset get Function Real Address
if (!address)
{
return;
}
g_OrgDrawIndexedPrimitive = (char *)address;
jmpto = address + 5;
DWORD oldProtect = 0;
if(VirtualProtect((LPVOID)address,5,PAGE_EXECUTE_READWRITE,&oldProtect))//change mem protect
{
DWORD value = (DWORD)MyDrawIndexedPrimitive - address - 5; //<---calculate the offset
__asm
{
mov eax,address
mov byte ptr[eax], 0xe9
add eax, 1
mov ebx, value
mov dword ptr[eax], ebx
}//<------start HOOK! Write 0xE9 XX XX XX XX to function header!
VirtualProtect((LPVOID)address,5,oldProtect,&oldProtect);//recover mem protect
}
3.how to start esp in CSGO:
Here comes the core step in this topic.My idea is to get to know is DrawIndexedPrimitive() function drawing a character then draw character whit disable Z axis buffer.
MyDrawIndexedPrimitive() function has seven parameters.There are only one parameters is useful to us: NumVertices(The span of the rendered vertex index),the other useful information is mStride(The size of the memory occupied by each vertex in the data stream).
Code:
if(Device_Interface->GetStreamSource(0,&pStreamData,&iOffsetInBytes,&mStride) == D3D_OK)
{
pStreamData->Release();
}
if(mStride == 32 && IsTargetNumVertices(NumVertices) && (NumVertices >200))//<------Filter condition
{
Device_Interface->SetRenderState( D3DRS_ZENABLE,FALSE);//<--------Disable Z axis buffer
Original_DrawIndexedPrimitive(Device_Interface, Type, BaseIndex, MinIndex, NumVertices, StartIndex, primCount);
Device_Interface->SetRenderState( D3DRS_ZENABLE,TRUE );//<--------Enable Z axis buffer
Original_DrawIndexedPrimitive(Device_Interface, Type, BaseIndex, MinIndex, NumVertices, StartIndex, primCount);
}
the last problem is how to get the character NumVertices? I used a stupid way:
I start a game map without any character,then collect all the NumVertices in our MyDrawIndexedPrimitive() function,these NumVertices surely no character NumVertices. Our filter condition is set to not ESP if NumVertices hits.Other cases(draw character NumVertices) we Disable Z axis buffer to start esp.Here we have finished our Esp work!
Virus Scan:
https://www.virustotal.com/gui/file/...4c34/detection
https://www.virustotal.com/gui/file/...6b61/detection