Emotet File Drop While Debugging

In doing some dynamic analysis on the latest Emotet samples, I was running into an issue getting the persistent copy of the malware to execute. In its normal flow of execution, Emotet will drop itself into C:\Users\<username>\AppData\Local and make a call to CreateProcessW to continue execution. I was unable to break on CreateProcessW. Instead, the code would terminate.

It turns out Emotet was making a call to SHFileOperationW to do the file drop. SHFileOperationW takes a structure named _SHFILEOPSTRUCTA.

typedef struct _SHFILEOPSTRUCTA {
  HWND         hwnd;
  UINT         wFunc;
  PCZZSTR      pFrom;
  PCZZSTR      pTo;
  FILEOP_FLAGS fFlags;
  BOOL         fAnyOperationsAborted;
  LPVOID       hNameMappings;
  PCSTR        lpszProgressTitle;
} SHFILEOPSTRUCTA, *LPSHFILEOPSTRUCTA;

Here is the structure in memory.

As you can see the wFunc param is set to 01 or FO_MOVE. The result was C0000043 (STATUS_SHARING_VIOLATION). This was causing an issue because my debugger had a handle on the file preventing the move from occurring. I needed to change the value to FO_COPY or 02 to copy the file instead. With this the code continued execution as expected.

How Emotet Resolves APIs

If you take a look at an unpacked Emotet sample, something will certainly stick out to you. The sample will have few to no imports. Yet the malware is clearly making heavy use of the Windows API to achieve its objectives. So how is it doing this? It is making use of a well-known shell coding technique to dynamically load APIs at runtime without the use of strings.

Emotet is locating the DLL name from the Process Environment Block. The malware will search for the desired module name and then locate the image base. From the image base of the located module, it is then able to walk the export table locating function pointers for its own import table. In Windows, the FS register points to the Thread Environment Block, or TEB. The offset 0x30 contains a pointer to the Process Environment Block, or PEB. From there the malware will walk the structure to _PEB_LDR_DATA which contains the head of a doubly-linked list called InMemoryOrderModuleList. This list contains the list entries containing BaseDllName and DllBase. When the entry point to the PE header is located, the PE structure is walked to find the export table. Emotet will then loop over the exported names to find the API function it is searching for.

Let’s take a look at this in action. The sample I am looking at is 0b96754a84bc2c01e4e8d64a534c03b5636fb6e958f7c381f9c27e646466cd32.

Sub_403640 starts off by grabbing a reference to the TEB and then grabbing a pointer to the PEB at offset 0x30. From there, a pointer to the _PEB_LDR_DATA structure is saved off along with the module hash that was stored in ecx prior to the function call.

The code then loops over the BaseDllNames comparing them to the module hash. If the hashed BaseDllName matches the hash that was passed in, the DllBase is moved into eax prior to returning from the function.

The next function to look at is sub_4037C0 which locates the specific API in the selected module. Two parameters are moved into registers for this function call. edx contains the hash and ecx will contain the module address that was just resolved. The beginning of the function starts by getting the offset of the PE header. Next, the RVA of the IMAGE_DIRECTORY_ENTRY_EXPORT is located. From there, the table of exported functions is located which is an RVA from the base of image. The function then begins a loop over the exported functions calculating a hash of each function name as it progresses. The function pointer is located by getting the RVA of the ordinals and then finding the specific ordinal of the function. The RVA of function pointers is then located before locating the specific RVA of the function. The RVA is converted to a virtual address before being stored.

The two function calls Sub_403640 (GetModuleAddress) and sub_4037C0 (GetAPIAddress) will be paired together throughout the code. Once Emotet has resolved the API in a given module, parameters are pushed onto the stack before the call eax.

Unpacking Emotet

In this post I take a look at unpacking Emotet to discover hard coded command and control servers.  The MD5 for the sample I’m looking at is 8db38c7f70214ee08e166cde8b9163c6.

This sample of Emotet uses a customized packer.  Instead of trying to reverse the algorithm to unpack the next stage, we can use dynamic analysis.  I’ll let the malware do the unpacking for me and grab the next stage out of memory.  The process will need to allocate memory for the next stage, so it’s a good assumption that we will see a call to VirtualAlloc.  Open up the sample in x32dbg and set a breakpoint on VirtualAlloc.  When the breakpoint is hit, we can note the parameters that were passed to the function.

LPVOID VirtualAlloc(
  LPVOID lpAddress, 0x0
  SIZE_T dwSize,  // 0xc000
  DWORD  flAllocationType, // 0x3000 i.e. MEM_COMMIT | MEM_RESERVE
  DWORD  flProtect // 0x4 i.e. PAGE_READWRITE
);

As you can see, the sample is letting the system determine where to allocate the memory with read write permissions.  After the call to VirtualAlloc, the eax register will contain the base address of the allocated region.  I dumped the memory at that address to keep an eye on it.  After letting the code run to the next breakpoint, I can see the memory has been populated.  Next, I jump to the memory map and dump the memory to a file.  

Opening the dump in a hex editor displays the following.

The file clearly contains a PE file but there is some extra code at the beginning of the file.  I’m unclear as to what this extra code is at this time, I may come back to look at it later. To move things along, I just looked for the magic number and trimmed the rest of the contents to the beginning of the file.  

Opening the file in IDA just to take a peek I noticed that there were zero imports.  Jumping to sub_403530 I noticed some signs of dynamically creating an import table.  Looking at some of the instructions I can see that it is grabbing a pointer to the process environment block.  From there it appears to be walking the structure to locate function pointers for its own import table. There is certainly more to research here, but I’ll save that for another post.

After unpacking, we can see the list of C2 servers is hard coded in the binary.  This information gets written to a buffer in the .data section of the code.  If we are looking to grab the IOCs from the sample, we want to let the malware run and write the C2 servers to the buffer and examine the memory.  In the following screenshot we can see the first IP address and port.

The list will contain a series of IP addresses.  The highlighted IP address and port will corollate to 24.249.63.138:80.  The first four bytes is the IP address followed by two bytes for the port.  The next two bytes can be ignored.  I extracted the following C2 servers from the sample.

24.249.63.138:80
2.45.165.235:80
149.210.171.237:8080
64.207.176.4:8080
183.82.123.60:443
50.63.13.135:8080
178.33.167.120:8080
95.66.182.136:80
184.162.115.11:443
190.17.94.108:443
110.142.161.90:80
122.176.116.57:443
175.181.7.188:80
182.71.222.187:80
78.188.33.71:80
177.144.130.105:443
182.176.116.139:995
41.77.74.214:443
212.112.113.235:80
78.189.60.109:443
75.127.14.170:8080
185.63.32.149:80
61.204.119.188:443
78.210.132.35:80
42.51.192.231:8080
85.100.122.211:80
37.46.129.215:8080
98.192.74.164:80
82.165.15.188:8080
82.79.244.92:80
82.146.55.23:7080
183.87.40.21:8080
183.131.156.10:7080
157.7.164.178:8081
37.70.131.107:80
210.213.85.43:8080
91.117.131.122:80
177.103.240.93:80
58.93.151.148:80
105.209.235.113:8080
187.72.47.161:443
153.137.36.142:80
192.241.220.183:8080
114.151.14.161:80
181.39.96.86:443
203.153.216.178:7080
109.236.109.159:8080
1.221.254.82:80
88.248.140.80:80
200.82.88.254:80
78.189.165.52:8080
94.206.82.254:443
46.32.229.152:8080
88.247.53.159:443
2.50.182.138:443
186.223.86.136:443
160.119.153.20:80
156.155.163.232:80
73.32.177.21:80
51.77.113.97:8080
72.27.212.209:8080
211.23.95.233:7080
139.59.12.63:8080
5.32.84.54:80
59.135.126.129:443
211.20.154.102:80
110.232.188.29:443
201.183.251.100:80
220.247.70.174:80
188.251.213.180:443
41.185.29.128:8080
1.217.126.11:443
110.2.118.164:80
152.169.31.120:8080
88.247.26.78:80
180.33.71.88:80
176.58.93.123:80
163.172.107.70:8080
70.60.238.62:80
160.226.171.255:443
186.84.173.136:8080
182.187.137.199:8080
158.69.167.246:8080
95.216.207.86:7080
68.183.18.169:8080
95.130.37.244:443
217.12.70.226:80
189.235.233.119:80
37.211.90.253:80
60.151.66.216:443
190.171.153.139:80
172.104.70.207:8080
46.17.6.116:8080
101.141.5.17:80
60.42.240.192:80
185.192.75.240:443
89.215.225.15:80
80.211.32.88:8080
181.167.35.84:80
77.74.78.80:443
186.10.92.114:80
91.83.93.103:443
91.117.31.181:80
178.62.75.204:8080
192.210.217.94:8080
125.209.114.180:443
78.188.170.128:80
162.154.175.215:80
187.177.155.123:990
45.55.179.121:8080
125.139.65.177:80
91.74.88.6:80
150.246.246.238:80
190.63.7.166:8080
50.116.78.109:8080
50.251.171.165:80
195.250.143.182:80
203.153.216.182:7080
85.100.115.92:80
186.147.245.204:80
185.244.167.25:443
51.38.134.203:8080
196.6.119.137:80
198.211.121.27:8080
144.76.56.36:8080
88.225.230.33:80
81.214.142.115:80