AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Snippets and Tutorials (https://forums.alliedmods.net/forumdisplay.php?f=112)
-   -   [IDA/DHooks]How to get vtable offsets (https://forums.alliedmods.net/showthread.php?t=191171)

Dr!fter 07-26-2012 21:42

[IDA/DHooks]How to get vtable offsets
 
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.

http://i.imgur.com/LXZBp.png

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

http://i.imgur.com/4jpzY.png

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

http://i.imgur.com/1ApQr.png

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.

http://i.imgur.com/oN4rQ.png

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

http://i.imgur.com/cRxla.png

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.

http://i.imgur.com/FENhW.png

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.

http://i.imgur.com/IObVb.png

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 :P
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 :D 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.

:fox:

Dr!fter 07-26-2012 21:43

Re: [IDA/DHooks]How to get vtable offsets
 
Reserved :fox:

Xaphan 07-27-2012 00:50

Re: [IDA/DHooks]How to get vtable offsets
 
Thank you Dr!fter !
Very much needed and well written ;)

Going now to try my luck at it.

Powerlord 07-27-2012 10:11

Re: [IDA/DHooks]How to get vtable offsets
 
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!

Dr!fter 07-27-2012 10:33

Re: [IDA/DHooks]How to get vtable offsets
 
Quote:

Originally Posted by Powerlord (Post 1759277)
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 07-28-2012 12:21

Re: [IDA/DHooks]How to get vtable offsets
 
Updated the first post to add some more info on windows offsets.

K.K.Lv 08-17-2012 01:11

Re: [IDA/DHooks]How to get vtable offsets
 
something like Orpheu of AMXX,
thx guy ;)

K.K.Lv 08-22-2012 23:45

Re: [IDA/DHooks]How to get vtable offsets
 
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");     } }

Dr!fter 08-23-2012 19:03

Re: [IDA/DHooks]How to get vtable offsets
 
Quote:

Originally Posted by K.K.Lv (Post 1779763)
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

Bacardi 09-20-2013 08:34

Re: [IDA/DHooks]How to get vtable offsets
 
Quote:

Originally Posted by Dr!fter (Post 1758960)
...
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 :P


All times are GMT -4. The time now is 12:25.

Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.