Raised This Month: $64 Target: $400
 16% 

[IDA/DHooks]How to get vtable offsets


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
Dr!fter
The Salt Boss
Join Date: Mar 2007
Old 07-26-2012 , 22:42   [IDA/DHooks]How to get vtable offsets
Reply With Quote #1

Hi! I've gotten a few requests for a dhooks tutorial so I decided to write this tutorial. This is (hopefully) Part I of II (can’t promise I’ll ever get to do Part II). This tutorial will give you a basic breakdown of how to use Dynamic Hooks (While also providing other useful information!).

Note for bigger version of the images click on them!

What you need:
IDA Free 5.0+ (Used in this tutorial is 5.0 Free. Normally I use 6.X)
linux_vtable_dump.idc

Downloads:
IDA Free 5.0 Download link is at the bottom of the page. Install before proceeding.
linux_vtable_dump.idc To save this file either click the link then right click and click Save As. Or Right click the link and click Save As. Save the file in the idc folder where you installed IDA.
Default on x86: C:\Program Files\IDA\idc
Default on x64: C:\Program Files (x86)\IDA\idc
Notepad ++ This isn’t a requirement.

Now that you have everything installed grab a copy of the server.so for your game. Normally this will already download when you install a server. If it does not download you can force it by forcing hldsupdatetool to download the linux binary. To do so just add "-linux" to the game param when using the hldsupdatetool. For example to download the linux binaries for CS:S I would use these options.
Code:
-command update -game "Counter-Strike Source-linux"
Now that you have the server.so, launch IDA and open the server.so file. It should something like this.



I usually like to keep a cleaner workspace so I close most of the tabs so it looks like this



After opening the file it will take a while to analyze (On 5.0 it takes about 45 minutes while 6.0 is about 10-20) But we can finish setting everything up while we wait! Let’s start by enabling the opcodes on each line. This isn’t as useful for this but is for finding signatures. Click on Options->General. This will bring up a box like below. Change "Number of Opcode bytes" to 10



Next (Note I only had to do this on 5.0 Free but you can check it on all versions) Click on Options->Demangled Names. This will bring up a box like bellow. Make sure that "Assume GCC v3.x names" is checked. If it is not, check it.



Now wait for the analysis to finish after it is complete the window will go into graph view to get out of graph view hit the space bar.

For this tutorial I will be hooking CCSGameRules::GoToIntermission(void). Click inside the "Function Names" box and press ALT+T to bring up the search. Search for GoToIntermission and double click the function. It should look something like



Click on the function name inside the IDA View-A and press CTRL+X to bring up the xrefs window. You should get something like this.



This function only exists on the CCSGameRules vtable which makes it easy. Double click it to go to the vtable. This should look something like this.



Make sure you are clicked within the vtable you want. Now click File->IDC File (or File->Script File in 6.0) and select the linux_vtable_dump.idc file.

By default the input will be 1, CHANGE IT TO 0 this will dump the linux values. Click ok and save the file somewhere (with a useful name like the vtable's name) This is how mine looks.

Code:
// Auto reconstructed from vtable block @ 0x00CEB180
// from "server.so", by ida_vtables.idc
0	CGameRules::Name(void)
1	CMultiplayRules::Init(void)
2	CBaseGameSystemPerFrame::PostInit(void)
3	CBaseGameSystemPerFrame::Shutdown(void)
4	CCSGameRules::LevelInitPreEntity(void)
5	CCSGameRules::LevelInitPostEntity(void)
6	CBaseGameSystemPerFrame::LevelShutdownPreClearSteamAPIContext(void)
7	CBaseGameSystemPerFrame::LevelShutdownPreEntity(void)
8	CBaseGameSystemPerFrame::LevelShutdownPostEntity(void)
9	CBaseGameSystemPerFrame::OnSave(void)
10	CBaseGameSystemPerFrame::OnRestore(void)
11	CBaseGameSystemPerFrame::SafeRemoveIfDesired(void)
12	CBaseGameSystemPerFrame::IsPerFrame(void)
13	CCSGameRules::~CCSGameRules()
14	CCSGameRules::~CCSGameRules()
15	CBaseGameSystemPerFrame::FrameUpdatePreEntityThink(void)
16	CGameRules::FrameUpdatePostEntityThink(void)
17	CBaseGameSystemPerFrame::PreClientUpdate(void)
18	CMultiplayRules::Damage_IsTimeBased(int)
19	CMultiplayRules::Damage_ShouldGibCorpse(int)
20	CMultiplayRules::Damage_ShowOnHUD(int)
21	CMultiplayRules::Damage_NoPhysicsForce(int)
22	CMultiplayRules::Damage_ShouldNotBleed(int)
23	CMultiplayRules::Damage_GetTimeBased(void)
24	CMultiplayRules::Damage_GetShouldGibCorpse(void)
25	CMultiplayRules::Damage_GetShowOnHud(void)
26	CMultiplayRules::Damage_GetNoPhysicsForce(void)
27	CMultiplayRules::Damage_GetShouldNotBleed(void)
28	CMultiplayRules::SwitchToNextBestWeapon(CBaseCombatCharacter *,CBaseCombatWeapon *)
29	CCSGameRules::GetNextBestWeapon(CBaseCombatCharacter *,CBaseCombatWeapon *)
30	CCSGameRules::ShouldCollide(int,int)
31	CCSGameRules::DefaultFOV(void)
32	CCSGameRules::GetViewVectors(void)const
33	CGameRules::GetAmmoDamage(CBaseEntity *,CBaseEntity *,int)
34	CGameRules::GetDamageMultiplier(void)
35	CMultiplayRules::IsMultiplayer(void)
36	CCSGameRules::GetEncryptionKey(void)
37	CGameRules::InRoundRestart(void)
38	CGameRules::AllowThirdPersonCamera(void)
39	CCSGameRules::ClientCommandKeyValues(edict_t *,KeyValues *)
40	CCSGameRules::GetTaggedConVarList(KeyValues *)
41	CGameRules::CheckHaptics(CBasePlayer *)
42	CCSGameRules::LevelShutdown(void)
43	CTeamplayRules::Precache(void)
44	CMultiplayRules::RefreshSkillData(bool)
45	CCSGameRules::Think(void)
46	CMultiplayRules::IsAllowedToSpawn(CBaseEntity *)
47	CCSGameRules::EndGameFrame(void)
48	CGameRules::IsSkillLevel(int)
49	CGameRules::GetSkillLevel(void)
50	CGameRules::OnSkillLevelChanged(int)
51	CGameRules::SetSkillLevel(int)
52	CMultiplayRules::FAllowFlashlight(void)
53	CCSGameRules::FShouldSwitchWeapon(CBasePlayer *,CBaseCombatWeapon *)
54	CMultiplayRules::IsDeathmatch(void)
55	CTeamplayRules::IsTeamplay(void)
56	CMultiplayRules::IsCoOp(void)
57	CCSGameRules::GetGameDescription(void)
58	CMultiplayRules::ClientConnected(edict_t *,char  const*,char  const*,char *,int)
59	CTeamplayRules::InitHUD(CBasePlayer *)
60	CCSGameRules::ClientDisconnected(edict_t *)
61	CCSGameRules::FlPlayerFallDamage(CBasePlayer *)
62	CTeamplayRules::FPlayerCanTakeDamage(CBasePlayer *,CBaseEntity *)
63	CTeamplayRules::ShouldAutoAim(CBasePlayer *,edict_t *)
64	CGameRules::GetAutoAimScale(CBasePlayer *)
65	CGameRules::GetAutoAimMode(void)
66	CGameRules::ShouldUseRobustRadiusDamage(CBaseEntity *)
67	CCSGameRules::RadiusDamage(CTakeDamageInfo  const&,Vector  const&,float,int,CBaseEntity *)
68	CCSGameRules::FlPlayerFallDeathDoesScreenFade(CBasePlayer *)
69	CMultiplayRules::AllowDamage(CBaseEntity *,CTakeDamageInfo  const&)
70	CCSGameRules::PlayerSpawn(CBasePlayer *)
71	CMultiplayRules::PlayerThink(CBasePlayer *)
72	CCSGameRules::FPlayerCanRespawn(CBasePlayer *)
73	CMultiplayRules::FlPlayerSpawnTime(CBasePlayer *)
74	CCSGameRules::GetPlayerSpawnSpot(CBasePlayer *)
75	CCSGameRules::IsSpawnPointValid(CBaseEntity *,CBasePlayer *)
76	CMultiplayRules::AllowAutoTargetCrosshair(void)
77	CCSGameRules::ClientCommand(CBaseEntity *,CCommand  const&)
78	CCSGameRules::ClientSettingsChanged(CBasePlayer *)
79	CTeamplayRules::IPointsForKill(CBasePlayer *,CBasePlayer *)
80	CCSGameRules::PlayerKilled(CBasePlayer *,CTakeDamageInfo  const&)
81	CCSGameRules::DeathNotice(CBasePlayer *,CTakeDamageInfo  const&)
82	CGameRules::GetDamageCustomString(CTakeDamageInfo  const&)
83	CGameRules::AdjustPlayerDamageInflicted(float)
84	CGameRules::AdjustPlayerDamageTaken(CTakeDamageInfo *)
85	CMultiplayRules::CanHavePlayerItem(CBasePlayer *,CBaseCombatWeapon *)
86	CMultiplayRules::WeaponShouldRespawn(CBaseCombatWeapon *)
87	CMultiplayRules::FlWeaponRespawnTime(CBaseCombatWeapon *)
88	CMultiplayRules::FlWeaponTryRespawn(CBaseCombatWeapon *)
89	CMultiplayRules::VecWeaponRespawnSpot(CBaseCombatWeapon *)
90	CMultiplayRules::CanHaveItem(CBasePlayer *,CItem *)
91	CMultiplayRules::PlayerGotItem(CBasePlayer *,CItem *)
92	CMultiplayRules::ItemShouldRespawn(CItem *)
93	CMultiplayRules::FlItemRespawnTime(CItem *)
94	CMultiplayRules::VecItemRespawnSpot(CItem *)
95	CMultiplayRules::VecItemRespawnAngles(CItem *)
96	CGameRules::CanHaveAmmo(CBaseCombatCharacter *,int)
97	CGameRules::CanHaveAmmo(CBaseCombatCharacter *,char  const*)
98	CMultiplayRules::PlayerGotAmmo(CBaseCombatCharacter *,char *,int)
99	CGameRules::GetAmmoQuantityScale(int)
100	CCSGameRules::InitDefaultAIRelationships(void)
101	CCSGameRules::AIClassText(int)
102	CMultiplayRules::FlHealthChargerRechargeTime(void)
103	CMultiplayRules::FlHEVChargerRechargeTime(void)
104	CMultiplayRules::DeadPlayerWeapons(CBasePlayer *)
105	CMultiplayRules::DeadPlayerAmmo(CBasePlayer *)
106	CTeamplayRules::GetTeamID(CBaseEntity *)
107	CTeamplayRules::PlayerRelationship(CBaseEntity *,CBaseEntity *)
108	CTeamplayRules::PlayerCanHearChat(CBasePlayer *,CBasePlayer *)
109	CGameRules::CheckChatText(CBasePlayer *,char *)
110	CTeamplayRules::GetTeamIndex(char  const*)
111	CTeamplayRules::GetIndexedTeamName(int)
112	CTeamplayRules::IsValidTeam(char  const*)
113	CTeamplayRules::ChangePlayerTeam(CBasePlayer *,char  const*,bool,bool)
114	CCSGameRules::SetDefaultPlayerTeam(CBasePlayer *)
115	CCSGameRules::UpdateClientData(CBasePlayer *)
116	CCSGameRules::PlayTextureSounds(void)
117	CMultiplayRules::PlayFootstepSounds(CBasePlayer *)
118	CCSGameRules::FAllowNPCs(void)
119	CMultiplayRules::EndMultiplayerGame(void)
120	CGameRules::WeaponTraceEntity(CBaseEntity *,Vector  const&,Vector  const&,unsigned int,CGameTrace *)
121	CCSGameRules::CreateStandardEntities(void)
122	CCSGameRules::GetChatPrefix(bool,CBasePlayer *)
123	CCSGameRules::GetChatLocation(bool,CBasePlayer *)
124	CCSGameRules::GetChatFormat(bool,CBasePlayer *)
125	CGameRules::ShouldBurningPropsEmitLight(void)
126	CGameRules::CanEntityBeUsePushed(CBaseEntity *)
127	CCSGameRules::CreateCustomNetworkStringTables(void)
128	CGameRules::MarkAchievement(IRecipientFilter &,char  const*)
129	CMultiplayRules::ResetMapCycleTimeStamp(void)
130	CGameRules::OnNavMeshLoad(void)
131	CGameRules::TacticalMissionManagerFactory(void)
132	CGameRules::ProcessVerboseLogOutput(void)
133	CGameRules::GetGameTypeName(void)
134	CGameRules::GetGameType(void)
135	CMultiplayRules::ShouldDrawHeadLabels(void)
136	CGameRules::ClientSpawned(edict_t *)
137	CGameRules::OnFileReceived(char  const*,unsigned int)
138	CGameRules::IsHolidayActive(int)const
139	CMultiplayRules::GetDeathScorer(CBaseEntity *,CBaseEntity *,CBaseEntity *)
140	CMultiplayRules::VoiceCommand(CBaseMultiplayerPlayer *,int,int)
141	CMultiplayRules::HandleTimeLimitChange(void)
142	CMultiplayRules::InitCustomResponseRulesDicts(void)
143	CMultiplayRules::ShutdownCustomResponseRulesDicts(void)
144	CMultiplayRules::GetNextLevelName(char *,int,bool)
145	CMultiplayRules::UseSuicidePenalty(void)
146	CMultiplayRules::ChangeLevel(void)
147	CCSGameRules::GoToIntermission(void)
148	CTeamplayRules::GetCaptureValueForPlayer(CBasePlayer *)
149	CTeamplayRules::TeamMayCapturePoint(int,int)
150	CTeamplayRules::PlayerMayCapturePoint(CBasePlayer *,int,char *,int)
151	CTeamplayRules::PlayerMayBlockPoint(CBasePlayer *,int,char *,int)
152	CTeamplayRules::PointsMayBeCaptured(void)
153	CTeamplayRules::SetLastCapPointChanged(int)
154	CTeamplayRules::TimerMayExpire(void)
155	CTeamplayRules::SetWinningTeam(int,int,bool,bool,bool)
156	CTeamplayRules::SetStalemate(int,bool,bool)
157	CTeamplayRules::SetSwitchTeams(bool)
158	CTeamplayRules::ShouldSwitchTeams(void)
159	CTeamplayRules::HandleSwitchTeams(void)
160	CTeamplayRules::SetScrambleTeams(bool)
161	CTeamplayRules::ShouldScrambleTeams(void)
162	CTeamplayRules::HandleScrambleTeams(void)
163	CTeamplayRules::PointsMayAlwaysBeBlocked(void)
164	CCSGameRules::SpawningLatePlayer(CCSPlayer *)
165	CCSGameRules::SetAllowWeaponSwitch(bool)
166	CCSGameRules::GetAllowWeaponSwitch(void)
As you can see the linux offset is 147.

For windows anything before the destructor (~Classname method) is the same as on linux. After that it will be -1. As we can see the Destructor is at offset 13 so 0-12 are the same offset in windows. Everything after is -1 in windows. So since the linux offset is clearly higher than 13 we subtract one and get an offset of 146 for windows.

In some cases your function will be what is known as an overloaded function. For example the KeyValue functions on CBaseEntity.
Code:
CBaseEntity::KeyValue(char const*, char const*)	        30	29	
CBaseEntity::KeyValue(char const*, float)	        29	30		
CBaseEntity::KeyValue(char const*, Vector const&)	28	31
Overloaded functions are functions with the same name but different parameters. For overloaded functions the rule from above still applies but the order is reversed (The first set of offsets is windows while the second line is linux in the code above). So if you want the first function, you would get the offset for the last one and apply the -1 rule if needed! With these rules you should be able to find most offset. There is however some classes where the offsets still vary for other reasons and I will go into detail on how to get them from the windows binary in part II of the tutorial.

Now on to the plugin! As you can see the return type is not given but the params are. To get the return value you can either think of what would make sense to be returned or use hex rays and the paid version of IDA to find out more info (still not always guaranteed to be correct). I happen to know that this returns an int
Let’s start by creating our gamedata file.

Code:
"Games"
{
	"cstrike"
	{
		"Offsets"
		{
			"GoToIntermission"
			{
				"windows"	"146"
				"linux"		"147"
			}
		}
	}
}
Now the plugin:
PHP Code:
#pragma semicolon 1
#include <sourcemod>
#include <dhooks>

// int CCSGameRules::GoToIntermission(void)
new HandlehGoToIntermission;
public 
OnPluginStart()
{
    new 
Handle:temp LoadGameConfigFile("test.games");

    if(
temp == INVALID_HANDLE)
        
SetFailState("Why you no has gamedata?");

    new 
offset GameConfGetOffset(temp"GoToIntermission");

    if(
offset == -1)
        
SetFailState("Failed to get offset");

    
CloseHandle(temp);

    
hGoToIntermission DHookCreate(offsetHookType_GameRulesReturnType_IntThisPointer_IgnoreGoToIntermission);
}
public 
OnMapStart()
{
    
//Hook Gamerules function in map start
    //Set post to true since we don’t plan to block!
    
DHookGamerules(hGoToIntermissiontrue);
}
//Since this is set to ignore remove the this param and since it has no params remove the params param
// public MRESReturn: GoToIntermission (this, Handle:hReturn, Handle:hParams)  to like so.
public MRESReturn:GoToIntermission(Handle:hReturn)
{
    
PrintToServer("Going to intermission");

    return 
MRES_Ignored;

Compile and that is all there is to it! Hope this tutorial was useful and encourages people to use DHooks and get people more comfortable with IDA and vtable offsets. Feel free to correct me on anything that i might be wrong on.

Credits:
asherkin - Providing a better explanation of how -1 works on windows.


Last edited by Dr!fter; 11-15-2012 at 21:50.
Dr!fter is offline
Dr!fter
The Salt Boss
Join Date: Mar 2007
Old 07-26-2012 , 22:43   Re: [IDA/DHooks]How to get vtable offsets
Reply With Quote #2

Reserved
Dr!fter is offline
Xaphan
SourceMod Donor
Join Date: Jun 2008
Old 07-27-2012 , 01:50   Re: [IDA/DHooks]How to get vtable offsets
Reply With Quote #3

Thank you Dr!fter !
Very much needed and well written ;)

Going now to try my luck at it.
__________________
Xaphan is offline
Powerlord
AlliedModders Donor
Join Date: Jun 2008
Location: Seduce Me!
Old 07-27-2012 , 11:11   Re: [IDA/DHooks]How to get vtable offsets
Reply With Quote #4

You REALLY do need to check the windows offset on every release that your plugin breaks on. As other plugin/extension authors have found out the hard way, sometimes one offset will move and the other offset will move a different amount. There have even been updates where the Windows offset moved and the Linux offset stayed the same!
__________________
Am I back? Well, we'll see.
Powerlord is offline
Dr!fter
The Salt Boss
Join Date: Mar 2007
Old 07-27-2012 , 11:33   Re: [IDA/DHooks]How to get vtable offsets
Reply With Quote #5

Quote:
Originally Posted by Powerlord View Post
You REALLY do need to check the windows offset on every release that your plugin breaks on. As other plugin/extension authors have found out the hard way, sometimes one offset will move and the other offset will move a different amount. There have even been updates where the Windows offset moved and the Linux offset stayed the same!
Quote:
As you can see the linux offset is 147. As for windows, usually it is -1 so 146, this is not always the case though! I will go into more detail on Part II of this tutorial.
k
Dr!fter is offline
Dr!fter
The Salt Boss
Join Date: Mar 2007
Old 07-28-2012 , 13:21   Re: [IDA/DHooks]How to get vtable offsets
Reply With Quote #6

Updated the first post to add some more info on windows offsets.
Dr!fter is offline
K.K.Lv
Veteran Member
Join Date: Aug 2008
Location: GameFolder
Old 08-17-2012 , 02:11   Re: [IDA/DHooks]How to get vtable offsets
Reply With Quote #7

something like Orpheu of AMXX,
thx guy ;)
__________________
QQ:116268742
K.K.Lv is offline
Send a message via MSN to K.K.Lv
K.K.Lv
Veteran Member
Join Date: Aug 2008
Location: GameFolder
Old 08-23-2012 , 00:45   Re: [IDA/DHooks]How to get vtable offsets
Reply With Quote #8

how to get the offset of the object ?
code from your tut about DHooks:
Code:
public MRESReturn:OnTakeDamage(this, Handle:hReturn, Handle:hParams) {     PrintToServer("DHooksHacks = Victim %i, Attacker %i, Inflictor %i, Damage %f", this, DHookGetParamObjectPtrVar(hParams, 1, 40, ObjectValueType_Ehandle), DHookGetParamObjectPtrVar(hParams, 1, 36, ObjectValueType_Ehandle), DHookGetParamObjectPtrVar(hParams, 1, 48, ObjectValueType_Float));         if(this <= MaxClients && this > 0 && !IsFakeClient(this))     {         DHookSetParamObjectPtrVar(hParams, 1, 48, ObjectValueType_Float, 0.0);         PrintToChat(this, "Pimping your hp");     } }
__________________
QQ:116268742
K.K.Lv is offline
Send a message via MSN to K.K.Lv
Dr!fter
The Salt Boss
Join Date: Mar 2007
Old 08-23-2012 , 20:03   Re: [IDA/DHooks]How to get vtable offsets
Reply With Quote #9

Quote:
Originally Posted by K.K.Lv View Post
how to get the offset of the object ?
code from your tut about DHooks:
Code:
public MRESReturn:OnTakeDamage(this, Handle:hReturn, Handle:hParams) {     PrintToServer("DHooksHacks = Victim %i, Attacker %i, Inflictor %i, Damage %f", this, DHookGetParamObjectPtrVar(hParams, 1, 40, ObjectValueType_Ehandle), DHookGetParamObjectPtrVar(hParams, 1, 36, ObjectValueType_Ehandle), DHookGetParamObjectPtrVar(hParams, 1, 48, ObjectValueType_Float));         if(this <= MaxClients && this > 0 && !IsFakeClient(this))     {         DHookSetParamObjectPtrVar(hParams, 1, 48, ObjectValueType_Float, 0.0);         PrintToChat(this, "Pimping your hp");     } }
Its math, the class for CTakeDamageInfo is in the sdk so its easier https://mxr.alliedmods.net/hl2sdk-cs...mageinfo.h#112

The size of a vector is 16 EHANDLE is 4 and float is 4 So the values start from 0.

Vector m_vecDamageForce; //0
Vector m_vecDamagePosition; //12
Vector m_vecReportedPosition; //24
EHANDLE m_hInflictor; //36
EHANDLE m_hAttacker; //40
EHANDLE m_hWeapon; //44
float m_flDamage; //48
float m_flMaxDamage; //52
float m_flBaseDamage; //56
int m_bitsDamageType; //60
int m_iDamageCustom; //64
int m_iDamageStats; //68
int m_iAmmoType; //72
int m_iDamagedOtherPlayers; //76
int m_iPlayerPenetrateCount; //80

Last edited by Dr!fter; 04-23-2015 at 16:44.
Dr!fter is offline
Bacardi
Veteran Member
Join Date: Jan 2010
Location: mom's basement
Old 09-20-2013 , 09:34   Re: [IDA/DHooks]How to get vtable offsets
Reply With Quote #10

Quote:
Originally Posted by Dr!fter View Post
...
Now that you have everything installed grab a copy of the server.so for your game. Normally this will already download when you install a server. If it does not download you can force it by forcing hldsupdatetool to download the linux binary. To do so just add "-linux" to the game param when using the hldsupdatetool. For example to download the linux binaries for CS:S I would use these options.
Code:
-command update -game "Counter-Strike Source-linux"
Now that you have the server.so, launch IDA and open the server.so file. It should something like this
....
Can this done anymore with steamcmd ??
I'm tired to install second OS
Bacardi is offline
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 15:19.


Powered by vBulletin®
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Theme made by Freecode