Exploiting Memory Corruption to Upgrade AI Opponents in a Classic RTS Game

Jon Craton (jlcraton@anderson.edu)

November 9th, 2023

StarCraft

StarCraft

  • Real-time strategy game
  • Released in 1998
  • Played at a competitive level for the past 25 years

Use in Research

The domain of StarCraft has emerged as an important challenge for artificial intelligence research, owing to its iconic and enduring status among the most difficult professional esports and its relevance to the real world in terms of its raw complexity and multi-agent challenges.

Use in Education

Student StarCraft AI Tournament is an educational event, first held in 2011. It serves as a challenging competitive environment mainly for students (submissions by non-students are allowed too) of Artificial Intelligence and Computer Science.

Metagame Evolution

Bot Weaknesses

  • The game was poorly understood in 1998
  • Many strategies that were standard then would now be all-in
  • Modern greedy strategies would have been impossible to execute without modern tactics
  • Built-in AI agents use a very small number of mostly aggressive strategies

Problems

  • Play against bots is not dynamic for experienced players
  • New players develop terrible habits playing against bots

Solution

  • Replace the built-in AI agents to use more dynamic play styles
  • Include modern all-ins as well as aggressive, standard, and greedy play to encourage information gathering

Building the Agent

AI System

  • Driven by custom bytecode found in game data files
  • Individual instructions represent single in-game actions

Bytecode Example

0x06016F50 would instruct the system to build (0x06) 1 (0x01) barracks (0x6F) at priority 80 (0x50)

By combining many bytecode instructions, we can create complete scripted AI agents

An agent designed for the modern 1v1 metagame

Deployment

Sharing Game Data

  • Modifications of this sort can trivially be distributed by sharing modified game files
  • This creates challenges for users
  • This could result in account bans under certain anti-cheat systems

Triggers

  • StarCraft maps contain a basic trigger system that can allow scripted actions to take place

Trigger

Trigger {
  players = {P1},
  conditions = {
    Deaths(P1, AtLeast, 2, "Terran Marine");
  },
  actions = {
    SetDeaths(P1, Subtract, 1, "Terran Firebat");
  }
}

Memory Corruption

Vulnerable Code

int current_player = 1;
const int players = 8;
const int units = 255;
int death_table[players][units];

void set_deaths(int player, char unit, int deaths) {
    if (player == 0) {
        player = current_player;
    }

    death_table[player][unit] = value;
}

Arbitrary Memory Writes

Action: Modify death counts for player [p]: Add [d] deaths for unit [u]

  • p should be a number between 1 and 8, but is not bounds checked
  • We can exploit this to create actions that set values in known memory locations
  • We can’t use this to perform indirect writes via a pointer

Arbitrary Memory Conditions

Condition: Player [p] has suffered [d] deaths of unit [u]

  • p should be a number between 1 and 8, but is not bounds checked
  • We can exploit this to create conditions that trigger on values in arbitrary memory locations

Destructive Memory Copy

for i = 30, 0, -1 do
   Trigger {
       players = {P1},
       conditions = {
           Deaths(addr1 - death_table/4, AtLeast, 2^i, 0)
       },
       actions = {
           SetDeaths(addr1 - death_table/4, Subtract, 2^i, 0)
           SetDeaths(addr2 - death_table/4, Add, 2^i, 0)
       }
   }
end

AI Script Loading

  • StarCraft loads aiscript.bin from the game files when needed
  • It is loaded dynamically in a position that changes from run to run
  • However, the location of the pointer to this location is fixed

Memory Locations

Address Description
0x0058A364 Death Table Start
0x006509B0 Current Player
0x0068C104 Pointer to aiscript.bin
*0x0068C104 aiscript.bin

Current Player Triggers

  • There are triggers that execute for each player
  • The trigger looks up the current player in memory
  • This can be leveraged to dereference a pointer by overwriting current_player in memory

Current Player Trick

  • Set the current_player to (-death_table / 4) to remove offset
  • Add target pointer to current_player

Steps

  1. Set the current player to the base address of of the death table
  2. Add the aiscript.bin pointer value to the current player value
  3. Set deaths for current player unit 0 to write a word of aiscript.bin
  4. Increment current player and write next word
  5. Repeat until complete

More data structure info | Complete Exploit

Future

What if this exploit gets patched?

Patch

  • Patch 1.13f
  • Release: 2006-01-18

Fixed several bugs that contributed to game exploits.

Patch

  • Patch 1.21.0
  • Release: 2017-12-07

Added an EUD “Extended Unit Death” emulator that supports hundreds of EUD offsets for custom maps.

Presentation