Archive for the ‘Chal9. Ransomware Challenge’ Category

Rule: Decrypt File (EXE)

Run target to get basic information:


Figure 1

Let’s open the target in OllyDBG, search all referenced text strings, we’ll get like this:


Figure 2

Follow 0x0044A775 address and set BP at 0044A792 |. FF15 B8C04400 call dword ptr [<&MSVCR100.scanf>]; \scanf:


Figure 3

Press F9 to run and input any key you like, then press enter, we’ll back to OllyDBG:


Figure 4

After target gets the input key, next it calculates the input key length:


Figure 5

Next, it opens the file whose name is specified in the parameter filename and mode is rb (read, binary file):


Figure 6

This target opens file that named file in the same directory to read in binary mode, then gets character from stream and stores to the buffer at 0x5415B8 address:


Figure 7

Compare values store at the buffer with the file content is opened with WinHex, we have the same values:


Figure 8

Next, we will see the snippet that use the input key to decrypt the values are stored at the 0x5415B8 address. Let’s see how decryption routine performs:


Figure 9

This is the pseudo-code for the snippet:

For (i=0; i< sizeof(file); i++)
	FileContent[i] = FileContent[i] ^ InputKey[i] ^ 0xFF;

The decryption result:


Figure 10

Next, reopen file in write mode:


Figure 11

The next snippet takes each value from the buffer and writes back to file:


Figure 12

Content of file after write back:


Figure 13

Because the rule of this challenge is Decrypt File (EXE), so we know that the file after decrypt will be a normal exe file. As we know, the normal exe file has the valid PE header same as the picture bellow:


Figure 14

We also have the decryption algorithm in the previous analysis: FileContent[i] = FileContent[i] ^ InputKey[i] ^ 0xFF; so FileContent[i] must equal 0x4D, 0x5A, 0x90, etc. To find the InputKey we only need to do: ValidPEHeader[i] ^ FileContent[i] ^ 0xFF = InputKey[i]. Summarize we have calculation table like this:

Validheader[i] operator Filecontent[i] operator default value inputkey[i]
0x4D ^ 0xDE ^ 0xFF 0x6C (l)
0x5A ^ 0xC0 ^ 0xFF 0x65 (e)
0x90 ^ 0x1B ^ 0xFF 0x74 (t)
0x00 ^ 0x8C ^ 0xFF 0x73 (s)
0x03 ^ 0x8C ^ 0xFF 0x70 (p)
0x00 ^ 0x93 ^ 0xFF 0x6C (l)
0x00 ^ 0x9E ^ 0xFF 0x61 (a)
0x00 ^ 0x86 ^ 0xFF 0x79 (y)
0x04 ^ 0x98 ^ 0xFF 0x63 (c)
0x00 ^ 0x97 ^ 0xFF 0x68 (h)
0x00 ^ 0x9A ^ 0xFF 0x65 (e)
0x00 ^ 0x8C ^ 0xFF 0x73 (s)
0xFF ^ 0x73 ^ 0xFF 0x73 (s)
0xFF ^ 0x6C ^ 0xFF 0x6C (l)
0x00 ^ 0x9A ^ 0xFF 0x65 (e)
0x00 ^ 0x8B ^ 0xFF 0x74 (t)

Code in C:

#include <stdio.h>
#include <stdlib.h>

int main()
    unsigned int valid_PE[16] = {0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00};
    unsigned int encrypted_PE[16] = {0xDE, 0xC0, 0x1B, 0x8C, 0x8C, 0x93, 0x9E, 0x86, 0x98, 0x97, 0x9A, 0x8C, 0x73, 0x6C, 0x9A, 0x8B};
    unsigned int defVal = 0xFF, i = 0;
    unsigned char key[16] = {0};

    for (i=0; i<16; i++)
        key[i] = valid_PE[i] ^ encrypted_PE[i] ^ defVal;

    printf("The decrypt key is: %s \n", key);
    return 0;

Okay, we have the decrypt key is: letsplaychess. Run program and input key we will have the decrypt file. Let’s rename file to add the exe extension. Use RDG Packer Detector to check file:


Figure 15

Ohhh, it’s packed by UPX. Using UPX to unpack file:


Figure 16

After unpack successful, run file to get the key:


Figure 17