<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Reverse-Engineering on The Dark Programmer&#39;s Tome of Secrets</title>
        <link>https://blog.devcouncil.org/tags/reverse-engineering/</link>
        <description>Recent content in Reverse-Engineering on The Dark Programmer&#39;s Tome of Secrets</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en-us</language>
        <lastBuildDate>Sun, 16 Feb 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.devcouncil.org/tags/reverse-engineering/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>Jailbreaking an All in One ISP Router: Sagemcom F@ST 5655v2</title>
        <link>https://blog.devcouncil.org/posts/sagemcom-jailbreak/</link>
        <pubDate>Sun, 16 Feb 2025 00:00:00 +0000</pubDate>
        
        <guid>https://blog.devcouncil.org/posts/sagemcom-jailbreak/</guid>
        <description>&lt;img src="https://blog.devcouncil.org/posts/sagemcom-jailbreak/innards.jpg" alt="Featured image of post Jailbreaking an All in One ISP Router: Sagemcom F@ST 5655v2" /&gt;&lt;h1 id=&#34;the-problem&#34;&gt;The problem
&lt;/h1&gt;&lt;p&gt;With the rapid expansion of high-speed access, Fiber-to-the-Home is becoming the standard for providing connectivity to urban residences. While FttH provides great benefits when it comes to speed and reliability, it is usually accompanied by a renunciation of our right to handle our own infrastructure.&lt;/p&gt;
&lt;p&gt;Most ISPs that install FttH provide All-in-One devices as the CPE, which does both the Fiber-to-Ethernet modulation and the typical router / switch / access point tasks we nowadays expect from our routers. This device usually has a very locked down set of features. Hardly ever you will see any VLAN or firewall configuration available to the end-user, for example.&lt;/p&gt;
&lt;p&gt;This is a very comfortable setup for the non-technically inclined, but it becomes excessively burdensome for any task that requires a minimum of customization.&lt;/p&gt;
&lt;p&gt;My case is not out of the ordinary in this regard. Around 2019, our fiber connection was serviced by MasMovil, which kindly also supplied us with a Sagemcom F@ST 5655v2, an AIO router with moderate specs, enough to service our 300MbE connection.&lt;/p&gt;
&lt;p&gt;At the time, I started reading up on IPv6. I found it terribly interesting and was wondering why its adoption was so lacking, especially in Spain, which averaged around 3% at the time, trailing all big european countries except Ukraine.&lt;/p&gt;
&lt;p&gt;I evidently also read about Hurricane Electric, an internet service provider that specializes in IPv6 connectivity. They are one of the biggest providers of IPv6 transit, being considered a tier 1 network in this protocol. They are also an IPv6 tunnel broker: they provide individuals that lack native IPv6 with IPv6 tunnels to be able to access the IPv6 internet.&lt;/p&gt;
&lt;p&gt;Here is the catch: To be able to use these tunnels, you require a router that can be configured for such a task, which is to run a &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/6in4&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;6in4 tunnel&lt;/a&gt;. The router that MasMovil provided obviously did not allow for such a feature. Therefore, there was only one thing I could do: Figure out a way to replace it with my own.&lt;/p&gt;
&lt;p&gt;This task would not prove easy. I quickly learned that the protocol that most ISPs use for last-mile connectivity is GPON, and these GPON connections require a password in order to decode the traffic and connect to them.&lt;/p&gt;
&lt;p&gt;Alas, I did not have such password. Reading online I found that you can ask for such password when the technician first installs the equipment, but I did not know that at the time, so I did not think to ask then.&lt;/p&gt;
&lt;p&gt;The only place that I could potentially obtain this password from is the router itself. I would need to access the router and extract this secret from inside.&lt;/p&gt;
&lt;h1 id=&#34;first-steps-search-online&#34;&gt;First steps: search online
&lt;/h1&gt;&lt;p&gt;The obvious first reaction was to search online. There I found &lt;a class=&#34;link&#34; href=&#34;https://medium.com/@thafresh/isps-doing-whatever-they-like-with-our-hardware-118d727fc76e&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a few&lt;/a&gt; blog posts describing a way to open ssh access into several models of Sagemcom routers, such as the &lt;a class=&#34;link&#34; href=&#34;https://forums.whirlpool.net.au/thread/98m5pxw3?p=8#r64876434&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;F@ST 5355&lt;/a&gt; or &lt;a class=&#34;link&#34; href=&#34;https://forum.openwrt.org/t/openwrt-based-talktalk-sagemcom-fast-5364-tinkering/49961&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;5364&lt;/a&gt;. I attempted to reproduce these attacks without luck. Searching a bit more it turned out that &lt;a class=&#34;link&#34; href=&#34;https://bandaancha.eu/foros/extraer-gpon-router-sagemcom-fast-5655v2-1731346&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;such attack was patched&lt;/a&gt; in the newest firmware version, which I had.&lt;/p&gt;
&lt;p&gt;With such bad prospects, I chose to buy the same model off second-hand to replicate the attack and obtain more info on the internals of this machine to be able to craft a new attack.&lt;/p&gt;
&lt;p&gt;Having booted this second-hand router, I successfully managed to apply the hack to gain ssh access. Unfortunately, there was no way of replicating this on the newer version.&lt;/p&gt;
&lt;h1 id=&#34;second-strategy-uart&#34;&gt;Second strategy: UART
&lt;/h1&gt;&lt;p&gt;Just for fun I chose to pry open the plastic casing that protected the router PCB. I couldn&amp;rsquo;t make much sense of that was going on in there, but after looking around for a bit, I did see something familiar.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.devcouncil.org/posts/sagemcom-jailbreak/innards.jpg&#34;
	width=&#34;4032&#34;
	height=&#34;3024&#34;
	srcset=&#34;https://blog.devcouncil.org/posts/sagemcom-jailbreak/innards_hu_d854e09226c2c6b.jpg 480w, https://blog.devcouncil.org/posts/sagemcom-jailbreak/innards_hu_c22fcb6ec663c5e9.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Try to find the UART pads!&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I managed to spot a set of 4 pads lined up and very clearly labeled. It had to be a UART connector. I already had little hope for this attack, but I had to try it anyway. I bought a cheap USB to UART converter and connected it to the board.&lt;/p&gt;
&lt;p&gt;After rebooting the device, I was presented with the following log:&lt;/p&gt;
&lt;details&gt;
    &lt;summary&gt;UART Log (Abridged) (Click to expand)&lt;/summary&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;CFE version 1.0.38-116.174 for BCM96838 (32bit,SP,BE)
Build Date: Fri Jan 20 18:54:28 CET 2017 (g601671@rmm-1186759)
Copyright (C) 2000-2013 Broadcom Corporation.
Version cfe-ram: 7.31.17.1

U-Boot 2011.12
Version: 7.31.17.1-full (Jan 20 2017 - 18:53:37) 
Copyright (C) 2011 - 2013 Sagemcom All rights reserved
Board: Sagemcom fast
CPU: Broadcom BCM68380 (Chip1 Rev4)
DRAM:  256 MiB
NAND:  128 MiB
Using default environment

## Booting kernel from Legacy Image at 8c3df000 ...
   Image Name:   scOS SG3V10000295 (masmovil_v0.3
   Created:      2020-05-26   5:24:05 UTC
   Image Type:   MIPS Linux Kernel Image (gzip compressed)
   Data Size:    2424832 Bytes = 2.3 MiB
   Load Address: 80010000
   Entry Point:  803ba690
   Verifying Checksum ... OK
   Uncompressing Kernel Image ... OK

Starting kernel ...

Linux version 3.4.11-rt19 (g533718@rmm08492) (gcc version 4.6.2 (GCC) ) #1 SMP PREEMPT Tue May 26 07:23:57 CEST 2020
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;This log does not do much for the task at hand, but it does provide some interesting information.&lt;/p&gt;
&lt;p&gt;We gather that it is running on U-Boot 2011.12, a GPL 2.0 licensed micro-bootloader. U-Boot by default would allow you to press &lt;code&gt;Ctrl+C&lt;/code&gt; to abort the boot and drop you into a command prompt with useful commands, such as &lt;code&gt;md&lt;/code&gt; (memory display) which allows for reading the contents of specific memory locations. I tried interacting with the terminal, but the only thing I got it to print was &lt;code&gt;Got Ctrl&lt;/code&gt; when I pressed &lt;code&gt;Ctrl+C&lt;/code&gt;, with no other reaction.&lt;/p&gt;
&lt;p&gt;It seems Sagemcom might have modified their version of U-Boot to disable the command prompt, thus locking down any possibility of interacting through the UART. According to the GPL, they should provide the source to anyone that asks. After contacting them on three different email addresses, they refused to provide the GPL-licensed code, which means they&amp;rsquo;re in clear violation of the license. I afterwards found on the internet a squashfs image which included the supposed bootloader binary for a router in the same family. Just for fun, I did some decompiling with Ghidra, and what I found would not surprise you.&lt;/p&gt;
&lt;p&gt;The following is the original u-boot source code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// arch/mips/lib/board.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;board_init_r&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;gd_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;id, ulong dest_addr)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;puts&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Net:   &amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;eth_initialize&lt;/span&gt;(gd&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;bd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;/* main_loop() can return to retry autoboot, if so just run it again. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (;;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;main_loop&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;/* NOTREACHED - no way out of command loop except booting */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the following I managed to decompile from the binary:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;board_init_r&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;gd_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;id, ulong dest_addr)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;puts&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Net:   &amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;eth_initialize&lt;/span&gt;(gd&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;bd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (gd&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;unknown_3 &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sagem&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sb3_sagem_init&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#75715e&#34;&gt;/* WARNING: Subroutine does not return */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;hang&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;main_loop&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt;( true );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;They modified the source very explicitly to avoid reaching the &lt;code&gt;main_loop&lt;/code&gt; function, which handles the Ctrl+C command to drop into boot prompt.&lt;/p&gt;
&lt;p&gt;It seemed like this avenue was dead.&lt;/p&gt;
&lt;h1 id=&#34;breakthrough-impersonate-the-acs-server&#34;&gt;Breakthrough: Impersonate the ACS server
&lt;/h1&gt;&lt;p&gt;I searched a bit more online and found &lt;a class=&#34;link&#34; href=&#34;https://www.electronicayciencia.com/2020/10/obteniendo-ploam-password-fast-5657.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a new article&lt;/a&gt; that managed to escape me at first. It is not specific to my router model, but at first glance it looked like it might do the trick.&lt;/p&gt;
&lt;p&gt;The essence of this blog post&amp;rsquo;s attack is to impersonate the ACS (Application Configuration Service) server, which is responsible for configuring every aspect of the router remotely by the ISP. We impersonate it by acting as a proxy between the router and the real ACS server, thus being able to listen to their conversation. It looked promising at first, but I ran into a small roadblock. Whereas the post author&amp;rsquo;s model allows for this ACS server to be within the LAN, mine only allowed this connection through the fiber port.&lt;/p&gt;
&lt;p&gt;I then had the idea of trying to use the second-hand router I got to impersonate the real router. Since the second-hand router was already cracked, I managed to change the interface in which the ACS connection would be established to an ethernet connection. In this way, I could set up a laptop to do the proxying between the second-hand router and the ACS server.&lt;/p&gt;
&lt;p&gt;From this ordeal I got a rough understanding of what exactly was being communicated in this conversation: A huge amount of SOAP requests and responses. Some of them more than a Megabyte long. Most of their content was useless, but I got a rough understanding of how these communications were happening, which messages were sent in response to which requests, or what was the general content of these request and response bodies.&lt;/p&gt;
&lt;p&gt;I felt ready to attempt the same on the real router. I spun up an EC2 instance with the same proxy script that  I was using earlier, and set its ip address as the ACS url in the router. Before restarting the router, I did a simple smoke test to make sure it was working. I tried to send a request myself pretending to be the router, and the result discouraged me significantly. My EC2 instance could not connect to the ACS server. It seems they might be refusing any connections coming from outside their network.&lt;/p&gt;
&lt;p&gt;Not falling for despair, I decided to act as the server myself. For every request that the router would send, I quickly crafted a fake response based on the communications I gathered earlier. In particular, I crafted the following response:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;soap:Envelope&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;xmlns:cwmp=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;urn:dslforum-org:cwmp-1-0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;xmlns:soap=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://schemas.xmlsoap.org/soap/envelope/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;xmlns:soap-enc=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://schemas.xmlsoap.org/soap/encoding/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;xmlns:xsd=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://www.w3.org/2001/XMLSchema&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;xmlns:xsi=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://www.w3.org/2001/XMLSchema-instance&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;soap:Header&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;cwmp:ID&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;soap:mustUnderstand=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;27b552c7&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/cwmp:ID&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/soap:Header&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;soap:Body&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;cwmp:SetParameterValues&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;ParameterList&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;soap-enc:arrayType=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cwmp:ParameterValueStruct[2]&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;ParameterValueStruct&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;Name&amp;gt;&lt;/span&gt;Device.Services.X_MM_RemoteAccess.SSHEnable&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/Name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;Value&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;xsi:type=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;xsd:boolean&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;true&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/Value&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/ParameterValueStruct&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;ParameterValueStruct&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;Name&amp;gt;&lt;/span&gt;Device.Services.X_MM_RemoteAccess.TELNETEnable&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/Name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;Value&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;xsi:type=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;xsd:boolean&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;true&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/Value&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/ParameterValueStruct&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/ParameterList&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;ParameterKey&amp;gt;&lt;/span&gt;n/a&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/ParameterKey&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/cwmp:SetParameterValues&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/soap:Body&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/soap:Envelope&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And it worked! This finally allowed me to force the server to open the ssh ports it has been guarding so strongly. The username and password were the same as the ones used for the web interface, which I already had. I was in! It was only one more step to obtain the GPON password:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat /opt/filesystem1/data/optical_conf.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3455xxxxxxxxxxxxxxxx
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;just-for-fun-decompiling-the-firmware&#34;&gt;Just for fun: Decompiling the firmware
&lt;/h1&gt;&lt;p&gt;We already captured the flag that we were looking for, but there was still a thing that bothered me. In order to let the user keep backups of the config, the web UI exposes a config backup page. Clicking the backup button downloads a file called &lt;code&gt;device.cfg&lt;/code&gt;. From the start it was obvious they would not let anyone meddle with the router configuration that easily, so I was already expecting some hardships when opening this file. The reality was even worse. The file started with the magic byes &lt;code&gt;AEAD&lt;/code&gt;. These aren&amp;rsquo;t really any standard format that I could find, but considering AEAD stands for Authenticated Encryption with Associated Data, this pointed in only one direction: The file was encrypted. I therefore took it as a challenge to decrypt it. Since I was already in full control of the router, I could easily download all the binaries that it was using to decompile them and try to reverse the encryption.&lt;/p&gt;
&lt;p&gt;Searching for the magic bytes within the libraries led me straight to the source: &lt;code&gt;libgsdf.so.1&lt;/code&gt;. Doing some decompiling of the library with Ghidra (which was made easier thanks to the debug symbols they graciously left in the binary) I found the function in which this string was being referenced. The function was called &lt;code&gt;gsdfAeadEncrypt&lt;/code&gt;, and what lay inside was straight up the encryption key:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;KEY[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;}&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;KEY[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0xa2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;KEY[&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;X&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;KEY[&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\x13&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;KEY[&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0xdd&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;KEY[&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0x9d&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;KEY[&lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;z&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;KEY[&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\x15&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;KEY[&lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;gt;&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;KEY[&lt;span style=&#34;color:#ae81ff&#34;&gt;9&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;`&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;KEY[&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0xa0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;KEY[&lt;span style=&#34;color:#ae81ff&#34;&gt;11&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;(&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;KEY[&lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0xba&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;KEY[&lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0xdd&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;KEY[&lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0xb2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;KEY[&lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0x88&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which, converted to a more readable format, is &lt;code&gt;0x7da25813dd9d7a153e60a028baddb288&lt;/code&gt;. @Sagemcom: You can make me remove this from here if you give me the modified u-boot source code. Deal?&lt;/p&gt;
&lt;h1 id=&#34;addendum&#34;&gt;Addendum
&lt;/h1&gt;&lt;p&gt;After having done all of this back in 2020, someone else decided to independently discover how to extract the encryption key and posted their results on &lt;a class=&#34;link&#34; href=&#34;https://www.electronicayciencia.com/2021/02/descifrar-configuracion-sagemcom-fast5657.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;their blog&lt;/a&gt;, which cites other blog posts as their sources. Due to my procrastination, I only found out about this while writing this post 5 years after the fact. I still decided to publish this post because, hey, why not. I also did something that they did: Cross compile a small tool to run the decryption library in a more convenient way. Go read about it in their blog post! Although, in contrast as to how they did it, I actually did a cross-compilation from an x86 machine to the MIPS architecture of the router, which involved downloading and installing a cross-compilation toolchain.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Reverse engineering a mouse configurator</title>
        <link>https://blog.devcouncil.org/posts/mouse-configurator-reverse-engineering/</link>
        <pubDate>Mon, 28 Aug 2023 00:00:00 +0000</pubDate>
        
        <guid>https://blog.devcouncil.org/posts/mouse-configurator-reverse-engineering/</guid>
        <description>&lt;img src="https://blog.devcouncil.org/posts/mouse-configurator-reverse-engineering/thumbnail.png" alt="Featured image of post Reverse engineering a mouse configurator" /&gt;&lt;h1 id=&#34;preamble-the-problem&#34;&gt;Preamble: The problem
&lt;/h1&gt;&lt;p&gt;Once upon a time I had a mouse. This little mouse had five buttons. The typical three, plus a forward and backward on the side. It was nothing fancy, but it got me hooked on mice with additional buttons. There&amp;rsquo;s something very satisfying about moving through your browser history with a single button that I could not relinquish. After this mouse broke seven years ago, in 2016, I bought a brand new Mars Gaming MM4 18-button mouse. It has a nice 12-button keypad on the side, which can be configured with a propietary tool for Windows.&lt;/p&gt;
&lt;p&gt;I was in university at the time, and Microsoft gave us free Windows keys through the Inspire program. I was already a Linux fanboy, but I had to keep Windows installed to run some programs that were necessary for my university, such as Solidworks, so I put up with this mouse configurator for the time being.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.devcouncil.org/posts/mouse-configurator-reverse-engineering/mm4-config.png&#34;
	width=&#34;801&#34;
	height=&#34;638&#34;
	srcset=&#34;https://blog.devcouncil.org/posts/mouse-configurator-reverse-engineering/mm4-config_hu_1cefdc7c2487769.png 480w, https://blog.devcouncil.org/posts/mouse-configurator-reverse-engineering/mm4-config_hu_10b0ab528f988e75.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;The propietary mouse configurator that is used to customize the Mars Gaming MM4 mouse&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;125&#34;
		data-flex-basis=&#34;301px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;After I was done with university, I chose to nuke the Windows partition, which left me with no way of modifying the button mapping or changing the DPI resolution profiles. I tried running the configurator through Wine, but it did not work. It would boot, but it would refuse to communicate with the mouse. I then did the only sensible choice and decided to reverse engineer the configurator tool, or more specifically, the USB communication protocol.&lt;/p&gt;
&lt;h1 id=&#34;reverse-engineering-the-communication-protocol&#34;&gt;Reverse engineering the communication protocol
&lt;/h1&gt;&lt;p&gt;To be able to reverse engineer the communication protocol that the mouse uses, I would firstly need an easy way of intercepting and processing the communication between the computer and the mouse. This proved easy, since Wireshark, our beloved network packet sniffer, can be used to intercept USB communications&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;. I then spent a couple of days using the configurator, tweaking a single parameter, capturing the USB output and analyzing it to find how that tweak was encoded in the wire.&lt;/p&gt;
&lt;p&gt;The mouse configurator seemed to be sending and receiving a dozen or so packets to and from the mouse. For each of the tweaks I made, I saved the packets into a pcap file with the data before and after the tweak. To convert the pcap files into a more manageable file format I wrote a small script in python. This scirpt uses the &lt;code&gt;pyshark&lt;/code&gt; library to open the files, extract the info I wanted and write it out as a plain csv, with the binary data displayed as hexadecimal. I then loaded these csv files into Libreoffice Calc for further processing.&lt;/p&gt;
&lt;p&gt;Having the data before and after the tweak allowed me to very easily see the differences that resulted in the tweak being applied. It was a matter of a game &amp;ldquo;Find the differences&amp;rdquo;, only I have a computer to find them for me. Any information I uncovered from this analysis I wrote down into Ghidra, which has a convenient Data Type Manager which lets you define data types, their structure, size and add explanatory comments to them.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.devcouncil.org/posts/mouse-configurator-reverse-engineering/ghidra-packet.png&#34;
	width=&#34;568&#34;
	height=&#34;701&#34;
	srcset=&#34;https://blog.devcouncil.org/posts/mouse-configurator-reverse-engineering/ghidra-packet_hu_62fc87fb1a2b369e.png 480w, https://blog.devcouncil.org/posts/mouse-configurator-reverse-engineering/ghidra-packet_hu_75d3d36f0efae9f1.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;The packet that assigns actions to each of the buttons of the mouse, as seen in Ghidra&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;81&#34;
		data-flex-basis=&#34;194px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;With this same procedure I managed to reverse engineer around 75% of all the data being sent, and almost all of the exposed features on the configurator tool, with the exception of complex macros&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. I was satisfied with the work I had put in, but all of this would be in vain if I didn&amp;rsquo;t use it to create my own configuration tool.&lt;/p&gt;
&lt;h1 id=&#34;implementing-a-new-driver-in-ratbag&#34;&gt;Implementing a new driver in ratbag
&lt;/h1&gt;&lt;p&gt;I don&amp;rsquo;t need to say this, but creating your own configuration tool from scratch is a very hard task. That&amp;rsquo;s why I chose to implement my findings into the &lt;a class=&#34;link&#34; href=&#34;https://github.com/libratbag/libratbag&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;ratbag&lt;/a&gt; project. Ratbag, plus its frontend &lt;a class=&#34;link&#34; href=&#34;https://github.com/libratbag/piper&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Piper&lt;/a&gt;, are MIT/GPLv2 licensed tools for configuring input devices, chiefly mice. They are, as far as I know, the predilect tool for this kind of task in Linux.&lt;/p&gt;
&lt;p&gt;Figuring my way around the repositories took a couple of days, but seeing how other drivers were implemented helped significantly. Implementing a new driver is a matter of implementing two main components: The &lt;code&gt;probe&lt;/code&gt; component, which obtains the current running configuration of the mouse, and the &lt;code&gt;commit&lt;/code&gt; component, which applies the configuration to the mouse. Implementing the &lt;code&gt;commit&lt;/code&gt; component proved easy, since I simply had to replicate the behavior that I previously reverse engineered. I even made it more efficient by not commiting configuration that hasn&amp;rsquo;t been changed, which the propietary tool does not do.&lt;/p&gt;
&lt;p&gt;I then went ahead implementing the &lt;code&gt;probe&lt;/code&gt; component. There is only a slight problem here. The propietary mouse configurator hardly does any probing. It only probes the device id, likely to confirm that it&amp;rsquo;s a supported device. It does not probe the current configuration of the mouse, such as buttons, LEDs and DPI resolutions. The configuration that shows up when the tool is launched is the one that is saved to disk on the host machine.&lt;/p&gt;
&lt;p&gt;It didn&amp;rsquo;t take long while messing around to adapt the protocol to add this new feature. I analyzed the packet that probes the device id and identified the section that allowed for reading values from the mouse. Luckily, the same technique can be applied to the rest of the configurable values so that they can be read.&lt;/p&gt;
&lt;p&gt;In parallel, I was also doing some changes in the Piper project. I needed to create an svg that resembled the mouse that would serve as the UI. Interestingly, Piper doesn&amp;rsquo;t use svg merely for display. It uses specific attributes to identify the location where to put clickable buttons on the UI, or layers to choose which leads to show on each screen, and which ones to highlight on mouse hover.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.devcouncil.org/posts/mouse-configurator-reverse-engineering/piper-mm4.png&#34;
	width=&#34;1008&#34;
	height=&#34;646&#34;
	srcset=&#34;https://blog.devcouncil.org/posts/mouse-configurator-reverse-engineering/piper-mm4_hu_9a449c99a36ba5dd.png 480w, https://blog.devcouncil.org/posts/mouse-configurator-reverse-engineering/piper-mm4_hu_edc686d8f4d788f1.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;The Mars Gaming MM4 mouse as it appears in Piper&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;156&#34;
		data-flex-basis=&#34;374px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;After I successfully implemented all of the features I considered necessary, I decided to open PRs to &lt;a class=&#34;link&#34; href=&#34;https://github.com/libratbag/piper/pull/692&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Piper&lt;/a&gt; and &lt;a class=&#34;link&#34; href=&#34;https://github.com/libratbag/libratbag/pull/1364&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;libratbag&lt;/a&gt;. After a protracted (by me) review process, both PRs were successfully merged, and will be available in the following release, likely to be v0.18.&lt;/p&gt;
&lt;h1 id=&#34;final-thoughts&#34;&gt;Final thoughts
&lt;/h1&gt;&lt;p&gt;Even though this project was a success, I feel a slight bittersweet aftertaste. I successfully managed to implement everything that I wanted, but what is the likelihood that someone will be using this 8 year-old mouse nowadays, and on linux on top of that? Even I myself don&amp;rsquo;t use the tool that often.&lt;/p&gt;
&lt;p&gt;I am at least glad to be able to have a free and open implementation of the protocol for posterity&amp;rsquo;s sake. At the very least, I hope this post encourages anyone to try the same for their own mice or any other device, either with the specific goal of re-implementing the configuration protocol, or simply exploring the possibilities that the USB protocol can offer.&lt;/p&gt;
&lt;p&gt;And finally, this is a great example as to how free software benefits everyone. I benefit because I can run and modify the program without any restrictions. The project benefits from the contributions, and other users benefit from the collaboration and implementation of new features. This is just a small part of why I love free software.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;The Wireshark USB dissector seems to not be fully implemented. In particular, the USBHID component does not seem to be parsing the GET_REPORT Response, so the response data does not get dissected and displayed neatly. Given this, I attempted to implement my own dissector that would parse the responses into a proper USBHID response packet. I got fairly deep into implementing this, but the usefulness was dwarfed by the effort of implementing and using it, so I did not proceed any further.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;I intentionally chose to forgo reverse engineering the macros. I had never used them, nor was planning to, and it would have added a significant amount of additional work to this process.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
        </item>
        <item>
        <title>Fishing Fantasy, or how to fix a 15 year old game-breaking bug</title>
        <link>https://blog.devcouncil.org/posts/fishing-fantasy-bug-fix/</link>
        <pubDate>Sun, 12 Mar 2023 00:00:00 +0000</pubDate>
        
        <guid>https://blog.devcouncil.org/posts/fishing-fantasy-bug-fix/</guid>
        <description>&lt;img src="https://blog.devcouncil.org/posts/fishing-fantasy-bug-fix/thumbnail.jpg" alt="Featured image of post Fishing Fantasy, or how to fix a 15 year old game-breaking bug" /&gt;&lt;h1 id=&#34;introduction-fishing-fantasy&#34;&gt;Introduction: Fishing Fantasy
&lt;/h1&gt;&lt;p&gt;There are videogames that can make you reexperience it as if it was the first time. For me, one of these is Tomb Raider 3. It is the first videogame I remember playing (or trying to). I am using the word &amp;ldquo;playing&amp;rdquo; a bit loosely here, since I must have been no older than 3, sitting on my dad&amp;rsquo;s lap and rage quitting after the first encounter with an enemy. I could hardly move the character, let alone aim and defeat even the monkeys in the starting area. It was nevertheless very exciting to watch my dad play. The brightest memory I have is watching my dad fight a three-headed dragon in Trajan&amp;rsquo;s Markets while jumping left to right and avoiding deadly fireballs.&lt;/p&gt;
&lt;p&gt;Another game that sits very close to my heart is the main topic of this article. This game is called &amp;ldquo;Fishing Fantasy: Buzzrod&amp;rdquo;, which came out in 2005 for the PS2. It is a cartoonish looking RPG fishing game with focus on exploration and experimentation. You play as Patt Possom, a possum archaeologist striving to be like his renowned archaeologist uncle. While looking through his uncle&amp;rsquo;s books, he finds a note describing an ancient civilization which worshipped fish as messengers of the gods. He decides to go on an expedition to this remote region and figure out the secrets of the ancients.&lt;/p&gt;
&lt;p&gt;The mechanics of this game are simple. You need to catch fish to obtain items to craft lures with which to catch more fish. The game is divided in levels, each one with a specific goal of catching certain types or amounts of fish. Each fish only spawns at specific locations and times of day, and can only be caught with specific lures. And the game does not make it easy on you. It does not give any hint as to their possible location and time of day. My father and I kept a journal with all of our findings, hand-drawn maps of the locations, and which lures can be used to catch each fish.&lt;/p&gt;
&lt;h1 id=&#34;the-unskippable-level&#34;&gt;The unskippable level
&lt;/h1&gt;&lt;p&gt;There is a big catch with this game: The last level is impossible to finish. The level&amp;rsquo;s objective is to catch the legendary Skullcanth fish. This fish can only be caught with the Buzz lure, but to craft it you need the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2× Mysterious Lithograph 1&lt;/li&gt;
&lt;li&gt;2× Mysterious Lithograph 2&lt;/li&gt;
&lt;li&gt;3× Mysterious Lithograph 3&lt;/li&gt;
&lt;li&gt;1× Big Fallen Leaf&lt;/li&gt;
&lt;li&gt;1× Honey&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These lithographs are given after completing each level, of which there are 6 before the final stage, but the lure requires 7 of them. Therefore, this lure is impossible to craft, making Skullcanth impossible to catch and making the level impossible to complete.&lt;/p&gt;
&lt;video width=&#34;100%&#34; autoplay=&#34;true&#34; loop=&#34;true&#34;&gt;
	&lt;source src=&#34;recipe_before.webm&#34; type=&#34;video/webm&#34;/&gt;
	&lt;p&gt;Recipe menu with Buzz selected, showing one missing crafting item&lt;/p&gt;
&lt;/video&gt;
&lt;p&gt;We must have spent weeks with my dad trying to figure out where to get the missing lithograph, revisiting all levels, catching each fish dozens of times, but in the end we gave up. 15 years later, I decided to replay this game on an emulator for nostalgia&amp;rsquo;s sake. When faced with the same bug, I chose not to despair, to go further and investigate.&lt;/p&gt;
&lt;h1 id=&#34;reading-hex-and-finding-the-buggy-byte&#34;&gt;Reading hex and finding the buggy byte
&lt;/h1&gt;&lt;p&gt;When faced with such a task, your first instinct should be to search online for similar experiences. Due to not being an incredibly popular game, there were very few hits. Most of them were complaining about this exact same issue. There was exactly one comment that mentioned overcoming this bug by modifying memory card data. This was my first attempt, but making sense of memory card data layout proved too hard. I found out after the fact that my emulator was compressing the saves in the virtual memory card, the likely culprit of my confusion when analyzing the save games.&lt;/p&gt;
&lt;p&gt;Another avenue that opened up was trying to modify the game binary itself. This is evidently not possible in a real PS2, but given modern emulator technology, it becomes a trivial task. As such I was ready for diving in with &lt;a class=&#34;link&#34; href=&#34;https://github.com/afrantzis/bless&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Bless&lt;/a&gt; into the hexadecimal ocean to find my legendary bugfix.&lt;/p&gt;
&lt;p&gt;Going in I had the goal of finding the location where the recipe data is located. I assumed that all of the properties for a given lure would be defined together, including its name, properties, such as taste, light or smell, as well as its recipe. The lure that we need to craft is called Buzz, so I searched for that straight away. The name of the lure is a bit unfortunate, given that the game is called Buzzrod, which produced hundreds of erroneous hits.&lt;/p&gt;
&lt;p&gt;After skipping the first few results, I seemed to find my objective. A region of the binary with the names and descriptions of lures separated by a bunch of binary data. It was not immediately clear where each lure ended and the next one began. For this I scrolled up to the first entry of this list to find the pattern which the list follows. It appeared that each entry in the list started with the byte pattern &lt;code&gt;0xF8FFFF7F&lt;/code&gt;, after which followed the name of the lure. This pattern seemed to hold at the end of the list, so I took it as confirmation.&lt;/p&gt;
&lt;p&gt;The objective now was to find the recipe within this 368 byte long region of memory. We know that the recipe requires 2 items of a type, 2 more of another type, 3 more of another, plus 1 more of 2 different types. The task proved easy. The sequence &lt;code&gt;26 01 26 01 27 01 27 01 28 01 28 01 28 01 2B 01 2C 01&lt;/code&gt; immediately lit up. We can deduce that this lure requires the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2× &lt;code&gt;Item(id=0x26)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;2× &lt;code&gt;Item(id=0x27)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;3× &lt;code&gt;Item(id=0x28)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;1× &lt;code&gt;Item(id=0x2B)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;1× &lt;code&gt;Item(id=0x2C)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We need to modify this sequence so that we only require 2 items of id &lt;code&gt;0x28&lt;/code&gt;, while not breaking address references. As easy as deleting one of the &lt;code&gt;28 01&lt;/code&gt; and appending &lt;code&gt;00 00&lt;/code&gt; at the end of the recipe, right after &lt;code&gt;2C 01&lt;/code&gt;. If all you came here for is to fix your .bin file, you can stop reading now.&lt;/p&gt;
&lt;p&gt;We are now ready to boot up the game again and see what happens. We head straight to the lure crafting menu, to find that our lure is ready to craft!&lt;/p&gt;
&lt;video width=&#34;100%&#34; autoplay=&#34;true&#34; loop=&#34;true&#34;&gt;
	&lt;source src=&#34;craft_buzz.webm&#34; type=&#34;video/webm&#34;/&gt;
	&lt;p&gt;Crafting the lure Buzz&lt;/p&gt;
&lt;/video&gt;
&lt;p&gt;With our new lure at our disposal, we set out to catch the legendary Skullcanth. Since a picture is worth a thousand words, the following 4:30 minute long video at 30 fps is worth over 8 million words. Enjoy:&lt;/p&gt;
&lt;div class=&#34;video-wrapper&#34;&gt;
    &lt;iframe loading=&#34;lazy&#34; 
            src=&#34;https://www.youtube.com/embed/cxIDwTS2Whg&#34; 
            allowfullscreen 
            title=&#34;YouTube Video&#34;
    &gt;
    &lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;Before sending us back to the start menu, the game gives us a (not so) cryptic message.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Congratulations.&lt;/p&gt;
&lt;p&gt;Something good might happen if you save the current state.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Sounds very intriguing. What happens if we load this new save?&lt;/p&gt;
&lt;h1 id=&#34;beyond-skullcanth&#34;&gt;Beyond Skullcanth
&lt;/h1&gt;&lt;p&gt;After loading this new save game, a new cutscene is shown, and we find ourselves in The Lost Ruins, the main lobby and warp hub of the game.&lt;/p&gt;
&lt;div class=&#34;video-wrapper&#34;&gt;
    &lt;iframe loading=&#34;lazy&#34; 
            src=&#34;https://www.youtube.com/embed/Q_gh32dUx-Y&#34; 
            allowfullscreen 
            title=&#34;YouTube Video&#34;
    &gt;
    &lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;The very first thing that we notice is that the warp gates, which used to be pale blue, turned into a lightsaber red color. It doesn&amp;rsquo;t take long to find out that we&amp;rsquo;ve been rewarded with the monumental task of catching the legendary fish of each stage. What follows is, to my knowledge, a playlist of never seen before legendary fishes being caught.&lt;/p&gt;
&lt;div class=&#34;video-wrapper&#34;&gt;
	&lt;iframe loading=&#34;lazy&#34;
	        src=&#34;https://www.youtube-nocookie.com/embed/videoseries?list=PLFEwFuT2MpC9l8htP6PLx3hZnJz78k1Ds&#34;
	        allowfullscreen
	        title=&#34;YouTube Playlist&#34;
	&gt;
	&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;After catching Opa, the last legendary fish, we are rewarded with one last cutscene, altogether with the final progress screen. The game suggests again that something good might happen if we save the current state. We load the new save again and are greeted by a new cutscene. However, this is the end of the novelty, since we are sent back to The Lost Ruins with the same objective we had earlier: Catch every legendary fish. We can take this as an opportunity for collecting any leftover items or crafting the last few lures, as well as experimenting with the different lures and fish.&lt;/p&gt;
&lt;h1 id=&#34;making-sense-of-hex-data&#34;&gt;Making sense of hex data
&lt;/h1&gt;&lt;p&gt;My desire to fully understand the game did not stop here though. I had the full binary description of all the lures, but it was mostly unintelligible. It is likely that the same kind of data exists for the different fish and items. Might these values hold the key to understanding the affinity of each fish for specific lures? What else could I uncover in these values?&lt;/p&gt;
&lt;p&gt;The task of finding the properties for the fish and items proved as easy as it it was to find the lures. A quick search by name and I easily found the range of bytes that corresponded to their properties. After I found these binary ranges I developed &lt;a class=&#34;link&#34; href=&#34;https://github.com/Qjammer/fishing-fantasy-data-extruder&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a small script in python&lt;/a&gt; to split them and analyze the contents with the &lt;code&gt;struct&lt;/code&gt; package. Some fields were mostly self-explanatory. Each item&amp;rsquo;s name and description were encoded in plain ASCII as a fixed length string. We also know where to find the recipe. Apart from these, though, the rest looks like random bytes.&lt;/p&gt;
&lt;p&gt;After exploring the data a bit more using Bless, we can already identify certain patterns in some values. For example, the values between &lt;code&gt;0x3F&lt;/code&gt; and &lt;code&gt;0x41&lt;/code&gt; can signify a floating point number, such as &lt;code&gt;CC CC 4C 3F&lt;/code&gt;, which represents (in little endian) the value 0.8, while &lt;code&gt;00 00 70 41&lt;/code&gt; is equal to 15.0. We won&amp;rsquo;t get much further than that by simply examining the structure, though. We have to put on our experimentation hats, modify some values and see how they affect the behavior of each item in the game. With this procedure, I managed to decypher the greatest majority of values, such as fish lure preferences or item drops, as well as moderately fun facts and images, such as the weight range being encoded in hectograms, or a tiny but very ferocious Red Plate.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.devcouncil.org/posts/fishing-fantasy-bug-fix/TinyRedPlate.png&#34;
	width=&#34;2560&#34;
	height=&#34;1440&#34;
	srcset=&#34;https://blog.devcouncil.org/posts/fishing-fantasy-bug-fix/TinyRedPlate_hu_8a6da125b875bd64.png 480w, https://blog.devcouncil.org/posts/fishing-fantasy-bug-fix/TinyRedPlate_hu_c544c23b753f88f8.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;A tiny Red Plate trying to eat a lure bigger than itself&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I could have called it quits here, but I was in the process of creating &lt;a class=&#34;link&#34; href=&#34;https://fishingfantasy.fandom.com&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a wikia for this game&lt;/a&gt;, and there was one critical thing missing: Item icons. I had to get the original icons used for each of the in-game items. I obviously searched online for any traces of these assets, but all I found was &lt;a class=&#34;link&#34; href=&#34;http://www.s-f.co.jp/soft/ps2/buzzrod/index.htm&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;the original website of the game developer&lt;/a&gt;. There are some item icons in there; unfortunately, not all of them.&lt;/p&gt;
&lt;p&gt;I decided to jump back into the binary to find them. Luckily, the binary image was in .iso format, which can be easily extracted into several files and folders. That&amp;rsquo;s where my luck ran out. All I was left with is a bunch of files with unknown extensions, such as &lt;code&gt;.BD&lt;/code&gt;, &lt;code&gt;.SD&lt;/code&gt;, &lt;code&gt;.PAC&lt;/code&gt;, etc, and no way of opening them. After looking through the generated files, I concluded that the image items must be stored in the file named &lt;code&gt;CDROM.PAC&lt;/code&gt; for two reasons. Firstly, it was the biggest file in the archive, and secondly, the rest of the files were adequately grouped in folders with meaningful names, and none of them referenced any image, picture, or texture keywords.&lt;/p&gt;
&lt;p&gt;I, as one would expect, opened this file in a hex editor, and what I found would not surprise you. It&amp;rsquo;s an archive file. It started with the magic bytes &lt;code&gt;PACK&lt;/code&gt; and a list of filenames. I searched online for a long while, but unfortunately I found nothing resembling it, nor anything that claimed to open this file format.&lt;/p&gt;
&lt;h1 id=&#34;writing-your-own-archiving-format&#34;&gt;Writing your own archiving format
&lt;/h1&gt;&lt;p&gt;Again, I was left with no choice but to write my own archiving utility. Surprisingly and luckily for me, I&amp;rsquo;m not the first lunatic to have had this need. I found this little project called &lt;a class=&#34;link&#34; href=&#34;https://aluigi.altervista.org/quickbms.htm&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;QuickBMS&lt;/a&gt;. QuickBMS is a GPLv2 licensed &amp;ldquo;universal script based files extractor and reimporter&amp;rdquo;.  It has its own domain specific language to describe the structure of the archiving format, including endianness and byte alignment, which it uses to unpack a given file archive.&lt;/p&gt;
&lt;p&gt;After several trial and error iterations, I managed to write &lt;a class=&#34;link&#34; href=&#34;https://github.com/Qjammer/fishing-fantasy-data-extruder/blob/main/PACK.bms&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a script&lt;/a&gt; that made QuickBMS produce a couple thousand file-looking things on my folder.  Most of these files had fairly cryptic names consisting of 3 letters followed by 4 numbers, such as &lt;code&gt;CDB_0120.TXL&lt;/code&gt;. A few of them, though, were very understandable. Some of them even familiar, such as &lt;code&gt;lure.info&lt;/code&gt; and &lt;code&gt;fish.info&lt;/code&gt;, which contained the information we analyzed earlier.&lt;/p&gt;
&lt;p&gt;After perusing this catalog and inspecting a few files, I realized that all files with the extension &lt;code&gt;.TXL&lt;/code&gt; were archives with the exact same format as &lt;code&gt;CDROM.PAC&lt;/code&gt;. One of these files, coincidentally, was called &lt;code&gt;ITEM.TXL&lt;/code&gt;. Could it contain my precious item icons? I ran the QuickBMS script against all of these files and what I found inside left me with mixed feelings. On the one hand, I was definitely getting closer to my goal. Inside &lt;code&gt;ITEM.TXL&lt;/code&gt; lay a list of files titled &lt;code&gt;Mat01.tm2&lt;/code&gt;, clearly referencing the lure construction materials within the game. On the other hand, I had no clue what the extension &lt;code&gt;.tm2&lt;/code&gt; could possibly mean.&lt;/p&gt;
&lt;p&gt;Searching online led me to conclude that this is a propietary format called &lt;code&gt;TIM2&lt;/code&gt; created by Sony for the PlayStation 2. Unfortunately, this format is not widely used outside of its designated purpose, so the tooling is scarce. Searching for programs that could open such file format showed only one: XnViewMP, a freeware image organizer. Why that was the only known program that can handle these images we&amp;rsquo;ll never know. I proceeded to install this program and it did indeed open these files without a hitch. It only had some trouble with transparencies, but that can be understood given the rarity of this format.&lt;/p&gt;
&lt;p&gt;I could have stopped there. Simply load each image into the program, export them as pngs, fiddle around with transparencies and be done with it. I obviously didn&amp;rsquo;t stop there.&lt;/p&gt;
&lt;h1 id=&#34;implementing-a-new-format-in-imagemagick&#34;&gt;Implementing a new format in ImageMagick
&lt;/h1&gt;&lt;p&gt;I set out to fully understand this file format. How can such a format be almost forgotten about? I searched online for a specification of the format and, to my surprise, I actually found some interesting stuff. I found &lt;a class=&#34;link&#34; href=&#34;http://wiki.xentax.com/index.php/TM2_TIM2&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a fairly complete specification of the format&lt;/a&gt; in a wiki called XeNTaX, dedicated to preserving game file formats, as well as &lt;a class=&#34;link&#34; href=&#34;https://tcrf.net/User:Kojin/TIM2_Information&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;another fairly complete spec&lt;/a&gt; in another wiki called &amp;ldquo;The Cutting Room Floor&amp;rdquo;, dedicated to unearthing and researching unused and cut content from videogames. It feels encouraging to see that I&amp;rsquo;m not the only one that took the time to uncover some secrets and preserve some history. Plus, what would the internet be without these hyper-specific communities? I also found &lt;a class=&#34;link&#34; href=&#34;https://flandre-scarlet.moe/blog/352/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a very detailed post in japanese&lt;/a&gt; and &lt;a class=&#34;link&#34; href=&#34;https://nextstage.ru/threads/tim2-tekstury.1063/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a forum post in russian&lt;/a&gt; with some more details, plus some more webpages which I&amp;rsquo;ll leave below in the references.&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;But that was not all that I found. It would appear that somebody leaked &lt;a class=&#34;link&#34; href=&#34;https://github.com/rinrin-/crass/blob/master/cui/AFS/tim2.cpp&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;some kind of internal tool on github&lt;/a&gt; that was used for loading and handling TIM2 images. It contains a copyright notice for &amp;ldquo;2002 Sony Computer Entertainment Inc.&amp;rdquo;, and the files are prefixed with &amp;ldquo;SCE CONFIDENTIAL&amp;rdquo;. The comments, once converted to EUC-JP encoding, seem to be coherent and insightful, which leads me to believe that it might be Sony&amp;rsquo;s original source code. Nevertheless, I chose to proceed without the aforementioned leaked specification for one simple reason: it would be copyright infringement.&lt;/p&gt;
&lt;p&gt;After reading and re-reading all these resources many times, I began to have some idea as to how this image format was designed. Luckily for me, it was a fairly simple format, without any compression like png or jpeg.&lt;/p&gt;
&lt;p&gt;This format uses a technique called &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Indexed_color&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;indexed color&lt;/a&gt;. The binary is divided into two parts. Firstly, the CLUT (Color LookUp Table) with the palette of the image, and secondly, the list of pixels, each referencing one of the entries in this CLUT. Additionally, the CLUT can be stored in two different CSM (CLUT Storage Mode). On CSM1 the CLUT is shuffled, so it needs to be deshuffled. The reason it is shuffled appears to be related to memory bus layout of the PS2&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;. The long and short of it is that the 2nd and 3rd block of each page in the CLUT must be swapped.&lt;/p&gt;
&lt;p&gt;After gathering all of this documentation, I set out to write my own decoder for the TIM2 format in ImageMagick. I quickly found out that ImageMagick already supports the &lt;code&gt;TIM&lt;/code&gt; image format, the predecessor of &lt;code&gt;TIM2&lt;/code&gt;, so I used it as a template for implementing my own. After many hours of figuring out how the ImageMagick API worked, I managed to produce the following image:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.devcouncil.org/posts/fishing-fantasy-bug-fix/Mat41.tm2.png&#34;
	width=&#34;64&#34;
	height=&#34;64&#34;
	srcset=&#34;https://blog.devcouncil.org/posts/fishing-fantasy-bug-fix/Mat41.tm2_hu_fbfff012e41a400.png 480w, https://blog.devcouncil.org/posts/fishing-fantasy-bug-fix/Mat41.tm2_hu_d83d292985ce9c64.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;100&#34;
		data-flex-basis=&#34;240px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s it! I managed to extract the image icons that I was looking for! I immediately uploaded them into the wiki I was building. At the same time, &lt;a class=&#34;link&#34; href=&#34;https://github.com/ImageMagick/ImageMagick/pull/1571&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;I opened a PR&lt;/a&gt; for ImageMagick to include my &lt;code&gt;TIM2&lt;/code&gt; image decoder. It took a couple of weeks for my PR to be accepted, and it was finally included in ImageMagick 7.0.8. It makes me proud to say that running &lt;code&gt;magick identify -list format&lt;/code&gt; now shows &lt;code&gt;TM2* TIM2      r--   PS2 TIM2&lt;/code&gt; among the supported formats.&lt;/p&gt;
&lt;h1 id=&#34;addendum&#34;&gt;Addendum
&lt;/h1&gt;&lt;p&gt;It seems I may not have been the first to post proof of fixing this bug. I later found out that someone posted &lt;a class=&#34;link&#34; href=&#34;https://youtu.be/53QSbCzbRL4&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;videos&lt;/a&gt; of some of the Legendary fish being caught and even &lt;a class=&#34;link&#34; href=&#34;https://youtu.be/K_rI_IhbbMA&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;finishing the game&lt;/a&gt; on YouTube. The author mentions on the comments using a modified save game they found online, so I can still take credit for being the first to document how to fix the actual bug, instead of using external workarounds.&lt;/p&gt;
&lt;p&gt;Additionally, I found out there exists a version of the game made specifically for the japanese market, titled &amp;ldquo;BuzzRod: Fishing Fantasy&amp;rdquo;. I found out that this version of the game is not bugged, as shown in &lt;a class=&#34;link&#34; href=&#34;https://youtu.be/2kIeh3x7E5s?t=7716&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a video&lt;/a&gt; by a japanese youtuber. Either it isn&amp;rsquo;t bugged, or he fixed it as well, which sounds unlikely.&lt;/p&gt;
&lt;p&gt;Regarding the TIM2 encoder, there are still some weird issues about it. When I was implementing it, I was exclusively trying to convert from .tm2 to .png, as that was the format I wanted to use in the wiki. I later found out that for some odd reason, converting to other formats does not work as well as it does for .png. For example, converting to .gif does not preserve the transparency, and converting to .jpg produces an almost completely black image.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://psi-rockin.github.io/ps2tek/#gstextures&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://psi-rockin.github.io/ps2tek/#gstextures&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;http://web.archive.org/web/20190605163250/https://assemblergames.com/threads/hacking-ps2-game-files-extracting-images.53696/page-2&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://web.archive.org/web/20190605163250/https://assemblergames.com/threads/hacking-ps2-game-files-extracting-images.53696/page-2&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;http://ps2linux.no-ip.info/playstation2-linux.com/download/ezswizzle/TextureSwizzling.pdf&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://ps2linux.no-ip.info/playstation2-linux.com/download/ezswizzle/TextureSwizzling.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
        </item>
        
    </channel>
</rss>
