The Free Software Foundation has a list of the “four essential freedoms” that they consider paramount to free software; this is the second.
The freedom to study how the program works, and change it so it does your computing as you wish (freedom 1). Access to the source code is a precondition for this.
In theory, this sounds incredible. You mean I can just take a piece of software that does 95% of what I want and then add the other 5% myself? Sign me the FUCK up.
I just wish it was that simple. ¯\_(ツ)_/¯
In the 2000s, there was a lot of talk about "Tivoisation" — the practice of releasing devices that ran FOSS but which you couldn't actually upload modified code to. This led to the release of the GNU GPL version 3 in 2007, which added clauses prohibiting this practice. I think there's a more insidious issue today, wherein software has grown so complex that we can't easily do it on our own machines, even if we run a completely libre environment.
Let's put it to the test. I’m one of those weird people who enjoys using vim keybindings to edit text. I’d love to have that ability across all text fields on my desktop. That should be easy if I’m running a FOSS desktop environment, right?
… Right?
I’m generally a KDE enjoyer, so I guess I should begin by grabbing the source code for Qt. Let’s pretend that I’ve made some nice changes to teach the magic of hjkl
to QLineEdit and friends. Now I’d like to get it running.
I’ll figure out how my distro builds packages and I’ll try and use the same tooling to build something compatible, and install it, replacing the supplied version. So far so good! Except for the apps that ship their own version of Qt, so I guess I’ve got to track down the source code for the same version, apply my patches, build it using the same options, and shove the .so files into the right place.
Finally, thanks to the magic of FOSS, I’ve got the experience I’ve always wanted. Until a week later, when I install updates, and now half of my applications won’t run because the new versions are linked against a newer version of Qt.
-headdesk-
I should note that this article isn’t meant to be a dig at free software — there are excellent examples of FOSS that offer rich, user-friendly customisation, like Firefox extensions.
Rather, I want to highlight that the ability to edit the source code doesn't always correlate 1:1 with the ability to adapt a...
]]>Wherein I finally make the multiplayer mode in SEGA SPLASH! GOLF playable (more or less), and release the source code to my custom server.
Welcome back to the final instalment of this absurd series about reverse-engineering and reviving a long-dead MMO. A quick recap:
In part 1, "They Made A Golf MMO With Sonic In it (Real!) (Not Clickbait!) (Only A Bit)", I dug into the game for the first time and managed to get it to the main menu. In part 2, "Reviving Sega's forgotten golf MMO after 14 years", I got the single-player Practice Mode working and put the game's entire item catalogue into the shop.
As cool as this is, I think I've objectively done a pretty terrible job so far. "MMO" stands for Massively Multiplayer Online game. I've made the game connect to a server, so you can say it's online, but I've completely failed at the massively multiplayer bit. That's a 33% success rate. I'd like to get a passing grade for this project.
Furthermore, the Practice Mode is extremely limited and you can't experience most of the game's content that way. It'd be a real shame to cut it off here before I fix the other bits.
Oh, by the way, if you're not interested in reading the 39 pages of fluff and just want to see something cool, scroll to the bottom of the page and there's a nice demo video.
First off - what do we need to implement? SEGA SPLASH! GOLF includes a number of cross-player online interactions which we can summarise as follows:
It'd be cool to eventually get all of these working, but we need to prioritise a little bit.
As I mentioned at the end of Part 2, I want to actually get something usable out of this project before I lose steam and/or run out of free time, and that means ignoring my perfectionist streak and setting some boundaries.
I'm not aiming to write a production-quality game server that could handle hundreds or thousands of players. I'm aiming to reimplement enough of the game's interactions so that people can at least experience what it had to offer, and document them well enough that someone else could extend it if the need ever...
]]>Wherein I recover enough of SEGA SPLASH! GOLF to make the single-player Practice Mode work, enable the shops and character customisation, and even fix a couple of bugs along the way.
Let's recap for a moment. In part 1, "They Made A Golf MMO With Sonic In it (Real!) (Not Clickbait!) (Only A Bit)"...
We need to go further. We have the technology.
But first, I'd like to tell you about our spons-
Until now, I've been working with just game version 0,956,4,12, which is a client that was given to me by biggestsonicfan - it came from their personal archives, since they actually played the game back when it was live. It turns out they had one more useful thing up their sleeves though!
The game was released in April 2008, but there was actually a closed beta phase before that, and they gave me an archived copy of the client. It's missing features, but it does have some interesting differences...
This version of the game isn't packed with ASProtect, which makes it easier to analyse. The code for debug logging also looks different.
In the build I'm trying to revive, each debug call is expanded by the compiler into a bunch of function calls:
Aren't those empty strings suspicious...? Well, in the closed beta, they actually represent the function name and the line number. I'd wager that the original code looks something like this:
#ifdef BETA
#define DEBUG_LOG(...) \
logger->writeTimestamp(); \
logger->writeTextW(L" "); \
logger->writeTextW(__FUNCTION__); \
logger->writeFormat(L"(%4d)", __line__); \
logger->writeTextW(L" "); \
logger->writeFormat(__VA_ARGS__); \
logger->writeTextW(L"\n");
#else
#define DEBUG_LOG(...) \
logger->writeTimestamp(); \
logger->writeTextW(L" "); \
logger->writeTextW(L""); \
logger->writeFormat(L""); \
logger->writeTextW(L" "); \
logger->writeFormat(__VA_ARGS__); \
logger->writeTextW(L"\n");
#endif
So, for any log message that exists in this build of the game, I know the class name and function name that generated it. All of the packet handlers have names like Circuit::func_ACK_CHG_MODE
and Circuit::func_SEND_TITLES
.
The function I showed in Part 1 for handling the RoomStat structure is called PartyInfo::ConvertFrom
... which is actually kinda funny, because there's several different PartyInfo methods that all accept a structure and read some data from it, and they're all called PartyInfo::ConvertFrom
. Shoutout to function overloading.
Anyway, these logs are how I was able to confirm the names of all the Task virtual methods, as well as some other things I mentioned in Part 1 like the name of the cGUIMan
class and the CTopTask::InitColorDialog()
method. All of these small bits of...
I got nerdsniped into reviving SEGA SPLASH! GOLF, a long-forgotten MMO that you've probably never heard of - I certainly hadn't.
Software preservation is a pretty hot topic these days. Everybody gets frustrated, understandably, when games get pulled from online storefronts or those storefronts close down. A recent report from the Video Game History Foundation estimates that "87% of classic games are not in release"; that's dire.
"I'll just download a ROM!", you might say. Sure. That's great for offline games... but what about anything that requires a server?
One of the earliest examples of this issue is Nintendo's Satellaview, an accessory for the SNES that received a bunch of exclusive downloadable games via a satellite link. Most of this content is lost to time, except for what the community has managed to recover from the cached data on memory packs.
However, MMOs might just be one of the hardest hit genres. Let's dive into one!
The 2000s had a glut of free-to-play MMORPGs that all seemed to be pulled out of the same playbook:
I'd never heard of SEGA SPLASH! GOLF before, but I was encouraged to look into it by biggestsonicfan, who supplied me with a copy of the game client.
According to the page on Sega Retro, SSG was released in 2008 in Japan, and shut down in February 2009 after less than 10 months. I guess that explains why I'd never heard of it - that's also an impressively short amount of time to keep a game running.
Anyway, I've got the game... what next? Well, we'll need to figure out how it works, and that means getting past the various layers of security on the game. There's also the added challenge of figuring out how the protocol works, with no existing servers or packet captures to use as a guide.
You might ask: "How much faff can there be on a game from 15 years ago that didn't even make it through its first year?"
Online games have been rife with cheating forever, in many forms. Shooters get wallhacks (that allow you to e.g. see players behind walls) and aimbots. Fall Guys requires Easy Anti-Cheat so that you can't just use memory hacks to double your speed. Hell, even the high score leaderboards for the jump-rope minigame in Super Mario Odyssey are full of fake scores.
The ideal way to thwart this is by having the server be authoritative, but that's not always easy - especially when timing is concerned. Imagine a version of Fall Guys where when you press the jump button, the server has to check whether you're allowed to jump before you can do it. The latency involved would make it unplayable!
So the only alternative is for...
]]>I was encouraged to try running NixOS on my server (the one that hosts this website!), and I decided to give it a shot. But... how do I move 7+ years worth of services from Arch to one of the weirdest Linux distros out there, with no prior experience?
As of April 2023, I've been running some form of VPS for almost a decade and a half, and slowly learning various sysadmin-y skills.
My first one ran Ubuntu 8.04 LTS, which somehow survived for far too long without getting popped.
In 2015, I moved to RamNode and tried running FreeBSD for a bit, which was fun until I ran into some weird IPv6 issue which seemed to be caused by an aspect of RamNode's setup that I've long since forgotten. I needed functioning v6 for my IRC bouncer to work properly, so I started up a new one running Arch Linux.
$ head /var/log/pacman.log
[2015-12-09 19:37] [PACMAN] Running 'pacman -r /mnt -Sy --cachedir=/mnt/var/cache/pacman/pkg --noconfirm base'
[2015-12-09 19:37] [PACMAN] synchronizing package lists
[2015-12-09 19:38] [ALPM] transaction started
[2015-12-09 19:38] [ALPM] installed linux-api-headers (4.1.4-1)
[2015-12-09 19:38] [ALPM] installed tzdata (2015g-1)
[2015-12-09 19:38] [ALPM] installed iana-etc (20151016-1)
[2015-12-09 19:38] [ALPM] installed filesystem (2015.09-1)
[2015-12-09 19:38] [ALPM] installed glibc (2.22-3)
[2015-12-09 19:38] [ALPM] installed gcc-libs (5.2.0-2)
[2015-12-09 19:38] [ALPM] installed ncurses (6.0-3)
Keeping an Arch-based server functioning for over 7 years is probably impressive, but I felt like I was due for an upgrade. RamNode have long since moved to OpenStack, and this box is on their "legacy SolusVM system" - how long would it be until they get rid of it and force me to migrate?
I also wanted to try setting up a Mastodon instance, but I thought that the 2GB RAM and the 40GB storage space might be a little limiting. I don't know exactly what CPU they're running on these hosts, as their KVM configuration hides that, but I also suspected that a VPS purchased in 2023 might perform better than one purchased in 2015 and now running on a legacy platform.
$ head /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 13
model name : QEMU Virtual CPU version (cpu64-rhel6)
stepping : 3
microcode : 0x1
cpu MHz : 2399.996
cache size : 4096 KB
physical id : 0
I'm not proud of this, but I never really learned the right way to do system administration - I usually just got stuff to work and then said "ok, I'm leaving it there". This bit me every once in a while, but I always had more interesting things to do with my time.
My server runs all the following services:
Wherein I run classic Mac command-line development tools on a modern computer, using Rust, Unicorn Engine and a pile of hacks.
I've been poking on-and-off at the classic Mac version of Yoot Tower, an underrated simulation game. I've wanted to try my hand at decompiling it, but to do that, I need a comparable compiler.
I won't talk too much about the game here because I would like to write another post about it at some point, but to cut a long story short, it appears to be compiled using Metrowerks CodeWarrior Pro 1 and the Metrowerks PowerPlant library from Pro 2.
These tools run okay in an emulated Mac OS environment using QEMU (except for the debugger), but it's not the most pleasant experience.
Getting files in and out of QEMU requires faffing about with networking, and editing code in an IDE from 1998 is cute but rather impractical for somebody used to VSCode and Neovim. There's also a strange issue where the mouse cursor occasionally jumps to the corner of the screen. There's fixes and workarounds for these issues, but it would be a lot nicer if I could just use my standard text editor outside the emulator.
With GameCube/Wii nonsense, I can run the command-line CodeWarrior compiler on a modern system very easily - it's a 32-bit Windows executable that runs natively under practically any Windows, or in WINE on Linux and Mac.
Unfortunately, the same isn't true here. Macintosh Garden has a Windows disc image for CW Pro 1 which supports cross-compilation, but Metrowerks only saw fit to support building code for 68K Macs from it, and Yoot Tower is PowerPC.
There was still hope, though. The CodeWarrior Reference CD contained documentation for a command-line compiler, which I spent an embarrassingly long time trying to find. It turns out it's included as part of their MPW package.
MPW is the Macintosh Programmer's Workshop, a rather strange tool that represents 80s Apple's take on a combined IDE and shell. You get a persistent document you can enter commands into, and you execute one by placing the cursor on the line and pressing ⌘-Enter - with the output being added to the document underneath.
All of the tools I needed could be accessed via MPW. Could I get these to run externally somehow?
There's an existing project on GitHub (ksherlock/mpw) which does this, but only for 68K executables, so that wouldn't do the job for me. It's definitely possible, though... am I masochistic enough to try and implement my own? (Spoiler: yes)
I've never touched any form of classic Mac development before, so this is a bit of an adventure. Here's an introduction to the platform just so you know what we're dealing with.
When you think of a Mac today, what comes to mind is probably Mac OS X macOS - a Unix-like system built on top of the XNU kernel. It's got lots of proprietary Apple libraries on top...
Wherein I investigate New Super Mario Bros. Wii, use Hashcat to help me recover symbols from the Nvidia Shield port, and go on a bunch of tangents about the other Nintendo games that use the same engine.
I've been poking at the NSMB series for a long time, starting with the level editor I wrote for the original DS game in 2007, and then re-wrote and open-sourced. When the Wii version was released in 2009, I built Reggie! Level Editor for it, and I subsequently spent a few years reverse-engineering the game engine while working on the Newer Super Mario Bros. Wii mod.
Nintendo has a long tradition of shipping games with interesting leftovers. Many first-party GameCube games came with .map files produced by the linker, telling you the name and address of every symbol in the executable. This was less common on the Wii, but they still sent out a few titles with un-stripped .sel files (used by their bargain-basement shared library system) that effectively gave us the same info. They even made the same mistake on the Switch; multiple versions of Splatoon 2 included full symbols.
They've never done this for any of the New Super Mario Bros. games, though. We don't know if there's an official name for this engine, but we've found the following titles so far that all use it:
This cross-pollination of code has some fun effects. The DS games all share the same crash debug screen. The single-purpose "Save Data Update Channel" for Skyward Sword includes random pieces of AC: City Folk.
I've researched NSMBW heavily, and built a ton of knowledge about the game engine. It always irked me though that I had very few official names for aspects of the engine. The state machine system in NSMBW gave us the names for classes that used it, since the binary included a plaintext name for every state (like daYoshi_c::StateID_Jump
). I also had some names for engine classes, since City Folk and SM64DS were both compiled with RTTI (runtime type information) enabled.
We did have full symbols for the Zelda titles on the GameCube. Both Wind Waker and Twilight Princess are based off what appeared to be a predecessor to the engine in NSMB, sharing many of its concepts and even the cryptic naming conventions that led to functions like fpcLyIt_OnlyHereLY
and mDoDvdThd_param_c::addition
.
They're not the same, though. One major example is the actor/process system: in WW/TP, each actor/process has a table of function pointers that has to be awkwardly passed around. In the NSMB iteration, these are just virtual functions on the fBase_c
class which can be overridden by subclasses as necessary.
I'd lost hope that Nintendo would ever leak symbols for NSMBW...
]]>If you're not aware of AI Dungeon, it's a service that they describe as an "AI generated text adventure". You input text, and the massive model behind the scenes figures out what to say.
Modern 'artificial intelligence' models like GPT-2 and GPT-3 are pretty impressive in their ability to write sensible-looking text and generate new things. We've come a long way from the days of IRC bots that would use Markov chains to string together bits of sentences.
Occasionally, I see posts on Twitter that are along the lines of "I made an AI generate this article" or "I made a bot watch 1000 hours of X and then write Y". I'm pretty sure that almost every example I've seen of the latter is complete satire. There are folk who do things with actual AI, like Botnik, or the various Twitter bots that post tweets generated by GPT-2 which parody other popular accounts, but to the best of my knowledge, the stuff they've published still involves heavy manual curation.
I was thinking about them this morning, and it led me to wonder - how well can these do without any curation? AI Dungeon is one of the most accessible ways to play with modern AI models; you don't have to faff about with setting anything up, and you can basically type in any text you want.
I dug up my dusty account and started a "custom adventure". AI Dungeon suggests that you begin with a couple of sentences to describe who the protagonist is and what scenario they are in.
I set myself a few simple rules:
The result is as follows. I was originally just going to post this on Twitter, but screenshots of text aren't accessible and I ended up with too much to fit in the 4 images allowed for a single tweet anyway. Everything I typed is in bold blue text. I've adjusted the spacing to make the text more readable and I've added commentary/notes, but it's entirely unedited otherwise.
I decided to go with a mostly realistic scenario - I've been in this situation before, but as a human.
]]>You are an anthropomorphic dog standing in...
Anybody who used GeoCities in the early 2000s probably remembers using PageBuilder, the strange Java drag-and-drop interface that you would launch from your browser. I wanted to try it out again, but GeoCities is long gone. That's not stopping me, though...
Usually, the Wayback Machine does a pretty good job at archiving websites. It's great for static content, but anything with server-side interactivity falls flat. You can look at the GeoCities marketing material all you want, and it'll even show you an archived copy of the Yahoo! login form circa 2003. That's where it stops, though.
This means we can't experience the wonders of janky pre-XMLHttpRequest file management interfaces. So, we're going to be SOL for a lot of GeoCities. PageBuilder was mostly client-side though, so perhaps it's been cached somewhere...?
I did some searching and came across a couple of strange domains which just contained GeoCities new-account template pages from back in 2003. There's a direct link to PageBuilder on this page: http://geocities.yahoo.com/v/pb.html
I plugged that URL into the Wayback Machine. Picking any of the mid-2000s archived copies gets you a beautiful page describing PageBuilder itself. Unfortunately, we're once again taunted by technological bitrot: "You must be logged in to use PageBuilder!"
This page also has a bunch of quick-start links to launch PageBuilder with different preset templates. Alas, all of these just call a JavaScript function that redirects you to the login page.
My next thought was... this is a Java application, it's probably stored in a .jar file. Perhaps somebody else has already archived it. I did a Google search for yahoo pagebuilder jar
, and it's mostly junk, but the second results page links to a file on GitHub with stats about unbound links from GeoCities pages. This clued me into the existence of the pagebuilder.yahoo.com
domain.
It's a little clunky to get to, but the Wayback Machine allows you to list every URL it knows about on a given domain by using wildcards. I tried this on my newly found PageBuilder domain, and got a very interesting set of 6,171 results.
Sorting the results by MIME type returns archived copies of some very promising-looking URLs - these are just a small subset:
http://pagebuilder.yahoo.com:80/members/tools/pagebuilder/prod/client.2.61.67/code/client.jar
http://pagebuilder.yahoo.com:80/members/tools/pagebuilder/prod/client.2.61.67/code/ini/messages.properties
http://pagebuilder.yahoo.com:80/members/tools/pagebuilder/prod/client.2.61.66/code/ini/global.ini
http://pagebuilder.yahoo.com:80/members/tools/pagebuilder/server/read/clipart/backgrounds/Generic/pnkflame.gif
Here it looks like we've found the PageBuilder client! There were a bunch of different versions archived, so I grabbed the latest one the Wayback Machine had, which was 2.61.67.
It should be easy to get it to run - after all, it's Java. Write Once, Run Anywhere. We still have JVMs today.
$ java -jar client.jar
Error: Invalid or corrupt jarfile client.jar
Oh, of course. That would have been too simple.
PageBuilder isn't a standalone Java application, it's actually an applet. Applet support is kind of sparse in browsers these days, and I was on the sofa with my laptop (running macOS 10.14) and didn't want to faff about with installing different JREs and JDKs and browser plugins in...
]]>Earlier this month I wrote about my research into the FOTA updater on the Cosmo Communicator, wanting to learn how it fetched updates in the hopes of gleaning more information about the device and getting the raw OTA update files. This sent me down an absurd rabbit hole: I went into it assuming good faith, only to discover that the updater contained a curious level of obfuscation and complexity (for things that, in theory, should be simple and straightforward) and some patterns that were very reminiscent of malware.
I attained my goal of writing a script that could pretend to be a Cosmo and fetch the OTA data. This still left a lot of questions unanswered, though... so I delved further.
This post contains everything I've learned about Digitime's operations, based off research into their company, their currently-operating online services, and every sample I could track down of their software. Their distribution model makes it difficult to get samples, so there's bound to be aspects I've missed, but there's still enough information to get a broad overview of what they're doing.
Please see the note at the end of this post for more details on how the situation has progressed. In summary, Planet Computers were entirely unaware and started an internal investigation immediately after I notified them, and are working on mitigations/alternatives.
Shenzhen Digitime Technology (数联时代, or just Digitime) are a technology company based in Shenzhen that operates mobile device update infrastructure. Their main website at www.digitimetech.com boasts that they are a "globally leading FOTA service provider" with over 300 million devices.
A scrolling image carousel claims partnerships with Qualcomm, Mediatek and Spreadtrum (SoC vendors) and Revoview, WaterWorld and Bird (device manufacturers) - although this is most definitely not an exhaustive list; their About Us page claims "Digitime serves hundreds of worldwide Android terminal R&D companies, ODMs, and brands".
Closely linked is QiMing IoT (启明智物 or 深圳市启明智物科技有限公司), who also advertise FOTA services at www.qimingiot.com, have the same contact phone numbers as Digitime and even share the same legal representative, but are much younger - they were registered as a company in Guangdong Province in November 2018, and their domain name was registered a month later.
Digitime's main business (at least, to the public eye) is their FOTA service - this is what they advertise on digitimetech.com and this is the aspect that's most visible to users.
They provide Android ODMs/OEMs with the SystemFota updater APK, instructions on how to build OTA packages and a web portal where they can upload them and view statistics.
An example of this is visible on one GitHub repo where an engineer at Erobbing/Luobin appears to have mistakenly uploaded a Digitime package from April 2016: https://github.com/dante198406/OTA - It includes Chinese-language documentation on integrating the updater into the system, multiple...
]]>