Shadow Page Table

Solve time: 91 mins
Flag: [email protected]

This challenge was a nice little ransomware decryption challenge. I completed this challenge statically which I am proud of (too lazy to install a windows VM).

Once I unpacked the chall zip, I was presented with a folder called Files and a file called UnlockYourFiles.exe.

Running file on the binary showed me it was a windows binary.

UnlockYourFiles.exe: PE32 executable (console) Intel 80386, for MS Windows  

The crux of the chall was realizing we could guess the xor key by realizing that latin_alphabet.txt.encrypted is 26 bytes so probably one byte for each letter of the alphabet. I was able to confirm this guess by using it the key to decrypt the rest of the file. The xor decryption routine only operated on 8 bytes at a time. Here’s the xor decryption routine pseudcode:

 1004011f0    void do_xor(int32_t arg1, int32_t arg2)  
 2  
 3004011f0    {  
 4004011f0        int32_t ebx;  
 5004011f3        int32_t var_8 = ebx;  
 6004011fc        char* ecx = nullptr;  
 7004011fc          
 800401201        while (ecx < 8)  
 900401201        {  
1000401201            ebx = ecx[arg2];  
110040120f            ecx[arg1] = ROLB(ecx[arg1] ^ ebx, ecx) - ecx;  
1200401212            ecx += 1;  
1300401201        }  
14004011f0    }  

Where arg1 is the encrypted buf and arg2 is the key.

I rewrote the algorithm in python:

1def decrypt(buf,key):  
2    ecx = 0  
3    ebx = 0  
4  
5    while ecx < 8:  
6        ebx = key[ecx]  
7        buf[ecx] = rol(buf[ecx] ^ ebx,ecx) - ecx  
8        ecx += 1  

I then wrote a key search function based on the idea that we knew the original contents of latin_alphabet.txt.encrypted.

 1with open("Files/latin_alphabet.txt.encrypted","rb") as file:  
 2    bvar = file.read()  
 3      
 4known_cipher = "ABCDEFGH"  
 5  
 6def solve_for_key(buf):  
 7    key = []  
 8    for ecx in range(8):  
 9        for k in range(255):  
10            ebx = k  
11            out = rol(buf[ecx] ^ ebx,ecx) - ecx  
12            if out == ord(known_cipher[ecx]):  
13                key.append(k)  
14  
15    return key  
16key = solve_for_key(bvar)  
17print(key)  

I started with lowercase “abcdefgh” but it didn’t work so I swapped it for “ABCDEFGH” and then it worked. It took me a while to correctly implement rol in python. Got confused between hex and dec conversions and how to handle the high bits.

My decryption routine worked on text until it got to the encrypted images and then it would totally break. I realized it was a bug in my sub instruction implementation. The assembly sub instructions wraps around when it goes negative my python implementation did not. So I added:

1can =  l - ecx  
2if can < 0:  
3	can = 255 + (l - ecx)  
4out.append(can)  

Which was still wrong! It should be 256.

1can =  l - ecx  
2if can < 0:  
3	can = 256 + (l - ecx)  
4out.append(can)  

And then I could decrypt the images as well!

Final solve script

 1import glob  
 2with open("Files/latin_alphabet.txt.encrypted","rb") as file:  
 3    bvar = file.read()  
 4  
 5print(len(bvar))  
 6  
 7known_cipher = "ABCDEFGH"  
 8  
 9  
10  
11def rol(val,shift):  
12    return (val << shift | ((val >> (8 - shift)) )) & 0xFF  
13  
14def decrypt(buf,key,length=8):  
15    out = []  
16    ecx = 0  
17    ebx = 0  
18  
19    while ecx < length:  
20        ebx = key[ecx]  
21        l = rol(buf[ecx] ^ ebx,ecx)  
22        can =  l - ecx  
23        if can < 0:  
24            can = 256 + (l - ecx)  
25        out.append(can)  
26  
27        ecx += 1  
28  
29    return out  
30  
31  
32assert rol(0x26,4) == 0x62  
33  
34  
35def solve_for_key(buf):  
36    key = []  
37    for ecx in range(8):  
38        for k in range(255):  
39            ebx = k  
40            out = rol(buf[ecx] ^ ebx,ecx) - ecx  
41            if out == ord(known_cipher[ecx]):  
42                key.append(k)  
43  
44    return key  
45  
46def apply_key(buf,key):  
47    no_bufs = len(buf) // 8  
48    out = []  
49    for i in range(no_bufs):  
50        start = i*8  
51        end = i*8+8  
52        s = buf[start:end]  
53        p = decrypt(s,key)  
54        out.extend(p)  
55      
56  
57    r_len = (len(buf) // 8) *8  
58    l = len(buf)  
59    # decrypt last bit  
60    if r_len != l:  
61        diff = l- r_len  
62        s = buf[r_len:]  
63        p = decrypt(s,key,diff)  
64        out.extend(p)  
65  
66    return out  
67  
68key = solve_for_key(bvar)  
69print("keylen:",len(key))  
70  
71def decrypt_file(path):  
72    with open(path,"rb") as file:  
73        bvar = file.read()  
74  
75    decrypted_path = path[:-10]  
76  
77    pvar = apply_key(bvar,key)  
78  
79    
80  
81    with open(decrypted_path,"wb") as file:  
82        file.write(bytes(pvar))  
83  
84  
85  
86for file in glob.glob("Files/*.encrypted"):  
87    print(file)  
88    decrypt_file(file)  

Bling Bling

> python3 solve.py  
26  
keylen: 8  
Files/critical_data.txt.encrypted  
Files/cicero.txt.encrypted  
Files/commandovm.gif.encrypted  
Files/capa.png.encrypted  
Files/flarevm.jpg.encrypted  
Files/latin_alphabet.txt.encrypted  
> cat critical_data.txt  
(>0_0)> [email protected] <(0_0<)