A few years ago, I was reading David Kushner’s book “Masters of Doom: How Two Guys Created an Empire and Transformed Pop Culture” when I found the story about the Quake shareware CD-ROM:
“Instead of just distributing Quake shareware over the Internet for free, id could sell a CD-ROM containing both the shareware and an encrypted version of the full game. Someone would buy the shareware for $9.95, then could call up id directly and pay $50.00 for the code to unlock the complete game.”
Here is an image of the “QUAKE Unlock” tool included in the CD-ROM:
Call 1-800-IDGAMES and unlock the full version of Quake for only $45.00.
It is easy to imagine what happened next, but here is another quote from the same book:
“Quake’s shareware retail experiment had proved disastrous. In theory, id was going to cut out retailers by allowing gamers to buy the shareware and then call an 800 number to place an order and receive a password that would unlock the rest of the game. But gamers wasted no time hacking the shareware to unlock the full version of the game for free.”
The tool was called QCRACK.EXE, and it was released by Agony from the GNOMON cracking group. Here is the first screen (including the usage instructions):
C:\IDSTUFF>QCRACK.EXE ■ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= ■ ■ agony! pray to the one you will pay! ■ ■ usage: qcrack [-g <game>] <challenge> ■ eg, qcrack Q12345678901 ■ eg, qcrack -g quake Q12345678901 ■ ■ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= ■ ■ Greetz to Akoo and the Mentality guys ■ working hard to bring you the latest ■ and greatest! ■ ■ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= ■ ■ The author of this excellent program ■ takes no responsibility for its use ■ and makes no warranty either expressly ■ stated or implied. This program may ■ not be used unless proper licensing ■ has been previously obtained from the ■ copyright holder of the locked program.
And here is QCRACK.EXE generating a serial number for the challenge string in the first image:
C:\IDSTUFF>QCRACK.EXE Q33333961566 ■ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= ■ ■ agony! pray to the one you will pay! ■ ■ Challenge String: Q33333961566 ■ SKU File: sku.17 ■ DOC File Location: flowlib.dir ■ Game Detected: quake2 ■ Serial Number: B198544010 ■ ■ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
But the story did not end there: the CD-ROM also included encrypted versions of every first-person shooter previously released by id Software:
Just click on the photo of your choice and get more info on how to order and unlock your favorite idware!
Here is the list of id games that could be unlocked by QCRACK.EXE:
- Quake
- Final Doom
- Doom II: Hell on Earth
- The Ultimate Doom
- Master Levels for Doom II
- Hexen: Beyond Heretic
- Hexen: Deathkings of the Dark Citadel
- Heretic: Shadow of the Serpent Riders
- Wolfenstein 3D
And since this was based on a commercial software protection solution called TestDrive (See: Transformation of ephemeral material) it was even possible that software from other vendors could also be unlocked. Pretty impressive.
I decided to reverse engineer QCRACK.EXE to unveil its secrets. I spend a couple of weekends working on it back in August 2016, but I eventually got stalled and lost interest. Then, a few weeks ago (in January 2018), I restarted working on it and was finally able to understand the general idea:
The general idea :)
Here is the quick description:
- The challenge string is used to calculate a game number.
- The game number is used as an index to extract the code name (e.g., "doom2", "wolf3d"...) from the SKU.17 file.
- The code name is used to extract a 512-bytes *.DOC file from the the FLOWLIB.* pseudo-filesystem.
- The code name and the string "Testdrive Corp." are combined and hashed into a 256-bytes SRC buffer
- SRC is used to transform DOC into another 512-bytes DST buffer.
- QCRACK.EXE includes (hard-coded) its own 508-bytes buffer which is transformed using the DST buffer (OLD + DST → NEW)
- The challenge string is used to calculate a "depth" and "offset".
- The "depth" and "offset" values are used to select some values from NEW.
- The selected values are XORed to calculate MAGIC
- A bit reversal permutation of the game number is calculated
- The MAGIC value and the permuted game number are used with some numeric constants to calculate the serial number.
I quickly noticed that a lot of work could be avoided if I were able to dump from memory the values of NEW for each code name. Here is an updated flowchart remarking the essential parts of the process:
The essential components
I tried a few debuggers but they didn't support the format (either they didn't support COFF or they got confused by the DPMI). I guess some old debugger should work but I decided it was easier to write a basic memory dumper...
I first tried to modify the arguments to the printf() calls and it kinda worked. But then, at some point, I hex-edited the binary to add an INT 3 opcode (0xCC) in order to generate a SIGTRAP and I noticed it printed a useful backtrace.
■ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= ■ ■ agony! pray to the one you will pay! Exiting due to signal SIGTRAP Breakpoint at eip=00002a37 eax=0004ff54 ebx=00050074 ecx=0005007a edx=00051066 esi=00000200 edi=00056000 ebp=000500a8 esp=0004fed8 cs=01a7 ds=01af es=01af fs=017f gs=01bf ss=01af Call frame traceback EIPs: 0x00002a37 0x00003333
I decided I could abuse that output to leak the memory values I wanted by moving the values into the registers before triggering the SIGTRAP. Here is my code to retrieve 24 bytes from an arbitrary address using the EAX, EBX, ECX, EDX, ESI and EDI registers:
def get_24_bytes(addr, game, challenge, breakpoint):
with open(TARGET_EXE, "r+b") as f:
addr = struct.pack("L", addr)
f.seek(breakpoint - BASE_ADDR)
f.write("\x68" + addr) # PUSH ADDR
f.write("\x5F") # POP EDI
f.write("\x8B\x07") # MOV EAX,DWORD PTR DS:[EDI]
f.write("\x8B\x5F\x04") # MOV EBX,DWORD PTR DS:[EDI+0x04]
f.write("\x8B\x4F\x08") # MOV ECX,DWORD PTR DS:[EDI+0x08]
f.write("\x8B\x57\x0C") # MOV EDX,DWORD PTR DS:[EDI+0x0C]
f.write("\x8B\x77\x10") # MOV ESI,DWORD PTR DS:[EDI+0x10]
f.write("\x8B\x7F\x14") # MOV EDI,DWORD PTR DS:[EDI+0x14]
f.write("\xCC") # INT3
p = subprocess.Popen([TARGET_EXE, "-g", game, challenge],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
output, errors = p.communicate()
pattern = "eax=(.*) ebx=(.*) ecx=(.*) edx=(.*) esi=(.*) edi=(.*)\r"
match = re.findall(pattern, errors).pop()
result = [struct.pack("L", int(reg, 16)) for reg in match]
return binascii.hexlify("".join(result))
And it was trivial to expand it to dump arbitrary lengths:
def get_many_bytes(addr, count, codename, challenge, breakpoint):
ptr, data = 0, ""
while ptr < count:
data += get_24_bytes(addr + ptr, codename, challenge, breakpoint)
ptr += 24
return data[:count*2]
Here is the output for the code name “quake2” (which is the correct codename for the game Quake, it is not related to the game Quake 2, which didn't exist back then):
I repeated the process for each game and I was finally able to write a working keygen:
# -*- coding: utf-8 -*-
"""
Created on Sun Feb 11 13:53:37 2018
@author: Ruben Molina
"""
DOOM2 = [1275, 6221, 556, 1556, 2458, 3521, 1242, 8275, 73, 23, 4583, 6785,
2346, 3153, 4836, 315, 325, 2720, 6793, 5472, 1294, 784, 4361, 5678,
121, 4773, 4147, 8339, 2843, 8658, 1321, 2197, 6608, 7258, 1363, 4862,
6184, 5906, 563, 5169, 7369, 6528, 6930, 2333, 6789, 1196, 8506, 3525,
3774, 2976, 8211, 331, 1983, 1214, 578, 2302, 8633, 1728, 1926, 3653,
202, 2486, 3319, 3159, 3359, 1175, 6654, 5637, 3375, 8539, 5721, 8372,
8309, 7529, 8591, 6159, 8674, 991, 5919, 5353, 3989, 1360, 3687, 3671,
4388, 5833, 3799, 1620, 4160, 6646, 3981, 8267, 7121, 3291, 6793, 418,
3385, 7694, 474, 4744, 2573, 5798, 424, 2676, 5802, 379, 2853, 4574,
660, 1330, 4218, 3528, 5516, 4897, 1664, 4783, 3787, 4021, 2830, 3747,
246, 7466, 6194, 5759, 5677, 6811, 7919, 4586, 5919, 5836, 5645, 7234,
1036, 6297, 2849, 8283, 4159, 7360, 5079, 4854, 92, 8191, 4230, 6088,
6, 2199, 7607, 8393, 6920, 4684, 4614, 2486, 2145, 1612, 594, 1027,
688, 1618, 151, 5144, 6976, 4625, 3113, 8496, 7449, 4225, 5305, 6283,
1875, 6871, 8811, 1621, 8422, 6484, 216, 4977, 70, 2320, 5168, 3044,
2144, 7652, 7011, 6495, 3067, 4844, 1811, 8002, 1662, 7299, 8898,
1419, 2191, 5656, 6326, 8584, 2624, 1074, 8635, 8789, 4204, 2068,
5384, 5260, 7373, 8593, 1483, 4647, 480, 3813, 6330, 201, 8517, 2006,
1397, 6983, 6319, 930, 2432, 5478, 7218, 706, 4649, 6779, 7065, 2672,
4792, 1564, 1972, 4781, 8488, 7632, 1577, 4254, 5771, 7913, 49, 1722,
2629, 945, 7852, 8481, 3428, 3568, 6475, 6726, 6621, 1342, 3199, 902,
6295, 3882, 450, 4452]
MASTER = [1197, 6229, 653, 1757, 2334, 3358, 1107, 8426, 97, 199, 4360, 6773,
2420, 3170, 4629, 480, 343, 2640, 6729, 5564, 1403, 956, 4464, 5735,
135, 4733, 4292, 8350, 2834, 8662, 1388, 2082, 6532, 7310, 1433,
4763, 6315, 5999, 627, 5149, 7251, 6471, 7003, 2524, 6803, 1054,
8703, 3432, 3748, 2994, 8373, 441, 2035, 1233, 654, 2130, 8595, 1673,
1906, 3702, 235, 2340, 3191, 3249, 3504, 1103, 6549, 5880, 3533,
8519, 5852, 8198, 8295, 7453, 8585, 6230, 8605, 1018, 6024, 5255,
3941, 1343, 3623, 3638, 4478, 5826, 3751, 1616, 4113, 6468, 4037,
8374, 7136, 3111, 6789, 290, 3393, 7865, 270, 4823, 2716, 5800, 282,
2697, 5746, 339, 2818, 4392, 752, 1453, 4318, 3407, 5557, 4902, 1773,
4768, 3810, 3976, 3070, 3607, 150, 7673, 6260, 5714, 5788, 6695,
7811, 4473, 6139, 5691, 5692, 7419, 1232, 6359, 2983, 8439, 4101,
7368, 5024, 4796, 223, 8112, 4248, 5913, 25, 2103, 7600, 8293, 6914,
4690, 4614, 2442, 2218, 1608, 585, 1102, 542, 1638, 85, 5305, 7096,
4847, 3178, 8671, 7595, 4113, 5367, 6287, 2044, 6778, 8936, 1690,
8415, 6488, 29, 5034, 209, 2345, 5301, 2907, 2298, 7548, 6956, 6414,
2860, 4780, 1915, 8079, 1636, 7359, 8744, 1314, 2113, 5753, 6154,
8503, 2746, 1170, 8560, 8827, 4250, 2111, 5469, 5263, 7270, 8469,
1478, 4809, 482, 3739, 6283, 145, 8620, 1911, 1312, 7102, 6358, 883,
2508, 5406, 7249, 568, 4733, 6869, 6941, 2729, 4851, 1593, 1911,
4754, 8613, 7654, 1548, 4277, 5771, 7743, 143, 1702, 2654, 801, 7746,
8486, 3341, 3491, 6565, 6763, 6413, 1399, 3174, 790, 6170, 4079, 502,
4356]
WOLF3D = [1120, 6333, 727, 1709, 2364, 3348, 1061, 8396, 151, 51, 4560, 6820,
2304, 3164, 4705, 311, 364, 2591, 6716, 5596, 1379, 816, 4425, 5693,
245, 4710, 4203, 8362, 3045, 8637, 1330, 2156, 6641, 7294, 1482,
4741, 6184, 6109, 582, 5143, 7216, 6477, 7023, 2370, 6744, 1240,
8474, 3329, 3691, 2909, 8272, 458, 2011, 1179, 583, 2211, 8649, 1750,
1951, 3585, 58, 2450, 3072, 3285, 3341, 1054, 6620, 5648, 3412, 8628,
5758, 8192, 8296, 7488, 8489, 6342, 8632, 843, 6051, 5366, 3994,
1303, 3762, 3630, 4568, 5798, 3609, 1690, 4198, 6441, 3962, 8271,
7079, 3316, 6822, 320, 3447, 7820, 502, 4822, 2591, 5664, 508, 2772,
5871, 300, 3066, 4532, 591, 1420, 4234, 3445, 5475, 4937, 1698, 4688,
3620, 4039, 2828, 3620, 151, 7622, 6385, 5719, 5659, 6753, 7755,
4602, 6109, 5706, 5736, 7382, 1094, 6159, 2940, 8421, 4311, 7219,
4959, 4671, 215, 8067, 4313, 6102, 133, 2059, 7586, 8198, 7097, 4747,
4730, 2327, 2094, 1717, 730, 1236, 595, 1697, 14, 5367, 7026, 4837,
3243, 8666, 7676, 4263, 5321, 6268, 1926, 6901, 8778, 1574, 8374,
6439, 207, 4901, 171, 2398, 5228, 2988, 2250, 7628, 6926, 6560, 2838,
4857, 2012, 7984, 1592, 7418, 8914, 1389, 2161, 5853, 6188, 8693,
2676, 1193, 8674, 8906, 4213, 2093, 5423, 5141, 7271, 8453, 1358,
4671, 412, 3798, 6267, 201, 8693, 1885, 1460, 6994, 6147, 839, 2472,
5586, 7384, 545, 4656, 6687, 6990, 2788, 4633, 1604, 2011, 4786,
8461, 7645, 1741, 4212, 5714, 7820, 24, 1591, 2689, 939, 7693, 8497,
3575, 3494, 6605, 6760, 6613, 1449, 3298, 995, 6227, 4079, 469, 4449]
HERETC13 = [1185, 6158, 736, 1552, 2419, 3510, 1223, 8410, 234, 85, 4518, 6905,
2376, 3103, 4787, 419, 325, 2610, 6845, 5447, 1457, 892, 4467,
5667, 230, 4711, 4186, 8296, 3023, 8578, 1299, 2159, 6649, 7175,
1292, 4845, 6317, 6111, 536, 5243, 7385, 6498, 7010, 2456, 6896,
1279, 8598, 3397, 3605, 2873, 8268, 469, 1947, 1153, 565, 2265,
8574, 1584, 1975, 3808, 134, 2526, 3146, 3216, 3509, 1068, 6604,
5829, 3348, 8542, 5802, 8244, 8315, 7630, 8485, 6346, 8563, 809,
6038, 5352, 3881, 1398, 3718, 3785, 4397, 5647, 3632, 1700, 4214,
6622, 4043, 8285, 6952, 3092, 6737, 461, 3438, 7787, 477, 4628,
2792, 5887, 302, 2761, 5653, 339, 2957, 4424, 606, 1468, 4110,
3583, 5483, 4867, 1787, 4648, 3625, 3862, 2830, 3697, 137, 7499,
6244, 5684, 5635, 6860, 7859, 4573, 5941, 5772, 5831, 7419, 1244,
6239, 2992, 8347, 4301, 7205, 4946, 4849, 73, 8118, 4229, 6088,
138, 2083, 7607, 8386, 6944, 4748, 4800, 2344, 2109, 1660, 576,
1183, 676, 1699, 250, 5326, 7081, 4805, 3224, 8517, 7654, 4179,
5261, 6195, 1901, 6795, 8913, 1648, 8372, 6445, 64, 4880, 68, 2513,
5149, 2911, 2242, 7614, 6995, 6591, 2982, 4634, 1880, 8164, 1611,
7378, 8801, 1337, 2054, 5749, 6246, 8528, 2753, 1145, 8457, 8758,
4197, 2059, 5431, 5129, 7413, 8661, 1489, 4698, 480, 3746, 6354,
194, 8530, 1919, 1353, 7032, 6212, 916, 2391, 5592, 7365, 539,
4808, 6672, 6994, 2595, 4707, 1772, 1817, 4686, 8449, 7566, 1615,
4186, 5765, 7685, 82, 1733, 2703, 823, 7903, 8457, 3488, 3385,
6420, 6879, 6588, 1320, 3076, 987, 6343, 3978, 489, 4505]
DEATH = [1079, 6394, 610, 1552, 2327, 3434, 1106, 8328, 55, 46, 4512, 6734,
2345, 3157, 4769, 355, 384, 2758, 6692, 5507, 1294, 1008, 4561, 5746,
55, 4715, 4291, 8357, 2912, 8601, 1462, 2206, 6521, 7243, 1525, 4712,
6222, 6134, 757, 5124, 7335, 6472, 6966, 2492, 6838, 1032, 8618, 3519,
3787, 2923, 8337, 435, 1975, 1184, 618, 2281, 8573, 1605, 1860, 3718,
95, 2501, 3134, 3317, 3469, 1044, 6517, 5867, 3352, 8649, 5669, 8367,
8445, 7515, 8602, 6344, 8491, 892, 5978, 5243, 3881, 1327, 3603, 3767,
4474, 5808, 3615, 1586, 4255, 6521, 3916, 8325, 7161, 3262, 6709, 304,
3507, 7692, 476, 4836, 2791, 5774, 457, 2700, 5672, 336, 2904, 4386,
652, 1416, 4188, 3469, 5440, 4982, 1573, 4823, 3710, 3914, 2981, 3758,
150, 7490, 6217, 5730, 5754, 6812, 7700, 4599, 5919, 5851, 5827, 7381,
1149, 6272, 3051, 8252, 4239, 7422, 4927, 4658, 194, 8103, 4167, 6049,
55, 2191, 7515, 8438, 7062, 4669, 4700, 2468, 2303, 1563, 729, 1037,
708, 1560, 48, 5255, 6935, 4794, 3130, 8452, 7473, 4326, 5172, 6247,
1932, 6680, 8797, 1767, 8383, 6444, 83, 5018, 225, 2417, 5330, 2896,
2064, 7520, 6947, 6489, 3006, 4756, 1973, 8046, 1607, 7217, 8845,
1366, 2104, 5660, 6264, 8694, 2624, 1209, 8503, 8876, 4096, 2201,
5548, 5286, 7198, 8677, 1507, 4654, 478, 3691, 6227, 106, 8673, 1980,
1302, 7001, 6196, 804, 2375, 5437, 7328, 605, 4643, 6840, 6983, 2746,
4745, 1717, 1997, 4671, 8539, 7526, 1706, 4289, 5673, 7908, 12, 1724,
2678, 865, 7933, 8517, 3334, 3374, 6457, 6699, 6522, 1333, 3160, 824,
6160, 4067, 377, 4535]
HEXEN11 = [1088, 6308, 552, 1656, 2379, 3458, 1203, 8307, 57, 141, 4468, 6735,
2539, 3228, 4638, 424, 480, 2591, 6888, 5481, 1328, 918, 4596, 5729,
229, 4739, 4336, 8426, 3031, 8492, 1326, 2238, 6630, 7179, 1481,
4637, 6328, 6031, 573, 5226, 7171, 6523, 6928, 2527, 6671, 1126,
8449, 3460, 3714, 2872, 8245, 293, 2010, 1153, 512, 2257, 8699,
1690, 1827, 3765, 104, 2516, 3184, 3222, 3352, 1101, 6606, 5740,
3471, 8694, 5684, 8369, 8214, 7537, 8645, 6285, 8619, 1003, 6031,
5185, 3841, 1289, 3734, 3596, 4583, 5817, 3612, 1651, 4121, 6618,
3841, 8362, 7019, 3134, 6881, 313, 3402, 7786, 355, 4729, 2643,
5639, 470, 2804, 5639, 351, 2843, 4521, 656, 1502, 4305, 3340, 5436,
5072, 1571, 4807, 3609, 3933, 3039, 3826, 135, 7548, 6329, 5863,
5785, 6764, 7734, 4535, 6065, 5803, 5813, 7279, 1190, 6330, 2965,
8305, 4193, 7289, 4883, 4660, 19, 7945, 4198, 6109, 194, 2235, 7479,
8308, 7115, 4770, 4792, 2469, 2242, 1687, 597, 1263, 530, 1683, 126,
5226, 7064, 4625, 3119, 8661, 7440, 4263, 5364, 6341, 1822, 6788,
8884, 1549, 8200, 6603, 173, 4879, 58, 2340, 5229, 3002, 2153, 7457,
7007, 6476, 3032, 4846, 1914, 7981, 1699, 7320, 8873, 1477, 2221,
5884, 6231, 8493, 2571, 1052, 8663, 8759, 4213, 2191, 5504, 5257,
7312, 8627, 1483, 4625, 365, 3634, 6211, 231, 8699, 1863, 1392,
7040, 6188, 847, 2347, 5579, 7372, 664, 4640, 6904, 6963, 2636,
4627, 1626, 1984, 4637, 8538, 7625, 1637, 4099, 5713, 7914, 23,
1590, 2645, 782, 7913, 8558, 3507, 3435, 6564, 6839, 6626, 1357,
3275, 915, 6306, 3851, 286, 4548]
DOOM_SE = [1116, 6215, 532, 1664, 2481, 3338, 1255, 8314, 160, 31, 4411, 6820,
2499, 3305, 4846, 484, 389, 2630, 6736, 5548, 1318, 960, 4578, 5771,
242, 4637, 4264, 8363, 2860, 8557, 1452, 2167, 6515, 7293, 1393,
4664, 6262, 5949, 719, 5211, 7228, 6421, 6980, 2407, 6795, 1233,
8686, 3492, 3817, 2911, 8194, 387, 1857, 1114, 637, 2054, 8551,
1702, 1996, 3607, 183, 2433, 3289, 3169, 3440, 1200, 6540, 5773,
3427, 8626, 5759, 8234, 8402, 7508, 8482, 6156, 8533, 842, 6041,
5217, 4076, 1451, 3797, 3825, 4448, 5811, 3597, 1630, 4350, 6451,
4031, 8356, 6953, 3228, 6896, 405, 3390, 7741, 500, 4774, 2695,
5841, 389, 2755, 5790, 355, 3015, 4511, 592, 1497, 4247, 3508, 5620,
4990, 1579, 4816, 3743, 3904, 2853, 3686, 74, 7539, 6160, 5777,
5652, 6823, 7912, 4414, 5951, 5701, 5775, 7384, 1156, 6181, 2914,
8364, 4136, 7309, 4885, 4757, 182, 7988, 4209, 5902, 153, 2162,
7580, 8300, 7110, 4633, 4862, 2411, 2287, 1721, 731, 1278, 522,
1622, 82, 5235, 7120, 4652, 3112, 8538, 7440, 4351, 5352, 6370,
1797, 6909, 8745, 1659, 8355, 6541, 70, 5079, 245, 2430, 5308,
3036, 2231, 7504, 7166, 6470, 2826, 4726, 1949, 7946, 1730, 7364,
8899, 1376, 2293, 5776, 6231, 8602, 2571, 1101, 8470, 8957, 4291,
2214, 5603, 5241, 7196, 8617, 1335, 4811, 343, 3800, 6224, 225,
8564, 1818, 1397, 7025, 6207, 909, 2377, 5443, 7239, 577, 4826,
6855, 7091, 2657, 4710, 1753, 1841, 4625, 8493, 7488, 1636, 4098,
5887, 7800, 123, 1618, 2696, 777, 7731, 8607, 3376, 3478, 6613,
6848, 6563, 1347, 3125, 888, 6299, 4006, 294, 4366]
FINALDOS = [1263, 6201, 624, 1711, 2338, 3342, 1087, 8263, 169, 73, 4497, 6758,
2348, 3238, 4614, 416, 395, 2578, 6729, 5629, 1498, 1023, 4357,
5647, 214, 4782, 4161, 8323, 2853, 8455, 1372, 2200, 6547, 7213,
1400, 4784, 6275, 6122, 583, 5124, 7324, 6422, 7057, 2349, 6858,
1147, 8661, 3529, 3640, 2852, 8411, 368, 2025, 1078, 570, 2176,
8560, 1637, 1796, 3720, 252, 2337, 3271, 3180, 3455, 1075, 6419,
5708, 3356, 8551, 5633, 8393, 8416, 7463, 8546, 6320, 8686, 1006,
5956, 5170, 3882, 1400, 3831, 3661, 4472, 5858, 3812, 1672, 4105,
6543, 3882, 8402, 7029, 3301, 6806, 407, 3428, 7712, 345, 4721,
2616, 5694, 366, 2585, 5850, 370, 2840, 4493, 552, 1442, 4205,
3574, 5397, 4980, 1689, 4670, 3587, 3891, 2964, 3725, 70, 7495,
6396, 5735, 5764, 6706, 7823, 4430, 5977, 5858, 5848, 7337, 1136,
6186, 2836, 8406, 4257, 7340, 4927, 4687, 201, 8008, 4240, 5999,
37, 2296, 7645, 8378, 7079, 4659, 4828, 2474, 2246, 1620, 543,
1165, 647, 1747, 217, 5138, 7126, 4624, 3201, 8672, 7490, 4307,
5263, 6188, 1865, 6842, 8773, 1764, 8377, 6420, 195, 5095, 69,
2496, 5308, 2895, 2207, 7569, 7028, 6629, 2975, 4727, 1997, 8064,
1543, 7326, 8847, 1434, 2208, 5717, 6284, 8522, 2773, 1146, 8638,
8706, 4331, 2186, 5469, 5261, 7374, 8605, 1324, 4614, 413, 3645,
6258, 50, 8570, 1875, 1294, 7152, 6159, 786, 2473, 5560, 7323, 649,
4709, 6732, 7051, 2741, 4677, 1697, 1978, 4746, 8676, 7509, 1562,
4160, 5882, 7687, 89, 1776, 2808, 1014, 7798, 8589, 3447, 3388,
6528, 6867, 6502, 1368, 3137, 980, 6396, 4015, 273, 4454]
QUAKE2 = [1135, 6324, 663, 1727, 2334, 3411, 1093, 8405, 142, 0, 4410, 6873,
2341, 3132, 4790, 450, 434, 2632, 6759, 5630, 1456, 1012, 4572,
5865, 212, 4799, 4106, 8284, 2935, 8681, 1430, 2301, 6549, 7314,
1463, 4834, 6332, 6039, 725, 5229, 7207, 6580, 6925, 2513, 6797,
1152, 8451, 3425, 3804, 3033, 8441, 390, 1903, 1158, 596, 2196, 8531,
1770, 1978, 3724, 64, 2484, 3122, 3288, 3443, 1033, 6494, 5818, 3486,
8492, 5717, 8260, 8432, 7451, 8452, 6293, 8477, 806, 6072, 5283,
4000, 1414, 3708, 3682, 4589, 5782, 3713, 1709, 4197, 6626, 3878,
8303, 7090, 3216, 6733, 313, 3453, 7734, 331, 4777, 2693, 5660, 382,
2758, 5707, 509, 2826, 4595, 716, 1476, 4205, 3414, 5600, 4878, 1575,
4686, 3769, 4047, 2896, 3642, 243, 7642, 6151, 5638, 5758, 6798,
7731, 4567, 5991, 5699, 5788, 7405, 1115, 6336, 2880, 8271, 4171,
7266, 4920, 4784, 20, 8152, 4342, 6052, 205, 2143, 7609, 8217, 6959,
4845, 4742, 2534, 2117, 1791, 742, 1204, 656, 1594, 22, 5253, 7105,
4661, 3314, 8650, 7591, 4144, 5213, 6147, 1948, 6899, 8859, 1565,
8273, 6612, 249, 5050, 148, 2453, 5215, 2838, 2061, 7450, 6996, 6459,
2912, 4627, 1846, 7996, 1752, 7197, 8959, 1280, 2203, 5693, 6383,
8516, 2687, 1074, 8487, 8893, 4315, 2165, 5560, 5330, 7285, 8622,
1342, 4775, 432, 3717, 6267, 233, 8601, 1884, 1395, 7146, 6208, 921,
2378, 5478, 7216, 632, 4770, 6773, 7092, 2649, 4662, 1685, 1886,
4695, 8508, 7642, 1679, 4348, 5655, 7847, 163, 1787, 2720, 815,
7922, 8586, 3348, 3523, 6643, 6734, 6516, 1300, 3143, 835, 6186,
4048, 295, 4472]
MAGIC = {0: DOOM2, 2: MASTER, 5: WOLF3D, 6: HERETC13, 7: DEATH, 8: HEXEN11,
10: DOOM_SE, 11: FINALDOS, 15: QUAKE2}
SKU = {0: "doom2", 2: "master", 5: "wolf3d", 6: "heretc13", 7: "death",
8: "hexen11", 10: "doom_se", 11: "finaldos", 15: "quake2"}
def bit_reversal_permutation(number, numbits):
""" sub_1CB0 & sub_173C """
return int(format(number % (2 ** numbits), "0%db" % numbits)[::-1], 2)
def get_depth_and_offset(d_plus_one, maxdepth_plus_one):
""" sub_1784 """
maxdepth = maxdepth_plus_one - 1
two_pow_maxdepth = 1 << maxdepth
depth, offset = 1, 0
while d_plus_one:
offset *= 2
if d_plus_one & two_pow_maxdepth:
offset |= 1
else:
d_plus_one -= 1
depth += 1
d_plus_one &= ~two_pow_maxdepth
two_pow_maxdepth >>= 1
assert depth <= (maxdepth + 1)
return depth, offset
def get_w(d_plus_one, maxdepth_plus_one):
""" sub_19EC """
depth, offset = get_depth_and_offset(d_plus_one, maxdepth_plus_one)
assert offset < (1 << (depth - 1))
return offset + (1 << (depth - 1) >> 1)
def get_d(depth, offset):
""" sub_18A8 """
assert offset < (1 << depth)
result = offset >> depth
result_counter = 7
counter = 0
depth_minus_one = depth - 1
if depth != 1:
while True:
counter += 1
result = offset >> (depth_minus_one - 1)
if result:
result = 1 << (result_counter - 1)
counter = result + counter - 1
offset &= ~(1 << (depth_minus_one - 1))
depth_minus_one -= 1
result_counter -= 1
if depth_minus_one <= 0:
break
return counter
def get_magic_number(depth, offset, game_number):
""" sub_1A34 """
magic_array = MAGIC[game_number]
magic_number = magic_array[254 - 2 * get_w(get_d(depth, offset) + 1, 8)]
while depth > 1:
depth -= 1
offset >>= 1
magic_number ^= magic_array[255 - 2 * get_w(get_d(depth, offset) + 1, 8)]
return magic_number
def get_serial(challenge):
""" sub_218C """
print "Challenge String:\t%s" % challenge
assert len(challenge) == 12
chall_s4 = int(challenge[1: 1 + 4])
chall_s7 = int(challenge[5: 5 + 7])
alpha, game_number = divmod(((chall_s7 ^ (0x3F * chall_s4)) // 0x103), 0x81)
# challenge checksum
assert ((chall_s4 / 0x80) + (alpha % 7) + game_number + (chall_s4 & 0x7F) +
(alpha / 7) == (chall_s7 ^ (0x3F * chall_s4)) % 0x103)
print "Game Detected:\t\t%s" % SKU[game_number]
beta = (alpha % 7) | (chall_s4 & 0x7F) << 3
gamma = ((1 << (beta & 7)) - 1) & (beta >> 3)
offset = (1 << (beta & 7)) - bit_reversal_permutation(gamma, (beta & 7)) - 1
depth = (beta & 7) + 1
assert depth <= 7 and offset <= 0x7FFE
magic_number = get_magic_number(depth, offset, game_number)
bit_reversed_game_number = (
bit_reversal_permutation(game_number, 7) + magic_number + 0x18)
serial = (bit_reversed_game_number -
(bit_reversed_game_number & 0xFFF80) + 0x83 *
((magic_number ^ 0x1EA3) + 0x1700A1))
print "Serial Number:\t\tB%s\n" % serial
return serial
# demo: some challenges from QUAKE Unlock
get_serial("Q83241448425") # wolf3d
get_serial("Q01332198347") # heretc13
get_serial("Q67992401927") # death
get_serial("Q42513469227") # hexen11
get_serial("Q74370370896") # master
get_serial("Q86021533743") # doom_se
get_serial("Q51236847478") # doom2
get_serial("Q21791335793") # finaldos
get_serial("Q85870332245") # quake2
Here is the output:
And QUAKE Unlock accepted each one of them :)
Thank you for buying this awesome id product.





Is there a way unlock the full encrypted games without Windows 9x?
ResponderEliminarThat would require reversing FLOW.EXE too. I'm not really interested in how that one work, but I might give it a try some day.
EliminarHello Ruben Molina,
ResponderEliminardo you have tried it with Quake106?
Link:
https://ftp.gwdg.de/pub/misc/ftp.idsoftware.com/idstuff/idouts/
Thanks for the link. It looks like those files use an updated version of TestDrive. I took a quick look at QUAKEIT.EXE and found that the challenge strings are longer and a few magic numbers changed, but the protection looks quite similar.
EliminarI also noticed that most MJ3 files match the ones from the Quake Shareware CD-ROM. The only new file is QUAKE106.MJ3. (The CD-ROM contained Quake version 1.01.)
It might be possible to update the keygen to add support for the new files, but this would require implementing some functions that I previously avoided through my memory dumper. However, since a 1.01-to-1.06 patch is publically available for Quake, I don't see the need to update the keygen.