Jump to content
Double Fine Action Forums


DFA Backers
  • Content Count

  • Joined

  • Last visited

Everything posted by SmashManiac

  1. OK, I verified and I don't think generating the incantation would cause a crash after all. I may be wrong, but it's unlikely. Worst case scenario, it's only going to copy 44 bytes past the end of the block of text, which is going to be ignored when comparing with the user input since the block of text is NULL-terminated. So the only real cause of concern for crashes is the patch applied on ntdll.DbgUiRemoteBreakin, which I'm pretty sure is the cause of the weird stuff gateway2006 was experiencing. Speaking of which, I forgot to mention that the patching code is executed twice: once when starting the program, and another time when it terminates. Pretty sure this is another bug since there is no point in patching anything after the main code has ended. As for the list of incantations, I started doing it manually, but there are a lot more combinations than I expected...
  2. Just noticed while looking back the thread that T3slider had already found the "Ida" message. Sorry about that. In any case, I'm done! First, the decompiled code. Note that I called Incantation the final result and Book the huge blob of text that was originally posted by MonoS up to " BY THE FEAR OF OTHERS." var Hash = sha1(kernel32.GetVolumeNameForVolumeMountPointA(kernel32.GetVolumePathNameA(kernel32.GetWindowsDirectoryA()))); var HashLength = 20; var IncantationLength = 4; memcpy(Incantation, Book, IncantationLength); Incantation[4] = '\0'; var SentenceEnd = Book+4; for (var HashPos = 0; HashPos < HashLength; HashPos += 2) { var HashCopyLength = HashLength - HashPos; if (HashCopyLength >= 2) { // always true lol HashCopyLength = 2; } memcpy(Seed, Hash+HashPos, HashCopyLength); var RandomByte = 0x00; for (var c = 0; c < HashCopyLength; c++) { // RNG RandomByte ^= Seed[c]; } var MatchingWordCount = 0; var Word = strstr(Book, Incantation+IncantationLength-4); // looking for last 4 letters of incomplete incantation inside Book if (Word) { // always true lol do { // counting number of matches if (Word < Book+1526) { // Book has a length of 1530 characters MatchingWordCount++; } Word = strstr(Word+4, Incantation+IncantationLength-4); } while (Word); if (MatchingWordCount == 0) { break; // uh-oh, this may cause a crash because the sentence has already ended } var RandomWordNumber = RandomByte % MatchingWordCount; // pick random match MatchingWordCount = 0; Word = strstr(Book, Incantation+IncantationLength-4); while (Word) { // start counting again until find the random pick if (MatchingWordCount == RandomWordNumber) { memcpy(Incantation+IncantationLength, Word+4, 4); // append the 4 characters after the random pick to the incantation IncantationLength += 4; Incantation[incantationLength] = '\0'; SentenceEnd = Word + 8; break; } MatchingWordCount++; Word = strstr(Word+4, Incantation+IncantationLength-4); } } } while (Incantation[incantationLength-1] != '.') { // no more random stuff, copy what remains of the current sentence Incancation[incantationLength] = *SentenceEnd; IncantationLength++; SentenceEnd++; } Incantation[incantationLength] = '\0'; // end incantation return IncantationLength; So basically, here's how the incantation is generated: 1 - Get the SHA-1 hash of the volume GUID path of the Windows install directory 2 - Copy the first 4 characters of the block of text in the incantation 3 - Count all matches in the block of text for the last 4 characters of the incantation 4 - Pick one match at random using the following formula: (bitwise XOR of 2 bytes of the hash, starting from the left) modulo (number of matches) + 1 5 - Append the 4 characters following the random pick at the end of the incantation 6 - Repeat steps 3 to 5 until no match is found or until all bytes of the hash have been used 7 - Complete the rest of the incantation with what followed the rest of the last random pick up to a period I have been able to verify the validity of this method using my own hash/incantation combination. This is both simple and brilliant. I love it. One more thing: As I noted in comments, I noticed the possibility of a crash if the last 4 characters picked overflows the end of the block of text. Not sure if that case is possible or not yet though. In any case, I believe the EXE has revealed all of its secrets now. I guess the only worthwhile thing left to do now is to make a list of all possible incantations and their probabilities.
  3. Used the entire day today getting used to debugging with OllyDbg and reading x86 assembler. Turns out that debugging a self-extracting program is a pain in the donkey, since OllyDbg can't figure out what's executable and what's not. But it was worth it. -- First, I was able to decompile the debugger detection code into pseudocode. It's... doing things it really should not do. Note that DebuggerDetected() is how I called the code that overwrites "SUCCESS/HASH/" with "FROM/DEBUGGER". It doesn't do anything else. As for the pseudocode, behold: var Debug = kernel32.GetProcAddress(kernel32.LoadLibraryA("ntdll.dll"), "DbgUiRemoteBreakin"); var DebugLength = 0x00; do ( DebugLength++; } while (Debug[Length-1] != 0xCC); // 0xCC = INT3 instruction var CustomDebug = new byte[0x1000]; memcpy(CustomDebug, Debug, DebugLength); if (DebugLength > 0x00) { var a = 0x00; do { if (Debug[a] == 0xE8) { // 0xE8 = CALL instruction CustomDebug[a+0x01] = Debug[a+0x01]-CustomDebug+Debug; // really dirty patch } a++; } while (DebugLength > a); } Debug[0x00] = 0xB8; // MOV instruction Debug[0x01] = DebuggerDetected; Debug[0x05] = 0xD0FF; // CALL instruction Debug[0x00] = 0xB8; // MOV instruction Debug[0x08] = CustomDebug; Debug[0x0C] = 0xD0FF; // CALL instruction Debug[0x0E] = 0xC2; // RETN instruction // by coincidence, Debug[0x0F] == 0x0000 if (kernel32.IsDebuggerPresent()) { DebuggerDetected(); } Notice that ntdll.DbgUiRemoteBreakin is overwritten in the process. This is the resulting pseudocode: DebuggerDetected(); CustomDebug(); return 0; So basically, what this code does is: - Copy the function ntdll.DbgUiRemoteBreakin in a new array of 4096 bytes - Patch the copied function so that calls performed within the copy remain in the copy - Patch the original function so that a call to DebuggerDetected() followed by a call to the patched copy is executed if a debugger attempts to attach to the process - Call kernel32.IsDebuggerPresent() to check if a debugger was already attached to the process before the patch, and call DebuggerDetected() if applicable What I find rather surprising with this method is how badly the patch is applied. And by that I mean that it doesn't work. The idea is neat, but it makes incorrect assumptions about the contents of the function and how memory is allocated. For example. it assumes that bytes 0xCC and 0xE8 are automatically INT3 and CALL instructions respectively. Turns out that on my Windows 7 64-bit PC, one instance of 0XE8 inside the function is actually a parameter, which completely corrupts the code. So if I try to attach OllyDbg after "YOUR INCANTATION: " has been printed, the process crashes. Oops. -- Also, I finally found the unknown data while debugging! My assumptions were correct: it's a SHA-1 hash of the volume GUID path on which Windows is installed. For example, mine is: \\?\Volume{62ca4546-c809-11df-990d-806e6f6e6963}\ To find out yours, simply run mountvol in cmd. So to recap, here's how to generate the tweet manually: - Get the volume GUID path on which Windows is installed - Hash the path with SHA-1 - Encode the hash in Base64 - Append "SUCCESS/HASH/" or "FROM/DEBUGGER" immediately before the encoded hash - Encrypt the result using the following RSA public key: - Encode the encrypted data in Base64 - Append "@Noughtceratops " before the encoded data So now we can all send fake tweets to Brandon! Well except me, since I don't have a Twitter account anymore. But that's besides the point. -- One mystery left: how is the incantation generated? Stay tuned!
  4. My current assumptions: - The unidentified 20 bytes is a SHA-1 hash - The hash is computed only once - Whatever is hashed is something that has a high probability to be unique to each PC - Whatever is hashed is used as the seed to generate the incantation What I tried without success to determine what is used as a seed: - Rainbow table attack - Changing the location of the EXE - Hashing my Windows product ID - Hashing my computer's name - Hashing my Windows username - Hashing my network card's MAC address - Hashing my HDD volume number - Hashing my HDD serial number - Hashing my CPU serial number - Change capitalization or encode to Base64 before hashing - Capture Windows events generated by the EXE through Process Monitor I'm getting to the point where I might as well start going step-by-step through the program while deciphering the assembly code to understand what's going on, which I'm not looking forward to considering I'm not familiar with the x86 instructions set. I've been able to verify by myself that the incantation generation starts immediately after pressing Enter on "YOUR INCANTATION: ", but not the inner workings of the process.
  5. +1 for a GOG key. I won't go in the details to avoid a useless debate, but I despite Humble Bundle.
  6. I went back to my first computer I used and did the custom RSA key patch trick again. This is the result: SUCCESS/HASH/J+DteJIfgxx0m9Li6OheFvszgN4= Also, I believe I figured out what is this new base64-encoded data: a SHA-1 hash. I base this on the fact that the decoded data is 20 bytes long, and considering the concatenated string literally contains the word "HASH". But a hash of what? I haven't figured it out yet. I tried hashing my incantations, but they weren't matching. By the way, so far the tweet construction is looking as such: unknown data -> SHA-1 -> Base64 -> append to "FROM/DEBUGGER" if debugger detected or "SUCCESS/HASH/" otherwise -> RSA 512-bit -> Base64 -> append to "@Noughtceratops " -> copy to clipboard Just... wow. -- I also did a more throughout analysis of the contents of the EXE, and found more cool stuff. First of all, I found an obvious string near the end of the EXE that other people missed, probably because they incorrectly decrypted the EXE from the video by not figuring out where the ENC file ended inside the MP4: "One last puzzle brought to you by Double Fine Productions, and a very special Hack ‘n’ Slash character, Ida." Super interesting tidbit, especially considering the main character's name has been revealed to be Alice, not Ida. We'll have to look forward to that character! Speaking of which, IDA* is a graph search algorithm. Hmmm... Next, at the end of the huge blob of strings previously found with the incantation stuff, right after the string "YOUR INCANTATION: ", I found the strings "aes" and "rijndael". I didn't realize they were strings when I solved the puzzle months ago, but turns out that AES encryption is a Rijndael cipher. Probably just an easter egg, but it's pretty funny. Also, the huge blob of strings contains the "FROM/DEBUGGER" string, but not the "SUCCESS/HASH/" string. It was located in a different location entirely. Interestingly enough, immediately before it are pages of zeros, but there's some data afterwards before more pages of zeros appear. Not sure if it's relevant for analysis since it contains some trivial stuff like the base64 alphabet (why am I not surprised), but it might be worth a look once we understand the program better. Finally, speaking of the "FROM/DEBUGGER" string, I believe the strings "ntdll.dll" and "DbgUiRemoteBreakin" immediately afterwards are there because the EXE is testing ntdll!DbgUiRemoteBreakin to detect the debugger. I'm not familiar enough with debuggers and the Windows API to confirm this, but that's my guess. ...I really need to learn how to use debuggers.
  7. Well, the puzzle might be solved, but not how it works, and that's the part that's been bugging me for a while now. The theory that the RSA key is used to encrypt the tweet before encoding to base64 makes sense. So how about hacking the RSA key with a custom one for which we know the private key? So I generated a custom key pair for which the public key had the same number of bytes than the real one. I found a match while generating 512-bit keys. Here is my custom key pair, again encoded in base64 (and split in multiple lines to not break the forums): I first thought of hacking the key directly in the EXE, but the data is compressed so that's hardly feasible. It's easily possible to do the next best thing and hack it in memory while the program is running. I used Process Hacker to do this job. And it actually worked. First of all, I've been using a different computer, so I got a different incantation: AND WITH THIS INCANTATION I FOREVER INTWINING OURSELVES TO OUR COMBINED DESTINIES WHICH PRODUCE A KIND OF INFINITE REWARD IN THE CONSTRUCTION OF MECHANISMS TO AID OUR DISCOVERY OF KNOWLEDGE AND TRUTH. Then, I ran the hacked program a few times and collected the tweets. Every tweet was different, but after applying my private key on it I got consistent results. By consistent, I mean that I got 2 unique results, depending on whether I was running the process through OllyDbg or not. Through OllyDbg: FROM/DEBUGGERO/DcajbDGml/Rgr2TEFVYKzUkgo= Normal execution: SUCCESS/HASH/O/DcajbDGml/Rgr2TEFVYKzUkgo= So it looks like the first 13 characters is the method used to crack the incantation, followed by a unique base64-encoded string for which I have yet to decipher its meaning. Any ideas from there? It might help if others would try hacking the public key as well and post their results... P.S.: I'm starting to wonder if Brandon eats base64-encoded cereals for breakfast...
  8. OK, I have to revive this thread, because there are some mysteries yet to be solved related to this puzzle, and I just found an interesting lead. Previously, Illessa discovered this base64-encoded string while investigating the memory map of the executable: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMeqDCPIoPMd8CSnjGI96lJG3ijSEMDFuJCG4yaWUgbzpHijnyhQtAWn8PXhWOeie0v56AcqjXtKuSeSeLalrZsCAwEAAQ== I decided to dig a little deeper, so I first converted the data to hexadecimal: 30 5C 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 05 00 03 4B 00 30 48 02 41 00 C7 AA 0C 23 C8 A0 F3 1D F0 24 A7 8C 62 3D EA 52 46 DE 28 D2 10 C0 C5 B8 90 86 E3 26 96 52 06 F3 A4 78 A3 9F 28 50 B4 05 A7 F0 F5 E1 58 E7 A2 7B 4B F9 E8 07 2A 8D 7B 4A B9 27 92 78 B6 A5 AD 9B 02 03 01 00 01 I decided to search if the first few bytes could give a clue as to what it was. Turns out, I found a correlation between the first 24 bytes of this sequence and the beginning of multiple RSA keys. For example, it can be found in this official Cisco documentation: > An Introduction to IP Security (IPSec) Encryption So I think it's safe to assume that this is a RSA key. But for what? And why is it there in the first place? -- Also, nobody has figured out yet how the incantation and tweet are generated. Here are mine: AND SPIRIT WHICH CAN BREAK THE BOUNDARIES OF UNDRESTANDING SUCH THAT I ALWAYS REALIZE THE POWERS I HAVE OVER HIDDEN BUT NOT INACCESSIBLE TRUTHS. @Noughtceratops AxhEzVOUxfmceQbsoGSGbn8hqwPgalZhBpzdIchseZaNY/8979YoymMc0mzXsUBixIqy5MoriU4TVWw6sJNpog== Again, the tweet is base64-encoded data, but I haven't been able to deduce anything from it by itself. If somebody could compile all the tweets generated so far, convert them all to hex data and compare them, we might be able to figure something out...
  9. I saw the news release on GOG.com and didn't notice they were free releases! Thanks for pointing it out!
  10. I don't think it's possible to have a realistic motion-based sword-fighting engine, if only because controllers cannot simulate weight nor resistance without being incredibly expensive.
  11. Design it any way you want, DRM is always going to punish the legitimate user and be bypassed by pirates. In average, DRM only prevents pirate copies for 0.20 days. Last year, that number was in the negative. Source:Vigilant Defender
  12. Thanks a lot for the reply gsm, and I also find your input very interesting! I don't have anything else to add though so I'll leave it at that.
  13. I agree with that. What you're saying makes a lot of sense, although it doesn't quite seem to match the information contained in the original post in terms of time flexibility for individual tasks, at least in how the data is displayed to the team. But in any case, it seems odd to me that the concept of a fixed development cycle is present, even if it's just a monthly one. It doesn't seem to be a system that is flexible enough in my opinion. Sure, you're going to waste a lot less time than if the entire project was planned in advance, but you're still going to lose all the time until the next monthly review for the tiniest of details. Not to mention, making any kind of daily report takes a lot of time on the long run and most of it is wasted on the obvious or the pointless. The whole revision process needs to be continuous and event-based in my opinion to be fully effective. As I said earlier, having goals is usually a good thing, and I agree that they need to be clearly defined. In the context of video games however, they also need to be mutable. Clearly the job of the project manager is to make sure that the team follow the same set of goals and change them based on the team's feedback. My point however is that the project manager should not define individual schedules to synchronize the team, only priorities. I might have been unclear, but my point was to avoid unnecessary pressure, not completely remove the pressure. Oh, and if anybody is motivated for their job simply because of free food or drinks, there's something seriously wrong somewhere.
  14. This seems to me like a really strange management model in the context of video game development. Everything is so strict and detailed up to the minute. How are you supposed to maintain creativity and keep a critical eye on your work and the team's when your own schedule for the month is so tight and rigid? Seems to me like this would cause major overhead and slow down the entire development process. In fact, this is exactly what I witnessed during my own professional career in the video games industry. Besides, it's pretty much impossible to make a reliable time estimate for something as complex as software. This adds a lot of constant pressure on the entire team, burning them down in the long term and forcing them to rush through late tasks in a way that will either downgrade the quality of the product or extensively delay the product's completion later on. And then in the end, everybody is supposed to do overtime to make the schedule work somehow, causing even more wasted resources and an exhausted team that is even less productive than before. I'm not saying that it's not OK to have a set of goals in advance or that time management isn't important, but rather that excessive planning can be as bad as no planning at all.
  15. Again, what are you talking about? The origami killer's identity? Because that wasn't part of the game's ending, so I'm very confused by your comments.
  16. Uh, I didn't notice anything wrong with Heavy Rain's ending. What are you guys talking about? Also, you don't have to agree with David Cage's philosophy about games to appreciate his talks. I just find interesting the way he approaches game design in order to create emotions.
  17. I have to disagree with you here: - Knowing that Don's message is pre-recorded is completely irrelevant for solving the puzzle. - The game informs you about that fact in the message room if you didn't notice it in Domino's room. - Personally I didn't have any problem with that, but I agree that it should have been more obvious. However, I'm surprised you didn't point out about the devious rope of clothes hidden at the very end of the alley that could be noticed only if you walked on the left side. I still rage about that one...
  18. Hi everyone, I just remembered about a relatively obscure keynote by David Cage (Fahrenheit, Heavy Rain) I assisted last year, and since I thought it was related to Double Fine Adventure I wanted to share it with you: Description: Concordia University held three of the 29 symposiums staged under the banner of Entretiens Jacques Cartier. On October 1, the symposium titled Experiencing Stories with/in Digital Games / Récit(s) et jeux numériques was held in the J.A. DeSève Cinema. Keynote Speaker: David CAGE, Founder and CEO, Quantic Dream.
  19. The Hostage Trials, because you always wanted Solid Snake to kidnap your buddy and call you for ransom.
  20. A world made of mayonnaise. Inside the sun. Some miniature HQ that controls somebody's brain. A parallel universe in which time goes backwards and affects our universe. A barn. An empty place in the middle of Antarctica. An asylum where inmates are normal and doctors crazy. The Internet central office. Through the quantum hole that eats my socks inside my dryer. A cat/dog food processing facility. The Auschwitz concentration camp. A dump. A corrupted heaven. Tim Schafer's dream home. Whetever's behind the mysterious door inside the Blue Casket. Paradox Land. A refuge for homeless people. An alien spaceship as imagined in the early 1900.
  21. (I think) hes just referring to that hes _not_ talking about just an open game that is just complete freedom and you can do literally anything, like in the real world. not VR as in simulating that youre there. Sorry Mats, but I don't understand the meaning of your sentence. Besides, I'd prefer to have the answer directly from Avi anyway.
  22. I think you're getting the wrong impression. It's always the same 4-6 people that writes huge walls of texts in their posts, and it's hard to reply to them without writing another wall of text in return. But I agree that those people should structure their text better. But most importantly, people write a lot here because they're passionate about discussing video game design and there's no real equivalent elsewhere. Writing novels could never achieve that.
  23. Just thought of something. Maybe it would be better waiting until DFA is released before sending the surveys. It would allow additional feedback.
  24. Hey Avi, how do you define virtual reality in the first place? For me, it means interacting with a computer software without any noticeable interface from the user, and that definition doesn't match anything you've written so far. I'm not quite sure about what you call detachment either, but it's true that I don't feel a lot of empathy in general. I rarely watch TV/movies and read novels other than comedy. For instance, in my entire gaming experience, I've only emotionally bonded with 3 characters: Aeris from Final Fantasy VII, Kratos from Tales of Symphonia, and Miles Edgeworth from Phoenix Wright: Ace Attorney. Not that I haven't shared emotions with other characters as well, but they never felt interesting enough to me to be even worth consideration. Also, I don't understand your comment about games not being more about oneself than passive media. If you're the one doing the input, how can it no be about yourself? Even if you just influence rather than have total control, it's still your decisions and your interactions. If I didn't care about my input, I wouldn't play video games in the first place. And finally, I find it extremely ironic when people think they can design better stuff by knowing less about what they're trying to create. It just makes no sense at all. Pretty much, yeah. Impressive list of skills, but all of them seemed completely irrelevant to game design, except for the one that you explicitly stated you didn't have.
  • Create New...