Finished with QCRACK

calling it done

Posted by eric on March 25, 2018

Ruben has cracked QCRACK, and he kindly reached out to me once more with help on my own reversing efforts. I wrap up my own reversing efforts having felt I’ve learned all I could from this exercise.

The related posts and pages are:

Recap

(This is a recap, and captures some things I don’t think I have elsewhere.)

To just run QCRACK you’ll need the DJGPP files CWSDPMI.EXE, CWSDPRO.EXE, CWDSTUB.EXE, and CWSPARAM.EXE.

To use QCRACK, pass it a challenge string generated by the Quake Shareware program.

qcrack q12345678901

At this point it will complain about not having the sku.17 file that is used to find the game the challenge string is for based on a number generated from the challenge string.

If you already know the game, you can pass that to QCRACK

qcrack -g quake2 q12345678901

This bypasses the need for the sku file.

Regardless of how you get the game the challenge is for, it then uses that info to look up the .DOC file in flowlib.lib based on where flowlib.dir points to for that game. (You could also extract the .DOC files from flowlib.lib.)

So in addition to QCRACK.EXE and the DJGPP files, you should also have sku.17, flowlib.dir, and flowlib.lib from the Quake shareware CD.

Last Steps

I was stuck at where the last blog post left off because the disassembler seemed to have been breaking down. I believe radare2 was tripping over QCRACK using 32-bit extensions at those points.

Ruben made the breakthrough with basically a one-shot debugger script (the functions of which can be found in the link to his site I give above, my version that I made as a full script I used is found here). It injects a SIGTRAP signal that causes an error with a few bytes of memory displayed. He wrote it so it runs QCRACK to output those few bytes, parses that output and collects those bytes, then runs again to print a few more bytes and grabs those, etc, until you have all the bytes you need.

This helped me because in reversing with the disassembler it doesn’t actually run the executable so the block of memory that it builds up isn’t there, and the way I was getting around the mangling of the instructions is I navigate to each instruction. It displays the first few instructions in the display correctly, but then they get messed up.

Nothing really to say about the reversed code; it’s just several arithmetic and bit operations. My C reimplementation is here, and of course done in JavaScript in the qcracker webpage I mention above.

One problem with my reversing is I found an instance of an input challenge string, Q76820422412, that my implementation gives a different result than QCRACK. Some thoughts on how this might be: It could be bit operations, such as a shift left in a 16-bit word in the original is done in 32 or more bits in my implementation, and shift back to the right those bits aren’t cleared out as in the original, or perhaps a bit mask is off. Regarless, the nature of the key gen is that the results of this difference rarely propagates to the final output.

More considerations that were beyond the scope of this work are to investigate if there’s any deeper understanding. For instance, for things like the validity check, is there an underlying equation? Because I’m wondering if there’s some rules that say how to generate a valid challenge, or if the operations are arbitrary and it just generates a challenge until it gets what it says is a good one.

That leads to other considerations. How are the challenge strings generated? How does the Test Drive scheme in general work? How does it encrypt files in general, and how are they fully unencrypted?

But this is where I leave it off. I have achieved my goal of a first reverse engineering project and seeing how QCRACK works. Thanks again to Ruben. I have worked on this on and off for several years now and am ready to move on.