How to update offsets and signatures for reverts dependent on MemoryPatching (UNDER CONSTRUCTION!) - rsedxcftvgyhbujnkiqwe/castaway-plugins GitHub Wiki
Written by: VerdiusArcana
Editing and proofreading by: protons oppai
How to Find Memory Patch Revert Functions in Ghidra (Windows) for TF2
This guide assumes you are already familiar with basic Ghidra operations such as:
- Navigating the Listing view
- Navigating the Decompile view
- Using the String search ("Defined Strings")
- That you have computer knowledge and programming knowledge in general
The following instructions walk through how to locate the functions in the Team Fortress 2 Windows Server binary using Ghidra, this will be necessary to update signatures and/or offsets for the reverts for the Weapon Reverts Plugin.
After this section, we will go through what needs to be done to accomplish each revert.
A quick look at CodeBrowser
- Save Disk, should be pressed whenever after you are done analyzing and decompiling a binary on first run, thereafter it should be pressed whenever you find and name a function, change plate comments, or when you update any Global Var.
- This is where you filter for functions. On Linux the symbols are already in, but it can be hard to directly type in something
likeCTFWeaponBaseMelee::OnSwingHit
because on Linux they look typically like this:_ZN18CTFWeaponBaseMelee10OnSwingHitER10CGameTrace
as the so called "Mangled name" contains the var types too. So you will have to make do with just inputting the function name. Such asOnSwingHit
- Output of any scripts you run. Typically the makesig output appears here. (See section: makesig.py script)
Decompile
Window. Whenever you see "Decompile
Window" in the instructions of this How to, this is the tab meant.- Defined Strings. Whenever you are told to search for a string, this is where you do it.
!!!STRONGLY RECOMMENDED!!!
-
First: Copy the .so and .dll from their respective folders (Dedicated server install folders typically found in
/tf/bin/
) to a new folder.- Name the folder something like
tf2_serverbinaries_DATEOFTF2UPDATE
- For example:
tf2_serverbinaries_13May2025
- For example:
- After running Ghidra, click on
File>New Project...
- Make sure "Non-Shared Project" is selected.
- For Project directory, choose the directory you placed the .so and .dll files in, which in our example is
tf2_serverbinaries_13May2025
- For name, it would be appropriate to name if something like TF2-Server-Date, which for our example could be
TF2-Server-13May2025
- Name the folder something like
-
Press
Finish
.- Now it should say "Active Project: TF2-Server-Date"
- Now click
File>Import File
. - Unless you intend to make new memorypatches entirely, you can just choose .dll first, but I recommend having both of them decompiled.
- So begin with choosing the .so file and just follow Ghidra's instructions. DO NOT CHANGE ANYTHING!!!
-
Once it's done, press OK.
- Now when you double click on the file in your project, it will open a window called
CodeBrowser
. - It will also immediately ask you if you want to analyze the file. Just press "Analyze" or "OK".
- And just press OK until no more dialog pops up, you will see a processing bar doing stuff in the
CodeBrowser
window at the bottom right. And your computer fans will probably speed up. - This is quite a heavy operation, depending on your computer it can take anywhere from 15 minutes to 45 minutes. So lean back and relax or go do something else. DO NOT CLOSE ANY GHIDRA WINDOWS DURING THIS.
- Now when you double click on the file in your project, it will open a window called
-
After it's done and you see no more stuff happening in the bottom right.
- Click the little Save Disk icon at the top left of
CodeBrowser
if it's not already greyed out.
- Click the little Save Disk icon at the top left of
-
Now close the
CodeBrowser
Window and proceed to the Ghidra window where you have your project.- Proceed to import the
server.dll
and repeat the process.
- Proceed to import the
-
Once you have both the .so and .dll files analyzed and decompiled, you can go to
File>Open...
to open the other file (if you are following along, the
latest decompile you will have open in theCodeBrowser
Window is the .dll file, so just choose the .so file).- This makes it so you don't need to have several
CodeBrowser
Windows open.
- This makes it so you don't need to have several
Before we begin:
FUN_********
is a function that Ghidra has discovered, but since the Windows binary does not contain debug information, Ghidra has labeled it according to it's starting address. I'm not gonna go into technical depth about this. When you see things likeDouble-Click on the FUN_
and similar mentions in this guide as I don't write out the fullFUN_
name, it's because it's pointless for me to write out the address that comes attached, likeFUN_106ac67a
because you might see something different.
What to do when you find a function (also strongly recommended)
-
When you find and have verified a function, name it for future usage and to make it easier to cross reference stuff.
-
Rightclick the
FUN_
in theDecompile
window and pick "Edit Function Signature". -
Look at the field
Function Name
. -
In here, copy and paste the function name from this document to this field, then press
OK
. DO NOT CHANGE ANYTHING ELSE!!! -
I also tend to copy over the "plate comment" from the .so binary (Linux) and adding it too onto discovered functions in the Windows binary.
-
For example for
CObjectSentrygun::OnWrenchHit
function.- The plate comment in the .so at the top of
Decompile
window saysCObjectSentrygun::OnWrenchHit(CTFPlayer*, CTFWrench*, Vector)
- Select it with the cursor and
CTRL+C
, then go back to the server.dllListing
Window, then go to the function you discovered (in this caseCObjectSentrygun::OnWrenchHit
), again right click the function name in theDecompile
window.
- The plate comment in the .so at the top of
-
But this time, hover the mouse over
Comments
and chooseSet Plate Comment
. -
Make sure the
Plate Comment
tab is selected. Paste in theCObjectSentrygun::OnWrenchHit(CTFPlayer*, CTFWrench*, Vector)
and change nothing else, just press OK. -
Once you are done, press that tiny save disk to the very top-left of the
CodeBrowser
Window.
The Functions we need to hunt down.
Note:
CTFMinigun::GetProjectileDamage
andCTFMinigun::GetWeaponSpread
were originally located by sheer dumb luck. These instructions are not going to work if Valve messes to much. Pray Valve doesn’t touch these functions ever again so you can just plop in the already found signatures and be happy.
CTFMinigun::GetProjectileDamage
Signatures (last updated 13th May 2025)
"windows" "\x55\x8B\xEC\x51\x56\x8B\xF1\xE8\x2A\x2A\x2A\x2A\xF3\x0F\x10\x8E\x2A\x2A\x2A\x2A\x0F\x57\xD2\x0F\x2F\xCA\xA1\x2A\x2A\x2A\x2A\xD9\x55\x2A\x72\x2A\xF3\x0F\x10\x40\x2A\xF3\x0F\x5C\xC1\xEB\x2A\x0F\x28\xC2\xF3\x0F\x10\x9E\x2A\x2A\x2A\x2A\x0F\x2F\xDA\x5E\xF3\x0F\x5C\x05\x2A\x2A\x2A\x2A\x72\x2A\xF3\x0F\x10\x48\x2A\xF3\x0F\x5C\xCB\xEB\x2A\x0F\x28\xCA\x0F\x2F\xC1\x77\x2A\x0F\x28\xC1\xF3\x0F\x10\x1D\x2A\x2A\x2A\x2A\x0F\x2F\xD8\x76\x2A\xF3\x0F\x5C\x05"
"linux" "@_ZN10CTFMinigun19GetProjectileDamageEv"
Finding It Without a Signature
You need to find CTFWeaponBase::GetProjectileDamage
first to help
verify that you have found CTFMinigun::GetProjectileDamage
!
- Search for the string:
mult_dmg_disguised
- Look at its cross-references (XREFs) in the
Listing
Window.
You should see a singleFUN_
there. Double-Click it. - Rename the
FUN_
toCTFWeaponBase::GetProjectileDamage
Now with CTFWeaponBase::GetProjectileDamage
discovered.
We can make a attempt at finding CTFMinigun::GetProjectileDamage
-
Search for the string:
ring_of_fire_while_aiming
-
Look at its cross-references (XREFs).
Ignore any that are withinFUN_
labeled functions — you're looking for one that isn't automatically named with aFUN_
-
If you're in the right spot, the disassembly (listing view) should resemble this:
1061c675 68 1c 5f PUSH s_ring_of_fire_while_aiming_108d5f1c = "ring_of_fire_while_aiming"
8d 10
1061c67a 6a 00 PUSH 0x0
1061c67c e8 6f 05 CALL CALL_ATTRIB_HOOK_INT int CALL_ATTRIB_HOOK_INT(int par
bc ff
1061c681 83 c4 14 ADD ESP,0x14
Navigating From There
If you see the above, you're likely in the correct spot. Scroll down slightly:
- You should see a
FLDZ
instruction. - You should also see a
RET
shortly after. - After a small gap of undefined bytes (
??
), a new function should begin.
In Ghidra (In the Windows Binary of TF2), a function (That is not Undefined) could look like this:
(Just took a random function to show what it can look like
the function in the image is NOT CTFMinigun::GetProjectileDamage
)
That new function after the bunch of ?? is very likely CTFMinigun::GetProjectileDamage
.
Immediately following that function in memory should be a new function.
which is very very likely to be CTFMinigun::GetWeaponSpread
.
Verifying
You can cross-check your find like this:
-
Make sure you already found and labeled:
CTFWeaponBase::GetProjectileDamage
CTFWeaponBase::GetWeaponSpread
-
In the function you believe is
CTFMinigun::GetProjectileDamage
, you should see an early call toCTFWeaponBase::GetProjectileDamage
.
Also, if you look in the Decompile
window to your right,
you should see something that looks like this code snippet in it with values such as
0.75
,1.0
,1.25
and so on:
fVar3 = fVar2 - 0.75; if (fVar2 - 0.75 <= fVar4) { fVar3 = fVar4; } if (fVar3 < 1.0) { fVar2 = (fVar3 - 0.2) * 1.25; if (fVar2 <= 0.0) { fVar2 = 0.0; } if (1.0 <= fVar2) { fVar2 = 1.0; } fVar1 = (float10)((fVar2 + 1.0) * 0.5 * (float)fVar1); }
CTFMinigun::GetWeaponSpread
Signature (last updated 13th May 2025)
"windows" "\x55\x8B\xEC\x51\x56\x8B\xF1\xE8\x2A\x2A\x2A\x2A\xF3\x0F\x10\x8E\x2A\x2A\x2A\x2A\x0F\x57\xD2\x0F\x2F\xCA\xA1\x2A\x2A\x2A\x2A\xD9\x55\x2A\x72\x2A\xF3\x0F\x10\x40\x2A\xF3\x0F\x5C\xC1\xEB\x2A\x0F\x28\xC2\xF3\x0F\x10\x9E\x2A\x2A\x2A\x2A\x0F\x2F\xDA\x5E\xF3\x0F\x5C\x05\x2A\x2A\x2A\x2A\x72\x2A\xF3\x0F\x10\x48\x2A\xF3\x0F\x5C\xCB\xEB\x2A\x0F\x28\xCA\x0F\x2F\xC1\x77\x2A\x0F\x28\xC1\xF3\x0F\x10\x1D\x2A\x2A\x2A\x2A\x0F\x2F\xD8\x76\x2A\x0F\x57\xC9"
"linux" "@_ZN10CTFMinigun15GetWeaponSpreadEv"
Finding It Without a Signature
You need to find CTFWeaponBase::GetWeaponSpread
first to help
verify that you have found CTFMinigun::GetWeaponSpread
!
- Search for the string:
mult_spread_scales_consecutive
- Look at its cross-references (XREFs) in the
Listing
Window.
You should see a singleFUN_
there. Double-Click it. - Rename the
FUN_
toCTFWeaponBase::GetWeaponSpread
Now with CTFWeaponBase::GetWeaponSpread
discovered.
We can make a attempt at finding CTFMinigun::GetWeaponSpread
-
Just look at the next function after
CTFMinigun::GetProjectileDamage
in theListing
Window -
Verify if you found the correct one by confirming that it makes an early call to
CTFWeaponBase::GetWeaponSpread
. And again, you can also checkDecompile
window to your right and
you should see something that looks like this code snippet in it with values such as
0.75
,1.0
and so on (it's slightly different fromCTFMinigun::GetProjectileDamage
):
fVar4 = fVar2 - 0.75;
if (fVar2 - 0.75 <= fVar3) {
fVar4 = fVar3;
}
if (fVar4 < 1.0) {
if (fVar4 <= 0.0) {
fVar4 = 0.0;
}
if (1.0 <= fVar4) {
fVar4 = 1.0;
}
fVar1 = (float10)((1.5 - fVar4 * 0.5) * (float)fVar1);
}
- If you successfully found it, Rename the
FUN_
toCTFMinigun::GetWeaponSpread
CTFPlayer::ApplyPunchImpulseX
Signature (last updated 13th May 2025)
"windows" "\x55\x8B\xEC\x83\xEC\x08\x53\x56\x8B\xF1\xB3\x01"
"linux" "@_ZN9CTFPlayer18ApplyPunchImpulseXEf"
Finding It Without a Signature
-
Search for the string:
aiming_no_flinch
-
Click on the result once.
-
Look at its cross-references (XREFs) in the
Listing
Window.
You should see a singleFUN_
there. Double-Click it. -
If you are really unsure, look now at the decompiled code in the
Decompile
Window. You should see this line in there:uVar5 = FUN_101dcbf0(0,"aiming_no_flinch",(int)this,0,'\x01');
-
Rename the
FUN_
toCTFPlayer::ApplyPunchImpulseX
CTFProjectile_BallOfFire::Burn
Signature (last updated 13th May 2025)
"windows" "\x53\x8B\xDC\x83\xEC\x08\x83\xE4\xF0\x83\xC4\x04\x55\x8B\x6B\x2A\x89\x6C\x24\x2A\x8B\xEC\x81\xEC\x48\x02\x00\x00\x56\x57\x8B\xF9\x8B\x8F"
"linux" "@_ZN24CTFProjectile_BallOfFire4BurnEP11CBaseEntity"
Finding It Without a Signature
-
Search for the string:
Weapon_DragonsFury.BonusDamage
-
Click on the result once.
-
Look at its cross-references (XREFs) in the
Listing
Window.
You should see a singleFUN_
there along with one withoutFUN_
in it. Double-Click it (do not click on the one without aFUN_
). -
You should now be in the correct function. You can double-check by seeing if code similar to this appears:
local_d4 = "Weapon_DragonsFury.BonusDamage"; if (param_1[6] == 0) { iVar6 = 0; } else { iVar6 = (int)*(short *)(param_1[6] + 6); } FUN_1032bab0(local_60,iVar6,&local_d8); FUN_1012eab0(local_a8); if (piVar4 != (int *)0x0) { FUN_10211f60(&local_d8); local_b8 = 0; local_b4 = 0.0; local_d4 = "Weapon_DragonsFury.BonusDamagePain"; FUN_104496a0(local_114,(int)piVar4); if (piVar4[6] == 0) { iVar6 = 0; }
-
A extra way to doublecheck: These 3 strings should appear in the same function:
Weapon_DragonsFury.BonusDamage
,Weapon_DragonsFury.BonusDamagePain
and
Weapon_DragonsFury.BonusDamageHit
-
Rename the
FUN_
toCTFProjectile_BallOfFire::Burn
CTFWeaponBaseMelee::OnSwingHit
Signature (last updated 13th May 2025)
"windows" "\x55\x8B\xEC\x81\xEC\x50\x01\x00\x00\x53\x56\x57"
"linux" "@_ZN18CTFWeaponBaseMelee10OnSwingHitER10CGameTrace"
Finding It Without a Signature
-
Search for the string:
speed_buff_ally
-
Click on the result once.
-
Look at its cross-references (XREFs) in the
Listing
Window.
You should see a singleFUN_
, Double-Click it. -
You should now be in the function, to doublecheck, you can look in the
Decompiled
Window and look for this code snippet:iVar5 = CALL_ATTRIB_HOOK_INT(0,"speed_buff_ally",(int)this,0,'\x01'); if ((0 < iVar5) && (*(int *)(param_1 + 0x4c) != 0)) { CTFPlayerShared::AddCond(this_00 + 0x6b8,4.48416e-44,2.0,(int *)0x0); CTFPlayerShared::AddCond(piVar4 + 0x6b8,4.48416e-44,3.6,(int *)0x0); FUN_10487ba0((int)this,(int)piVar4,this_00,0x42,1); }
See how the first FUN_ call inside the if statement has 2.0 and the second has 3.6? Yes that's for The Disciplinary Action.
-
After you have renamed the
FUN_
toCTFWeaponBaseMelee::OnSwingHit
, you might as well grabCTFPlayerShared::AddCond
at the same time.- Go back to the if statement that had that
2.0
and3.6
in theFUN_
's`parameters. - Double-click either of them (not the third one!).
- name the
FUN_
toCTFPlayerShared::AddCond
.
- Go back to the if statement that had that
CTFGameRules::PlayerMayCapturePoint
Signature (last updated 13th May 2025)
"windows" "\x55\x8B\xEC\x53\x56\x57\x8B\x7D\x2A\x8B\xD9\x85\xFF\x74\x2A\x8B\x07\x8B\xCF\x8B\x80"
"linux" "@_ZN12CTFGameRules21PlayerMayCapturePointEP11CBasePlayeriPci"
Finding It Without a Signature
Search for the string "#Cant_cap_disguised" Click on it then check out the XREF. Click on the FUN_
Done.
-
Search for the string:
#Cant_cap_disguised
(And yes, the # is part of the string do not omit it!)
-
Click on the result once.
-
Look at its cross-references (XREFs) in the
Listing
Window.
You should see a singleFUN_
, Double-Click it. -
Rename the
FUN_
toCTFGameRules::PlayerMayCapturePoint
CObjectSentrygun::OnWrenchHit
Signature (last updated 13th May 2025)
"windows" "\x55\x8B\xEC\x83\xEC\x08\x53\x56\x8B\xF1\x57\x80\xBE\x2A\x2A\x2A\x2A\x00\x74"
"linux" "@_ZN16CObjectSentrygun11OnWrenchHitEP9CTFPlayerP9CTFWrench6Vector"
Finding It Without a Signature
-
First, we need to find
CTFWrench::GetRepairAmount
- Start by searching for the string:
mult_repair_value
- Click the result once.
- Look at its cross-references (XREFs) in the
Listing
Window. you should see twoFUN_
's, both of them areCTFWrench::GetRepairAmount
- Double-click either of the two it does not matter.
- Rename the
FUN_
toCTFWrench::GetRepairAmount
-
Now while still in the function
CTFWrench::GetRepairAmount
, look at theListing
Window. IMAGE_HERE -
Double-Click on one of the
FUN_
's, if you arrive at a fairly short function, it's the wrong one. go back and try the other one. -
Now in the
Decompile
window, click once anywhere inside of it. then pressCTRL+F
to open theDecompiler find text
dialog.- For
Find:
type
0.33
- Ensure that
String
is selected as format. - Press
Next
- Keep pressing
Next
until the dialog saysReached the bottom, continued from top
- What you want to check: If
0.33
appears 3 times in the decompiled code, and that it's attached to code similar to this:
if (*(int *)((int)this + 0xb34) == 1) { fVar8 = (float10)((float)fVar8 * 0.33); }
- If it does, then you are in the correct function.
- For
-
Rename the
FUN_
toCObjectSentrygun::OnWrenchHit
CTFLunchBox::ApplyBiteEffects
Signature (last updated 13th May 2025)
"windows" "\x55\x8B\xEC\x51\x53\x8B\xD9\x56\x57\x6A\x01"
"linux" "@_ZN11CTFLunchBox16ApplyBiteEffectsEP9CTFPlayer"
Finding It Without a Signature
-
Search for the string:
lunchbox_healing_scale
-
Click on the result once.
-
Look at its cross-references (XREFs) in the
Listing
Window.
You should see a singleFUN_
there. Double-Click it. -
Rename the
FUN_
toCTFLunchBox::ApplyBiteEffects
CTFProjectile_Arrow::BuildingHealingArrow
Signature (last updated 13th May 2025)
"windows" "\x55\x8B\xEC\x83\xEC\x24\x53\x56\x57\x8B\x7D\x2A\x8B\xD9\x57"
"linux" "@_ZN19CTFProjectile_Arrow20BuildingHealingArrowEP11CBaseEntity"
Finding It Without a Signature
-
Search for the string:
arrow_heals_buildings
-
Click on the result once.
-
Look at its cross-references (XREFs) in the
Listing
Window.
You should see a singleFUN_
there. Double-Click it. -
Rename the
FUN_
toCTFProjectile_Arrow::BuildingHealingArrow
CBaseMultiplayerPlayer::AwardAchievement
Signature (last updated 13th May 2025)
"windows" "\x55\x8B\xEC\x83\xEC\x20\x56\x8B\xF1\x8D\x4D\x2A\xE8\x2A\x2A\x2A\x2A\x56\x8D\x4D\x2A\xC7\x45\x2A\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x8D\x45\x2A\x68\x2A\x2A\x2A\x2A\x50\xE8\x2A\x2A\x2A\x2A\xFF\x75"
"linux" "@_ZN22CBaseMultiplayerPlayer16AwardAchievementEii"
Finding It Without a Signature
It's a good idea to first find two additional functions to make
it easier to identify the AwardAchivement function.
WRITE_SHORT
and
UserMessageBegin
-
WRITE_SHORT
- Search for the string:
WRITE_SHORT called with no active message\n
- Click on the result once.
- Look at its cross-references (XREFs) in the
Listing
Window.
You should see a singleFUN_
there. Double-Click it. - Rename the
FUN_
toWRITE_SHORT
-
UserMessageBegin
- Search for the string:
UserMessageBegin: Unregistered message
- Click on the result once.
- Look at its cross-references (XREFs) in the
Listing
Window.
You should see a singleFUN_
there. Double-Click it. - Rename the
FUN_
toUserMessageBegin
-
Now with these two functions discovered, search for the string:
AchievementEvent
-
Now you will see two
FUN_
's, double-click on one of them. look in theDecompile
Window.- If you see a bunch of
FUN_
's like this:
FUN_1043f740(DAT_10a92324,"Geiger",1); FUN_1043f740(DAT_10a92324,"Train",1); FUN_1043f740(DAT_10a92324,"HudText",0xffffffff); FUN_1043f740(DAT_10a92324,"SayText",0xffffffff); FUN_1043f740(DAT_10a92324,"SayText2",0xffffffff); ...
that just keep going and going, you got the wrong
FUN_
, go back and double-click the other one. - If you see a bunch of
-
Now looking in the
Decompile
Window, you should see something like this:FUN_1030c540(local_24); local_24[0] = &PTR_`scalar_deleting_destructor'_1078e4f0; FUN_1030c960(local_24,(int)this); UserMessageBegin(local_24,0x1079725c); WRITE_SHORT(param_1); WRITE_SHORT(param_2); FUN_1026fce0(); FUN_1030c6e0(local_24); return;
If you do, then you are in the correct
FUN_
. -
Rename the
FUN_
toCBaseMultiplayerPlayer::AwardAchievement
Preparing to make it easier to decode the mess in Decompile Window
Functions that are good to have to make it easier to read the Decompile Window
CTFPlayerShared::InCond
Found in CTFWeaponBaseGun::GetProjectileDamage
.
Use the function filter and search for it (you did name the function when you found it in the steps
for CTFMinigun::GetProjectileDamage
, right?).
When the function has been opened in the Decompile
Window,
click somewhere inside of it. Then press CTRL+´F
to open
the search window.
For Find:
, enter mult_dmg_disguised
. Make sure
String
is selected. Then press Next
.
You should now have arrived at
something that looks something like this:
bVar2 = FUN_1051ff20(piVar3 + 0x6b8,3); if (!bVar2) goto LAB_106385b3; fVar8 = FUN_1044b7d0((float)fVar8,"mult_dmg_disguised",(int)param_1,0,'\x01'); local_8 = (float)fVar8;
Look at the first line, what's interesting is the last parameter, which is 3.
Keep this in mind.
Now go to the original SourceCode (source sdk 2013).
Search for mult_dmg_disguised
in the file
src/game/shared/tf/tf_weaponbase_gun.cpp
.
You ought to arrive at something like this:
// Some weapons mod dmg when not disguised bool bDisguised = pPlayer && pPlayer->m_Shared.InCond( TF_COND_DISGUISED ); if ( bDisguised ) { CALL_ATTRIB_HOOK_FLOAT( flDamage, mult_dmg_disguised ); }
If you also check the file src/game/shared/tf/tf_shareddefs.h
.
The Value of `TF_COND_DISGUISED``is 3.
Besides as the final verify: We know that mult_dmg_disguised
only has a single FUN_ in the XREF.
bVar2 is assigned whatever we got from FUN_1051ff20
which can be nothing else but InCond function.
Rightclick on FUN_1051ff20
in the Decompiled
Window in Ghidra.
Name it CTFPlayerShared::InCond
.
CALL_ATTRIB_HOOK_FLOAT
Just follow the steps for CTFPlayerShared::InCond
as the FUN_
directly after the if statement is that one.
Vars that are good to have to make it easier to read the Decompile Window
Something one can do to make it easier to read the decompiled code
and compare to the .so binary (and the original source code)
is to find and name the vars.
gameeventmanager
Search for the string halloween_pumpkin_grab
and click it, in the XREF you should see PackTouch (PackTouch is always avaible
despite Windows TF2 server binary not containing debug symbols).
Double Click on PackTouch
.
Now go to Decompile
Window.
You should see something like this:
piVar8 = (int *)(**(code **)(*DAT_10a2b7d4 + 0x18))("halloween_pumpkin_grab");
That DAT_ is the gameeventmanager.
Rightclick on it in the Decompiled
Window,
then pick Rename Global
.
In the dialog option, look at Enter Label:
Name it gameeventmanager
, change nothing else and just press OK.
Don't forget to press the tiny Save Disk Icon in the top left!
engine
Located just below the gameeventmanager
in PackTouch.
Since you have already done the steps for it, you can just rightclick
on the DAT_ and repeat with renaming
The code should look something like this:
uVar7 = (**(code **)(*DAT_10a2b7b4 + 0x3c))();
but use engine
instead as the label.
gpGlobals
Probably one of the most important global vars to name to make it easier for you.
It's found in CTFWeaponBaseGun::GetProjectileDamage
.
Open the function so it appears in the Decompiled
Window.
Click somewhere in that window, and press CTRL+F.
In Find:
, write accuracy_scales_damage
, make sure
String
is selected and press Next
.
Directly below the search result is a line that looks kinda like this:
ìVar6 = DAT_10a2b7e8;
.
Or for more context:
fVar8 = CALL_ATTRIB_HOOK_FLOAT(1.0,"accuracy_scales_damage",(int)param_1,0,'\x01'); iVar6 = DAT_10a2b7e8;
It's the line directly below the call to that float function.
That DAT_ is the gpGlobals.
Rightclick on it in the Decompiled
Window,
then pick Rename Global
.
In the dialog option, look at Enter Label:
Name it gpGlobals
, change nothing else and just press OK.
Don't forget to press the tiny Save Disk Icon in the top left!
makesig.py - the wonder tool that builds signatures for you.
makesig.py is a script that helps you build the shortest unique signatures for the Windows Binary.
It can also be used for Linux if for some weird reason the mangled name does not work,
but 99.99% of the time you will not need to use a byte signature for the Linux binary.
The ultimate chad: nosoop, made this tool. You can go here if you want to see the original.
https://github.com/nosoop/ghidra_scripts
Big thanks to our lord and savior (he also made SourceScramble. Kneel apes!)
You can find the script in the makesig.py section (It's quite large which is why it has it's own
wikipage): WIKIPAGE HERE
After you have copied the script, Look at the top of your CodeBrowser
window. Find Window
, click it. Then click at Script Manager
.
Alternatively click on the Green Play Button in the toolbar.
With the Script Manager open, it ought to ask you the first time around where you want your scripts.
If it did not, click this button.
Then, in the Bundle Manager
Window, click the red + sign.
A dialog option should open asking you to choose a folder,
jar or bnd files.
You want to create a new folder in whatever location is appropriate for you.
If Linux:
/home/YOUR_USER_NAME/ghidra_scripts
If Windows:
C:\Users\YOUR_USER_NAME\Mina dokument\ghidra_scripts
The folder MUST be named ghidra_scripts
or Ghidra
will not accept it.
Once you are done, make sure it's ticked in the square checkbox
in the Bundle Manager, Ghidra should have done this automatically but best to check.
Now close down Bundle Manager
and press the button next to the Refresh Button
.
Ghidra will ask you what type of script you are planning to make.
Choose Jython
if it's not already selected, and press OK.
It will then ask you to select a directory, you should
now see the earlier ghidra_scripts
folder that you created.
Select it, and for Enter script file name:
write in makesig.py
and press OK
.
If you see this dialog:
Then just press OK.
It should now open a editor, it should look kinda like this:
Just remove everything inside of makesig.py, then paste in the makesig.py code you either got from this wiki or nosoops original.
Press the tiny Save Disk, and you are done.
Speeding up makesig.py usage
Instead of having to constantly open the script manager, you can assign a hotkey to
the makesig.py script.
If you have issues finding the makesig.py script, just type makesig
into the Filter:
field at the bottom of Script Manager
.
Then, rightclick the makesig script and select Assign Key Binding
.
Now, just press your Hotkey, then click OK.
(I use CTRL+NUMPAD0 if you are wondering).
Finally using makesig.py
Now we are setup to start generating signatures.
We will use CTFWeaponBaseGun::GetProjectileDamage
for this exercise.
Begin by opening the function in the CodeBrowser
.
Once you have it open, look in the Listing
Window.
Click on either the function name in the Decompiled
Window
OR the start address of the function (you do not need to select it as if selecting text, just click once).
After you have clicked one of the two (which one does not matter).
Press your hotkey or open Script Manager
and double-click on makesig.py
You will see a dragon logo that looks like it's chewing on bits of data (lmfao).
after it's done loading, you should see this:
You want to have start of function
selected, then press OK
.
After just a few seconds, you should see output at the bottom of CodeBrowser
Window.
If you are using my modified one from the wiki, you will see this:
Signature for CTFWeaponBaseGun::GetProjectileDamage Shortest Unique: Ghidra: 55 8B EC 83 EC 1C 53 56 8B D9 57 89 5D Gamedata: \x55\x8B\xEC\x83\xEC\x1C\x53\x56\x8B\xD9\x57\x89\x5D Optional 24-Byte Signature: Ghidra: 55 8B EC 83 EC 1C 53 56 8B D9 57 89 5D ? E8 ? ? ? ? 8B F8 85 FF 74 Gamedata: \x55\x8B\xEC\x83\xEC\x1C\x53\x56\x8B\xD9\x57\x89\x5D\x2A\xE8\x2A\x2A\x2A\x2A\x8B\xF8\x85\xFF\x74 Optional 32-Byte Signature: Ghidra: 55 8B EC 83 EC 1C 53 56 8B D9 57 89 5D ? E8 ? ? ? ? 8B F8 85 FF 74 ? 8B 17 8B CF 8B 92 ? Gamedata: \x55\x8B\xEC\x83\xEC\x1C\x53\x56\x8B\xD9\x57\x89\x5D\x2A\xE8\x2A\x2A\x2A\x2A\x8B\xF8\x85\xFF\x74\x2A\x8B\x17\x8B\xCF\x8B\x92\x2A
If you are using the original one nosoop made, you will see this:
Signature for CTFWeaponBaseGun::GetProjectileDamage 55 8B EC 83 EC 1C 53 56 8B D9 57 89 5D \x55\x8B\xEC\x83\xEC\x1C\x53\x56\x8B\xD9\x57\x89\x5D
The one without \x is used to search in the binary for that sequence of bytes
which can be handy (Search>Memory...
. While the \x one is
for the gamedata folder.
There's not much more to it really. The next section will take all we have learned so far, and show how to update signatures and offsets.
How to update signatures and offsets
UNDER CONSTRUCTION