On geektimes.ru recently there was an article that "craftsmen" hacked NES Classic Mini. However, they did not even mention that the Russians had done it. No, not me, but a man under the name madmonkey. I immediately decided to write an application under Windows with a friendly interface, so that it could be done in a couple of clicks. In this article I want to tell in more detail about the essence of “hacking”, how everything is arranged in the NES Mini, and about the difficulties that have been faced.
And yes, I again offer my presentation in two versions: a video and a traditional text article. Whom like more.
Video
Article
Introduction
NES Classic Mini. It is the NES Classic Edition in the USA. Very controversial thing. On the one hand, this is just an emulator on Linux, which is of collectible value, and it is much better to buy some Raspberry-Pi. Even the official website tells us that in the first place it is just a good gift for collectors and players, nothing more. ')
On the other hand, it’s still a ready-made solution that has a familiar design, original controllers and works right out of the box on modern TVs, what else does an ordinary user need?
There are many disputes on this topic, but everyone agrees with one thing - there are obviously few built-in thirty games. Let the most hits be collected there, but there is a lack of the ability to add or, which would be logical, to buy other games. Especially for the people of Russia, where piracy reigned in the 90s, and other games were very popular with us. The pirates did not deliver many hits to us, but they introduced us, for example, to Battle City, which did not officially go outside Japan, but in Russia it was probably even more recognizable than Mario.
After the console was released, there were many attempts to correct this situation, I also tried to do it, but my brain and Linux knowledge was clearly not enough. Yes, I disassembled the console and soldered to the UART pins, but only the Linux console boot loader broadcasts there. Yes, according to instructions from the Internet, I was able to run my own Linux build on it, but I did not get access to the internal NAND memory.
So I was gathering dust from this console without work, until one day a man under the nickname madmonkey hacked the NES Mini. The funny thing is that for hacking do not need anything to solder or disassemble. Everything is done through the console connection via a micro-USB connector, which is intended for power. This is done the most common micro-USB cable, which comes in the kit. The fact is that the NES Mini is based on the Allwinner processor, and they have a so-called FEL mode, which is used for debugging and USB firmware. On different devices, you can switch to this mode in different ways, and in the case of the NES Mini, you just need to hold down the RESET button during power up. Having done this, you can use the special program to read the RAM, write it and run the code for execution.
How does hacking work?
Roughly speaking, there is no protection, except for the fact that most NAND is encrypted, but the key lies in the clear in the unencrypted part of the memory. At the same time on the official website of Nintendo you can find the source code of the loader. Yes, in accordance with the GPL license, Nintendo is obligated to upload the source codes of its developments. So madmonkey was able to compile the boot loader, load it into NES Mini RAM, run it, read the Linux kernel along with the RAM disk image and write it back in the same way. Next thing technology. Madmonkey sketched a program called “hakchi”, which allows you to read the Linux kernel, patch it and stitch it back, eventually you can add your games.
It immediately became interesting to me to understand how this works in order to learn something new and, perhaps, somehow improve. But it was not so easy. I probably spent the whole day studying his scripts, while snapping and snarling at my family and friends at the slightest attempt to distract me. But in the end I figured it out. For me, this was the discovery that in Linux you can mount one directory on top of another. To mount, but not to create simlinka. Games are on a section that is read only. But at the same time, the NES Mini has a relatively huge section of 300 megabytes, which is available for recording, it stores the save games and settings in it. Madmonkey scripts create a directory for games on this section, copy the contents of the original directory there and mount our directory on top of the original one at the early stage of the system boot. As a result, the folder with the games becomes available for writing, and the original files remain intact, which is important, and the shell does not notice that the directory has been replaced. Similarly, you can replace the system files by opening access to the console via UART, which finally allows you to look at the entire file system and facilitates debugging.
What's inside?
Soon I wrote a simple program that, via hexdump via UART wire, extorts the entire file system. This is a very slow process, but I really wanted to see what was there.
As I have already said, the games are in a special directory, for each game there is a separate subdirectory with a cover, a config and the actual ROM of the game. The funny thing is that these ROMs are in the usual ".nes" format, and they are no different bytes from those ROMs that can be easily found on the Internet. You say, “So what? Games are the same, why should they be different? ”
But the fact is that the iNES format was developed by pirates who were the first to dump cartridges and write emulators. The iNES file header uses mapper numbering, which was also developed by pirates. Then I fell into the sediment. No, I certainly understand that Nintendo is easier to download your own games from the Internet than to search somewhere in the archives of the firmware of cartridges 30 years ago. But I did not think that they would do that. So, Nintendo sells us pirated copies of their own games? Soon I was told that it was practiced on the Nintendo Wii. And in the news it turns out there is already a little hype about it.
Whatever it was, we are only at hand. If the NES Mini uses a pirated game storage format, it means that you can run pirated copies of games from the Internet on it without any special modifications. This, again, made madmonkey. I still wondered how the NES Mini defines the game mapper. Then I couldn’t even think of that pirated headlines.
Hakchi2 development
But back to the fact that I decided to write a simple and convenient program for downloading games to the NES Mini. An analogue of the one that made madmonkey, but such that, sorry for the pun, even a monkey could figure it out. With the names I have very tight, and since his program is called hakchi, then let mine be called hakchi2. No matter how strange it is. The ideal interface I saw for myself is this: on the left there should be a list of games with checkmarks, on the right - the settings for the highlighted game. At the bottom of the button - add games and flash. So to press somewhere not there or it will be simply impossible to get confused.
As for the fact that the program "under the hood", it performs three basic actions:
Dumps the Linux kernel from the NES Mini. To do this, through the FEL mode, the u-boot is loaded into the console's RAM, it is given the command to read data from the NAND memory again into RAM, and then the kernel is read from there to the computer.
Stitches a modified kernel into the NES Mini. We need only one modification - so that when loading our script is launched, if it exists. Accordingly, this action must be performed only once. The process of writing a kernel in NAND memory is performed on the same principle as reading, only the other way around.
Builds a modified kernel with scripts and games, but does not flash it, but loads it into RAM and executes it. Scripts at the same time mount the necessary sections, record new games, and then turn off the console.
For disassembling and assembling the kernel, I, like madmonkey, use ready-made programs from the Android Kitchen set. That is, I just run other people's executables with the right parameters and in the right order.
But the process of reading and writing memory is somewhat more complicated, and here it is better to work directly. There are ready libraries, but in C, and I write in C #. Of course, you could write a wrapper for unmanaged code, but I googled the description of the FEL protocol and decided to write my own library from scratch. Nothing complicated there, and it soon even earned, to my surprise.
To work with ROMs, I used my own libraries that were already ready. Experienced to find out which mappers are supported by the emulator built into the NES Mini, so that the program will immediately screen out games that won't start. By the way, if you don’t know what the word “mapper” means in this context, read my article about dumping NES / Famicom / Dendy cartridges .
Then I made it possible to change various settings for games, added the ability to select covers and automatically pinch them, added a button to automatically search for covers in Google, at the last moment decided to add Russian as well, in addition to my curve English. And in this form laid out the whole thing in the network, calling version 2.0. Because "hakchi2".
It seems that I really managed to do everything so that the program could be used without any instructions at all, she remembers whether the user dumped the kernel, requested the modified kernel, she says what to do at what moment. And hakchi2 really gained popularity very quickly, despite the fact that many antiviruses cursed it because of the utilities and drivers in the same archive. Many were afraid to become part of the Russian botnet.
The most interesting problems and challenges
Windows and driver installation
The most difficult problem at the initial stage for me was installing the driver. If I decided to make the program simple, the driver should be installed as easily as possible. I didn’t want to give users complicated instructions or send them to a website to download a separate utility. I'm talking about Zadig .
This is a great application for easy and quick installation of popular basic USB drivers, in our case it is WinUSB . By the way, I don’t understand why the user needs to perform a bunch of complex actions, and Windows requires a digital signature from the developer when to install the driver directly from Microsoft. Fortunately, Zadig is open source, and even with the console version in the examples. I quickly made a simple program out of it, which immediately starts the driver when it starts up.
The subtleties of the FEL protocol
Needless to say, how many bugs surfaced at first ... Most of all, I suffered with the error “pipe read error” that occurred at the moment when it was impossible to initialize the device after running the code in memory for execution. However, it did not appear every time, but completely by accident, which is why I mistakenly believed many times that I finally found at least some regularity. But no, the error occurred completely by accident. And most of all I was strained by the fact that if, at the moment when the NES Mini stopped responding to my program, to launch the original madmonkey hakchi, the console would come out of a stupor and continue to work. That is, madmonkey is somehow correctly initializing itself, and something is wrong with me. But how much I have not studied its source, I did not see anything special there. As a result, I found a program that intercepts and shows USB traffic and began to compare everything by-byte.
Here is an example of how initialization / verification should be performed:
I had a problem in the second step, when I received the answer. For some reason, it was not the data that I expected. It turned out that my mistake was that in this case I was trying to re-initialize, from the very beginning. The program from madmonkey (or rather the fel_lib library) in this case repeats, starting right from the second step, after which the device starts responding normally. Some shamanism, but the error disappeared forever.
"LED-bug", as foreigners called it
However, besides that, I ran into a much more strange bug. Probably this is the strangest and most obvious bug in my whole life. Scripts for copying games at the end of the process turn off the console, so the user must wait until the LED goes out. But many people complained that the LED did not go out even after half an hour. People in the forums shared their experiences. For someone, everything works perfectly, but for someone, the LED does not go out. Someone thinks that there are different versions of consoles, for someone everything started to work on another computer. Dozens of people tried to find at least some pattern. Again, there were many different illusions, but in the end there was a man who found the 100% correct pattern. At first I didn’t believe it, but they all began to confirm this with one voice.
My program does not work if I unzip it with WinRAR, but it works if I unzip it with 7zip. How can this be?
It turns out that some versions of WinRAR, under certain conditions, do not preserve file attributes when unpacking, and when we compile a RAM disk for the Linux kernel under Windows, symlinks must necessarily have a “system” attribute. I couldn’t even imagine that the problem was in the archiver, especially since I use WinRAR myself. Soon I added a file attribute to the program, and the problem disappeared forever. True, under Windows 10 sometimes for some reason it is impossible to change attributes, but now at least an error is written about it.
Fonts
At this stage, the program has already become quite stable, but there were still a number of problems that concerned the console itself and its shell.
I decided to start with fonts. The problem is that the original fonts in the NES Mini contain only the necessary characters, and the names of many of the added games were not displayed correctly.
This task seemed quite solvable at first glance, because right in the directory with the games are the files “title.fnt” and “copyright.fnt”, and you just need to edit or replace them. However, not a single font editor agreed to open them, you need to somehow understand what the format is.
If you swap these files, the text in the name of the game becomes small.
It turns out that the font is raster, not vector, and in it the characters are contained in the form of drawings. If you open the file in a hex editor, you can see that every font close to the beginning contains a signature “BMF”.
The google request for the “BMF font” led to the site , where there was both a utility for generating fonts and a detailed description of the format, which I immediately rushed to read. Yes, each file really should contain a BMF signature, but at the very beginning of the file. In the case of the NES Mini, there were still some 9 bytes in front of it, they were different in different files (except for the first byte). I hoped that they are not needed or irrelevant, but when changing any of them, the console simply did not start, showing a black screen. It turns out that it is necessary to understand the meaning of these nine bytes. The first is always one. Then two bytes are some values, then two zeros. Again, two bytes are values ​​and again two zeroes. After that, the font data was already coming. I immediately thought that these pairs resemble two 32-bit numbers. I looked at the first one, compared it with the file size, I did not see any patterns. Similarly with the second one, but then I decided to add them up and get the exact file size without this header. It turns out that these numbers tell us about the size of some sections in the file. I rewind the file to the value specified in the first four bytes and saw the PNG file header.
I pulled him out of there and yes, this is a picture with all the characters.
It is logical, because the program for generating fonts gives several files at the output. At NES Mini, they are simply merged into one. I likewise gathered together the header and the files of the generated font, dropped the result on the NES Mini and the missing characters appeared.
It would seem that now everyone should be happy now, but soon the Japanese owners of Famicom Mini started writing to me, complaining that they had lost all the hieroglyphs. I politely explained to them that I have a bad language with Japanese, or rather nothing at all. But I was not too lazy to tell you what I found out, and how to generate the font yourself. Soon they sent me a Japanese font, and I included it in the distribution.
Scripts easily define a console region to select from two fonts. Thanks to the Japanese under the nickname xsnake. Now the people have already figured out and began to actively lay out a variety of fonts, even Comic Sans is, where do without it.
Modification of the game controller driver
People kept asking for some unreal functionality. Many did not have enough opportunity to press the RESET button, that is, to exit the menu without releasing the controller from their hands. I immediately said that it was impossible. I don’t have emulator sources, I don’t have to change the functionality of the buttons, but I soon realized that if I connected the Wii Classic Controller (they are compatible), which has more buttons, then the HOME button works like an exit to the menu. That is, in the emulator code this is provided. In this case, the emulator uses the library SDL2, in which the open source code, but to rebuild and replace such a huge library for the sake of such a simple function is somehow not cool. Again, I began to look at the sources that Nintendo provides, and I saw the source code of the controller driver there. Yes, that's exactly what you need! The internal code name of the controller, by the way, is “Clovercon”. From the word “clover” (clover). The shell on NES Min - Clover is similarly named, and the name of the console model itself is CLV-001. I think it’s clear to everyone now what this “CLV” means.
The driver code is very simple, and I quickly found where to insert just one line:
if (down&& select) home = 1;
I compiled the driver without any problems, which is surprising, because I’m not good friends with Linux, and then suddenly compiled a kernel module, but I was glad early. The insmod utility refused to load this module. After a short googling, I realized that this was due to the fact that the vermagic was not the same. This is a string inside the module that describes the version of the Linux kernel and the parameters with which it was going. This is done banal in order to ensure binary compatibility. In short, you need to assemble the driver with the same kernel parameters for which the NES Mini core was built. And how do I know them? Yes, Nintendo posted on its website and the source code of the kernel, but there is no file with the settings. I suffered for a long time, changing various kernel parameters, from the vermagic line it was approximately clear what was missing or what was superfluous.
However, when the vermagic lines matched and the module was loaded, the system refused to respond to button presses. At the same time, it was impossible to debug it, because The kprint in the NES Mini core was cut, as was the dmesg buffer. As a result, I almost gave up, losing all hope, but climbed into the “Kernel hacking” section and began to remove all the checkmarks in a row.
Experienced Linux users will probably laugh at me, but in the end, the driver suddenly started working. I got my way, the combination down + select began to open the menu.
True, people soon began to ask to make the opportunity to choose a combination of buttons. It would seem like? After all, they are sewn into the driver binary, but I just added a text line to the code from which the driver takes a combination, and before loading it to the console, my program finds this line and changes the values.
The main thing is not to forget about the “volatile” directive, so that the compiler understands that the string can change “from the outside”, and that there is no need to cut the code for its verification.
All of this would have made tremendous sense if Nintendo had not made such a short wire at the controllers. Extension is now a must.
Soon there were people who started asking for turbo buttons. I always considered them cheating, which we were taught from childhood, because in Russia almost no one has ever seen the original controllers. And I ignored these requests until they began to come from foreigners. I think there is nothing special to tell here, just another driver modification. Now you can hold down select + A or select + B for a second to turn on the turbo on the corresponding button. In the case of the Classic Controller, the X and Y buttons immediately work like turbo A and turbo B.
Overcoming limitations
As for the limit on the number of games, everything is not entirely clear. The fact is that in NES Mini you can fill in about 97 games without problems, but saving stops working. And the fewer games in the menu, the more savings can be made, but the point is not the limitations of the size of flash-memory, there is still a lot of space on the section. It seems that the shell can not or does not try to get so much RAM to load all the pictures, because each saved game is accompanied by a screenshot, and if you count the total number of games, the size of their covers, the size of screenshots and take into account that all of this is stored in memory in uncompressed form, it turns out a very large number.
At first, I thought I would have to put up with it. Moreover, I have no idea what kind of games you can load there in such a quantity, for myself, I can hardly type thirty pieces, and half of them are already preinstalled in the console, but the people suffered a lot and asked. And then I remembered that for each game in the config, the path to the emulator and the command line parameters are indicated.
So after all, you can run not only an emulator, but also any script that does not interfere with launching a script that will mount another directory with games, what the user will look like folders. I tried it - it worked out!
In the end, I was able to record as many as 600 games at a time. My program automatically splits them into folders, sorting alphabetically. With this approach and conservation continue to work fully, and nothing slows down. I also want to make it possible to choose the algorithm for generating the folder tree and the ability to change their pictures, but at that moment I thought that it was time to stop and finally remove all of this video, but write this article.
Interesting features
During this month, many other different functions were added, such as support for Game Genie cheat codes and automatic filling of information about games, now I don’t remember everything. Many bugs and interesting features were found.
For example, the console refuses to start if there is at least one among the games, in the title of which there are apostrophes and any number in a row. I had to enter a check for this.
Unusual special effects in games are in fact protection against epilepsy attacks, which is enabled by the command line parameter.
By the way, the built-in emulator has many other parameters, it readily displays them itself. True, for some reason they do not all work. For example, PAL emulation cannot be turned on with all the desire. And yes, the European version of the console contains American versions of games. And the BIOS for the Famicom Disk System is also there, although the games for it came out only in Japan. So they also run.
Of the cartridge games, not very many mappers are supported, but all the most popular ones are in place:
0 (NROM) - the simplest games without a mapper, for example Ice Climber, Pac-Man, etc.
1 (MMC1) - a lot of good games, the second most popular mapper.
2 (UxROM - UNROM / UOROM) - games like Castlevania, Contra, Duck Tales, etc.
3 (CNROM) - many simple games, but with a large amount of graphics
4 (MMC3) - the most popular mapper, a lot of games
5 (MMC5) is a very difficult and most sophisticated mapper, surprisingly, there is his support, because there’s not a single game for him in the standard set
7 (AxROM - ANROM / AMROM / etc.) Is a simple mapper that is used by games like Battletoads.
9 (MMC2) - used only by the game Punch Out !!
10 (MMC4) - used by only a few Japanese games
86 - rare mapper, where few used
87 - rare mapper, in few places used
184 - rare mapper, where few used
However, they continue to overwhelm me with letters asking me to add support for one or another mapper to the program, not realizing that this does not depend on me. Although in theory it is quite possible to compile another emulator for NES Mini, but I will leave this venture to people smarter.
Among the original games there is one hidden. More precisely, this is not a game, but production tests, something like a service menu. Perhaps some tricky combination can be accessed without dancing with a tambourine.
CaH4e3 (a well-known romhaker in certain circles) has already begun to disassemble the emulator file. Funny fact - it hides a message from the developers. More precisely from a certain captain Hanafuda.
In fact, Hanafuda are the playing cards that Nintendo produced in the nineteenth century. Sanchez says that there are pointers to this text, that is, some code uses it. It is possible that this is a working Easter egg.
Another funny thing: if you create a “pixelart” folder in the directory with any game and put any PNG image there, it will be shown in the background when the console is idle. It is better to watch a video from the beginning of the article to understand what it is about.
Anyway, the memory of the console is full of different images, sounds and scripts that can be edited. So if you want to quite really pump your console strongly.
Results
Perhaps this is the first console hacking, which brings profits to publishers, not losses. After all, they don’t sell games separately, and now the console itself is simply swept away from the store shelves. It seems that in Nintendo they sat and waited impatiently for it to be hacked already, therefore they did not make any protection. So I hope they do not strike me a strike. And they will not sue, the more illegal I seem to be doing nothing until I distribute the game.