Solving reversing challenges from MalwareTech.com

dusty
5 min readMar 6, 2022

MalwareTech.com’s Windows Reversing challenge is composed of 7 challenges from 4 different categories. This article will show you how I solved all challenges.

strings

strings1 — [★☆☆☆☆]

strings1.exe contains an un-encrypted flag stored within the executable. When run, the program will output an MD5 hash of the flag but not the original. Can you extract the flag?

There is an unencrypted flag inside the provided binary, and the binary will print the MD5 hash of the flag and exit. The challenge is about static analysis and not using a debugger / dynamic analysis and dumping techniques, so we will only use static analysis methods for this article.

Figure 1. strings window from IDA

There are several strings inside the binaries, but only one string gets hashed.

Figure 2. decompiled start() function

We don’t have to look up every strings’ xref. By simply taking a look inside the binary’s start() function, we can locate the actual flag.

strings2 — [★☆☆☆☆]

strings2.exe contains an un-encrypted flag stored within the executable. When run, the program will output an MD5 hash of the flag but not the original. Can you extract the flag?

Like the strings1 challenge, there is an unencrypted flag inside the provided binary.

Figure 3. decompiled start() function from strings2

The strings2 binary’s start() function uses its stack to pass the flag to the hash function.

strings3 — [★★☆☆☆]

strings3.exe contains an un-encrypted flag stored within the executable. When run, the program will output an MD5 hash of the flag but not the original. Can you extract the flag?

Similar to strings1 and 2, the binary will contain an unencrypted flag inside of it.

Figure 4. decompiled start() function from strings3

By reversing the provided binary’s start() function, we can confirm that a resource with uID=272 is loaded into a buffer by using the LoadStringA function. We can obtain the flag by using tools such as Resource Hacker.

Figure 5. Resource Hacker view of strings3 binary

shellcode

shellcode1 — [★☆☆☆☆]

shellcode1.exe contains a flag stored within the executable. When run, the program will output an MD5 hash of the flag but not the original. Can you extract the flag?

The binary has obfuscated flag and shellcode to deobfuscate it, and we can deobfuscate the flag by reversing the shellcode.

Figure 6. decompiled start() function of shellcode1 binary

Using IDA, we can see that start() function reads 13 bytes shellcode from the data section’s 0x404068 and executes it.

Figure 7. shellcode from data.0x404068

By pressing ‘c’ inside IDA View, we can convert 0x404068’s data type to code. From the decompiled start() function and shellcode at 0x404068, we can see that the obfusticated flag is located at 0x404040, and is ROL-ed 5 times for each byte.

The string at offset 0x404040 is 32620a3adb9a422a62621a7a222a694a9a72a26952aa9aa269327a92692ac282627a4aa29aeb0000 and the Python code below can be used to deobfuscate it.

Figure 8. result of rol.py

shellcode2 — [★★☆☆☆]

shellcode2.exe contains a flag stored within the executable. When run, the program will output an MD5 hash of the flag but not the original. Can you extract the flag?

Similar to strings2, start() function uses the stack to store the flag.

Figure 9. decompiled start() function from shellcode2
Figure 10. start() function calling sub_404040

The deobfuscation happens in function sub_404040.

Figure 11. the deobfuscation routine of function sub_404040

sub_404040 function uses LoadLibraryA function to dynamically load the necessary function to load and deobfuscated the flag. The Python script below is a simple implementation of the deobfuscation routine from sub_404040.

Figure 12. result of decrypt.py

De-virtualization

vm1 — [★★★☆☆]

vm1.exe implements a simple 8-bit virtual machine (VM) to try and stop reverse engineers from retrieving the flag. The VM’s RAM contains the encrypted flag and some bytecode to decrypt it. Can you figure out how the VM works and write your own to decrypt the flag? A copy of the VM’s RAM has been provided in ram.bin (this data is identical to the ram content of the malware’s VM before execution and contains both the custom assembly code and encrypted flag).

The challenge provides a simple 8-bit VM implementation and memory file ram.bin to run the VM. We reverse the VM binary to find out how VM works, and write a script to decrypt the flag.

Figure 13. start() function of vm1

The provided binary’s start() function copies 507 bytes of data in unk_404040 into the buffer, and calls function sub_4022E0.

Figure 14. decompiled sub_4022E0 function

sub_4022E0 function will keep executing until sub_402270 returns result that is not 1. sub_402270 takes 3 arguments, byte from buffer’s 255 + 0 byte location to 255 + 2 byte location..

Figure 15. decompiled sub_402270 function

sub_402270 modifies buffers data or its internal register according to the first argument passed. The Python script below will mimic the behavior of sub_402270 and decrypt the flag from the ram.bin file

Figure 16. result of run.py

Ransomware

ransomware1 — [★☆☆☆☆]

The administrator for FlagCorp was using an outdated Windows 7 system and got infected with some ransomware. We believe this variant was most likely written by a scriptkiddie due to the fact it was so badly designed it encrypted itself. One of our malware analysts was able to recover the encryption function from memory but doesn’t know much about cryptography. Can you find a way to decrypt flag.txt?

The challenge provides a binary with encryption routine, encrypted flag, and several encrypted pictures from the Sample Pictures directory.

Figure 17. encryption routine from ransomware1

v4[i] ^= *(_BYTE*)(a2 + i % 0x20); tells us that XOR key is 32 bytes long. But we don’t have the actual key used to encrypt flag since a2=0 is passed to the sub_401000.

The Sample Pictures directory is from Windows 7’s sample images, and we can download the original files from archive.org. The script below uses Chrysanthemum.jpg to obtain the XOR key by XOR-ing encrypted file with the original one.

Figure 18. result of decrypt.py

--

--