Prep: Infinite Health and Mana (Locally)

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:

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:

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:

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:

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:

Go back to the game. Find a rat and get killed, respawn, now we have max Int32 amount of health 😎

Last updated