The previous owner liked to run his engine inside this house all day long, and before he sold it, he
painted over all the doors. Can you find the right force and offset to crack it?

I spent this weekend playing DEFCON qualifiers, and I found this VM rev challenge that I ended up really enjoying.

We're given a file crackme.tscript.dso with a very unclear description of how to proceed. Some searching of the file extension yields that this is a TorqueScript file for the Torque 3D game engine.

I found the following repo https://github.com/florczakraf/dso-tools/tree/master which seemed to be a TorqueScript decompiler of sorts. Unfortunately, it was written for TorqueScript DSO version 43, and as we discovered:

version50

I discovered I was able to use the Torque3D GitHub repository as a reference to figure out the bytecode specification. I then spent the next hour decompiling the bytecode by hand. Don't ask me why I did this, I couldn't tell you. Eventually I came to my senses, but not after some cope:

cope

Now, when I say came to my senses, I mean that I decided to write 700 lines of Python to print some rough bytecode decompilation, painstakingly parsing every opcode used. At no point did I consider hm, maybe I should solve this dynamically somehow. You know, maybe use the game engine that already exists?

Anyway yeah sometimes it's fun to do things the hard way. After writing the whole decompiler, the DSO was clearly a flag checker:

checker

Let's walk through the checks. The script first loads a bunch of immediate values into memory, which are used later. After that it starts checking our input, and I'm sure the checks are slightly involved, but I was able to get through the first several by just searching for CMPNE operations, because they end up directly comparing each character to the desired ASCII value. This gets us up to flag{vmprotect?_where.

After that, the next checks are still pretty simple, but instead use a SUB operation with the desired ASCII value and then a comparison to 0 based on that later. This gets us up to flag{vmprotect?_where_we_re_going_we_.

The next checks get the ASCII value, and then iteratively subtract powers of 2 corresponding to the correct character ASCII value. For the next letter, they subtract 64, then 32, then 8, then 4. This corresponds to 108, or l. This pattern gets us up to flag{vmprotect?_where_we_re_going_we_ll_need_protecti.

Then there's one final series of checks. This one took a lot longer to figure out, but I ultimately determined it was the following system of equations:

sum(flag[-16:]) - flag[-16] - 1 = 1327
sum(flag[-16:]) - flag[-15] - 1 = 1394
sum(flag[-16:]) - flag[-14] - 1 = 1332
sum(flag[-16:]) - flag[-13] - 1 = 1347
sum(flag[-16:]) - flag[-12] - 1 = 1372
sum(flag[-16:]) - flag[-11] - 1 = 1360
sum(flag[-16:]) - flag[-10] - 1 = 1394
sum(flag[-16:]) - flag[-9] - 1 = 1365
sum(flag[-16:]) - flag[-8] - 1 = 1333
sum(flag[-16:]) - flag[-7] - 1 = 1347
sum(flag[-16:]) - flag[-6] - 1 = 1326
sum(flag[-16:]) - flag[-5] - 1 = 1338
sum(flag[-16:]) - flag[-4] - 1 = 1391
sum(flag[-16:]) - flag[-3] - 1 = 1347
sum(flag[-16:]) - flag[-2] - 1 = 1324
sum(flag[-16:]) - flag[-1] - 1 = 1333

There were probably some other checks involved here, but I wrote the below Python script to see some valid solutions:

vals = [1327,1394,1332,1347,1372,1360,1394,1365,1333,1347,1326,1338,1391,1347,1324,1333]
for c in range(32, 128):
    s = chr(c)
    total = vals[0] + c + 1
    for i in range(1, len(vals)):
        if total - vals[i] - 1 >= 32:
            s += chr(total - vals[i] - 1)
        else:
            break
    print(total, s, sum([ord(i) for i in s]) - ord(s[0]))

One solution was s0n_FR0Mm_th3_vm, and after moving the s from the front to the end, and adding a closing bracket, we get our flag:

flag{vmprotect?_where_we_re_going_we_ll_need_protecti0n_FR0Mm_th3_vms}

There were much simpler ways to solve this challenge (because I highly doubt the other 25 solvers of this challenge did all this), but honestly sometimes I enjoy writing an absurd amount of code to solve a challenge the hard way. If you want to see the code and VM simulation output (trust me, you don't), here it is.