SmashManiac

Secret room

72 posts in this topic

For those that didn't notice, there is a Data/Content/Secret/Rooms/SecretRoom.lua, and this file is encrypted.

I'm assuming you are supposed to have a book item pointing to this file, place it on the pedestal in DRMRoof, input the correct key, and hack one of the exits to point to it after deciphering. Problem is, with the exception of the Steam Workshop content, I explored every nook and cranny of the game I could think of, and I did not find any hints as to what that key could be, and none of my guesses worked. I was hoping that Christo would reveal a clue after deciphering PrincessChambersCopy, but that room unfortunately contains nothing of interest.

(For the curious, I was able to decipher PrincessChambersCopy by hacking Book.lua to replace math.random() with string.char().)

I also tried using some of the keys used in pre-release teaser puzzles, but to no avail. What I'm afraid of is that the key might be hidden in the original prototype, and the only way to get it right now is to purchase the overpriced Amnesia Fortnight 2012 bundle. I know that there is a similar puzzle in the prototype and that it unlocks a secret message from Brandon, but I have no idea what its contents is...

Share this post


Link to post
Share on other sites

Oh wow, that was a most unexpected gift! Thank you very very much! :)

I'll report back with my investigation results.

Share this post


Link to post
Share on other sites

Hey no worries! I'm keen to see if you dig anything up. Even if you don't you get to try the prototypes. :)

Share this post


Link to post
Share on other sites

OK, so I've been able to confirm that the key to unlock HiddenMessage.txt in the prototype is NOT the same key used to encipher the secret room in the final game. Good to know that much.

A possible lead though is that HiddenMessage.txt makes a reference to Brandon's wife/girlfriend. It's possible, although unlikely, that the secret room key is the same as her name. Unfortunately, I have no idea what it might be.

Share this post


Link to post
Share on other sites

It was a Steam key for the Amnesia Fortnight 2012 prototypes. :)

By the way, I'm still looking for Brandon's wife/girlfriend's name, since I don't have any other leads. I even thought of contacting the Office of The County Clerk of San Francisco, but consulting the registry ain't free and might not even yield results. Maybe a DF employee would be willing to share this information?

Share this post


Link to post
Share on other sites
It was a Steam key for the Amnesia Fortnight 2012 prototypes. :)

By the way, I'm still looking for Brandon's wife/girlfriend's name, since I don't have any other leads. I even thought of contacting the Office of The County Clerk of San Francisco, but consulting the registry ain't free and might not even yield results. Maybe a DF employee would be willing to share this information?

have you tried the game credits? Im not sure if her name is mentioned there.. but its worth a shot.. :)

Share this post


Link to post
Share on other sites

I'm probably not telling you guys anything you don't already know, but if you go back to the prison (Dweeb Keep) and use the debug tools artifact to open the treasure chest behind the unhackable gate in the Armory, you get an artifact that lets you change the root library directory. You can use that artifact to change the default root directory to "Data/Content/Secret". When you do that, go into the first level of the tower (Dour Tower, I believe it's called) hack the doors with bombs as you normally would to proceed. (The word "library" is spelled out in cursive collision marking above the door.)

If you've used the artifact to change the root library directory, you'll enter a smaller version of the library. If you look around, you can find a tome that contains the SecretRoom.lua item. What you're supposed to do from there, I have no idea, but I remembered the OP saying that you needed some kind of book item to be able to decipher the puzzle. I plan on continuing to play as I haven't finished the game yet.

secretroomslua.png

secretroomslua.png.adbc7e943076866c6a43c

Share this post


Link to post
Share on other sites

Yes, that's the book I was talking about. You need to use it in DRMRoof, which is near the end of the game.

Share this post


Link to post
Share on other sites

It's better if you just change it to Data/ , so you see every book, but yeah, was there, got nothing out of it. Ah, this is really hard :P

Share this post


Link to post
Share on other sites

I tried figuring out what kind of symmetric-key algorithm is used by DFHack.encipherbuffer(). Whatever it is, it looks like a block cipher with blocks of 256 bits, with a constant salt of 8 bits applied to the buffer. I say "constant" because the output is always the same.

My guess is that it's aes-256-cbc like in the first teaser puzzle, but I can't confirm it because I haven't been able to figure out what the salt is.

Share this post


Link to post
Share on other sites

Did anyone take a look at the Soundtrack? I'm thinking Hacker's Delight might contain something. Quick glance shows a "hidden track" after the initial song. Sounds like Bob's song. Also sounds like it might be an SSTV file. Unfortunately my Stereo Mix isn't showing up (stupid drivers...) Anyone able to look into this?

Share this post


Link to post
Share on other sites

I disassembled DFHack::_decipherBuffer. The algorithm is almost totally identical to covergentEncryptMem from the silent text project. The first argument to find_cipher is hardwired to "aes". I was hopping that the cipher would turn out to be something weak or broken, but that turns out not to be the case. The intended solution is to find the password, not break the algorithm, which is kind of ironic given the plot of the game.

Share this post


Link to post
Share on other sites

I had no idea the game had a soundtrack, but if it's just Bob's song, I believe it was already analyzed back in Early Access and nothing special was found in it.

tjablin, have you been able to replicate the cipher with exactitude? I've been looking at OllyDbg for 2 days now trying to do so without success. All I'd like to do is reproduce the cipher with openssl or something similar.

By the way, I didn't look at this yet, but does anybody know what's the condition the game uses to determine if decryption was successful?

Share this post


Link to post
Share on other sites

Not yet, but I'm somewhat close, I think. Do you know how to get the enciphered version of PrincessChambers.lua? I'd like to use it as a test vector. I think the logic for checking if the decryption is valid is in the function that calls DFHack::_decipherBuffer.

Share this post


Link to post
Share on other sites

Yeah, if you go into DRMRoof.lua, I'm pretty sure you can set the condition of the beam to off through a conditional somewhere, thereby acquiring PrincessChambers.lua without decrypting it.

Share this post


Link to post
Share on other sites
Did anyone take a look at the Soundtrack? I'm thinking Hacker's Delight might contain something. Quick glance shows a "hidden track" after the initial song. Sounds like Bob's song. Also sounds like it might be an SSTV file. Unfortunately my Stereo Mix isn't showing up (stupid drivers...) Anyone able to look into this?

I posted about that track when the game first came out. Brandon said nothing was hidden there at the time, but he liked my idea and that they could maybe "patch one in down the road". See: http://www.doublefine.com/forums/viewthread/13880/

Share this post


Link to post
Share on other sites

Saving the enciphered version cleanly is pretty hard because of the way mods are currently handled, and I would need to use a security exploit I haven't disclosed publicly yet to do so, so I won't reveal it.

That said, this is what I use as a test vector myself:

- DFHack.encipherBuffer('message89012', 'thisisakey') returns a binary string equal to 8814292af4838cece05b7e29b5fae85f in hexadecimal.

- DFHack.encipherBuffer('message890123', 'thisisakey') returns a binary string equal to 95bddd270e6d9e79deb5a9145f1f59c4e00b51c5a9c0520a6582ea8b67cb16e5 in hexadecimal.

Also, after verification, the condition to determine if the decryption is successful is indeed when DFHack.decipherBuffer(bookData, key) does not return nil, in which case a file overwrite occurs. Not sure if this needs to be analyzed further or if this is sufficient information in itself.

Note that the game also checks if loadfile(path) returns a function or not to determine in which state the file is.

Share this post


Link to post
Share on other sites

I have a C version that I think is working correctly, but I want to polish the code a bit before I upload to bitbucket. For me, the encoded version starts out, "5d 46 a9 9d 8f ae a3 92" and the decoded version starts out, "80 3a 00 00 06 66 28 1c". The first four bytes of the decoded output are the size of the decoded output (little endian) which should be less than or equal to the size of the encoded input minus four.

Share this post


Link to post
Share on other sites
I have posted an initial version on Bitbucket. After the latest push, I can recover PrincessChambers.lua from the encoded version.

Very nice. Your code works great after some modifications (to make it work on Windows). For funsies, I was able to use your code to try some brute force, of course to no avail. I was mostly curious how fast it would run. After setting all available optimization settings, over the night, I was able to try 148,897,650 combinations of letters (upper and lower), numbers, and a few punctuation characters. Sadly, all this indicates is that the password is at least 5 characters in length, and/or contains non-alphanumeric characters that aren't '!', '.', '?', ' '.

In addition, I tried some simple dictionary attacks, which I tried each word in a variety of arrangements, such as 'word', 'Word', and 'WORD', so whatever the key is, it's not just a simple word.

I was also able to do the reverse and encipher the plain text princess chambers LUA with the "With this incantation..." key, and it resulted in the original ciphertext.

At least your code basically proves that we aren't meant to break the encryption itself, as was mentioned earlier. We are simply meant to find the key the normal way, probably through clues somewhere in the game.

tl;dr It appears your code is a perfect replication of the decryption method that the game uses, and as a bonus, can be reversed to encipher like the game. However, it's AES-256, so game over, man.

Share this post


Link to post
Share on other sites

Would you mind pushing the modifications necessary to get the code to build on Windows upstream? I tried running strings on all of the files in the game and using the output as passwords (minus strings containing ' and "), but none of them worked. Also, I suspect that two rounds of decoding might not really have been necessary. I think my version of the cipher text ended up double encoded when I entered, left, and re-entered the room before solving the puzzle. How did you detect whether the password was correct? Right now, the game just checks that the four four-bytes interpreted as a little-endian integer are less than or equal to the size of the cipher text minus four. I suspect the "less than" is not "equal to" due to padding. I think all of the bytes past the size of the "deciphered" size should be zero. Maybe it would be worth reversing the encipher function as well?

Share this post


Link to post
Share on other sites
Would you mind pushing the modifications necessary to get the code to build on Windows upstream? I tried running strings on all of the files in the game and using the output as passwords (minus strings containing ' and "), but none of them worked. Also, I suspect that two rounds of decoding might not really have been necessary. I think my version of the cipher text ended up double encoded when I entered, left, and re-entered the room before solving the puzzle. How did you detect whether the password was correct? Right now, the game just checks that the four four-bytes interpreted as a little-endian integer are less than or equal to the size of the cipher text minus four. I suspect the "less than" is not "equal to" due to padding. I think all of the bytes past the size of the "deciphered" size should be zero. Maybe it would be worth reversing the encipher function as well?

Yeah, I should be able to do that tonight.

That's what I was going to try next, but you beat me to it. I considered the key valid if both rounds of deciphering succeeded without any of the existing validity checks failing.

Actually, I assumed your ciphertext was correct. When enciphering, I also used two passes so that it takes two passes to decipher. I could dump mine to be sure though. I don't think it would be double encoded unless it's supposed to. Otherwise, the deciphering should fail by putting in the correct key after leaving and entering (unless they try multiple passes just in case), which would be quite a nasty progression blocker. Also, two passes would make sense because quite a few keys result in false positives on the first round according to the "<=" check you mentioned, and it's pretty much guaranteed that the second pass will fail after a false positive first pass. A better check would have been to check if it's also greater than the original size minus the block size, but that's unnecessary with two passes. It's definitely worth verifying.

For sure, the padding must be zeroed out. If it isn't, the last block of the resulting ciphertext doesn't match the original ciphertext when reversing the process.

I think it's worth reversing the encipher process just to make sure that there isn't any funny business going on, but I don't expect it to provide us with anything we don't have at this point.

Share this post


Link to post
Share on other sites

(Double-posting so subscribers will be notified, as there is new information.)

I've prepared my version of your code; I just ran out of time. It does seem like your ciphertext got double encoded by accident. There's a global variable that's supposed to prevent that, but there's a bug where the game saves the enciphered version of the book and doesn't save the global variable that prevents it from being enciphered multiple times, so it gets enciphered when already enciphered.

I've managed to get the ciphertext for PrincessChambers.lua directly from the game, and it was encoded twice, but after entering the key in the game to decipher the book, the beam wouldn't turn off, meaning I got the progression blocker I mentioned earlier. So I went to a state before initially entering the DRMRoof, entered it again for the 'first' time again, dumped the PrincessChambers.lua ciphertext, and it was indeed encoded only once. It is exactly the same as the result of deciphering your enc.lua with one pass. So I would suggest doing only one pass from now on, though technically there is no guarantee that SecretRoom.lua is only encoded once. However, since it's pretty obvious that we are meant to decipher the book on the pedestal, and that only does one pass of deciphering, it's a very safe assumption.

It would probably be a good idea to try using the strings from the game again, using only one pass. Also, if brute forcing watch out for false positives. One example is 'hq8'. The result of deciphering with that key (and many others) passes the validation checks, but the length is usually nowhere near the original size, which is why I said a better check would limit the valid size to between the ciphertext length minus header and that minus the block size. Unfortunately, entering a false positive key to decipher SecretRoom.lua on the pedestal results in the game replacing SecretRoom.lua with garbage data, as it thinks it was successfully deciphered. The "SecretRoom.lua has been modified" message shows as well. Lucky that we can go back in time...

Share this post


Link to post
Share on other sites

Avoiding this trouble with false positives while brute-forcing and game bugs are two of the reasons why I wanted to replicate the cipher outside the game. I'm completely burned out trying to figure out that stuff though, so let me know if you guys are able to do so.

Share this post


Link to post
Share on other sites
Avoiding this trouble with false positives while brute-forcing and game bugs are two of the reasons why I wanted to replicate the cipher outside the game. I'm completely burned out trying to figure out that stuff though, so let me know if you guys are able to do so.

Well, we have the cipher replicated, and I made the changes necessary to filter out all false positives (as long as the result is a compiled LUA file). tjablin, if you give me the rights on your Bitbucket project, I'll push my changes so that it will work on Windows as well and provide the ability to encipher the same way the game does. My username on Bitbucket is mrnetrix.

For anyone who just wants to try the compiled Windows version, you can get it here: http://www.mediafire.com/download/k3an8tsjuvk7l3u/dfcipher.zip

I didn't include the encrypted SecretRoom.lua in case that's not allowed since it is technically copyrighted material. Anyone that owns the game can easily copy over the file from "...\SteamApps\common\HacknSlash\Data\Content\Secret\Rooms\SecretRoom.lua" and run the tool on it.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now