MalwareTech Beginner Malware Reversing Challenges shellcode1 Writeup

Environment

Explanation

We have several malware reversing challenges this page on MalwareTech
This is a write-up of “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?

Solution

1. Opening the shellcode1.exe

Let’s open the shellcode1.exe.
As we can see on a following picture, it shows a MD5 encrypted flag.

placeholder

Just like strings challenges, we have to “decrypt” this MD5 hash and get original text.

2. Analyzing assembly code

Same as last challenge, to encrypt the original text, a function MD5:digestString is used.

placeholder

It’s argument is in an offset “Str” and it must be a text which we’re looking for.
However, it is already encrypted and sounds like does not mean anything.

placeholder

In this assembly code, we can find the “offset Str” one more time.

placeholder

As we can see, it’s getting the length of Str and storing it into [ecx+4].
Then, figure out what it ecx.

placeholder

Sounds like the value of ecx is return value of HeapAlloc.

DECLSPEC_ALLOCATOR LPVOID HeapAlloc(
  HANDLE hHeap,  // A handle to the heap from which the memory will be allocated. This handle is returned by the HeapCreate or GetProcessHeap function.
  DWORD  dwFlags,  // The heap allocation options.
  SIZE_T dwBytes  // The number of bytes to be allocated.
);

And the return value is a pointer to the allocated momory block.
This means, after these instructions below, values of ecx and ecx+4 are

ecx: pointer to allocated heap
ecx+4: length of Str

Then we still have 3 functions which we have to analyze.

call    ds:VirtualAlloc
call    memcpy
call    [ebp+Dst]

Sounds like return value of VirtualAlloc is set in [ebp+Dst]. placeholder According to the official document, the arguments of VirtualAlloc are

LPVOID VirtualAlloc(
  LPVOID lpAddress,        // The starting address of the region to allocate. 
  SIZE_T dwSize,           // The size of the region, in bytes.
  DWORD flAllocationType,  // The type of memory allocation.
  DWORD flProtect          // The memory protection for the region of pages to be allocated.
);

and in this case, VirtualAlloc is called like

LPVOID WINAPI VirtualAlloc(0, 0Dh, 1000h, 40h);

Next, look at memcpy.

void *  memcpy(
  void * destination,   // Pointer to the destination array where the content is to be copied, type-casted to a pointer of type void*.
  const void * source,  // Pointer to the source of data to be copied, type-casted to a pointer of type const void*.
  size_t num,           // Number of bytes to copy.
);

This means, in this case, memcpy is called like

memcpy([ebp+Dst], offset unk_404068, 0Dh)

We can find that the unknown function [ebp+Dst] is from offset unk_404068. Looks like just some encrypted codes. However, we can convert the data to code with C key.

placeholder

Sounds like this doing followning things.

1. put value of [esi] into edi
2. put value of [esi+4] into ecx
3. Rotate left the values of esi 5 times
4. Do this procedure for esi length + 4 times

At this time, the value of esi is [ebp+var_4]. This means it is heap space allocated.
Now, we have offset Str in the heapspace.
In summerize, the value which Str is modified by this function above is the original text.

3. decryption

Now we know what we have to do.
After selecting the data we need, we can export it with “Edit->Export data” (or Shift+E) and choose C hex for python code. placeholder

Then, what we have to do is writing a code for decryption.

#! /usr/bin/python


flag = bytearray([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, 0x00])


rol = lambda val, r_bits, max_bits: \
(val << r_bits%max_bits) & (2**max_bits-1) | \
((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits)))

for i in range(len(flag)):
    flag[i] = rol(flag[i], 5, 8)

print flag

By executing this code, we can obtain the original text.

root@kali:~# ./rol.py 
FLAG{SHELLCODE-ISNT-JUST-FOR-EXPLOITS}