Hacking The 3ds III: Browsing the memory
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 binwalk -e
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!