<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2026-02-09T17:51:05+09:00</updated><id>/feed.xml</id><title type="html">My Blog</title><subtitle>My blog</subtitle><entry><title type="html">Mineral Memory Addresses in BW 1.16.1</title><link href="/2026/01/08/mineral-address.html" rel="alternate" type="text/html" title="Mineral Memory Addresses in BW 1.16.1" /><published>2026-01-08T00:00:00+09:00</published><updated>2026-01-08T00:00:00+09:00</updated><id>/2026/01/08/mineral-address</id><content type="html" xml:base="/2026/01/08/mineral-address.html"><![CDATA[<p>This entry is about mineral memory addresses in StarCraft: Brood War patch 1.16.1</p>

<h1 id="memory-scanner">Memory Scanner</h1>
<p>I used cheat engine for memory scanning which can be downloaded <a href="https://www.cheatengine.org/downloads.php">here</a><br />
Clicking on the download link doesn’t seem to download anything for me. I had to go to the link to download it.<br />
Deselect any additional/optional programs when installing.</p>

<h1 id="finding-your-mineral-memory-address">Finding your Mineral Memory Address</h1>
<p>First select and open brood war in cheat engine.<br />
I used chaos launcher to run brood war in windowed mode.<br />
Create a single player game on Astral Balance.<br />
(New/first) Scan for the value 50. After training a peon and spending your minerals (next) scan for the value 0.</p>

<p>The scan found three memory addresses.<br />
The value of the 2nd and 3rd addresses revert back to the original value after changing them.<br />
So the first address is the address holding the mineral value.<br />
<img src="/assets/3_min_addresses.png" alt="p1" /></p>

<p>The map Astral Balance only has a top and bottom position.<br />
When I am on the bottom position the mineral address is StarCraft.exe+17F0F0 (0x57F0F0) and StarCraft.exe+17F0F4 at the top position.<br />
The mineral addresses goes up by 4 bytes.<br />
The address for StarCraft.exe is 0x400000.</p>

<p>If you open the map C:\Program Files (x86)\Starcraft\Maps\BroodWar(2)Astral Balance.scm with StarEdit.exe you can see that Player 1 (Red User Selectable) is at the bottom.<br />
<img src="/assets/astral_balance_p1.png" alt="p2" /></p>

<p>While the 1st mineral address changes based on your starting location, the 2nd address which is StarCraft.exe+28C230 (0x68C230) and is only readable is constant even in a new game.</p>

<h1 id="finding-your-player-number-memory-address">Finding your Player Number Memory Address</h1>
<p>Create a single player game on Astral Balance.<br />
(New/first) scan for the player number based on your position.<br />
For example you are player 2 if you are on top and player 1 if on bottom.<br />
Keep making a new game and (next) scan based on your player number.<br />
Eventually after switching player numbers you will find several addresses.<br />
This address keeps track which player number you are.<br />
StarCraft.exe+17F0B0 (0x57F0B0)<br />
<img src="/assets/player_num_address.png" alt="p3" /></p>

<h1 id="finding-your-mineral-address-based-on-your-player-number">Finding your Mineral Address based on your Player Number</h1>
<p>If during a game you read your player number from 0x57F0B0, subtract your player number by one, multiply by 4 and add by 0x57F0F0, then you can automatically find your mineral address and write to it.<br />
For example:</p>
<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;Windows.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">**</span> <span class="n">argv</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">HWND</span> <span class="n">bw_window</span> <span class="o">=</span> <span class="n">FindWindow</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="s">L"Brood War"</span><span class="p">);</span>

  <span class="n">DWORD</span> <span class="n">process_id</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">GetWindowThreadProcessId</span><span class="p">(</span><span class="n">bw_window</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">process_id</span><span class="p">);</span>

  <span class="n">HANDLE</span> <span class="n">bw_process</span> <span class="o">=</span> <span class="n">OpenProcess</span><span class="p">(</span><span class="n">PROCESS_ALL_ACCESS</span><span class="p">,</span> <span class="nb">true</span><span class="p">,</span> <span class="n">process_id</span><span class="p">);</span>

  <span class="n">DWORD</span> <span class="n">player_num</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">DWORD</span> <span class="n">bytes_read</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">ReadProcessMemory</span><span class="p">(</span><span class="n">bw_process</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="mh">0x57F0B0</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">player_num</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">bytes_read</span><span class="p">);</span>

  <span class="n">player_num</span><span class="o">--</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">min_address</span> <span class="o">=</span> <span class="n">player_num</span><span class="o">*</span><span class="mi">4</span> <span class="o">+</span> <span class="mh">0x57F0F0</span><span class="p">;</span>

  <span class="n">DWORD</span> <span class="n">new_min_value</span> <span class="o">=</span> <span class="mi">555</span><span class="p">;</span>
  <span class="n">DWORD</span> <span class="n">bytes_written</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">WriteProcessMemory</span><span class="p">(</span><span class="n">bw_process</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="n">min_address</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">new_min_value</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">bytes_written</span><span class="p">);</span>

  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>C++ code was tested with Visual Studio 2019 on Windows 10.<br />
Visual Studio should be run as administrator or OpenProcess doesn’t work.<br />
Starter code was used from <a href="https://gamehacking.academy/pages/3/02/">here</a></p>

<p>Delphi port of this code was tested on Delphi 12 on Windows 11 and also should be run as an administrator.</p>
<div class="language-pascal highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">program</span> <span class="n">Project1</span><span class="p">;</span>
<span class="cm">{$APPTYPE CONSOLE}</span>

<span class="cm">{$R *.res}</span>

<span class="k">uses</span>
  <span class="n">System</span><span class="p">.</span><span class="n">SysUtils</span><span class="p">,</span>
  <span class="n">Windows</span><span class="p">;</span>

<span class="k">var</span>
  <span class="n">bw_window</span><span class="p">:</span> <span class="n">HWND</span><span class="p">;</span>
  <span class="n">process_id</span><span class="p">:</span> <span class="kt">DWORD</span><span class="p">;</span>
  <span class="n">bw_process</span><span class="p">:</span> <span class="kt">THandle</span><span class="p">;</span>
  <span class="n">player_num</span><span class="p">:</span> <span class="kt">DWORD</span><span class="p">;</span>
  <span class="n">bytes_read</span><span class="p">:</span> <span class="kt">DWORD</span><span class="p">;</span> <span class="c1">//NativeUInt
</span>  <span class="n">min_address</span><span class="p">:</span> <span class="kt">Integer</span><span class="p">;</span>
  <span class="n">new_min_value</span><span class="p">:</span> <span class="kt">DWORD</span><span class="p">;</span>
  <span class="n">bytes_written</span><span class="p">:</span> <span class="kt">DWORD</span><span class="p">;</span> <span class="c1">//SIZE_T (or NativeUInt)
</span>
<span class="k">begin</span>
  <span class="n">bw_window</span> <span class="p">:=</span> <span class="n">FindWindow</span><span class="p">(</span><span class="nb">nil</span><span class="p">,</span> <span class="s">'Brood War'</span><span class="p">);</span>

  <span class="n">process_id</span> <span class="p">:=</span> <span class="m">0</span><span class="p">;</span>
  <span class="n">GetWindowThreadProcessId</span><span class="p">(</span><span class="n">bw_window</span><span class="p">,</span> <span class="n">process_id</span><span class="p">);</span>

  <span class="n">bw_process</span> <span class="p">:=</span> <span class="n">OpenProcess</span><span class="p">(</span><span class="n">PROCESS_ALL_ACCESS</span><span class="p">,</span> <span class="nb">True</span><span class="p">,</span> <span class="n">process_id</span><span class="p">);</span>

  <span class="n">player_num</span> <span class="p">:=</span> <span class="m">0</span><span class="p">;</span>
  <span class="n">bytes_read</span> <span class="p">:=</span> <span class="m">0</span><span class="p">;</span>
  <span class="n">ReadProcessMemory</span><span class="p">(</span><span class="n">bw_process</span><span class="p">,</span> <span class="kt">Pointer</span><span class="p">(</span><span class="mh">$57F0B0</span><span class="p">),</span> <span class="p">@</span><span class="n">player_num</span><span class="p">,</span> <span class="m">4</span><span class="p">,</span> <span class="n">bytes_read</span><span class="p">);</span>

  <span class="n">Dec</span><span class="p">(</span><span class="n">player_num</span><span class="p">);</span>
  <span class="n">min_address</span> <span class="p">:=</span> <span class="n">player_num</span><span class="p">*</span><span class="m">4</span> <span class="p">+</span> <span class="mh">$57F0F0</span><span class="p">;</span>

  <span class="n">new_min_value</span> <span class="p">:=</span> <span class="m">555</span><span class="p">;</span>
  <span class="n">bytes_written</span> <span class="p">:=</span> <span class="m">0</span><span class="p">;</span>
  <span class="n">WriteProcessMemory</span><span class="p">(</span><span class="n">bw_process</span><span class="p">,</span> <span class="kt">Pointer</span><span class="p">(</span><span class="n">min_address</span><span class="p">),</span> <span class="p">@</span><span class="n">new_min_value</span><span class="p">,</span> <span class="m">4</span><span class="p">,</span> <span class="n">bytes_written</span><span class="p">);</span>
<span class="k">end</span><span class="p">.</span>
</code></pre></div></div>

<h1 id="finding-the-instruction-that-subtracts-minerals">Finding the instruction that subtracts minerals</h1>
<p>First, attach starcraft into a debugger. I used <a href="https://sourceforge.net/projects/x64dbg/files/snapshots/">x32dbg</a> for this because starcraft is a 32-bit program.<br />
I couldn’t find starcraft at first when trying to attach it. I checked “Enable Debug Privilege” in Preferences, Engine to see it.<br />
After starting a game on Astral Balance, I put a Hardware, Write, Dword breakpoint on the address of my player number mineral.<br />
The game paused on the instruction at 0x004672C2 after spending minerals.</p>
<pre><code class="language-x86asm">mov edx, dword ptr ds:[eax+0x57F0F0]
mov ecx, dword ptr ds:[eax+0x6CA51C]
sub edx, ecx
mov dword ptr ds:[eax+0x57F0F0], edx
</code></pre>
<p>The eax register holds your player number in terms of 4 bytes (player 1 = 0, player 2 = 4)<br />
Your mineral count is then moved to the edx register.<br />
The mineral amount that is substracted is added to the ecx register and then substracted from the edx register.<br />
The result in edx is then moved back to your mineral address.<br />
Filling the instruction with NOPs prevents your minerals from being reduced anymore.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[This entry is about mineral memory addresses in StarCraft: Brood War patch 1.16.1]]></summary></entry></feed>