Decrypting Noita's files
After I got my hands on a game called Noita I couldn't help but get curious about how the game was implemented, so naturally I tried to take a look at its files.. But most interesting files were hidden away inside of a file named "data.wak". How could I gain access to these files?
Discovery
I tried to see if it was some kind of known file format by using the file
tool inside of Linux. This tool contains a database of known file formats and will immediately give an indication of what the file-type of any file could be. But in this case file
only gave the nondescript description 'data'.
This meant that it wasn't a known file format.. The next step was to analyse the file with ent
, this tool measures the entropy of the file, in this case it told me that the entropy of the file was 7.999 bits per byte, this means that the file contained no detectable redundancy. That indicates that the file is either encrypted, compressed or both.
Misstep
Inside of the accessible game files there was a folder named licenses, after looking through it I found out that Noita used a compression library called "fastlz". I spent a lot of time trying to use this library to decompress the .wak file, with no success.
I decided to take a closer look at what the game was actually doing with the file data instead of trying things on a hunch.
Ghidra and GDB
My next step was to look at what the code was actually doing, for this I used Ghidra to look a the disassembled and decompiled code. With this I created theories about how the code worked.
To find out what code I needed to look at I used GDB to set breakpoints on standard Linux file loading functions. This way I eventually found out what code dealt with loading "data.wak".
After a lot of trail and error I found the exact point at which the file names got loaded from "data.wak". This was a great milestone for me, so I took a picture 😁.
The file name secrets_secrets_secrets.png piqued my interest and kept me motivated!
After more experimentation I found out where the file contents got loaded, I also discovered the file's contents was loaded in-place of the unreadable version. This meant that unreadable and readable version of these files are the exact same size, so that rules out compression, it's only encrypted.
Misstep 2: Reimplementing AES by looking at assembly code
Noita used standard AES encryption.. I do not have enough experience with this kind of stuff to recognise that, so instead I went through the long and painful process of recreating the AES algorithm by looking at the disassembly/decompiled code in Ghidra & GDB.
This took a while, but eventually I managed to extract all files from "data.wak". Success! Secrets Secrets Secrets!
So what was the contents of secrets_secrets_secrets.png? Here it is:
This was a very cool surprise . After sending a couple emails and waiting a bit I got to see my name in the credits of the game!
I'm very proud of this accomplishment, I didn't have any reverse engineering experience so it took a lot of time and effort.
You can checkout the code I wrote to extract all of the files here: https://github.com/dextercd/Noita-Wak-Extractor/blob/master/src/enc.cpp
I hope this was interesting to you! :-)