Below are the slides my presentation at the Maine ISC(2) chapter meetup on June 10, 2020.
This post is a sequel to the post covering the sample “Bank Statement.bat.” I had received this message before the Bank Statement message, but I found the sample in the previous post was less obfuscated and easier to reverse engineer.
In this post, I will cover the different ways that this sample hid the decoding routes and how I was able to gather the data to run the same decoding script I used before to extract the payload from the PNG data within this sample.
The metadata between the two samples is different but still tries to represent this .NET compiled binary is from “Apple Inc.” In this dump below, you see that this sample attempts to represent itself as an iTunes Visualizer.
Architecture: IMAGE_FILE_MACHINE_I386 Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI Compilation Date: 2020-Apr-16 11:34:55 Comments: iTunes Visualizer Host CompanyName: Apple Inc. FileDescription: iTunes Visualizer Host FileVersion: 220.127.116.11 InternalName: Vi8BESIfUtQA5qX.exe LegalCopyright: © 2000-2020 Apple Inc. All rights reserved. OriginalFilename: Vi8BESIfUtQA5qX.exe ProductName: iTunes Visualizer Host ProductVersion: 18.104.22.168 Assembly Version: 22.214.171.124 Matching compiler(s): Microsoft Visual C# v7.0 / Basic .NET .NET executable -> Microsoft
As with the previous sample there is an PNG file embedded in the binary. however the images is 20 pixels larger in each dimension.
DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 Microsoft executable, portable (PE) 26921 0x6929 PNG image, 300 x 300, 8-bit/color RGBA, non-interlaced 26999 0x6977 Zlib compressed data, compressed 404804 0x62D44 Copyright string: "CopyrightAttribute"
Visually looking at the PNG data, it looks similar to the PNG data from the Bank Account.bat sample. Seeing this, I started to think I may be able to use the same method I used previously to decode the payload. As a first attempt, I ran the script as-is, and as I expected, it didn’t correctly decode the file. I was already assuming at least that this sample would use a different key.
I started to look at the sample in dnSpy to find the key and the decoding methods in this binary. The first thing I noticed is that this .NET file either had more obfuscation or was just obfuscated differently than the previous binary I investigated. I was able to follow the flow from the entry point to where the sample starts a new process. There is not whole lot else interesting in the code after this point in the method.
After running the sample using the dnSpy debugger to decode the arguments of the Process.Start method call; I found that the sample executes “installUtil.exe” a .NET utility with the /u and the path to the location of the sample.
Pulling up the documentation for installUtil.exe utility I found the following:
"Installutil.exe uses reflection to inspect the specified assemblies and to find all Installer types that have the System.ComponentModel.RunInstallerAttribute attribute set to true. The tool then executes either the Installer.Install or the Installer.Uninstall method on each instance of the Installer type. Installutil.exe performs installation in a transactional manner; that is, if one of the assemblies fails to install, it rolls back the installations of all other assemblies. Uninstall is not transactional."
Note: I ran de4dot in between to make life a little easier to parse. It did not note any specific obfuscators.
In short, the /u installUtil.exe option runs the Uninstall method of the binary in the argument, in this case, the sample we are investigating. I searched the sample’s code for “Install” and found the following Uninstall method. This method looks very similar to the method that executed the PNG parsing function on the Bank Account.bat malware. For example, this method has similarly named variables and a similar flow to the PNG decoding method in the other sample.
When attempting to extract the data from the variables and reverse the methods, I found that smethod_0 and other related methods are heavily obfuscated and very hard to analyze statically. I switched to dynamic analysis and executed this sample in dnSpy. I used the following options to run in it using installUtil.exe and set a breakpoint in the Uninstall method.
After running the code, I hit the breakpoint I expected in the Uninstall function. Then I stepped over the “text” and “location” variables having their values assigned, revealing the PNG resources and the password in a similar format to the “Bank Account.bat” sample. Unfortunately, the process crashes when attempting to extract the code that is used to unpack the PNG. This crash is not an issue; I was able to retrieve the data I needed.
After only changing the extracted PNG file, XOR key, and final PNG pixel data value in the script I created for “Bank Statement.bat” Success, I was able to extract the payload.
The extracted payload looks to be very similar to the Bank Statement.bat payload. They both have the same filename in the metadata “ReZer0V2.exe.” However, some of the metadata is different, indicating they may be different versions of the payload.
My hunch was correct about these samples using the same encoding method for the PNG payload. I still have not reversed the payload yet, but there are some links to other work on this payload in my other post for the Bank Statement.bat sample. I enjoyed working on this sample, the different methods used to hide the decoding routine of the PNG data were a fun challenge.
Full Decode Script
import png import struct def print_list(thelist, quantity): if (quantity == 0): quantity = len(thelist) #print ("Decimal: ", end="") #for i in range(0, quantity): # print (thelist[i], ", ", end="") #print ("") print ("Hex: ", end="") for i in range(0, quantity): print (hex(thelist[i]), ", ", end="") print ("") print ("ASCII: ", end="") for i in range(0, quantity): print (chr(thelist[i]), ", ", end="") print ("") ############ filename = "be8ff-2.bmp" # 0x0 , 0x58 , 0x0 , 0x41 , 0x0 , 0x64 , 0x0 , 0x67 , 0x0 , 0x57 , 0x0 , 0x6b , 0x0 , 0x4b plain_key = "EMe2A6he" key = bytearray(plain_key.encode("utf-16be")) print_len = 50 print ("Key: ") print_list(key, 0) print ("Key len: ", len(key)) ## #### Load PNG bmp_full_data = png.Reader(filename=filename).read() bmp_img_data = list(bmp_full_data) ## #### Reverse Start data_array =  output_array =  print ("") print ("Loading Image data") print ("IMG height: ", len(bmp_img_data)) row_count = 0 #print ("Row: ", i, len(bmp_img_data[i]), end='') while (row_count < len(bmp_img_data)-4): #print (row_count, " ", end="") for i in range(0,len(bmp_img_data)): # AARRGGBB R = bmp_img_data[i][row_count] # 05 G = bmp_img_data[i][row_count+1] # 16 B = bmp_img_data[i][row_count+2] # 01 A = bmp_img_data[i][row_count+3] # 00 data_array.append(B) data_array.append(G) data_array.append(R) data_array.append(A) row_count += 4 #print (".. row loaded") print ("1st bytes") print_list(data_array[:4], 4) first_bytes_value = struct.unpack("<I", bytearray(data_array[0:4])) decode_data = data_array[4:] ## #### XOR_DEC Start key_counter = 0 print ("Data Length: ", len(data_array)) print ("") print ("Pre XORed data") print_list(decode_data, 50) outfile = open ("test-prexor.bin", 'wb') outfile.write(bytearray(decode_data)) outfile.close() print ("") print ("XORing Image data") # below is either B5 or 00 ^ 112 #lastdata = 0x67 static_xor_val = 0x67 lastdata = decode_data[len(decode_data)-1] key_modifier = lastdata ^ static_xor_val #key_modifier = 0xb5 ^ 112 # 0xc5 #key_modifier = 0 print("key: ", lastdata, " len: ", len(decode_data)-1, "found key: ", hex(decode_data[len(decode_data)-1]), " mod key: ", key_modifier) key_counter = 0 for xor_i in range(0,len(decode_data)): key_value = key[key_counter] output_array.append(decode_data[xor_i] ^ key_modifier ^ key_value) if (key_counter < len(plain_key)-1): key_counter += 1 else: key_counter = 0 print ("Final Output") print_list(output_array, print_len) outfile = open ("test-postxor.bin", 'wb') outfile.write(bytearray(output_array)) outfile.close()