<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://blog.tbender.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.tbender.io/" rel="alternate" type="text/html" /><updated>2026-05-10T21:23:41+00:00</updated><id>https://blog.tbender.io/feed.xml</id><title type="html">blog.tbender.io</title><subtitle>Personal blog of Thomas Bender.</subtitle><entry><title type="html">Applying RPCS3 patches to PS3 Executables</title><link href="https://blog.tbender.io/2026/05/10/applying-rpcs3-patches-to-ps3-executables/" rel="alternate" type="text/html" title="Applying RPCS3 patches to PS3 Executables" /><published>2026-05-10T19:56:01+00:00</published><updated>2026-05-10T19:56:01+00:00</updated><id>https://blog.tbender.io/2026/05/10/applying-rpcs3-patches-to-ps3-executables</id><content type="html" xml:base="https://blog.tbender.io/2026/05/10/applying-rpcs3-patches-to-ps3-executables/"><![CDATA[<p>A quick one for now. I’ve been digging into a bit of reverse engineering as of late.</p>

<p>There’s a patch for Tekken Tag Tournament 2 in RPCS3 that caught my attention: “Reduce input lag”.</p>

<p><img src="./2026-05-10-applying-rpcs3-patches-to-ps3-executables/image.png" alt="rpcs3-patches" /></p>

<p>This patch shaves two frames of input delay off the game in offline modes. You just toggle it on in the emulator and you’re done.</p>

<p>I wanted the patch on PS3 hardware.</p>

<h2 id="rpcs3s-patchyml">RPCS3’s patch.yml</h2>

<p>RPCS3 keeps its patches in a single <code class="language-plaintext highlighter-rouge">patch.yml</code>. Each patch is keyed by a SHA-1 hash of the loaded PPU module (the game’s main executable), and underneath are one or more entries. An entry is a small tuple: a type (something like <code class="language-plaintext highlighter-rouge">be32</code> for a big-endian 32-bit integer), a runtime virtual address, and the value to write there. So a patch is really just a list of byte writes against specific addresses in memory.</p>

<p>The hash is the interesting part. RPCS3 derives it from the ELF’s program headers and segment payloads in a particular order. If I recompute that same hash on a real PS3 ELF, I’d have the same key into <code class="language-plaintext highlighter-rouge">patch.yml</code> that the emulator uses.</p>

<h2 id="the-plan">The plan</h2>

<p>It something like this:</p>

<ol>
  <li>Decrypt the game’s <code class="language-plaintext highlighter-rouge">EBOOT.BIN</code> into an ELF.
    <ul>
      <li>RPCS3 already has this function</li>
    </ul>
  </li>
  <li>Compute the PPU hash on that ELF the way RPCS3 does it.</li>
  <li>Look up the patch in <code class="language-plaintext highlighter-rouge">patch.yml</code> by hash, translate each entry’s virtual address into a file offset using the ELF’s PT_LOAD segments, and write the encoded value.</li>
  <li>Re-encrypt the patched ELF back into a fake-signed <code class="language-plaintext highlighter-rouge">EBOOT.BIN</code> that CFW will accept.
    <ul>
      <li>oscetool does this</li>
    </ul>
  </li>
  <li>FTP it onto the PS3, run the game.</li>
</ol>

<h2 id="the-script">The script</h2>

<p>I wrote a small Ruby script for the middle bit. Given a decrypted ELF and a patch name, it derives the PPU hash, finds the matching entries, applies each one to the byte buffer, and writes a new ELF. Ruby’s <code class="language-plaintext highlighter-rouge">Array#pack</code> and <code class="language-plaintext highlighter-rouge">String#unpack</code> handle big-endian format codes natively. <code class="language-plaintext highlighter-rouge">N</code> for 32-bit, <code class="language-plaintext highlighter-rouge">Q&gt;</code> for 64-bit, and <code class="language-plaintext highlighter-rouge">g</code> and <code class="language-plaintext highlighter-rouge">G</code> for floats. PS3 executables are big-endian ELF64, so the encoders for each patch type ended up being one-liners.</p>

<p>This can be re-written into Python if there’s demand; I’m more familiar with Ruby so I stuck with it.</p>

<p>I’ve uploaded the script here: https://github.com/tbender4/ps3_elf_patcher</p>

<p>It haven’t tested it past Tekken Tag Tournament 2. YMMV.</p>

<h2 id="re-encrypting">Re-encrypting</h2>

<p>After the script writes the patched ELF, the result has to be encrypted to run on the PS3. I used <a href="https://github.com/spacemanspiff/oscetool">OpenSCETool</a> for this.</p>

<h2 id="deployment">Deployment</h2>

<p>This requires a modded PS3. FTP into the PS3, navigate to <code class="language-plaintext highlighter-rouge">/dev_hdd0/game/&lt;TITLEID&gt;/USRDIR/</code>, back up the existing <code class="language-plaintext highlighter-rouge">EBOOT.BIN</code>, and drop in the patched copy.</p>

<p>And that’s a wrap! Here’s a quick video of Practice Mode in PS3 with the input lag option effectively no-oped and second video showing the Skip Auto-Save Warning patch: https://x.com/tbender95/status/2053582940504773034</p>]]></content><author><name></name></author><summary type="html"><![CDATA[A quick one for now. I’ve been digging into a bit of reverse engineering as of late.]]></summary></entry><entry><title type="html">Hello World</title><link href="https://blog.tbender.io/2026/05/10/hello-world/" rel="alternate" type="text/html" title="Hello World" /><published>2026-05-10T19:15:00+00:00</published><updated>2026-05-10T19:15:00+00:00</updated><id>https://blog.tbender.io/2026/05/10/hello-world</id><content type="html" xml:base="https://blog.tbender.io/2026/05/10/hello-world/"><![CDATA[<p>It’s been a while. bender’s blog is back.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[It’s been a while. bender’s blog is back.]]></summary></entry></feed>