Counter-Strike Source Radar Hack Tutorial

August 21, 2010 by Asbra — Leave a comment

This is a re-post from my old blog, ilsken.net
This tutorial explains how to make all players shown on the radar, always. The technique shown in this tutorial is also applicable to other games.

You will need 2 tools:
– Memory scanner (I use Cheat Engine)
– Debugger (I use OllyDbg and x64dbg)

  1. Start a local game
  2. Join a team
  3. Add a bot in opposite team
  4. Set sv_cheats 1 and bot_stop 1
  5. Walk up to the bot so you see it on your radar
  6. Search for value 1 as type 1 byte
  7. Turn around or walk a bit so the bot doesn’t show on radar anymore
  8. Next search for 0
  9. Repeat steps 5 to 8 until you have a few values left

Then try freezing some of them, walk away from the bot and it should stay visible on the radar.
Do that until you have 1 value left.

Alright, now I open debugger, go to the address that I found earlier.
Right-click it, Breakpoint -> Memory Breakpoint, Access

And it hits on an instruction that looks like this:
14C41803 |> 8A8437 1D0D0000 MOV AL,BYTE PTR DS:[EDI+ESI+D1D]

Remove your memory breakpoint and put a regular breakpoint on it.

Add a few more bots & add the addresses right after the one you found as 1 byte also, if you found eg. 12345030, then you add 12345031 12345032 12345033 12345034 etc.
Try freeze them all to 1 and you should see all enemies on radar all the time.

Alright, now take a look at what’s in EDI and ESI.

If we run/break a few times we see that EDI moves similiar to this:
EDI 00000002
EDI 00000003
EDI 00000006

It’s obvious that it’s player index in the array.

ESI 20A428A8
ESI 2725AE10

ESI should look similar to this (addresses vary ofc. depending on allocation base of the modules)

In your memory-scanner (CE) search for the first ESI value, 20A428A8 as 4 bytes (remember to tick the Hex box).

We find it in a bunch of places.
Disconnect your server & make a new one.

Now when we break on
14C41803 |> 8A8437 1D0D0000 MOV AL,BYTE PTR DS:[EDI+ESI+D1D]
check the value of ESI (our pointer) and look in CE if some of the addresses we found before holds the new ESI.

I found 2 static places for this:
client.dll+4CE070
client.dll+4D4BA4

So now we know that:
*(client.dll+4CE070) = ESI
*(ESI + index + D1D) set to 1 to show on radar

To be sure of finding things on next update I search for the address of client.dll+4CE070 and find that it’s found static at:
14B02E70 /$ A1 70E0F614 MOV EAX,DWORD PTR DS:[14F6E070]
14B02E75 |. 85C0 TEST EAX,EAX
14B02E77 |. 74 06 JE SHORT client.14B02E7F
14B02E79 |. 05 A8040000 ADD EAX,4A8
14B02E7E |. C3 RETN
14B02E7F |> 33C0 XOR EAX,EAX
14B02E81 \. C3 RETN

So we make a byte-signature for this so we easily can find it:
A1 ?? ?? ?? ?? 85 C0 74 06 05

Alright, now let’s code this up in C++

//Asbra.net
#include <Windows.h>

// FindPattern & DataCompare by dom1n1k
BOOL DataCompare( BYTE* pData, BYTE* bMask, char * szMask )
{
	for( ; *szMask; ++szMask, ++pData, ++bMask )
		if( *szMask == 'x' && *pData != *bMask )
			return FALSE;

	return ( *szMask == NULL );
}

DWORD FindPattern( DWORD dwAddress, DWORD dwLen, BYTE *bMask, char * szMask )
{
	for( DWORD i = 0; i < dwLen; i++ )
		if( DataCompare( (BYTE*)( dwAddress + i ), bMask, szMask ) )
			return (DWORD)( dwAddress + i );

	return 0;
}

DWORD MainThread( LPVOID lpArgs )
{
	HMODULE hClient = GetModuleHandleA( "client.dll" );
	while(hClient == NULL) { hClient = GetModuleHandleA( "client.dll" ); }
	
	DWORD dwDrawOnRadar = FindPattern((DWORD)hClient, 0x005E5000, (BYTE*)"\xA1\x00\x00\x00\x00\x85\xC0\x74\x06\x05", "x????xxxxx") + 1;
	dwDrawOnRadar = *(DWORD*)dwDrawOnRadar;
	
	while(1)
	{
		for(int i = 0;i < 0x4F;i++) // at 0x50 seems to be start of clan name
		{
			BYTE* pDrawOnRadar = (BYTE*)((*(DWORD*)dwDrawOnRadar) + 0xD1D + i);
			*pDrawOnRadar = 1;
		}

	}

	return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
{
	if(dwReason == DLL_PROCESS_ATTACH)
	{
		DWORD dwThreadID = 0;
		HANDLE hThread = CreateThread( NULL, NULL, (LPTHREAD_START_ROUTINE)MainThread, NULL, NULL, &dwThreadID );
	}
	
	return TRUE;
}

Can easily be done externally using WriteProcessMemory if you want to do that.

Anyhow, enjoy.

Asbra

Posts Facebook

Blogging out of many years of experience with gamehacking, programming, reverse-engineering and general tomfoolery.

No Comments

Be the first to start the conversation.

Leave a Reply