How detours work
Practically everyone uses detours without understanding how they work, I am going to describe a standard JUMP detour
hook:
For a detour we require the following:
- the address of the original function (from now on referenced as orig_func)
- the address of the hook function (from now on referenced as hook_func)
- number bytes to overwrite in the original functon (from now on referenced as detourLen)
OK first thing I will explain is detourLen, MS Detours and some other detour classes will get this value for you
automatically.
detourLen and the JUMP
The first thing you must know about detourLen is that it must have a minimum value, in the case of a JUMP detour the
number of bytes required to do the following:
JMP
so in bytes that is:
E9 00 00 00 00 // an address is 32bits (4bytes)
(E9 is the opcode for JMP instruction)
So the minimum detourLen for this type of detour is 5 bytes.
However we cannot go ahead and just write JMP at the original function and think thats it, because we could be
overwriting half of an intruction and leaving the end half as it was - causing a crash, confused? here's an example:
Lets have a look at kernel32.dll's LoadLibraryA:
Code:
8BFF MOV EDI,EDI
55 PUSH EBP
8BEC MOV EBP,ESP
837D 08 00 CMP DWORD PTR SS:[EBP+8],0
Now remember we need a minimum of 5 bytes to write the JUMP hook, so if you have a look there the 5th byte is the END
of an instruction (0xEC) so we are not writing into an new intruction!
Therefore the detourLen for LoadLibraryA is 5bytes.
Now let's have a look at kernel32.dll's GetHandleContext:
Code:
6A 78 PUSH 78
E8 26DCF9FF CALL kernel32.SetLastError
33C0 XOR EAX,EAX
We need a minimum of 5 bytes, so we go to the end of the second instruction - FF, that is a total of 7 bytes - so DetourLen
for GetHandleContext is 7 bytes.
Why 7 bytes? Because we cannot go and do this:
Code:
E9 00
00 0000F9FF
33C0 XOR EAX,EAX
As you can see we are writing into the middle of the instruction and leaving the end (F9FF), causing a crash. So instead we
specify detourLen as 7 bytes, and the detour function will do the following:
Code:
E9 00
00 00009090
33C0 XOR EAX,EAX
The 90 opcode is a NOP instruction (it does nothing except fill space) - now the code can be executed without trying to run
half an instruction!
So what IS a detour?
Now you cannot expect to go and overwrite part of the original function and think that it will still work properly! Pay close
attention:
What a detour does is COPY the number of bytes specified by detourLen to a memory allocated place. At the
memory allocated place, after the bytes it has just copied over it inserts a JUMP back to the original function, at
original function + detourLen. The detour function returns a pointer to the start of this allocated memory,
CONFUSINGLY named the "original" in many basehooks.
Example scenario with GetHandleContext - The detour
Confused? Let me show you a scenario:
orig_func address: 0x7C86B683 (in bytes: 83 B6 86 7C)
hook_func address: 0x50607080 (in bytes: 80 70 60 50)
// Beginning of GetHandleContext untouched
Code:
6A 78 PUSH 78
E8 26DCF9FF CALL kernel32.SetLastError
33C0 XOR EAX,EAX
Like we already ascertained GetHandleContext detourLen is 7 bytes, so the Detour function will do the following:
1. Copy the first 7 bytes to a memory allocated place
// Memory allocated place
Code:
6A 78 PUSH 78
E8 26DCF9FF CALL kernel32.SetLastError
2. Insert a JUMP back to the GetHandleContext + 7 bytes (0x7C86B683 + 7 = 0x7C86B69B)
// Memory allocated place
Code:
6A 78 PUSH 78
E8 26DCF9FF CALL kernel32.SetLastError
E9 9BB6867C JMP kernel32.GetHandleContext+7
3. Save a pointer to the start of this memory allocated place
4. Overwrite the first 5 bytes of GetHandleContext with JMP and pad the remaining bytes with 90 (NOP)
// Beginning of GetHandleContext detoured
Code:
E9 80706050 JMP hook_func (0x50607080)
9090 NOP NOP
33C0 XOR EAX,EAX
5. Return a pointer to the memory allocated place
Example scenario with GetHandleContext - The hack
Now what do we do with the pointer to that memory allocated place? Well that is what is call the ORIG in many basehooks
(i.e. orig_GetHandleContext or o_GetHandleContext).
It is our job to call this "orig" inside our detour function, so our detour hook might look like this:
Code:
HANDLE hook_GetHandleContext(...)
{
orig_GetHandleContext(...);
}
So how does the scenario execute?
1. The program makes a call to GetHandleContext
2. At the begining of GetHandleContext is the jump to your hooked function
3. Your hooked function is called
4. At the end of your hooked function you call the memory allocated place where the bytes you overwrote in the original
are executed
5. At the end of the memory allocated place is a jump to the original + detourLen
6. The original function continues as normal...
(PS the NOPing isn't essential, so long as the mem allocated place jumps past those "bad bytes")
Simple CS:S Console print hook
here is something simple -
first you will need:
ollydbg
c++ compiler
ok - now you will need some assembly know-how but its pretty simple all in all.
open css - then open ollydbg ->
hit attach - hit the "E" button at the top ->
scroll down to "engine.dll" and double click ->
right click on the CPU window (main one) after you do that ->
Find all referanced text strings ->
search for text (do this by right clicking) "Unknown command" ->
the string should be "Unknown command - %s" or something similar ->
doulbe click on it and some text should be there ...mine is this:
Quote:
0DA0C93F 50 PUSH EAX
0DA0C940 68 F879D60D PUSH engine.0DD679F8 ; ASCII "Unknown command "%s"
"
0DA0C945 FF15 4055D50D CALL DWORD PTR DS:[] ; tier0.Msg
now - here is how we hook this function ->
right click on "CALL DWORD PTR DS:[]" ->
follow ->
it should look a little something like this ->
Quote:
00883250 > 8B4C24 04 MOV ECX,DWORD PTR SS:[ESP+4]
00883254 8D4424 08 LEA EAX,DWORD PTR SS:[ESP+8]
00883258 50 PUSH EAX
00883259 51 PUSH ECX
0088325A 6A 00 PUSH 0
0088325C E8 0FFEFFFF CALL tier0.00883070
00883261 83C4 0C ADD ESP,0C
00883264 C3 RETN
you may or may not have noticed the original call used the sprintf() format - this is important and should be remembered.
so now we have the address 00883250 is the start of the function
so - before you just go and detour that i suggest you learn more about dynamic dlls (loaded in differant places)
we need to find the base address of of the current dll we are in (tier0.dll)... ->
itll say tier0 (or whatever dll) at the top ->
go to the "E" again, right click teir0.dll ->
copy to clipboard -> base (mine happens to be 0x00880000) ->
simple math will tell us that if the function is at 00883250 and the dll is at 0x00880000 ->
tier0.dll base + 0x00003250 = the function
ok - so now we are done, you may close css because we have some coding to do.
make 2 new files in your project - lets call them engine.cpp and engine.h (in case u wanna add more) and include all the
proper headers
now, since printing to the console uses sprintf() format - ill use a snippet from azorbix' add_log function to suit our needs -
put this in engine.h:
void pfnConsolePrint(const char *fmt, ...);
void hook_console();
now go to engine.cpp and add this (credits to azorbix and msdn):
#define console_css 0x00003250
void (*Orig_pfnConsolePrint)(const char *fmt, ...);
void hook_console()
{
Orig_pfnConsolePrint = (TYPE_pfnConsolePrint)DetourFunction(
(BYTE*)(((DWORD)GetModuleHandle("tier0.dll")) + (DWORD)console_css),
(BYTE*)pfnConsolePrint);
add_log("pfnConsolePrint [0x%X", (((DWORD)GetModuleHandle("tier0.dll")) +
(DWORD)console_css));
}
void pfnConsolePrint(const char *fmt, ...)
{
char szBuffer[1024];
bool onetime = true;
va_list args;
va_start(args, fmt);
memset(szBuffer, 0, sizeof(szBuffer));
_vsnprintf(szBuffer, sizeof(szBuffer) - 1, fmt, args);
va_end(args);
Orig_pfnConsolePrint(szBuffer);
}
its also hooked now - so you can read the text passed through the buffer if u want
whenever you want to use it - simple include engine.h and do something like:
pfnConsolePrint("hello number %i \n", rand()%255);
engine.h:
void pfnConsolePrint(const char *fmt, ...);
void hook_console();
engine.cpp:
void (*Orig_pfnConsolePrint)(const char *fmt, ...);
void hook_console()
{
Orig_pfnConsolePrint = (TYPE_pfnConsolePrint)DetourFunction(
(BYTE*)(DWORD)GetProcAddress(
GetModuleHandle("tier0.dll"), "Msg"),
(BYTE*)pfnConsolePrint);
add_log("pfnConsolePrint [0x%X]", (DWORD)GetProcAddress(
GetModuleHandle("tier0.dll"), "Msg"));
}
void pfnConsolePrint(const char *fmt, ...)
{
char szBuffer[1024];
bool onetime = true;
va_list args;
va_start(args, fmt);
memset(szBuffer, 0, sizeof(szBuffer));
_vsnprintf(szBuffer, sizeof(szBuffer) - 1, fmt, args);
va_end(args);
Orig_pfnConsolePrint(szBuffer);
}
main.cpp (in DLLMAIN):
hook_console();
then anywhere u want to use it do:
#include "engine.h"
then use it like:
int num = 3;
pfnConsolePrint("omg num %i", 3);
VERY BASIC : What are detours and how are they used?
As you can see from the title, this is going to be very basic and general. There is another tutorial on detours by Sinner that
is very detailed and good for more experienced users, but the ASM tends to scare the newer people. Refer to it if you want
more detail/a different approach. Anyways, let's get started.
What is a detour?
In normal English, a detour is an alternate route to continue on a certain path. Ultimately, a detour in programming boils
down to this as well. Since we're talking normal English, I'll give you this example:
You're driving along on Interstate 1337.
You get off of the interstate at exit 133b and make a right.
You're supposed to make another right turn about 3 miles down the road on to Imaginary Lane, but there is a detour telling
you to go straight.
A mile or so down the road, the detour tells you to make a right hand turn.
Then, one block down the road another right turn.
About a mile down the road you are told to go left.
You are now on Imaginary Lane, just as you had intended, but your path to it was modified by the detour.
The difference is that you control the detours you're using.
How are detours used?
Detours can be used for almost everything.
A code-esque example:
Suppose the game you are playing has some function that only draws weapons.
This function has 3 parameters:
1. a boolean to see if the weapon is on the ground or not.
2. a structure containing the data (name, model, etc) of the weapon it is currently drawing.
3. a dword for rendering effects that is defaulted to 0x00000000, which just so happens to be completely transparent in the
game.
So far, the game function would have to look something like:
Code:
void DrawWeapons(bool bOnGround, weapon_data_s *weap, dword color=0x00000000)
{
// blah, drawing code goes here
}
You find the memory address of this function, as well as the length needed for detour (the other tutorial that tells how to do
this, no sense rewriting it)
You create your own function of the same type as said function, with the same parameters (names don't matter - types do)
You then detour the original function with your function.
After your function is called and completed, you can call the original (not required in some cases)
Do something to make sure you know that it is detoured properly (add a log, draw something, etc)
We should have something like:
Code:
void My_DrawWeapons(bool bng, weapon_data_s *wd, dword clr)
{
// this is where you do your stuff.
add_log("DrawWeapons was called!");
Stored_DrawWeapons(bng, wd, clr);
add_log("DrawWeapons detour was a success!");
}
Now that we have the function detoured, let's get on with what you want to do next.
You want to color them red when in someone's hands.
You also want them to be invisible if they're on the ground.
You check whether the guns are in hands or on the ground.
If they are on the ground, you simply return without calling the stored function.
Otherwise, you change the parameter clr to red.
In hex, 0xRRGGBBAA is the format for an RGBA value.
That means that we want to set clr to 0xFF0000FF.
For our final function we should have:
Code:
void My_DrawWeapons(bool bng, weapon_data_s *wd, dword clr)
{
if(bng) return; // We don't want to draw the weapons on the ground.
clr = 0xFF0000FF; // We are setting this to red.
Stored_DrawWeapons(bng, wd, clr);
}
[Beginner] Aimbot + Simple ESP Tutorial
Welcome to my first tutorial
After one week of playing around with counter-strike i want to show up a little ESP and Aimbot that i did just for fun.
It would be nice if you could credit me when using this code (It took me nearly half-an-hour to program this...)
Let's go:
At first we need 2 new functions: On the one hand a function to check the team of a given entity and on the other hand a
function to draw our ESP box.
Let's begin with the first one. It should be placed somewhere above your HUD_ReDraw function.
Code:
int GetTeam(char *model)
{
// Check all terror team models
if (strstr(model, "arctic") ||
strstr(model, "guerilla") ||
strstr(model, "leet") ||
strstr(model, "terror"))
return 1;
// Check all counter team models
else if (strstr(model, "gign") ||
strstr(model, "gsg9") ||
strstr(model, "sas") ||
strstr(model, "urban") ||
strstr(model, "vip"))
return 2;
// No Team/Spec/...
return 0;
}
We're searching with strstr a string inside a string. Means we are searching the name of the model inside the whole model
path.
The second function uses the pfnFillRGBA engine function to render 4 blocks that respresent our box.
Code:
void DrawBox(int x, int y, int r, int g, int b, int a, int iRadius, int iThickness)
{
int iRad = iRadius / 2;
// top
gEngfuncs.pfnFillRGBA(x - iRad, y - iRad, iRadius, iThickness, r, g, b, a);
// bottom
gEngfuncs.pfnFillRGBA(x - iRad, y + iRad, iRadius + (iThickness / 2), iThickness, r, g, b,
a);
// left
gEngfuncs.pfnFillRGBA(x - iRad, y - iRad, iThickness, iRadius, r, g, b, a);
// right
gEngfuncs.pfnFillRGBA(x + iRad, y - iRad, iThickness, iRadius, r, g, b, a);
}
iThickness stands for the width of the box border and iRadius is the radius of our box.
Now we only need to add the final function that renders our ESP on screen and moves our cursor. To gain performance I
put ESP and Aimbot in one function and for this in one loop through all players. We start the function with some globals
that are used later on.
Code:
void DoEspAim(void)
{
// Player Entity pointers
cl_entity_t *pEnt = NULL, *pLocal = gEngfuncs.GetLocalPlayer();
// Playerinfo structure
hud_player_info_t pInfo;
// Get the playerinformation
gEngfuncs.pfnGetPlayerInfo(pLocal->index, &pInfo);
// Check for the team
int iOwnTeam = GetTeam(pInfo.model); // Team holen
We define 2 entity pointers. The second one saves the information of the Local player (you) and the first one will save the
Entity while in the loop. Finally we save our own Team in iOwnTeam to prevent aiming on teammates.
After that we define some other global variables that are needed to determine the position of a player on screen in relation
to the Crosshair position.
Code:
float fScreenPos[10];
float fDistFromCenter[3];
float fCenterDistance;
// ScreenX and Y / 2
int iScreenCenterX = gEngfuncs.GetWindowCenterX();
int iScreenCenterY = gEngfuncs.GetWindowCenterY();
// Nearest player
cl_entity_t *pNearestEnt = NULL;
float fNearest = -1.0f;
float fNearestAimTarget[3] = {0,0,0};
Now we need to browse all players with a for loop (at least 32) and save our Data in the pInfo struct.
Code:
for (int i = 0; i index == i) continue;
// Get Entity and check it
pEnt = gEngfuncs.GetEntityByIndex(i);
if (!isValidEnt(pEnt)) continue;
// Read PlayerInfo and Team
gEngfuncs.pfnGetPlayerInfo(i, &pInfo);
int iTeam = GetTeam(pInfo.model);
After this we set down the Z-Coordinate of our current Player higher to let us aim on the Head. At least this is a very very
basic method for doing this. If you get more advanced you could add a Vector that saves these values to move the aim
target. A bone or hitbox aimbot would be better, too. After this we get the screen coordinates with CalcScreen (It can be
found on this forum, too.)
Code:
pEnt->origin.z -= -20; // We want the pos of the Head
if (CalcScreen(pEnt->origin, fScreenPos))
{
// He is visible
Now we need the good old phytagoras We wanna calc the distance between the player and the crosshair on the screen to
compare it with the other players that are on screen.
The formula is a² + b² = c²
Code:
// Calculate the Distance in Relation to the screen center (crosshair
position)
fDistFromCenter[0] = iScreenCenterX - fScreenPos[0];
fDistFromCenter[1] = iScreenCenterY - fScreenPos[1];
// The phytagoras without the squareroot
fCenterDistance = square(fDistFromCenter[0]) + square(fDistFromCenter[1]);
To gain extra performance i have not used the squareroot to determine the exact values cause we only want to compare
values that are calced with this code, too.
Now we draw the ESP and continue with our aimbot
Code:
if (iTeam == 1) // Team = Terror = Red
{
DrawBox(fScreenPos[0], fScreenPos[1], 255, 10, 10, 255, 25, 2);
}
else if (iTeam == 2) // Team = CT = Blue
{
DrawBox(fScreenPos[0], fScreenPos[1], 10, 10, 255, 255, 25, 2);
}
else // Everything else will be kicked out of our loop (this could be done a
little bit further, too.
{
continue;
}
Now we check if the current player is an enemy or not (which actually only matters for our aimbot).
Code:
if (iTeam == iOwnTeam) continue;
We need to compare our calced values with the current minimum values to determine the nearest player for our aimbot. If
the current player is more near to the crosshair than an old one we overwrite all needed values.
Code:
if (fNearest 0 && fNearestAimTarget[1] > 0)
{
// Define the aimsmooth factor
#define AIM_SMOOTH 3
// Is the right mousebutton actually pressed?
if (GetAsyncKeyState(VK_RBUTTON))
{
//Calculate the interpolation
float x = fNearestAimTarget[0] - iScreenCenterX;
float y = fNearestAimTarget[1] - iScreenCenterY;
x /= AIM_SMOOTH;
y /= AIM_SMOOTH;
fNearestAimTarget[0] = iScreenCenterX + x;
fNearestAimTarget[1] = iScreenCenterY + y;
//Aim on the target
SetCursorPos((int)fNearestAimTarget[0], (int)fNearestAimTarget[1]);
}
}
Well in the SetCursorPos command we could add an delay to make the Aimbot more smooth. This could be done
calculating the distance from our crosshair to the enemy (x and y values) and dividing them by a "smooth-value". Then we
could subtract them from the current values.
Finally the last function needs to be called in the HUD_ReDraw function and it should be working Before posting dump
questions make sure your EngFuncs are names exactly like mine and that you have all needed functions like isValidEnt or
CalcScreen.
At least you could add some extra stuff very easy:
- Aimthrough 0/1
- Smooth setting
- Better teamdetection (using usermessages)
- etc. etc.
P.S.: Do what you want with it, i give a shit...
P.P.S.: Finally i wanna add a little piece of code to add a very basic Panickey which is very useful.
Code:
// Every key gets an array entry
bool bKeyPressed[256];
bool IsKeyPressed(int iKey)
{
// Search for global key states
if (GetAsyncKeyState(iKey))
{
if (!bKeyPressed[iKey])
{
bKeyPressed[iKey] = true;
return true;
}
}
else
bKeyPressed[iKey] = false;
return false;
}
For using a global panic key you should add a global panic variable, too.
Code:
bool bPanic = false;
And finally add it in the HUD_ReDraw where you already added DoEspAim().
Code:
if (IsKeyPressed(VK_F12)) bPanic = !bPanic;
if (bPanic) DoEspAim();
Client Aimbots
Aimbot tutorial
Introduction:
In the past many people asked me how they could improve “their” Aimbots. An endless list of people posted this question
in various coding forums, so I thought that this tutorial might be useful to some of you.
The Past:
Many good or less good programmers have made several attempts to improve their Aimbots. Snipity was the most
successful one according to me. He invented useful features as such as “No Spread” and “Auto wall”. Most of the OGC
tweaks of today is based on his work (mostly without crediting him, not surprisingly). There were also those guys who tried
to
improve their Aimbots by replacing PI. That is the most useless effort you could ever do. The normal pi is more than
enough.
What Aimbot method shall I choose?
There are mainly three sorts of “client” Aimbots; Vector based Aimbots, Bone based Aimbots and the newest generation of
Aimbots Hitbox based Aimbots.
The oldest and most used sort of Aimbots are still vector based Aimbots. They were the first sorts of Aimbots that
functioned client side. When they were introduced they were revolutionary compared to existing Aimbots
(OpenGL & Color- Aimbots). Vector Aimbots are simple to create and very rapid. Their disadvantage is the inaccuracy.
The basic vector Aimbot covers Vectors (or aiming offsets) for two states: sitting and standing. This is what the
CS Models do most of time. So you should be fine if you use this on an ordinary anti cheating server.
But cheating on anti cheat server is not what most cheaters do. They battle each other on so called hacking
servers. Cheat vs. Cheat. A frag/round (can sometimes) take less then a few seconds. So every shot should impact 100% at
the right spot.Vector Aimbots don’t cover a solution for the model’s position between the sequences and several other
sequences
such as (duck) jumping.This was noticed by bunny771, so he made the first Bone based Aimbot which solves this problem
pretty good.
Simply because it aimed for body parts it was sequence independent. A Step back is Sequence Based Aiming.
Of course sequence based aiming is better than Vector based Aiming but it doesn’t cover support for moments between
sequences.
What really improves my Aimbot?
Before we start I’ll give you a list of things that won’t help:
“Tweaking” of the pi;
To call findtarget() like 10 times in a frame;
(Right now I can’t think of more useless stuff :-/ )
A possible way to improve your Aimbot would be to apply the visibility checks to very predicted coordinates.
So you could aim earlier and use this as a base for your auto speed.
But remember, too much prediction makes people think that you use “AutoWall”.
bool bSoonvisible(int iIndex)
{
float to[3], lastpred = cvar.predahead;
cvar.predahead = cvar.vpreahead;// apply some leeb value here :)
PredictTarget(iIndex,(float*)to);
cvar.predahead = lastpred;
pmtrace_t tr;
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( me.pmEyePos, to, PM_WORLD_ONLY, me.ent->index, &tr );
return ( tr.fraction == 1.0 );
}
no Flash
241CF178 DFE0 FSTSW AX
241CF17A F6C4 05 TEST AH,5
241CF17D 0F8B 45040000 JPO client.241CF5C8 // k
241CF183 8B0D D4304124 MOV ECX,DWORD PTR DS:[244130D4] ; material.0DA85460
241CF189 8B11 MOV EDX,DWORD PTR DS:[ECX]
241CF18B 57 PUSH EDI
241CF18C 6A 00 PUSH 0
241CF18E 6A 01 PUSH 1
241CF190 68 3C8B2F24 PUSH client.242F8B3C ; ASCII "ClientEffect
textures"
241CF195 68 CC803324 PUSH client.243380CC ; ASCII "effects/flashbang"
Radar
241FD3E6 84C0 TEST AL,AL
241FD3E8 74 4C JE SHORT client.241FD436 // k
241FD3EA 8D5F FF LEA EBX,DWORD PTR DS:[EDI-1]
241FD3ED 53 PUSH EBX
241FD3EE 8BCE MOV ECX,ESI
simple zoom
240E8C30 8A81 E0000000 MOV AL,BYTE PTR DS:[ECX+E0] ; bool
CInput::CAM_IsOrthographic(void) // should return true for zoom
240E8C36 C3 RETN
Sniper crosshair
Radar
a simple & small radar patch , it shows the enemys / teammates or all players.
241C5E40 FF50 34 CALL DWORD PTR DS:[EAX+34]
241C5E43 3B4424 14 CMP EAX,DWORD PTR SS:[ESP+14]
241C5E47 75 0A JNZ SHORT client.241C5E53 // jne -> only team / je ->
only enemys
241C5E49 56 PUSH ESI
241C5E4A 57 PUSH EDI
241C5E4B 8D4B EC LEA ECX,DWORD PTR DS:[EBX-14]
241C5E4E E8 EDF9FFFF CALL client.241C5840
241C5E53 83C7 01 ADD EDI,1
241C5E56 83FF 40 CMP EDI,40
241C5E59 ^7E AF JLE SHORT client.241C5E0A