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.
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.dll, mfc42d.dll, mfco42d.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: CObject, CCmdTarget, CWinThread, CWnd, CDialog. 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).
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.
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_MSGMAP, AFX_DISPMAP, AFX_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.
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.
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.
The flowchart of creating and executing an MFC application is as follows:
The CVVSupApp :: InitInstance function is also a common code generated by MFC wizard
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).
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:
The CMalwareDlg::CMalwareDlg Constructor does the following initialization jobs. Note the copy string “192.168” into the field m_szMask:
When shown, CMalwareDlg::OnInitDialog will be called, and the main function that is important for doing the malware’s task is called here:
The Infect (we named) function is relatively long, so it should be presented via the flowchart below:
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:
GetSomeAPIAddrs function is a redundant function, function pointers are taken but completely unused. We guess this could be an old code.
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.
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.
The smanager_ssl.dll file (netapi32.dll) will be analyzed in the next post because it is relatively complex.
The ExecuteAndWait function is also a global function, using the ShellExecuteExA API to call and wait until the execution completes.
The Config of the Proxy on the victim machine is defined by the hacker through a struct as shown, PROXY_TYPE is an enum:
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.
The ReadProxyConfigFromRegistry function is a bit long so there are only important parts:
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“.
We recreated the C&C Info struct as follows:
And C&C info has been hardcoded by hackers in the code:
The content of smanager_ssl.dll* (netapi32.dll**) is original and after being updated from g_CCInfo structure via:
The function to load the extracted file and create the 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:
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)
