The controllers are capable of lots of things - most notably, emulating a CD reader. Sadly, using that functionality isn't that easy. Changing most of the properties with official tools require a full reflash, and finding firmware (which is unique to the NAND model used!) isn't easy. You can kinda use another tool call ModeConverter to change it, but it changes a lot of stuff in the process.
Note: This post is kinda rough. I blame the fact that my apartment has been 30 degrees celsius over the last two days.
So, where to start? Well, we should start by looking for information others have already gathered! Searching for a bit will reveal a couple key things:
Skimming through these, you'll find out that it uses vendor specific SCSI commands, and using them I was able to start by implementing a command to dump:
06 05 'R' 'D' 00 00...06 05 00 00...06 05 'I' 'N' 'F' 'O' 00 00...06 56 00 00...Additionally, I implemented a command to restore (or flash) "Vendor Info 2" with 06 06 01 00 00...
I also added in Read/Write XData, although I haven't looked into it much.
Once I had my "virgin" dump safely copied away, I could fire up Wireshark with USBpcap, and start running tools while looking at the commands. Using ImHex, I could diff dumps of "Vendor Info 2" where most things seemed to happen, and document fields as I discover them in the pattern editor. To my surprise, several tools just trampled existing fields, but the firmware seemed to cope fine. Hence I restored that "Vendor Info 2" a lot.
Repeated restores, captures, and tool wrangling culminated in me successfully being able to manually write an ISO image, and then hex edit "Vendor Info 2" to flip it over to CD emulation mode.
The code is on Github, and I'll implement "Vendor Info 2" editing later. The biggest limit is a lack of dumps, so please, submit them - just get in touch.
]]>I've censored company and product names, mostly because I don't want to end up high on Google when you search for "Company A crack". Also, as I post this, I've updated the theme to increase readability, and done a quick design pass on the code blocks. Feedback welcome.
I'll start with the obvious - I haven't actually made a crack in about 10 years, and I no longer have any devices with those cracks on them. Now that police and lawyers have no more reason to read...
When talking about whether something is legal in practice, there are two factors to consider.
Your legal liability is the laws and agreements you break, and how fucked you are if arrested or sued.
This is one of the more complex topics, and generally something to approach Legal over if you're doing this as part of a company.
In the European Union, you are largely going to operate under Article 5 § 3 of Directive 2009/24/EC, which grants exceptions to the rights enumerated in Article 4. Fundamentally, it means that if you have the right to use a program, you have the right "to observe, study or test the functioning of the program in order to determine the ideas and principles which underlie any element of the program if he does so while performing any of the acts of loading, displaying, running, transmitting or storing the program which he is entitled to do", even without the permission of the rightsholder.
Important thing to note there is "any of the acts of loading, displaying, running, transmitting or storing the program which he is entitled to do" which means you're severely limited on what you're actually allowed to do - you may not decompile code, for example. At least case law allows you to decompile software in order to fix bugs.
But, this is nuanced, I am not a lawyer, and if you care about this part, you need to ask one. I usually rely on the second factor.
This one is pretty simple - will the police come to arrest you, or will the company sue you?
First of all, if you're running around cracking shit, and constantly uploading them under a pseudonym, the police is going to come knocking on your door. Don't do that. Don't distribute cracks, use it as a learning opportunity at best.
Second, if you're doing things as part of your job, and your company is paying their license fees, and there's no way paying more money to the software company solves the problem, they probably don't care. Suing your customers is bad for business.
For example, say Company A makes some enterprise software that your company has purchased, which is used on an automatically provisioned machine. This has a DRM system that requires manually authorizing and deauthorizing it, or you have to contact their support to have a license key reissued. Your company has a policy that all automatically provisioned machines must be replaced monthly. Figuring out how this DRM ticks, and how to transfer the registration is technically against the license agreement, but in the end, Company A does not offer floating licenses, you're not using it on more machines than what you pay for, and you don't have to contact their support every three months because the machine got wiped before you could deauthorize it. Not that I would know.
Next, if you're cracking some enterprise software for your homelab, and not distributing the crack, most companies really don't care. If their minimum price is five digits USD, or "contact us", you're not a potential customer with your clapped out Dell PowerEdge that's 10 years out of support and requires an old version of Java 8 to run the remote KVM.
Some companies are more litigious though. You probably don't want to invite the trouble of any company whose running joke is that they have a bigger legal department than they have R&D.
Now that we've gone over legalities and your risk, and you've decided you want to try this, either as a first reverse engineering stint, or to try out making cracks, why enterprise software?
The simple answer is that copyright protection, DRM, whatever you want to call it, is a cost. Companies really don't want to spend more money on it than they have to, and for regular consumer software, they have to. All you have to do to see why is to use Google. CensoredEnterpriseProduct "crack" returns 11900 results, while CensoredDeveloperProduct "crack" returns 71500 results.
What this means in practice, is that enterprise software tends to not have obfuscation, or a bunch of third party tools trying to make your life harder. I've seen plenty of enterprise software ship with a class called LicenseManagement that has a function called Verify. You'll never find this in regular consumer software. This is great for getting started.
However, unlike a lot of customer software, they are snitches.
Enterprise software loves to snitch on the people running them. They will print licensing information in places obvious, in places non-obvious, and in some cases, especially for hosted software, have undocumented API endpoints that reveal enough information about the license key used that the software company can even scan the internet for improperly licensed instances.
The one thing they tend to not do, is call home. Enterprise comes with weird requirements and obstacles in deployment, and calling home is a sore subject at times. Usually, it's solved by enabling audits though the license signed when buying the software instead.
In other words, if you're cracking some enterprise software to run in a lab, don't expose it on the internet. It will probably rat you out.
Enterprise software is rarely looked at and appreciated - they are bought by higher ups in suits, and employees are forced to use them in their day to day work. Some of them are quite different when viewed from a different light - the technical side that enables it, using it when you feel like it, and exploring the possibilities and downright weird features that you know were added because of some requirement from a big customer.
It's a new frontier for technical exploration. Give it a shot.
]]>As you might know by now, this site uses Jekyll. All artwork is stored in a "collection" defined in _config.yml, set to output the individual documents:
collections:
artists:
artwork:
output: true
There is also an "artists" collection used to store artist information.
To use "Nature's Child" by Alby as an example:
There is an _artwork/alby-natures-child.md file that contains the metadata:
---
title: "Nature's Child"
author: "Alby"
date: "2024-08-19"
desc: "A young Dusty out in nature, wearing red overalls, peeking over a fence."
categories:
- safe
---
and then the actual image is stored as _artwork/alby-natures-child.png.
There is also an _artists/alby.md file that contains the metadata for Alby themselves:
---
title: "Alby"
site: "https://albys.space/"
---
Next, in _config.yml, there is a default layout set for all documents under the artwork collection:
defaults:
-
scope:
path: "_artwork"
values:
layout: artwork
This means that Jekyll will use _layouts/artwork.html to generate the actual document. I'll skip the majority of the document, but there are a couple of snippets that perform some magic:
First, this snippet finds the artist from the artists collection, and makes sure to link their site.
{%- assign artist = site.artists | find: "title", page.author -%}
<h2 class="artwork-artist" itemprop="author copyrightHolder" itemscope itemtype="http://schema.org/Person"><a href="proxy.php?url={{ artist.site }}" itemprop="name">{{ artist.title }}</a></h2>
Second, this snippet digs out the corresponding file and sticks it in an img tag.
{%- assign artwork_collection = site.collections | find: "label", "artwork" -%}
{%- assign artwork_file = artwork_collection.files | find: "basename", page.slug -%}
<img src="proxy.php?url={% link {{artwork_file.path}} %}" alt="{{page.desc}}">
The artwork indices are made in the same way, roughly.
That's about it for how things are set up right now.
]]>/.well-known/button.json with a button of my own.
This site uses Jekyll, so I basically just created the file manually where it should be, and explicitly included .well-known in the config.
include:
- .well-known/
Every now and then I stumble upon some old piece of malware, which has tagged along for years without anyone really caring, especially if it no longer works.
This downloader has proliferated on torrent sites for years, especially in keygens which traditionally have a high false positive rate. Needless to say, AV vendors tend to not care about false positives in warez.
The sample I'm analyzing is a keygen for some software - SHA256: f9dcc16f68be2a69df7bcbab6be54a87daaafa1f2b49ca3557da732abb12b8f8. Here is the VirusTotal report.
A quick glance at the binary shows that it's based on NSIS. Using a special build of 7zip you can decompile the NSIS script, to try to find out what it's doing.
7zip can also extract files from an NSIS installer, which means we get to see what's inside - it's incredibly bare, with three files inside $PLUGINSDIR. Two DLLs,
A1E09FB1739EF7557D18104B0D6A4C7725E1EC293F5404C80402F57FF9EBB9D0)A0CAC4CF4852895619BC7743EBEB89F9E4927CCDB9E66B1BCD92A4136D0F9C77)are genuine DLLs from NSIS 3.03. There is a file named "B" in this directory as well, helpfully carrying a modification date showing when infection occurred. 2018-10-07, in my sample.
The NSIS script is relatively simple, with some obfuscation we can basically ignore as it's only for decoding the information retrieved from the Command and Control servers, which are long down. The flow is basically as follows:
$PLUGINSDIR\<10 random characters>, first http://strong.girlsmist.online/lvx7.php?p=sevenzip&tid=...&pid=...&n=...&b_typ=pe and then http://pepper.cobwebdesign.host/lvx7.php?p=sevenzip&tid=...&pid=...&n=...&b_typ=pe. There's a timeout of 5 seconds on each, and the installer gracefully continues if both fail.boot, the URL is downloaded to $TEMP/<10 random characters>.exe and a "Windows Refresh" key is placed in HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce, pointing to the exe. This will make the payload run on boot. After this the "B" file is renamed to "setup.exe" and executed.first, the URL is downloaded to $PLUGINSDIR\<10 random characters>, and executed. After this the "B" file is renamed to "setup.exe" and executed.only, the URL is downloaded to $PLUGINSDIR\<10 random characters>, and executed. The "B" file is never executed.last, the URL is downloaded to $PLUGINSDIR\<10 random characters>, the "B" file is renamed to "setup.exe" and executed, and then, finally, the earlier downloaded payload is executed.Helpfully, my sample contained another sample. No clue why - could be to double dip on payments for dropping malware/adware, or a genuine mistake. This was great for figuring out what's random and what's constant, however.
There's a very obvious indicator for compromise - binaries named <10 random characters>.exe running under %TEMP%, so I'll focus on identifying infected files instead, and specifically this strain of this family. This is all byte sequences or strings found in the infected binary on disk.
03 9A 80 5C 42 2D 3E 03 9A 80 5C 73 65 74 75 70 2E 65 78 65 ("$PLUGINSDIR\B -> $PLUGINSDIR\setup.exe" rename string in NSIS script)
53 4F 46 54 57 41 52 45 5C 4D 69 63 72 6F 73 6F 66 74 5C 57 69 6E 64 6F 77 73 5C 43 75 72 72 65 6E 74 56 65 72 73 69 6F 6E 5C 52 75 6E 4F 6E 63 65 00 57 69 6E 64 6F 77 73 20 52 65 66 72 65 73 68 00 (SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce and "Windows Refresh" next to each other in the NSIS script string table)
03 99 80 5C ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 2E 65 78 65 00 and 03 9A 80 5C ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 2E 65 78 65 00
($TEMP\??????????.exe and $PLUGINSDIR\??????????.exe in NSIS script string table - the unknown bytes are the same in both entries)
03 9A 80 5C ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00
($PLUGINSDIR\?????????? in NSIS script string table - unknown bytes are different from the ones that would be used above)
http://strong.girlsmist.online/lvx7.php?p=sevenzip (C2 server 1)
http://pepper.cobwebdesign.host/lvx7.php?p=sevenzip (C2 server 2)
.php?p=sevenzip&tid= or .php?p=sevenzip&pid= (Generic detection of all strains I've found so far)
It's relatively trivial to recover the original file that's been infected - just open the infected file with 7zip, and extract $PLUGINSDIR\B. Note that there could be multiple layers of infection, so you should check if the file you extracted also contains a $PLUGINSDIR\B.
As far as I can tell, this is not the first strain of its kind, nor its last.
In early 2017, TrendMicro analyzed something similar as 'CRCK_KEYGEN.SM', given it is said in the technical details that it tries to connect to similar servers (same parameters). Once again, we see that whole "AV vendors doesn't care about that side of the internet" thing - I'd put "tries to download and run arbitrary code" above "is a keygen", but c'est la vie.
There's a pcap from a 2015 relative available, as well.
To my surprise, this campaign is still active - I can find samples still calling URLs with a related set of parameters, now to pe-mainin.com. Thanks to AlienVault keeping old whois data around, we can see that it's Wakenet AB who's most likely behind it. Very conventiently, pe-sixi.com, also linked to Wakenet, is hosting a fake 7zip download page at the moment, calling it "SevenZip". Through this, it's related to "C4DL Media", and P2Pcontrol.
There's a lot of unanswered questions. Who is/was infecting a ton of keygens and uploading them, for example?
While I wish I could go into more depth on more recent samples, I don't have access to download samples from VirusTotal or Hybrid Analysis, by virtue of doing this on my spare time.
]]>I found out about this whole challenge a bit late. 22 days after it started, in fact. I went onto the local auction site, and proceeded to bid home an HP Elite 8300 SFF charitably described by the seller as "defective" - the DVD drive is broken, the case is mangled, and worst of all, it completely fails to load BIOS, causing the EC to spin up the fans after a minute as a safety measure. I also bid home an R9 280X, but that ended up irrelevant in the end - we'll get to that when we come to that.

Current budget spent: 145 SEK / ~1000 SEK
I finally got the cheap computer, and boy, was it broken. The Embedded Controller was completely unresponsive - I spent a couple hours trying to revive it, to no avail. It sure was mangled though.
There was also a broken inductor right next to the Intel Ethernet IC, so you can guess how well that IC was working.
I did, however, order some RAM (open box deal) and a brand new SSD (literally the cheapest one available). I could've sourced it through eBay for cheaper, but, again, we'll get to that later.

At this point, I also noticed the configuration this machine shipped with - the signs of its past life. It's genuinely the first time I've seen a machine in the wild that shipped with FreeDOS. It's also been professionally refurbished, and has a (sadly damaged) Windows 10 Pro for Refurb PCs COA. If you figure out the serial key, let me know.
Current budget spent: 783 SEK / ~1000 SEK
I manage to get the EC to start by performing a hard reset of it, which involves removing all sources of power, holding the "Clear CMOS" button for a minute, and holding the power button for a minute, to really drain everything.
Going by the word of the seller, I also try to connect my SPI flasher to the BIOS chip on the motherboard - I was able to order a clip from Amazon before I got the computer thanks to this helpful post showing where it is and what clip I needed ahead of time. This failed spectacularly, because a dirt cheap SOIC-16 clip from Amazon has the rigidity of a wet noodle, and the plastic got chewed up instantly.
I ended up placing an order on Mouser for a €30 Pomona IC clip, a couple replacement inductors to try to replace the broken one, and a couple replacement flash ICs, in case it was broken.
I got the package with the RAM, unsurprisingly it did not boot. It was at this weekend I decided to visit my parents, and managed to get COVID.
For those of you wondering - I had pretty mild symptoms, except my sense of smell and taste got pretty messed up. Gasoline smelled like broccoli, for some reason. The biggest issue was the brain fog.
Finally having some energy back after COVID, I slowly started tackling this PC again. I dumped the flash with the SPI flasher and the new IC clip (which was well worth the money), and transplanted over the unique regions I knew of back into an image pulled from the most recent update. My theory was that the previous owner had tried to downgrade the BIOS, which bricks it, or that an upgrade had bricked it, which is common enough that you have people asking about it on the support forums.
When it still didn't boot, I decided to rip off the bandaid, and looked at the one place I hadn't looked - under the CPU. I hate this god damn mechanism. It's fragile, the off-kilter pressure gives bad heatsink contact, and it's hard to even spot if a pin is bent. And guess what? Eventually, I spotted two bent pins. One was right next to another one of the same net, so it probably would be fine, but the other one was the sole VCCIO pin on that part of the chip.
Ready to give up, I threw caution to the wind, and attacked it with some fine electrical pliers out of my iFixit kit. Miraculously, I managed to bend the straight up broken VCCIO pin to a location where it would contact the pad on the CPU.

I have never been this happy to see this stupid message.
You can see which pin I "fixed" and which was left broken, by looking at this map. I fixed M13, while J4 was left as-is.
This left me with a conundrum - because I suddenly had a chance at finishing this, but I was missing the special cable used to get SATA power from the motherboard, since the proprietary power supply routes that through the motherboard to make it easier to swap. I also had no way of powering the GPU.
In another burst of energy, I tried replacing the broken inductor, but my soldering iron's skinny tip couldn't even start heating up the solder. Annoying, but I had somewhat planned for this. We'll get to that later.
I also now realized that the flash is now in a weird mode where it reboots three times before it starts. It also always boots when powered up, no matter the settings. I also managed to wipe the model name from the BIOS. Whoops.
Using a PSU I dug out of the electronics recycling bin near my apartment in mid-November, I fired up the machine with the SSD, and installed Windows 10. I wouldn't recommend using random PSUs with cut cables from a recycling bin, but I had the fire extinguisher nearby :)
If you're eagle eyed, you might spot that there's a network card in there. You see, according to the rules of the challenge, you're only supposed to use parts acquired after the challenge started. That network card is 5+ years old at this point. Thing is - I ordered one for this machine, but it won't get here until the start of January because of eBay's "Global Shipping Program". You know, the program known for destroying whatever is sent through it.
This is a TP-Link TG-3468, and is generally what I go for when it comes to "needs a Gbps capable network card". I bought one for £5 - I'll be counting that into the budget, and you'll just have to pretend this card is that identical card.
Hoping that doesn't disqualify me, here's the results!
| Item | Cost | Cost USD |
|---|---|---|
| Base PC | 145 SEK | $13.90 |
| RAM | 399 SEK | $38.26 |
| SSD | 239 SEK | $22.92 |
| Extra PSU | Free in the recycling bin | $0 |
| Network card | £5 GBP | $6.04 |
Final cost: $81.12 USD
As for results of the tests, and scores:
| Item | Output | Score |
|---|---|---|
| Unigine Sanctuary | 325 | 32.5 |
| Cinebench | 1.562701 single core, 5.925838 multi core | 74.88539 |
| Google Docs | Average rounded to 4 (3.65, 3.01, 4.21 - but manual timing is inaccurate) | 56 |
| Price | $81.12 | 18.88 |
Final score: 182.26539
So, all in all, a fun thing to do, but christ, what a mess. I really wish I had the time to put that GPU in this, or even just run a single PSU, but that would necessitate a lot of splicing, since my dumpster PSU doesn't have a GPU power connector either. It would've been way easier if I didn't start 22 days late, or lost more than a week to COVID.
Starting late also basically barred me from buying things used internationally, because I couldn't wait a week for things to arrive until I had a basic system actually working. Not being able to wait meant I ended up paying essentially double for the RAM, for example.
I also probably wouldn't take a computer of unknown condition either to start with, but if I did, I would make sure to order enough spare parts to begin with to be able to just replace things if I can't fix them. That bent pin was really close to killing this whole project.
I'd love to see this return for next year - my one critique is probably that the Google Docs test is really finnicky, relying entirely on manual timing. I also wish there was a grace period for the builds, having a cut off date for ordering parts a couple days before the end of the year, but giving up to mid-January for them to arrive, just so your build doesn't get busted by things like the postal service being slow, or sellers not shipping out on time. The spirit of this is throwing together a powerful machine on the cheap in a limited time frame after all - and it sucks when you risk getting disqualified because of something out of your control.
I definitely plan on finishing this up sometime next year - I need to do something about the GPU, which involves making a custom fan duct, and also replacing the PSU, which, well, I probably want to do anyways. Might port coreboot to it, so I can more easily do UEFI crimes.
We're talking about a $14 computer that running with two separate PSUs at the same time, which sparks unless you connect both of them at the same time, missing a component from the motherboard, with a BIOS flashed that makes it reboot three times before starting. The fact that it runs is already pretty ridiculous.
That being said, I did try to get VR running on it, but the DisplayPort on the integrated graphics doesn't support monitors over 1080p. I ended up playing games for two hours on it by accident though! That integrated GPU isn't the best, but it sure can handle 720p Low, as long as your game doesn't need Vulkan or DX12, which the drivers are too old for.
]]>I consider these mods pretty non-intrusive and vital - they are all either worth starting a new save over, or can be added to existing ones.
Gives you a quick overview of how your colony is doing medical-wise. Purely UI, so can be added and removed at will.
Adds a bunch of tools that allows you to quickly harvest/haul/allow/forbid parts of the map. It's an essential mod to me, I use the tools all the time.
Fixes a ton of issues with doctoring in the base game (basically just "always using the same medicine type for everything" since 1.3) so you can reserve your glitterworld meds for infections and surgery.
Required by other mods mostly, but the ability to hit Ctrl+F12 to upload your logs and mod list is a godsend for getting help when troubleshooting.
Purely UI, gives you a better overview of how pawns are doing at the top of the screen.
Purely UI, gives you a much better panel when you select a colonist that lets you see their skills at a glance, etc.
Changes how surgery is calculated to be more based on skill and less reliant on RNG. Your region leading master surgeon will no longer rip off someone's arm when trying to install a wooden hand. Death is part of the game, but I'd much rather have my colonists die in a better way than a bad dice roll.
Purely UI, shows bubbles when pawns talk to each other. Makes things feel more alive.
These mods I consider nice to have, but might change too much for some people. These can still be added in the middle of a run.
Tosses in some small adjustments into the pathfinding algorithm to make pawns prefer paths that don't generate dirt. Saves so much sweeping.
Adds prosthetics for animals, so you don't need to put them down the moment they lose a leg. You know you want it.
Lets your caravans, well, set up camp. Means you can set up a small temporary shack if someone gets sick on the road, has saved my colonists' lives many times.
Basically lets you preset where people should go when drafted, so you don't have to set up your colonists manually every single time a raid shows up.
Adds a reason to potentially settle a longer distance away from others, because it doesn't make sense that a raid party shows up every 5 days if it takes 8 days to travel.
Turrets will now shoot escaping prisoners, and oppress slaves.
Like it says on the tin, prisoners don't have keys and need to tear down doors to make it out.
Makes it so "liquidy" filth disappears quicker on terrain such as sand, where it otherwise doesn't rain away.
Lets you build roads on the world map. Takes a lot of work, but makes longer caravan trips more viable.
Gotta plug my own stuff, I made it for a reason after all :)
Adds a robot vacuum you can build that sweeps the place. Probably going to rework this for 1.3 some time in the future - Ideology added a bunch of stuff this can use to ease development and maintainence.
Has some fun bugs - for example you can end up being chased by manhunter vacuums.
]]>This will be the first of a small series of posts on reverse engineering software and hardware.
I recently bought a thing on Gumroad. I quickly realized that said thing was uploaded as 391 items, and unless I did something, I'd be forced to hit Download and then Save on each and every one of them individually.

All projects start with a problem that you need to solve, and I really don't want to hit Download and Save for four hours straight.
The first approach is always the simplest. Hit F12 to open the developer tools in your browser, open the Network tab and refresh the page. See if there's any request you could use - these days there's usually a bunch of JavaScript in the frontend that hits an API. An API is always the first stop - it's designed for computers to make sense of, and it's designed to not require human intervention to use.
The product page didn't have an API, and the purchases page had an API that's not usable for what I want - namely to get a list of links to be able to download quickly.
The second approach is looking at native clients, which is pretty much guaranteed to be using an API. I downloaded their Android app from APKPure, and tossed it into jadx.
In general, if I need to reverse engineer a client, I go for the simplest option - start with apps in interpreted or JIT languages (Android uses Java, some Windows apps uses C#), and only move to apps in native languages (like on iOS) if you must. With Java and C# you can get readable code out of the box, while native languages require you to know some amount of assembly.
In jadx, I can see that the Android app uses a mobile API with standard REST semantics, and authentication is done through an OAuth 2.0 username/password flow. This is great - it's easy to implement yourself. All you need to do is grab the tokens from the app.
Reverse Engineering rarely come without some engineering in the end to actually put what you've figured out to use. In this case, because it's largely standards based, I can just use RestSharp to throw together something quickly in .NET 5, with great results.

I'll publish the code once I finish up the auth flow and make it usable without manually looking at API requests.
]]>Let me know if you find any accessibility issues, you have my contact details on the home page. Things I know of right now, that's on the to do list:
That is all. Kudos to Bit Assembly on Twitter for making the artwork.
]]>Go look at my Twitter instead. It's more exciting.
]]>