Hacking The 3ds 3: Memory Shenanigans

Introduction

Welcome again. Finally, it’s time to go back and continue hacking the Nintendo 3ds. Previously, I got raw RAM dumps where several unicode strings could be found, evidencing the data was not encrypted or secured at all in RAM. This also applies for code, binary’s code sections may be also loaded in memory (as we saw using entropy) so we can extract them and reverse them.

Identifying code

Even though I used binvis and could clearly see the differences between data and code, it wasn’t precise enough to get addresses. And we may want to have the best accuracy when extracting code, ensuring we don’t get anything else, to make later reversing easier. Firstly, before moving into more specific (command line) tools, I would like to mention an useful and handy program called Veles, an open source tool for binary data analysis. It is worth mention because it has an extensive collection of different views (entropy, density, different 3D and 2D models, etc…) which you may find good for your own usage. Here’s some screenshots from the RAM dump being analyzed and shown:

As you can see, it can be a game-changer tool. Human vision is good at identifying visual patterns, so this might give new points of view (and in this case, confirm what we first saw with binvis: that there are zones with higger entropy than the rest of the dump.)
Veles with caption mode enabled, showing reference addresses

We can select how much we want to represent, selecting different regions using the slider.

Actually, we’ll be back at Veles once we get some addresses, and use its built in functions to extract a chunk of the FCRam dump. Now let’s move on.

The next tool I will be using is cpu_rec an utility created by the people at airbus seclab. As its repository says, cpu_rec is a tool that recognizes cpu instructions in an arbitrary binary files. It supports a good bunch of architectures, including among others ARM64 or ARMel (Arm32 or Arm endian little), the later being the one the 3DS uses. Therefore, there was a chance it could detect chunks of code, so I had to try it.

A first run of cpu_rec in my Linux machine gave this output:

The output is not crystal clear for me, even though there is (apparently) an ARM (ARMel) chunk of code starting at address 0x9f000, with a size of 318 (bytes?). I haven’t been able to get a more precise result from cpurec. Surely there are other similar tools waiting for us to try. Let’s look into it.

Stronger Together

Back a month ago I decided to ask for more “blackbox hacking” information on the stack exchange RE page. I met wisk (@wiskitki) who has come up with some really great ideas to progress on this research. Firstly, we loaded one of the FCRam dumps on IDA. It is enough to set the processor to ARM, like this:

After the initial analysis, wisk got some insight:

Dumps are really interesting. They contain code, string, data, for instance, with this piece of code above, it’s possible to figure out the image base, the only issue is the difference between the case address and the jump table is not right, the case address should be higher than the address in the jump table. It means a MMU is involved and probably isolated from another part of the code. Focusing on the memory layout and page tables is important to reconstruct the real memory view and cut the image with different applications. We are still trying and learning how to reconstruct the jump table and/or map code.

But there’s more content!

I later decided to also run binwalk on the dumps and it was quite satisfying. Here’s the output:

binwalk fcram.bin 
DECIMAL       HEXADECIMAL     DESCRIPTION
7299258       0x6F60BA        Intel x86 or x64 microcode, sig 0x021e0001, pf_mask 0x00, 1A5A-01-16, rev 0x529c0000, size 2048
7993402       0x79F83A        Intel x86 or x64 microcode, sig 0x021e0001, pf_mask 0x00, 1A5A-01-16, rev 0x529c0000, size 2048
8000252       0x7A12FC        Intel x86 or x64 microcode, sig 0x0f15202a, pf_mask 0x3030404, 1F36-15-26, rev 0x37464b5c, size 16843009
50306088      0x2FF9C28       Intel x86 or x64 microcode, sig 0x00000016, pf_mask 0x803e5ec, 1C4C-08-01, rev 0x3f800000, size 2048
50567676      0x30399FC       Intel x86 or x64 microcode, pf_mask 0x00, 1AD4-08-05, rev 0x8051ad4, size 2048
60749628      0x39EF73C       TROC filesystem, 4279375 file entries
60752768      0x39F0380       TROC filesystem, 4279375 file entries
66907642      0x3FCEDFA       Base64 standard index table
66908802      0x3FCF282       TIFF image data, little-endian offset of first image directory: 8
66908816      0x3FCF290       TIFF image data, big-endian, offset of first image directory: 8
66909359      0x3FCF4AF       JPEG image data, EXIF standard
66909371      0x3FCF4BB       TIFF image data, little-endian offset of first image directory: 8
66909379      0x3FCF4C3       JPEG image data, EXIF standard
66909391      0x3FCF4CF       TIFF image data, big-endian, offset of first image directory: 8
66909662      0x3FCF5DE       TIFF image data, little-endian offset of first image directory: 8
66909674      0x3FCF5EA       TIFF image data, big-endian, offset of first image directory: 8
67105288      0x3FFF208       SHA256 hash constants, little endian
67135863      0x4006977       LZMA compressed data, properties: 0xB8, dictionary size: 0 bytes, uncompressed size: 2560 bytes
67139959      0x4007977       LZMA compressed data, properties: 0xB7, dictionary size: 0 bytes, uncompressed size: 6912 bytes
67742218      0x409AA0A       Minix filesystem, V1, little endian, 187 zones
67750612      0x409CAD4       Minix filesystem, V1, little endian, 21760 zones
67854766      0x40B61AE       Minix filesystem, V1, big endian, 31231 zones
67954296      0x40CE678       MySQL ISAM index file Version 5
67954300      0x40CE67C       MySQL ISAM index file Version 5
68035414      0x40E2356       MySQL MISAM compressed data file Version 7
68421348      0x41406E4       MySQL MISAM index file Version 3
69043542      0x41D8556       MySQL ISAM index file Version 5
69159852      0x41F4BAC       MySQL MISAM compressed data file Version 7
69349091      0x4222EE3       mcrypt 2.2 encrypted data, algorithm: blowfish-448, mode: CBC, keymode: 8bit
69403564      0x42303AC       MySQL MISAM compressed data file Version 7
69473406      0x424147E       MySQL ISAM index file Version 5
69618190      0x4264A0E       Minix filesystem, V1, big endian, 11810 zones
69879092      0x42A4534       MySQL ISAM index file Version 5
69938520      0x42B2D58       MySQL MISAM index file Version 8
70140594      0x42E42B2       Minix filesystem, V1, little endian, 1036 zones
70298452      0x430AB54       MySQL ISAM index file Version 5
70329090      0x4312302       MySQL MISAM index file Version 8
107215248     0x663F990       Intel x86 or x64 microcode, sig 0x0803b216, pf_mask 0x803b2b4, 19B4-08-01, rev 0x3f800000, size 2048
107216348     0x663FDDC       Intel x86 or x64 microcode, sig 0x00000016, pf_mask 0x803b2b4, 1E00-08-01, rev 0x3f800000, size 2048
107280616     0x664F8E8       Intel x86 or x64 microcode, sig 0x0803b216, pf_mask 0x803b2b4, 190C-08-02, rev 0x3f800000, size 2048
108395492     0x675FBE4       Intel x86 or x64 microcode, sig 0x00000002, pf_mask 0x80000000, 1E14-08-13, rev 0x8131e14, size 2048
110505168     0x6962CD0       Nintendo DS Game ROM Image  <-----
111811632     0x6AA1C30       SHA256 hash constants, little endian
113820944     0x6C8C510       SHA256 hash constants, little endian
118416828     0x70EE5BC       LZMA compressed data, properties: 0x6E, dictionary size: 0 bytes, uncompressed size: 5600 bytes
118814824     0x714F868       XML document, version: "1.0"
119871116     0x725168C       SHA256 hash constants, little endian
120699788     0x731BB8C       TROC filesystem, 4279375 file entries
120882924     0x73486EC       Certificate in DER format (x509 v3), header length: 4, sequence length: 887 <-----
120883815     0x7348A67       Certificate in DER format (x509 v3), header length: 4, sequence length: 602 <-----
120884421     0x7348CC5       Certificate in DER format (x509 v3), header length: 4, sequence length: 885 <-----
120885310     0x734903E       Certificate in DER format (x509 v3), header length: 4, sequence length: 954
120886268     0x73493FC       Certificate in DER format (x509 v3), header length: 4, sequence length: 863
120887135     0x734975F       Certificate in DER format (x509 v3), header length: 4, sequence length: 807
120887946     0x7349A8A       Certificate in DER format (x509 v3), header length: 4, sequence length: 1066
122021324     0x745E5CC       CRC32 polynomial table, little endian
122025420     0x745F5CC       CRC32 polynomial table, big endian
122225616     0x74903D0       SHA256 hash constants, little endian
122672248     0x74FD478       Certificate in DER format (x509 v3), header length: 4, sequence length: 1056
122674704     0x74FDE10       Private key in DER format (PKCS header length: 4, sequence length: 1190
122675936     0x74FE2E0       Certificate in DER format (x509 v3), header length: 4, sequence length: 1219
122677176     0x74FE7B8       Private key in DER format (PKCS header length: 4, sequence length: 1190
123549136     0x75D35D0       Certificate in DER format (x509 v3), header length: 4, sequence length: 893
123550033     0x75D3951       Certificate in DER format (x509 v3), header length: 4, sequence length: 1169
123551206     0x75D3DE6       Certificate in DER format (x509 v3), header length: 4, sequence length: 1056
123563013     0x75D6C05       Minix filesystem, V1, little endian, 30 char names, 37 zones
123936009     0x7631D09       Minix filesystem, V1, little endian, 30 char names, 38 zones
123936748     0x7631FEC       Intel x86 or x64 microcode, sig 0x08032070, pf_mask 0xffffffff, 2070-08-03, rev 0x8032050, size 2048
124047924     0x764D234       Base64 standard index table
124925352     0x77235A8       SHA256 hash constants, little endian
131945708     0x7DD54EC       SHA256 hash constants, little endian
132031212     0x7DEA2EC       SHA256 hash constants, little endian
132644480     0x7E7FE80       TROC filesystem, 4279375 file entries
132717080     0x7E91A18       SHA256 hash constants, little endian

There’s some false positives, like Intel x86 microcode (remember, the 3ds has an ARM processor not an x86 arch!). But remark there are certain bold lines. I’ve highlighted them because they are pretty interesting. The first one is a NDS Game ROM. Since the 3ds is backwards compatible with the NDS this did not surprise me. Inspecting further, we found data for PAPERPLANE, a dsi/nds game I bought from the eshop and had installed in my 3ds at the moment of the dumps:

Even though I did not run it before dumping the fcram memory, it is there! I did, in fact, load some nds-mode programs but not that one, so heh, who knows why! but we later found that the whole PAPERPLANE NDS executable had been loaded into fcram!

While I haven’t done the following yet, in theory, this would mean this is the first piece of code I can completely dump (with a good integrity) since the NDS format has been completely documented for a long time. You may have noticed that it is not a native 3ds piece of code, but hey! it would be an amazing entrypoint to start with. Since the binary is dump-eable and the extension known, and there’s amazing NDS/dsi debuggers out there (No$Gba mainly) we could dump this videogame (and surely any other dsi mode game that was installed) and look for vulnerabilities in the backwards nds mode. That would be a way to get initial unsigned code running, and try to escalate / break out of the emulator sandbox into native code.

And yet, we got even more data from binwalk. We did a <em>binwalk -e</em> run, which extracts all the formats found into separate files. Sadly we did not obtain much stuff, but some Certificates in DER format. After that, wisk was able to read them with OpenSSL:

A final throwback to strings with IDA

Least but not less important, I did a bit more of research into native 3ds binaries. After brainstorming, there’s plans to try and find out MAGIC numbers for unknown file formats and try to link them to 3ds executable binaries, thus being able to investigate them further. Meanwhile I tried to follow strings to code in IDA, but at this moment I’ve (mostly) failed.

One of the tests I did; looking up at the strings of this app, for example Configuración de la consola (having activated UNICODE string search in IDA) pointed to a bunch of other strings of the same app. Which were also close in memory to the same strings in other languages. Unfortunately I haven’t been able to reference (or Xref) this strings to any code. Surely that’s because there exists some type of string array / structure which is used to access the multiple strings, but eh.. I don’t know that much to figure it out yet.

Conclusions

There has been progress. Native code execution in the black box fashion has not been achieved yet, but It’s being worked out. In my view, future research will point towards correctly mapping the dumps, handling the MMU mess and being able to browse the FCRam images apropiately.
This post could not end without special thanks to @wisk who has provided a lot of knowledge and motivation into the research!

Leave a Reply