-
Notifications
You must be signed in to change notification settings - Fork 2
Linux CIA Conversion Guide
- Preparation
- Set up devkitPro - Build some packages without binaries.
- Get rsfgen.py, extractcci.sh and makecia.sh - Glue logic scripts.
- Get/Build Brahma2 - Run uncart.
- Get/Build uncart - Dump cartridges.
- Get/Build Relys/Project_CTR - Pick apart and reassemble 3DS games.
- Get Decrypt9WIP - Decrypt games and generate xorpads of eshop games.
- Build padxorer - Decrypt eShop games from xorpads
- Dump/Decrypt cartridge games with uncart/decrypt9wip
- Dump/Decrypt eShop games with decrypt9wip/padxorer
- Extract data from a cartridge CCI
- Determine NCCH files from eShop .app.out files
- Build CIA file from an extracted CCI
- Build CIA file from .app.out files
- Optional: Decrypt and unpack an eShop's RomFS and ExeFS
A. padxorer
After this section, you'll have a full set of tools for dumping and decrypting any game you've bought for the 3DS, as well as most .3ds files you may find on the internet. This only needs to be done once.
On your system, you'll need GCC and make. You also need a python 3 version. I have only tested with as early as python 3.4.
Create a directory to keep everything in. I have a directory named 3ds
in my
home where I keep all my 3DS-related stuff. For each game, you should put the
game's files in its own directory (and for the cartridge game tools, they expect
this layout.).
Each section with shell commands assumes you start at the root of this directory.
From https://sourceforge.net/projects/devkitpro/files/Automated%20Installer/
Get devkitARMupdate.pl and put it in the directory.
Make it executable:
chmod a+x devkitARMupdate.pl
Run it:
./devkitARMupdate.pl
Make a shell script and save it somewhere:
#!/bin/sh
PS1="devkitPro ${PS1}"
export DEVKITPRO="${HOME}/devkitPro"
export DEVKITARM="${DEVKITPRO}/devkitARM"
"Source" it (This pulls the environment variables in to your environment):
source activate.sh
Now you have a working 3DS dev environment. You can activate it at any time by sourcing that script.
Go to https://github.com/paulguy/minitools and save rsfgen.py, extractcci.sh and makecia.sh to the directory made in Preparation.
Make extractcco.sh and makecia.sh executable:
chmod a+x extractcci.sh makecia.sh
Go to https://github.com/delebile/Brahma2 and download the ZIP and extract it.
Go to https://github.com/Myriachan/libkhax/tree/master and download the ZIP, then extract the files within libkhax-master in to Brahma2-master/source/libkhax.
In your shell, make sure the devkitPro environment is set up.
Change to the directory:
cd Brahma2-master
Build it:
make
Put it on your 3DS.
Go to https://github.com/citra-emu/uncart and download the ZIP and extract it.
Make sure the devkitPro environment is set up in your shell.
Change to the directory:
cd uncart-master
Build it:
make
Create a directory on your SD card named brahma
then put uncart-master.bin in
it.
Create a directory somewhere to keep everything, name doesn't matter:
mkdir 3DS
Go to https://github.com/Relys/Project_CTR then download the source ZIP, extract it in to the directory you created in Preparation (This is necessary for the scripts to find everything.).
Rename the Project_CTR directory (Also necessary):
mv Project_CTR-master Project_CTR
Go in to the ctrtool directory:
cd Project_CTR/ctrtool
Build it:
make
Go in to makerom directory:
cd ../makerom
Build it:
make
Get the latest from: https://github.com/d0k3/Decrypt9WIP/releases
Put it on your 3DS.
Copy padxorer.c from Appendix A in to its own file at the root of the directory created in Preparation.
Build it following the instructions in the file.
Insert a game card and run uncart using Brahma2 and follow instructions then wait for it to complete. Move them to /D9Game on your SD card so decrypt9 can do its thing on them.
Follow the instructions in the README for Decrypt9WIP appropriate for the game you're looking to decrypt.
Make sure to use SysNAND / EmuNAND Options -> Update SeedDB for games that use the new style 9.6.0 encryption, though I'm not entirely sure how this works since I don't have any games that use this.
You'll want to use the Game Decryptor Options -> NCCH/NCSD Decryptor feature to actually decrypt the games.
Rename it to have a .cci extension and put it in a subdirectory of the root containing the Project_CTR directory:
mkdir "Name of Game"
mv /path/to/sdcard/D9Game/CTR-P-XXXX.3ds "Name of Game/Name of Game.cci"
Use the XORpad Generator Options -> SD Padgen SysNAND or EmuNAND option depending on where the games are installed. Select /title and hit A. You'll need a LOT of free storage on your SD card (basically enough for a whole second copy of all your games and a lot of time for this task to complete.
Create a directory to put the game .app files and xorpads then change to it:
mkdir "Name of Game"
cd "Name of Game"
Copy the files for the games you want to decrypt from your SD card. They're
generally kept in: (You'll only need the .app files)
/Nintendo 3DS/<unique id>/<some other id>/title/00040000/<game id>/content
.
The unique id is printed in the SD Padgen screen. The some other id doesn't matter since it'll be the only directory there.
Copy the matching xorpads from /Decrypt9
on the SD card to the same directory
as you put the .app files.
Run padxorer on each one. Each game may have 2 or 3 parts: the main game, the manual and possibly a download play image.
For example, I have the data and xorpads for Animal Crossing New Leaf. The data
consists of 26d87923.app
and 75df13fe.app
, while the xorpads for it are
title.00040000.00086300.content.26d87923.app.xorpad
and
title.00040000.00086300.content.75df13fe.app.xorpad
. So to use padxorer on it
you would do:
../padxorer 26d87923.app title.00040000.00086300.content.26d87923.app.xorpad
../padxorer 75df13fe.app title.00040000.00086300.content.75df13fe.app.xorpad
Now you have the decrypted components of an eshop game.
I personally don't know of a good way to identify which game is which based on title IDs. You might be able to look them up or just rely on some guesswork. FBI can tell you product codes ("CTR-P-XXXX") om the Delete and Launch modes, so that mighe help as a lead.
Change in to the directory where you put the decrypted file
cd "Name of Game"
Run extractcci.sh on it:
../extractcci.sh "Name of Game.cci"
This will take a while, just wait for it to complete.
You'll need to know which files are the Application, Manual or Download Play ("Child").
Change in to the directory:
cd "Name of Game"
Run the following for each .app file:
../Project_CTR/ctrtool/ctrtool -i XXXXXXXX.app.out | grep "^ > Content type:"
Replace XXXXXXXX to match the filename.
It should return the content type for that file. The main application being "Application", the manual being "Manual" and the Download Play being "Child". Make note of which is which.
Change to the directory containing the extracted files:
cd "Name of Game"
Run the makecia.sh script:
../makecia.sh "Name of Game.cci"
If all steps went well, you should now have a working CIA file.
Change in to the directory containing the decrypted .app.out files:
cd "Name of Game"
If your game has a Download Play "Child", the command would go like this:
../Project_CTR/makerom/makerom -f cia -content "AAAAAAAA.app.out:0" \
-content "BBBBBBBB.app.out:1" -content "CCCCCCCC.app.out:2" \
-o "Name of Game.cia"
Where AAAAAAAA is the file containing the Application, BBBBBBBB is the file containing the Manual and CCCCCCCC is the file containing the Download Play "Child".
If your game doesn't contain a Download Play "Child", the command would be this:
../Project_CTR/makerom/makerom -f cia -content "AAAAAAAA.app.out:0" \
-content "BBBBBBBB.app.out:1" -o "Name of Game.cia"
With the same substitutions as the Download Play example above.
Once this is complete, you should have a working CIA file.
This isn't very useful for anything other than picking apart game files or helping with making mods for use with HANS. You'll just need Decrypt9WIP and ctrtool.
Take the CIA you created in the previous section and drop it in the D9Game directory on the SD card, run Decrypt9WIP and use the Game Decryptor Options -> CIA Decryptor (deep) option. You'll probably need slot0x25KeyX.bin on your SD card root, and you might need to run through the SysNAND or EmuNAND Options (Depending on which NAND the game is installed on.) -> Update SeedDB option to update the seeddb.bin if the game uses the new style encryption.
The CIA file will be decrypted in-place. Just copy the file back. It can be
split back apart in to it's constituent NCCH images.
../Project_CTR/ctrtool/ctrtool -x "Name of Game.cia" --contents "Name of Game"
You'll get 2 or 3 files named Name of Game.<Content index>.<Content ID>
. You
want Content index 0000, which is the main application. 0001 is the Manual,
0002 is the Download Play child and if there's a 0007 present, that's a System
Update.
To get the files out, use:
../Project_CTR/ctrtool/ctrtool -x --decompresscode --exheader="exheader.bin" \
--plainrgn="plainrgn.bin" --exefsdir="exefs" --romfsdir="romfs" \
"Name of Game.0000.<Content ID>"
That gives you enough to put it back together later and then reassemble it in to a CIA, but I'll leave that up to the reader to figure out. This file and the scripts give enough information on how to do that.
This is a program that will XOR 2 files together, used for decrypting files from xorpads.
/*
padxorer by xerpi
compile with:
gcc -O3 padxorer.c -o padxorer
usage:
padxorer <input file 1> <input file 2>
the output will be <input file 1>.out
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#define BUF_SIZE (8*1024*1024)
void print_usage();
int main(int argc, char *argv[])
{
int ret_val = EXIT_SUCCESS;
if (argc < 3) {
print_usage();
ret_val = EXIT_FAILURE;
goto exit_fail_1;
}
FILE *fd_in1, *fd_in2, *fd_out;
if (!(fd_in1 = fopen(argv[1], "rb"))) {
printf("Error opening input file 1\n");
ret_val = EXIT_FAILURE;
goto exit_fail_1;
}
if (!(fd_in2 = fopen(argv[2], "rb"))) {
printf("Error opening input file 2\n");
ret_val = EXIT_FAILURE;
goto exit_fail_2;
}
fseek(fd_in1, 0, SEEK_END);
unsigned int in_size1 = ftell(fd_in1);
fseek(fd_in1, 0, SEEK_SET);
fseek(fd_in2, 0, SEEK_END);
unsigned int in_size2 = ftell(fd_in2);
fseek(fd_in2, 0, SEEK_SET);
unsigned int min_size = (in_size1 < in_size2) ? in_size1 : in_size2;
char *out_name = malloc(strlen(argv[1]) + strlen(".out") + 1);
sprintf(out_name, "%s.out", argv[1]);
if (!(fd_out = fopen(out_name, "wb+"))) {
printf("Cannot create output file\n");
ret_val = EXIT_FAILURE;
goto exit_fail_3;
}
unsigned char *data_buf1 = (unsigned char *)malloc(BUF_SIZE);
unsigned char *data_buf2 = (unsigned char *)malloc(BUF_SIZE);
#define BAR_LEN 50
unsigned int step_bytes = min_size/100;
unsigned int temp_bytes = 0;
size_t bytes_read1, bytes_read2, total_read = 0, min_read;
while ((total_read < min_size) && (bytes_read1 = fread(data_buf1, 1, BUF_SIZE, fd_in1)) &&
(bytes_read2 = fread(data_buf2, 1, BUF_SIZE, fd_in2))) {
min_read = (bytes_read1 < bytes_read2) ? bytes_read1 : bytes_read2;
total_read += min_read;
temp_bytes += min_read;
size_t i;
for (i = 0; i < min_read; i++) {
data_buf1[i] ^= data_buf2[i];
}
fwrite(data_buf1, 1, min_read, fd_out);
if ((temp_bytes >= step_bytes) || (total_read == min_size)) {
temp_bytes = 0;
unsigned int percent = (unsigned int)(total_read*(100.0/min_size));
printf("%3i%% [", percent);
int j;
int bar_size = (BAR_LEN*percent)/100;
for (j = 0; j < BAR_LEN; j++) {
if (j < bar_size) printf("=");
else if (j == bar_size) printf(">");
else printf(" ");
}
printf("]\r");
fflush(stdout);
}
}
fflush(fd_out);
fclose(fd_out);
free(data_buf1);
free(data_buf2);
printf("\nFinished!\n");
exit_fail_3:
free(out_name);
fclose(fd_in2);
exit_fail_2:
fclose(fd_in1);
exit_fail_1:
return ret_val;
}
void print_usage()
{
printf("padxorer by xerpi\n"
"usage: padxorer <input file 1> <input file 2>\n"
"the output will be <input file 1>.out\n");
}