Motivation
After the speed hack we do a quick infinite health and mana hack. Beware that this hack only works locally because we will only modify GameLogic.dll
instead of tampering the messages between client and server.
Infinite Mana Hack
Search "Mana" in symbols and we find a function named Player::UseMana(int)
:
WTF is this->m_inventory._Myhead
??? Rename the vars a bit:
Copy char __thiscall Player :: UseMana ( Player * this , int manaUsed)
{
World * gameWorld; // ecx
std :: _Tree_node < std :: pair < IItem * const , ItemAndCount > , void *> * oldMana; // eax
std :: _Tree_node < std :: pair < IItem * const , ItemAndCount > , void *> * newMana; // eax
gameWorld = GameWorld;
if ( GameWorld )
{
if ( ! GameWorld -> IsAuthority (GameWorld) )
return 0 ;
gameWorld = GameWorld;
}
oldMana = this -> m_inventory . mana;
if ( ( int )oldMana < manaUsed )
return 0 ;
newMana = (std :: _Tree_node < std :: pair < IItem * const , ItemAndCount > , void *> * )(( char * )oldMana - manaUsed);
this -> m_inventory . mana = newMana;
gameWorld -> SendManaUpdateEvent (gameWorld , (Player * )(( char * ) this - 112 ) , ( int )newMana);
return 1 ;
}
The mana deduction happens at:
Copy newMana = (std :: _Tree_node < std :: pair < IItem * const , ItemAndCount > , void *> * )(( char * )oldMana - manaUsed);
We can "NOP" out the mana subtraction:
Save the patch and go back to the game. Click "Offline Play" and test if mana is infinite now. It should work.
Infinite Health Hack (failed attempt)
Similarly, we can search for "Damage" in symbols and find this Player::Damage()
function:
Pseudocode:
Copy void __thiscall Player :: Damage ( Player * this , Player * instigator , IItem * item , int dmg , DamageType type)
{
int v6; // eax
int m_health; // esi
World * v8; // ecx
int dmga; // [esp+14h] [ebp+10h]
if ( ( ! GameWorld || GameWorld -> IsAuthority (GameWorld)) && ! this -> m_changingServerRegion )
{
if ( instigator == this )
{
v6 = ( int )( float )(( float )dmg * 0.25 );
}
else
{
if ( instigator
&& instigator -> IsPlayer (instigator)
&& ( ! this -> m_pvpEnabled || ! instigator -> IsPvPEnabled (instigator)) )
{
return ;
}
v6 = dmg;
}
m_health = this -> m_health;
dmga = v6;
Actor :: Damage ( this , instigator , item , v6 , type);
if ( this -> m_health < m_health )
this -> m_healthRegenCooldown = 20.0 ;
if ( item )
{
if ( dmga > 0 )
{
v8 = GameWorld;
this -> m_lastHitByItem = item;
this -> m_lastHitItemTimeLeft = 5.0 ;
v8 -> SendLastHitByItemEvent (v8 , this , item);
}
}
}
}
If we set v6
to 0 we should be free from damage. So here we can patch the binary to mov eax, 0
:
Press space key and hover your mouse on this line. Go to "Edit -> Patch program -> Assemble":
Well, the game crashes. We will try patching something else.
Infinite Health Hack (success)
Note that there is a "respawn" functionality in the game. Search "Respawn" in symbols and we can find a function named Player::PerformRespawn()
:
Pseudocode:
Copy void __thiscall Player :: PerformRespawn ( Player * this)
{
IUE4Actor * m_target; // ecx
LocationAndRotation choice; // [esp+Ch] [ebp-18h] BYREF
if ( this -> GetHealth ( this ) <= 0 )
{
this -> m_health = 100 ;
this -> m_mana = 100 ;
Player :: GetSpawnLocation ( this , & choice);
GameWorld -> SendRespawnEvent (GameWorld , this , ( const Vector3 * ) & choice , & choice . rotation);
m_target = this -> m_target;
if ( m_target )
m_target -> LocalRespawn (m_target , & choice . location , & choice . rotation);
}
}
Basically this code says the character can be respawned with 100 health and 100 mana. If we set this->m_health
to something like max Int32 (0x7fffffff
), we could gain an insane amount of health when we respawn. This is the relevant assembly:
Patch 0x00000064
to 0x7fffffff
: