MalwareTech Challenge - strings2.exe

Jun 21, 2019 • mtchallenge,tools,re

I have been teaching myself to reverse engineer binary programs so that I can use these skills to reverse engineer malware. I have been learning assembly code, and playing with new tools such as ghidra and radare2/cutter.

I found that @MalwareTech had some great binary analysis challenges on his blog and decided to check them out.

This write up covers the second challenge strings2.exe: ‘https://www.malwaretech.com/strings2’

Lets open this binary in cutter and analyze it with radare2. Once open lets navigate to the entry fucntion:

Right away, just as in the first challenge, it looks like we have the flag. This time it has been initialized as a stack string. Lets take a look at the assembly:

(fcn) entry0 200
|   entry0 ();
|           ; var int32_t var_28h @ ebp-0x28
|           ; var int32_t var_27h @ ebp-0x27
|           ; var int32_t var_26h @ ebp-0x26
|           ; var int32_t var_25h @ ebp-0x25
|           ; var int32_t var_24h @ ebp-0x24
|           ; var int32_t var_23h @ ebp-0x23
|           ; var int32_t var_22h @ ebp-0x22
|           ; var int32_t var_21h @ ebp-0x21
|           ; var int32_t var_20h @ ebp-0x20
|           ; var int32_t var_1fh @ ebp-0x1f
|           ; var int32_t var_1eh @ ebp-0x1e
|           ; var int32_t var_1dh @ ebp-0x1d
|           ; var int32_t var_1ch @ ebp-0x1c
|           ; var int32_t var_1bh @ ebp-0x1b
|           ; var int32_t var_1ah @ ebp-0x1a
|           ; var int32_t var_19h @ ebp-0x19
|           ; var int32_t var_18h @ ebp-0x18
|           ; var int32_t var_17h @ ebp-0x17
|           ; var int32_t var_16h @ ebp-0x16
|           ; var int32_t var_15h @ ebp-0x15
|           ; var int32_t var_14h @ ebp-0x14
|           ; var int32_t var_13h @ ebp-0x13
|           ; var int32_t var_12h @ ebp-0x12
|           ; var int32_t var_11h @ ebp-0x11
|           ; var int32_t var_10h @ ebp-0x10
|           ; var int32_t var_fh @ ebp-0xf
|           ; var int32_t var_eh @ ebp-0xe
|           ; var int32_t var_dh @ ebp-0xd
|           ; var int32_t var_ch @ ebp-0xc
|           ; var int32_t var_bh @ ebp-0xb
|           ; var int32_t var_ah @ ebp-0xa
|           ; var int32_t var_9h @ ebp-0x9
|           ; var int32_t var_8h @ ebp-0x8
|           ; var int32_t var_7h @ ebp-0x7
|           ; var int32_t var_6h @ ebp-0x6
|           ; var int32_t var_5h @ ebp-0x5
|           ; var LPCSTR lpText @ ebp-0x4
|           0x004022b0      push ebp
|           0x004022b1      mov  ebp, esp
|           0x004022b3      sub  esp, 0x28 ; '('
|           0x004022b6      mov  byte [var_28h], 0x46 ; 'F' ; 70
|           0x004022ba      mov  byte [var_27h], 0x4c ; 'L' ; 76
|           0x004022be      mov  byte [var_26h], 0x41 ; 'A' ; 65
|           0x004022c2      mov  byte [var_25h], 0x47 ; 'G' ; 71
|           0x004022c6      mov  byte [var_24h], 0x7b ; '{' ; 123
|           0x004022ca      mov  byte [var_23h], 0x53 ; 'S' ; 83
|           0x004022ce      mov  byte [var_22h], 0x54 ; 'T' ; 84
|           0x004022d2      mov  byte [var_21h], 0x41 ; 'A' ; 65
|           0x004022d6      mov  byte [var_20h], 0x43 ; 'C' ; 67
|           0x004022da      mov  byte [var_1fh], 0x4b ; 'K' ; 75
|           0x004022de      mov  byte [var_1eh], 0x2d ; '-' ; 45
|           0x004022e2      mov  byte [var_1dh], 0x53 ; 'S' ; 83
|           0x004022e6      mov  byte [var_1ch], 0x54 ; 'T' ; 84
|           0x004022ea      mov  byte [var_1bh], 0x52 ; 'R' ; 82
|           0x004022ee      mov  byte [var_1ah], 0x49 ; 'I' ; 73
|           0x004022f2      mov  byte [var_19h], 0x4e ; 'N' ; 78
|           0x004022f6      mov  byte [var_18h], 0x47 ; 'G' ; 71
|           0x004022fa      mov  byte [var_17h], 0x53 ; 'S' ; 83
|           0x004022fe      mov  byte [var_16h], 0x2d ; '-' ; 45
|           0x00402302      mov  byte [var_15h], 0x41 ; 'A' ; 65
|           0x00402306      mov  byte [var_14h], 0x52 ; 'R' ; 82
|           0x0040230a      mov  byte [var_13h], 0x45 ; 'E' ; 69
|           0x0040230e      mov  byte [var_12h], 0x2d ; '-' ; 45
|           0x00402312      mov  byte [var_11h], 0x42 ; 'B' ; 66
|           0x00402316      mov  byte [var_10h], 0x45 ; 'E' ; 69
|           0x0040231a      mov  byte [var_fh], 0x53 ; 'S' ; 83
|           0x0040231e      mov  byte [var_eh], 0x54 ; 'T' ; 84
|           0x00402322      mov  byte [var_dh], 0x2d ; '-' ; 45
|           0x00402326      mov  byte [var_ch], 0x53 ; 'S' ; 83
|           0x0040232a      mov  byte [var_bh], 0x54 ; 'T' ; 84
|           0x0040232e      mov  byte [var_ah], 0x52 ; 'R' ; 82
|           0x00402332      mov  byte [var_9h], 0x49 ; 'I' ; 73
|           0x00402336      mov  byte [var_8h], 0x4e ; 'N' ; 78
|           0x0040233a      mov  byte [var_7h], 0x47 ; 'G' ; 71
|           0x0040233e      mov  byte [var_6h], 0x53 ; 'S' ; 83
|           0x00402342      mov  byte [var_5h], 0x7d ; '}' ; 125
|           0x00402346      lea  eax, [var_28h]
|           0x00402349      push eax
|           0x0040234a      call sym.plaintext2.exe__md5_hash__YAPADPAD_Z
|           0x0040234f      add  esp, 4
|           0x00402352      mov  dword [lpText], eax
|           0x00402355      push 0x30 ; '0' ; 48 ; UINT uType
|           0x00402357      push str.We_ve_been_compromised ; 0x403020 ; "We've been compromised!" ; LPCSTR lpCaption
|           0x0040235c      mov  ecx, dword [lpText]
|           0x0040235f      push ecx ; LPCSTR lpText
|           0x00402360      push 0 ; HWND hWnd
|           0x00402362      call dword [sym.imp.USER32.dll_MessageBoxA] ; 0x403008 ; int MessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
|           0x00402368      push 0 ; UINT uExitCode
|           0x0040236a      call dword [sym.imp.KERNEL32.dll_ExitProcess] ; 0x403000 ; void ExitProcess(UINT uExitCode)
|           0x00402370      xor  eax, eax
|           0x00402372      mov  esp, ebp
|           0x00402374      pop  ebp
\           0x00402375      ret  0x10

Here we see the stack being initialized and then we see multiple mov byte... lines. This is where the flag is being addressed in memory byte by byte. We are then loading the address of the first byte into eax lea eax, [var_28h] and pushing it to the stack. Next a function is called that seems to compute an MD5 hash. When ran this binary will hash the flag and spit out the MD5 value.

All we have to do for this one is pull the flag out of the stack string and we have our flag. radare2 automatically converts the hex to ascii in a comment next to the instruction so it is easy to extract. However this could also be done programatically with python if needed:

stack_string = [0x46, 0x4c, 0x41, 0x47, 0x7b, 0x53, 0x54, 0x41, 0x43,
                0x4b, 0x2d, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x53,
                0x2d, 0x41, 0x52, 0x45, 0x2d, 0x42, 0x45, 0x53, 0x54,
                0x2d, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x53, 0x7d]

ascii_string = ''
for byte in stack_string:
    ascii_string = ascii_string + chr(byte)

print(ascii_string)

In the above code all we are doing is creating a list of bytes which is effectively just like the stack string in the assembly code. We then iterate through this list and use the chr() method to get the string character from the provided unicode code point (the current byte). That string is then added to the end result “ascii_string” and it is printed to the console when the loop exits. We can then take this flag, plug it into MalwareTech’s site, and voila! strings2.exe complete!