Solving MalwareTech Shellcode challenges with some radare2 magic!

Syscall59 — Alan Vivona
syscall59
Published in
4 min readJun 8, 2019

MalwareTech has published some challenges on his blog that are really fun to play with. The goal is to crack these binaries and find the correct flag using static analysis only! Let’s jump right in!

Shellcode1

The main function flow is the following:

1- Get the length of a string located at 0x404040 using Strlen
The string is the following:

addrs: 0x00404040string: 2b:B*bbz"*iJriRi2zi*bzJhex: \x32\x62\x0a\x3a\xdb\x9a\x42\x2a\x62\x62\x1a\x7a\x22\x2a\x69\x4a\x9a\x72\xa2\x69\x52\xaa\x9a\xa2\x69\x32\x7a\x92\x69\x2a\xc2\x82\x62\x7a\x4a\xa2\x9a\xeb\x00

2- Then it calls VirtualAlloc to make some space in memory with execution permissions (using the constant value for PAGE_EXECUTE_READWRITE)

Here the VirtualAlloc definition from Microsoft's docs:
LPVOID VirtualAlloc(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);

3- Copies a section of 15 bytes from data to the allocated memory region. The section contains the following code:

; DATA XREF from entry0 (0x4022ce)
0x00404068 8b3e mov edi, dword [esi]
0x0040406a 8b4e04 mov ecx, dword [esi + 4]
┌─> 0x0040406d c0440fff05 rol byte [edi + ecx - 1], 5
└─< 0x00404072 e2f9 loop 0x40406d
0x00404074 c3 ret

4- Calls the code shown above. Here’s the exact instruction:

0x004022e5      ff9560ffffff   call dword [s1]

The routine decodes the original string form the step 1 (located at 0x00404040) using a rotator decipher (rotating every piece 5 bits left). We can emulate this behavior outside the original program by putting together an assembly file that takes the string, decodes it and outputs the result:

global _start
section .text
_start: jmp envSetup encodedFlagStart: db
0x32,0x62,0x0a,0x3a,0xdb,0x9a,0x42,0x2a,0x62,0x62,
0x1a,0x7a,0x22,0x2a,0x69,0x4a,0x9a,0x72,0xa2,0x69,
0x52,0xaa,0x9a,0xa2,0x69,0x32,0x7a,0x92,0x69,0x2a,
0xc2,0x82,0x62,0x7a,0x4a,0xa2,0x9a,0xeb,0x00
encodedFlagEnd:
envSetup:
mov edi, encodedFlagStart
lea ecx, [encodedFlagEnd - encodedFlagStart]
decodeByte:
rol byte [edi + ecx], 5
dec ecx
jns decodeByte
printResult:
mov rax, 0x01
mov rdi, rax
mov rsi, encodedFlagStart
mov rdx, 43
syscall
exit:
xor rbx, rbx
mov rax, 0x3c
syscall

I used a custom script to assemble and link the file. Nothing fancy, it just gets the job done. Here we can see the flag is output to the console:

Shellcode 2

This challenge is pretty similar to the previous one, the main difference is that the shellcode payload is a little more complex.

The payload has some strings at the beginning that correspond to some DLLs and function names inside those DLLs.

Here we can see msvcrt.dll and kernel32.dll

Here we can see function names like fopen, fread, fseek and fclose

The strings are then used to load two DLLs in runtime make use of various functions form them (all taken from the strings at the beginning). Here’s the code are code samples with some comments I added to describe the exact flow:

These functions are used to open the msvcrt.dll file and load a fraction of its header text is read:

The extracted string is “This program cannot be run in DOS mode”, which is part of the header section.

This string is used as a key to decrypt the flag using a plain xor decryption routine.

To retrieve the flag I put together this simple python script

key = b'This program cannot be run in DOS mode'
flag = b'\x12\x24\x28\x34\x5b\x23\x26\x20\x35\x37\x4c\x28\x76\x26\x33\x37\x3a\x27\x3d\x6e\x25\x48\x6f\x3c\x58\x3a\x68\x2c\x43\x73\x10\x0e\x10\x6b\x10\x6f'
print(f"flag len : {len(flag)}")
print(f"key len : {len(key)}")
final_res = ''
for i in range(len(flag)):
print(f"op : i:{i},k:{key[i]},f:{flag[i]}")
res = chr(flag[i] ^ key[i])
print(f"res: {res}")
final_res += res
print(f"RESULT: {final_res}")

The resulting flag is:

FLAG{STORE-EVERYTHING-ON-THE-STACK}

--

--