2. Static code analysis

eToken.exe (VVSup.exe) is built with dynamic link DLL mode with MFC42.dll, so the .exe file will be small and the functions of the MFC42 libirary will be easily identified via the name import of the DLL. The name mangling rule of Microsoft VC ++ compiler reflects the class name, function name, parameter name, call type… of functions. IDA helps us to define the functions import by ordinal of MFC42.dll using the file mfc42.ids and mfc42.idt included with IDA.

However, VVSup is built with the RTTI (Runtime Type Information) option is disabled, so there is no information about the RTTI and Virtual Method Table of all classes in the file. We only have RTTI of class type_info, the root class of RTTI.

Figure 11. RTTI Info of type_info class

The analysis will show how to define classes, recreate the code of this malware, and share experience in applying when analyzing malwares/files using MFC.

Plugins used:

  • Simabus’s ClassInformer
  • Matrosov’s HexRaysCodeXplorer
  • MFC_Helper

The MFC C++ source code can be found in the srcmfc directory of the Visual Studio installer. Since MFC4.2 (MFC of VS6) is very old, it can be found on Github. We refer here. About the relationship chart of the classes of MFC (Hierarchy Chart), you can see at this link.

Three important dlls file to diffing/compare with MFC malware, for example in this sample eToken, are mfc42.dllmfc42d.dllmfco42d.dll. You can find and download the correct debug symbol file (.pdb) of the dlls you have. The most important one is mfc42d.dll (debug build), since its .pdb will contain full information about the types, enumes, classes, and vtables of the MFC classes. We export local types from mfc42d.dll to .h file, then import into our idb database. IDA’s Parse C ++ has an error, unable to parse the “<>” template syntax, so we find and replace pairs of “<” and “>” to “_” in .h files.

Parallel opening mfc42d.dll in new IDA together with IDA is parsing malware, copy names, types of classes, functions from mfc42d.dll. As mentioned, this malware is an MFC Dialog application, so we will definitely have the following classes in the malware: CObjectCCmdTargetCWinThreadCWndCDialog. According to the MFC Wizard’s auto-naming rule, we have classes with the following names: CVVSupApp (inherited from CWinApp), CAboutDlg (dialog About, resID = 100), CVVSupDlg (main dialog, resID = 102).

Figure 12. Scanning vtables, classes result

Scan results of vtables, classes of two plugins ClassInformer and HexRaysCodeXplorer.

Use MFC_Helper scan CRuntimeClass, as expected, CVVSupDlg has CRuntimeClass and add another class: CVVSupDlgAutoProxy. It shows that the hacker when running the MFC Wizard, clicked to select support OLE Control.

Figure 13. Detect classe after run MFC_Helper

Based on the import function CWinApp::GetRuntimeClass, we can determine CVVSupApp vtable, and based on CDialog::GetRuntimeClass we can define two vtables of the other two dialogs. But which dialog is About, which dialog is a malware dialog? Identify all the internal structures of MFX such as AFX_MSGMAPAFX_DISPMAPAFX_INTERFACEMAP

Using the Xref to feature call the CDialog constructor: void __thiscall CDialog::CDialog (CDialog *this, unsigned int nIDTemplate, CWnd *pParentWnd)nIDTemplate is the resID of the dialog, we define the vtable of CAboutDlg and CMalwareDlg. Because CMalwareDlg does not have CRuntimeClass and RTTI, so it is temporarily named like that. The hacker deleted the DECLARE_DYNAMIC_CREATE line of these two classes and the CVVSupApp class when build.

Figure 14. Identify vtable of CAboutDlg and CMalwareDlg

Relational Classes table of this malware:

Figure 15. Relational classes table of this malware

Copy the names of functions, types, function types, parameters … from the respective parent classes of the above classes, in the correct order in the vtable, identify the generated MFC Wizard functions and the functions the hacker wrote.

Figure 16. Result after copy name of functions, types, function types, parameters

Every MFC application has a global variable called theApp, belonging to the main class CXXXApp inheriting from CWinApp. In the case of this malware are: CVVSupApp theApp; This global variable is initialized by C RTL in the start function, called before main/WinMain, in table __xc_a. The functions in this table call after the C RTL constructors in __xi_a. These tables are the parameters passed to the internal _initterm function of C RTL.

Figure 17. TheApp global variable in the MFC application

The flowchart of creating and executing an MFC application is as follows:

Figure 18. Flowchart of creating and executing an MFC application

The CVVSupApp :: InitInstance function is also a common code generated by MFC wizard

Figure 19. CVVSupApp::InitInstance function

Constructor of CVVSupDlg: void CVVSupDlg::CVVSupDlg() is also common code generated by MFC Wizard. But in CVVSupDlg::OnInitDialog, which is called from CVVSupDlg::DoModal(), we can see immediately, at the end of the code that the MFC Wizard generated, CMalwareDlg is initialized and shown, then the malware exits forcibly exit (0).

Figure 20.  CMalwareDlg was created and shown

The value 129 is the resID of the CMalwareDlg dialog, and sizeof(CMalwareDlg) = 0x290, which is larger than the size of the parent CDialog. It proves that CMalwareDlg was added by hackers to some data members. Through analysis, we recreated the data members of CMalwareDlg:

Figure 21. Recreate data members of CMalwareDlg

The CMalwareDlg::CMalwareDlg Constructor does the following initialization jobs. Note the copy string “192.168” into the field m_szMask:

Figure 22. Copy “192.168” string to m_szMask field

When shown, CMalwareDlg::OnInitDialog will be called, and the main function that is important for doing the malware’s task is called here:

Figure 23. The Infect main function will do the malware’s job

The Infect (we named) function is relatively long, so it should be presented via the flowchart below:

Figure 24. Infect function flowchart

We’ll go into detail each of the important child functions called by the Infect function of the CMalwareDlg class. The UserIsAdmin function, using the IsUserAdmin() API of shell32.dll:

Figure 25. UserIsAdmin fuction

GetSomeAPIAddrs function is a redundant function, function pointers are taken but completely unused. We guess this could be an old code.

Figure 26. GetSomeAPIAddrs function

The Base64Decode function is like other Base64 decode functions, except that the Base64 code table is copied by the hacker to a char arrary m_szBase64Table and accessed from here. After being decoded Base64, the original ServiceName “TmV0QmlvcyBNZXNzYWdlciBSZWdpc3Rlcg==” will be “NetBios Messager Register“. The original ServiceDescription “TmV0QmlvcyBjb21tdW5pY2F0aW9uIGJldHdlZW4gc3lzdGVtIGNvbXBvbmVudHMu” would be “NetBios communication between system components.

The ExtractCabFile function is a global function, not part of the CMalwareDlg class. Note that the file is created with the attribute hidden.

Figure 27. ExtractCabFile function

The .cab file is completely embedded in the .data section, size = 94874 (0x1729A). Hackers declared the following equivalent: “static BYTE g_abCabFile[] = {0xXXXX, 0xYYYY};” (no const, so it will be located in .data section). Extracting that area, we have a .cab file containing a file, named smanager_ssl.dll, the date added to the cab is 04/26/2020 – 23:11 UTC, build date 26.04.2020 15:11:24 UTC.

Figure 28. The embedded .cab file contains the file smanager_ssl.dll

The smanager_ssl.dll file (netapi32.dll) will be analyzed in the next post because it is relatively complex.

Figure 29. RunExtrac32Exe function

The ExecuteAndWait function is also a global function, using the ShellExecuteExA API to call and wait until the execution completes.

Figure 30. ExecuteAndWait function

The Config of the Proxy on the victim machine is defined by the hacker through a struct as shown, PROXY_TYPE is an enum:

Figure 31. struct PROXY_CONFIG

The ReadProxyConfig function will read from the victim’s registry first, otherwise it will read from the Firefox pref.js file. We are still not clear why hackers tried to read from Firefox, maybe they did a reconnaisance to learn about the commonly used web browsers at the target.

Figure 32. ReadProxyConfig function

The ReadProxyConfigFromRegistry function is a bit long so there are only important parts:

Figure 33. The main job of the ReadProxyConfigFromRegistry function

The ReadProxyConfigFromFireFox function is very long so we won’t cover it in detail here. The UpdateFile function uses the memsearh equivalent function to find a string in the file’s content, and C&C Info will be written at the found location. In the case of this malware, the mask string is “192.168“.

Figure 34: The UpdateFile function uses the memsearh equivalent function to find a string

We recreated the C&C Info struct as follows:

Figure 35. struct of C&C info

And C&C info has been hardcoded by hackers in the code:

Figure 36. C&C information is hardcoded in the malicious code

The content of smanager_ssl.dll* (netapi32.dll**) is original and after being updated from g_CCInfo structure via:

Figure 37. Contents of smanager_ssl.dll file (netapi32.dll) before and after being updated

The function to load the extracted file and create the Scheduler Task:

Figure 38. Function LoadDllAndCreateSchedulerTask to load the extracted file and create a Scheduler Task

Then, if the malware is run with admin, it will register as a ServiceDll, with the name mentioned above, the Service registry key chosen at random from a table of ten elements, and appended “Ex“. These series include: “Winmads“, “Winrs“, “Vsssvr“, “PlugSvr“, “WaRpc“, “GuiSvr“, “WlanSvr“, “DisSvr“, “MediaSvr“, “NvdiaSvr“.

After appending Ex by the sprintf function, the registry key on the victim machine is created under the branch HKLMSOFTWAREMicrosoftWindows NTCurrentVersionSvchost will be one of the following strings: “WinmadsEx”, “WinrsEx”, “VsssvrEx”, “PlugSvrEx”, “WaRpcEx”, “GuiSvrEx”, “WlanSvrEx”, “DisSvrEx”, “MediaSvrEx”, “NvdiaSvrEx”.

Since the function is also a bit long, only the main points are covered here:

Figure 39. Create a registry key on a victim machine
Figure 40. Create service on victim machine

The RegistryCall function is a self-written function by hacker, it is a global function, also only doing tasks with the Registry. From our point of view, hackers’ programming styles are extremely messy and inconsistent (maybe this is how they intentionally confusing), which made it difficult for us to analyze. After registering as a Dll service, the Infect function completes and returns. Malware will exit because of the above call to exit(0) on OnInitDialog

We will provide .xml file containing analysis information on IDA so anyone interested in this malware can use it to re-import IDA and Ghidra using Ghidra’s plugin xml_importer.py

The IOCs of the malicious code have been noted in the article. You can write your own .bat file or script using PowerShell, VBS … to find and remove this malware on the victim’s computers.

Note:

Original smanager_ssl.dll

  • MD5: C11E25278417F985CC968C1E361A0FB0
  • SHA256: F659B269FBE4128588F7A2FA4D6022CC74E508D28EEE05C5AFF26CC23B7BD1A5

netapi32.dll (ie smanager_ssl.dll has updated CCInfo):

  • MD5: 43CE409C21CAD2EF41C9E1725CA12CEA
  • SHA256: 6C1DB6C3D32C921858A4272E8CC7D78280B46BAD20A1DE23833CBE2956EEBF75

 

Trương Quốc Ngân (aka HTC)

Malware Analysis Expert – VinCSS (a member of Vingroup)