Preliminary AnalysisThe malware is heavily obfuscated and contains a lot of packed data judging from its entropy scan.
Opening the executable in OllyDbg confirms our belief.
As per the following image, we can see a lot of garbage instructions, to throw analysis off track.
Additionally, it purposely throws a lot of exceptions, to render the execution flow nonlinear as per the following image of OllyDbg Log. Throwing exceptions also work as an anti debugging trick and as such must be passed to the application when being debugged.
Dropped filesThe malware drops a dll at
%temp%\o.dll and then immediately tries to load it. We can intercept the dll being loaded by setting a breakpoint on
LoadLibraryA as per the following images.
We will analyze the dropped dll later and continue analyzing the main file. We will prevent the load library by deleting the dropped dll.
If we open the sample in CFF Explorer, we can see that it has 3 sections with one being completely empty (size on disk = 0).
The malware will decrypt the second stage code, write in this empty section, process its import table and finally jump to the entry point of the decrypted code.
To intercept the writing of the decrypted code we can set a memory breakpoint on write on the section. To speed things up we can breakpoint on
LoadLibraryA which is used when processing the import table.
Finally, after a bit of tracing around we can see the jump to the OEP as per the following image.
Searching for strings in the newly decrypted region, shows that the second stage must be coded in Delphi as per the following image.
Dumping the second stageTo ease analysis, we can dump the decrypted code directly from memory. For this purpose, I have used Scylla (similar to ImpRec) for dumping and import rebuilding as per the following image.
Analysis of the second stageThe malware is coded in delphi as already found out. On executing it tries to find and terminate running programs having names of ravmon.exe, eghost.exe, mailmon.exe, kavpwf.exe, iparmour.exe, ravmond.exe, regsvc.exe, mcshield.exe, kvmonxp.exe, kregex.exe, kvxp.exe.
This is done by opening the process and calling
TerminateProcess as per the following image.
It creates a file at
C:\Windows\uninstall\rundl132.exe and then copies the first 98926 (0x1826E) bytes of itself. This size is written within the pe headers itself as per the following image.
It then proceeds to create a autorun entry in the registry (
HKCU\Software\Microsoft\Windows\CurrentVersion\Run) for the above file.
Analysis of o.dllo.dll is the file dropped in the temp directory. It is similarly obfuscated and encrypted just as the main malware. Opening the sample in CFF Explorer reveals that it too has an empty section which would be later filled up with the decrypted code while running.
Now as we did for the main sample, we can use dump the decrypted code from memory using Scylla (or ImpRec). The process is similar and is not being shown.
Analysis of second stage of o.dllThe main purpose of the second stage is to load a kernel driver as per the decompiled code from Hex-Rays.
BOOL __stdcall sub_1000B460(int a1, LPCSTR lpBinaryPathName, LPCSTR lpServiceName)
{
int v3; // ebp@1
SC_HANDLE v4; // esi@1
SC_HANDLE v5; // edi@2
HANDLE v6; // esi@12
signed int v8; // [sp+Ch] [bp-44h]@1
CHAR FileName; // [sp+10h] [bp-40h]@11
v3 = 0;
v8 = -1;
v4 = OpenSCManagerA(0, 0, 0xF003Fu);
if ( v4 )
{
v5 = CreateServiceA(v4, lpServiceName, lpServiceName, 0xF01FFu, 1u, 3u, 1u, lpBinaryPathName, 0, 0, 0, 0, 0);
if ( v5 || GetLastError() == 1073 && (v5 = OpenServiceA(v4, lpServiceName, 0xF01FFu)) != 0 )
{
v3 = StartServiceA(v5, 0, 0) || GetLastError() == 1056;
CloseServiceHandle(v5);
}
CloseServiceHandle(v4);
}
sub_10009C50(&FileName, "\\\\.\\");
sub_10009C00(&FileName, lpServiceName);
if ( v3 )
{
v6 = CreateFileA(&FileName, 0x80000000, 1u, 0, 3u, 0, 0);
GetLastError();
v8 = (signed int)v6;
}
*(_DWORD *)a1 = v8;
return v3 && v8 != -1;
}
Immediately after loading the driver, it is deleted from disk. Hence for our analysis, we need to set up a breakpoint on
CreateServiceA or
DeleteFileA In addition to the above method of loading the kernel driver, the malware can also inject shellcode in a suspended iexplore.exe process which loads the driver indirectly. The relevant code listing is as follows.
memset(&StartupInfo, 0, sizeof(StartupInfo));
ProcessInformation.hProcess = 0;
ProcessInformation.hThread = 0;
ProcessInformation.dwProcessId = 0;
StartupInfo.cb = 68;
ProcessInformation.dwThreadId = 0;
StartupInfo.wShowWindow = 0;
StartupInfo.dwFlags = 128;
sub_1000AC90(&ApplicationName, (int)&lpAddress);
result = (LPVOID)CreateProcessA(&ApplicationName, 0, 0, 0, 0, 0x84u, 0, 0, &StartupInfo, &ProcessInformation);
if ( result )
{
v23 = ProcessInformation.hProcess;
VirtualProtectEx(ProcessInformation.hProcess, lpAddress, 0x1000u, 0x40u, &flOldProtect);
v24 = WriteProcessMemory(v23, lpAddress, v11, nSize, &NumberOfBytesWritten);
VirtualProtectEx(v23, lpAddress, 0x1000u, flOldProtect, &flOldProtect);
if ( v24 )
{
SetThreadPriority(ProcessInformation.hThread, 2);
SetPriorityClass(ProcessInformation.hProcess, 0x100u);
ResumeThread(ProcessInformation.hThread);
CloseHandle(ProcessInformation.hProcess);
CloseHandle(ProcessInformation.hThread);
VirtualFree(v11, 0, 0x8000u);
result = (LPVOID)v24;
}
else
{
CloseHandle(ProcessInformation.hProcess);
CloseHandle(ProcessInformation.hThread);
VirtualFree(v11, 0, 0x8000u);
result = 0;
}
}
}
Analysis of the kernel driverThe purpose of the driver is to hide process, registry keys, or files on disks. It does this by hooking the SSDT (System Service Descriptor Table). The malware accepts IOCTL codes from its user mode component and works accordingly. The decompiled code which hooks the SSDT is as follows:
unsigned __int32 sub_10C8A()
{
unsigned __int32 result; // eax@3
unsigned __int32 v1; // [sp+0h] [bp-4h]@1
v1 = __readcr0();
__writecr0(v1 & 0xFFFEFFFF);
_disable();
*((_DWORD *)KeServiceDescriptorTable + dword_1165C) = dword_14CF4;
*((_DWORD *)KeServiceDescriptorTable + dword_11660) = dword_14CFC;
*((_DWORD *)KeServiceDescriptorTable + dword_11664) = dword_14D00;
if ( dword_11658 )
{
*((_DWORD *)KeServiceDescriptorTable + dword_11668) = dword_14D0C;
*((_DWORD *)KeServiceDescriptorTable + dword_1166C) = dword_14D08;
}
_enable();
result = v1;
__writecr0(v1);
return result;
}
Using Kernel Detective (or Rootkit UnHooker LE) we can view the hooks on an infected system as per the following image.
Conclusion & MitigationThe malware is quite advanced in its functionality and contains multi stage payloads. Removing the malware on an already infected system is difficult due to the kernel component. It has the capability to hide files, registry keys or running process on a system.
Restoring infected files is however easier. The malware acts as a prepender. The original executable is stored as an overlay. Hence to disinfect a file removing the first 98926 (0x1826E) bytes is sufficient.
Removing the kernel driver is difficult. One way to remove it is to boot the computer in safe mode, and remove the autorun entries in registry. Next time when the machine is booted in normal mode, the malware won't be loaded and we can safely delete all other artifacts left behind by the malware.
Greetz to Deque once again for her work in the field of malware analysis