The initial infection vector is a phishing email which has office document attachment. This document file has obfuscated VBA macros. By default, the Document file is opened in protected view, with the macros disabled. To evade this, Emotet document files have one image with instructions (Figure 1) asking user to enable content. Once the user enables the content the macros are then executed in background.
SHA256: 2d59e4dbfa860a68e014227f6bd9c13945d0d474b2d183c2f07e2c7a4864b24c
Fig 1 : Office document in protected view with macro disabled
Fig 2: obfuscated macro in office document file.
Inside the document file, there are multiple macros which have various obfuscated functions and variable names. After debugging this macro, we were able to de-obfuscate the macros and successfully extract all the URLs which are responsible for downloading the payload.
Fig 3: After de-obfuscating macros, we can see all URL which download Payload.
URLs inside document file:
These URL downloads the archive file which contains a DLL file.
SHA256: 8a674295c02e40a8bb1518752bfe3e4533eb81b5abb2efbd399dd1681d7b82ad
Fig 4: DLL after Extracting Archive.
Fig 5: Appended Null bytes.
This file is a bloated Emotet DLL file by appending null bytes at the overlay, actual PE size of file is in few hundred KB’s, but since null data appended at the end of file, file size increased up to few hundred MBs. (Here actual size is 667 KB and blotted file size is 538 MB)
Encrypted shell code and encrypted PE file are embedded within the resource section of the binary. Encrypted PE file size is of 0x2B000 bytes.
Fig 6 : embedded encrypted PE file and shell code blob in resource.
It uses “LdrFindresource_u” API to find encoded resource data and LdrAccessResource API to fetch the contents of a resource data. It calls NtAllocateVirtualMemory to allocate memory so it can decrypt shell code and payload in memory. Malware uses hardcoded 0x3B size of decryption key and customized decryption loop to decrypt payload PE file and shell code.
Fig 8 : Decryption Loop to decrypt actual payload embedded in resource section
Once it completes the decryption of shell code blob then it transfers execution control to this shell code using NtQueueAPCThread and NtTestAlert. NtQueueApcThread is used to queue an APC to the current thread pool, here shell code is added as an APC to current thread.
NtTestAlert is a system call that’s related to the alerts mechanism of Windows. This system call can trigger execution of any pending APCs that thread has. Once NtTestAlert API gets called shell code will start executing.
Fig 9 : Transfers execution control to injected shell code
Following is a snapshot from the shell code blob where we can see strings has been pushed to stack which will be later used to resolve API addresses dynamically.
Fig 10 : start of shell code
The task of shell code is to map the DLL file in virtual memory the way process aligned in memory and start the execution of actual payload DLL.
Fig 11 : Execution of shell code started
Malware uses API resolving functionality where it passes hard-coded checksum of API to stack or to a register and then compute checksum from the combination of DLL name string and API name. If the checksum matches it found the name of API that it wanted to use. In Fig 11 we can see 0xBDBF9C13 which is checksum DWORD used to resolve API “LdrLoadDll”.
Following are steps It follows:
After resolving LdrLoadDll it resolves LdrGetProcedureAddress API using hardcoded DWORD checksum 0x5ED941B5h.
Fig 12 : API resolver Function which takes Hard-coded DWORD HASH and resolve API address.
Fig 13 : API resolver Function where traverse export directory of every module
It uses LdrLoadDll and LdrGetProcedureAddress to resolve following API. All this API names has been pushed on to the stack at the start of shellcode execution.
These APIs will be used to map payload DLL in memory so it can start its execution.
Fig 14 : copy payload header data without DOS header and without string “This program cannot be run in DOS mode”
Fig 15 : changes protections of each section of mapped DLL in memory
It simply comes out of main entry of payload DLL and starts executing “DLLregisterServer” function from main DLL file. “DllRegisterServer” from main DLL (not the mapped payload DLL), there is “DllRegisterServer” function in injected payload as well. Objective of this function to check whether exported function of injected payload is “DllRegisterServer” or not. To check whether exported function is “DllRegsiterServer” it calculates the checksum of string “DllRegisterServer” and check with hard-coded DWORD checksum, if matches then continue its execution otherwise exits. It transfers execution to “DllRegisterServer” from the payload DLL.
Fig 16 : check exported function is “DllRegisterServer” from injected payload DLL
It decodes all necessary DLL names which needs to be loaded.
Following are DLL which are loaded by payload.
It loads all DLLs from above list.
API Resolve Functionality in Payload DLL
It resolves windows API Address of from the hardcoded DWORD checksum and it uses almost similar functionality as is used while resolving LdrFindresource_u, LdrAccessResource in main DLL.
The difference here is for every API it passes two hardcoded checksums, one for DLL name and another for API name while previously it was passing single DOWRD checksum ( combination of DLL name and API name )
It Access PEB structure and get the InLoadOrderModuleList by traversing PEB structure and then access Name of DLL , it calculates the checksum for every DLL and matches to passed DWROD checksum.
For e.g. it compares with hard-coded hash 0xAA83E8EA to find out loaded base address for kernel32.dll
If it resolves Base address for DLL, it enumerates export directory of each loaded DLL and calculate checksum of API name and compare with hard-coded DWORD checksum. If API name found, then take RVA from export directory and add it to base address of loaded DLL.
Here function which calculates checksum for DLL name and API Name are quite complex as compare to function found in main DLL.
Fig 17 : Function which resolve API address
Fig 18 : Calculate checksum for API name
Fig 19 : Decryption loop to get encoded DLL names
The following are some API Names and their respective DWORD checksum used in payload.
6AE056F0h : memset
609FD004h : CreateEventW
87CA8415h : CreateTimerQueue
9BD9AB80h : CreateTimerQueueTimer
160FBC8Dh : WaitForMultipleObjects
0E9E794B7h: BCryptOpenAlgorithmProvider
11B5B47Ah : BCryptGenRandom
35BF9169h : BCryptCloseAlgorithmProvider
69230A13h : GetModuleFileNameW
1D50CF79h : OpenSCManagerW
32655658h : CloseServiceHandle
0ABE413E5h: CreateToolhelp32Snapshot
0C60B628h : Process32FirstW
91BB593Ah : GetCurrentProcessId
0A2188CCBh: Process32NextW
6B466D98h : GetProcessHeap
D84B3D0A : GetModuleHandleA
8B1AD334h : HeapAlloc
3434C63Dh : CloseHandle
25A83B18h : OpenProcess
0B2D79594h: QueryFullProcessImageNameW
5D2B782Fh : PathFindFileNameW
0FC917Eh : SHGetFolderPathW
305B4B5Ah : lstrlenA
0C019E25Ah: StrCmpNIW
0AE929DCDh: lstrcpyW
32C0D23Ch : SHFileOperationW
0AE9B6EABh: _snwprintf
6A53AC4Dh : DeleteFileW
0A9867BD9h: CreateProcessW
73BF5525h : kernel32_SetEvent
0D3711A37h: DeleteTimerQueueEx
9D1964ACh : kernel32_ExitProcess
661CE361h : RtlExitUserProcess
It checks for folder path from which process is being run, if it is not being run from %appdata\Local% directory, then it moves main DLL to %AppData\Local% directory, Regsvr32.exe spawns a child process by passing command line argument as file path of moved DLL to %AppData\Local% directory and kills the parent, becoming a ‘non-existent process’; this is an anti-analysis technique that prevents debuggers from attaching to the process.
Fig 20 : Regsvr32.exe restarted with dropped DLL as argument.
It sends data over internet using WinHttp API.
Fig : 21 : encoded data send over C2 server
We have found various C2 URLs, from which it performs the command-and-control activity.
hxxps://91[.]121[.]146[.]47:8080/wueylobjdxujn/
hxxps://72[.]15[.]201[.]15:8080/wueylobjdxujn/
hxxps://187[.]63[.]160[.]88:80/wueylobjdxujn/
hxxps://104[.]168[.]155[.]143:8080/
hxxps://91[.]207[.]28[.]33:8080/wueylobjdxujn/
hxxps://167[.]172[.]199[.]165:8080/wueylobjdxujn/
hxxps://72[.]15[.]201[.]15:8080/wueylobjdxujn/
hxxps://187[.]63[.]160[.]88:80/wueylobjdxujn/
hxxps://164[.]90[.]222[.]65/wueylobjdxujn/
Share This Article
An Article By
An Article By
Security News
Security News