Monday, September 9, 2013

Back to the future - Analysis of an old Downloader

This article is an analysis of a Downloader first discovered ITW in 2006. It is widely detected by Anti-Virus vendors, also several reports are available:

http://www.threatexpert.com/report.aspx?md5=a595b08e16a0605e34c9bc310af89c2c
http://www.mcafee.com/threat-intelligence/malware/default.aspx?id=285381
https://secure2.sophos.com/en-us/threat-center/threat-analyses/viruses-and-spyware/Troj~Bckdr-QIB/detailed-analysis.aspx

It uses a couple of interesting techniques, although it later showed some were implemented in a sloppy way:

- Uses some sort of code obfuscation
- Sensitive strings are encrypted
- uses a kernelmode driver to hide its process

Virustotal statistics indicate this downloader is still in use, although the server of the sample I have analyzed isn't available anymore (more samples see Appendix).

Sample (UPX packed)
Target machine: x86
Size: 13.824 bytes
Compilation timestamp: 2006-11-25 19:29:09
SHA1: f18803def56bf6bfb067459ee6a9589d9f135c29
Virustotal: https://www.virustotal.com/de/file/2f771a5e0c9cda7bf8a6a771ba62585babb2df4eaa8be82accd9a3ca81d883a8/analysis/
Download (pw: infected): https://www.dropbox.com/s/8831saoza7nc1f7/downloader_f18803def56bf6bfb067459ee6a9589d9f135c29.zip
Appendix samples (pw: infected): https://www.dropbox.com/s/u4fei8nszhbwnn0/Appendix_samples.zip


Code Obfuscation
The usermode component is a mishmash of garbage code and real code in between, which makes it a tedious job to analyze. The garbage code are blocks of function calls for allocating memory buffers (malloc) and subsequently releasing them (free). Example of garbage code mixed with real code:

Figure 1: Example of code obfuscation scheme (left) and cleaned code (right)
String Decryption
All sensitive strings in the usermode component are encrypted with a simple xor algorithm. Every byte of the encrypted string gets decrypted by xoring it subsequently with every byte of the key beginning with the last. At runtime, each string is decrypted into a temporary buffer just before it gets used and afterwards cleared. This way, dumping of the decrypted strings in a whole isn't possible. An example of the reverse engineered decryption algorithm:

char key[] = {0x8A, 0x9E, 0xFC, 0xA3, 0xCC};
char cryptedString[] = {0xEF, 0xF3, 0xF3, 0xF7, 0xBD, 0xA8, 0xA8, 0xBF, 0xB2, 0xA9, 0xB5, 0xB2, 0xB2, 0xA9, 0xB6, 0xB5, 0xB7, 0xA9, 0xB5, 0xB1};

char *decryptedString;
char xoree;

size_t keyLength;
size_t cryptedStringLength;

int counter = 0;

keyLength = strlen(key);
stringLength = strlen(cryptedString);

decryptedString = malloc(1024);

while(counter < stringLength)
{
  xoree = cryptedString[counter];

  for(i=keyLength-1; i>=0; i--)
  {
     xoree = xoree ^ key[i];
  }

  strncat(decryptedString, xoree, 1);

  ++counter;
}

The decrypted strings of this sample can be found at the Appendix. It should be noted that some encrypted strings never get decrypted (artifacts, highlighted in Appendix).

Usermode component
For persistency this malware copies itself into system folder as "sescmgr.exe", alters its creation date to "17.8.2004 19:22:00" and adds a registry key into HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run ("sctrlmgr"). It also adds the TLD "realsearch.cc" into the list of Internet Explorer's trusted websites (HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains). To circumvent the Windows firewall it adds itself as "QoS SRVSP" into the trusted applications list (SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\StandardProfile\AuthorizedApplications\List), but only if it was executed on Windows 2000/XP/Server 2003. As you can see the malware uses pretty standard techniques for its own setup.

Figure 2: Windows firewall evasion
After this, the kernel driver gets copied from resource section into the Windows driver folder as "vissv.sys", again only if it was executed on Windows 2000/XP/Server 2003. Then, the file creation time is also changed to the same as above. There follows the driver persistency setup and loading by first creating a Windows service named "VISSV" (OpenSCManagerA + CreateServiceA) and then starting it (OpenServiceA + StartServiceA).

Figure 3: Service setup by Service Control Manager (driver persistency)

After the driver was loaded by the Service Control Manager, the usermode component communicates with it by using DeviceIoControl API function. It first sends the control code "900h" along with the address of the exported function NtQuerySystemInformation from ntdll.dll (lpInBuffer). If successful, it sends control code "A00h" along with the PID of itself. And last but not least, if successful it sends control code "1800h" along with an empty buffer. In the next Chapter we will see to what operations the control codes lead in the driver.

Figure 4: Communication with kernel driver

Next, a new Thread is created which handles the downloading and execution of the files. Since these files aren't available anymore, I mainly skipped this part of the malware. But if you want to get a general feeling of the downloading part, it's enough to take a look at the (decrypted) strings (in the Appendix).

Kernelmode component
The driver implements a dispatch routine for two major function codes, IRP_MJ_CREATE and IRP_MJ_DEVICE_CONTROL. As we have seen, the usermode component used the DeviceIoControl function to communicate with the driver, thus the control code IRP_MJ_DEVICE_CONTROL. The dispatch routine only looks for IRPs with MajorFunction IRP_MJ_DEVICE_CONTROL, otherwise (IRP_MJ_CREATE) it just calls IoCompleteRequest making sure the IRP isn't passed the way down the device stack. If the IRP has control code IRP_MJ_DEVICE_CONTROL, it reads the IOCTL and performs the following operations:

Control 0x900:
Check if NtQuerySysteminformation is already hooked by reading the first byte at address of NtQuerySystemInformation and comparing it to 0xB8. If it isn't hooked, save the next byte for later use (here 0xAD), which is the ordinal of NtQuerySystemInformation in the SSDT.

Control 0xA00:
Save the PID for later use.

Control 0x1800:
Hook the function NtQuerySystemInformation in SSDT by taking the ordinal saved before (0xAD) and changing the address to a handler inside the driver. The handler hides the process output by using the PID.

Control 0x1900:
Unhook the function NtQuerySystemInformation. Note: this routine never gets used (artifact), because this control code is never called. Curious!

This is the theory. In practice, as soon as the driver tries to hook NtQuerySystemInformation, my Windows XP system immediately freezes and ends up in an endless booting loop. A quick survey into the latest Minidump revealed the driver causes a system error with Bugcheck "ATTEMPTED_WRITE_TO_READONLY_MEMORY". A quick view with WinDbg revealed the following details:

kd> !analyze -v

*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

ATTEMPTED_WRITE_TO_READONLY_MEMORY (be)

An attempt was made to write to readonly memory.  The guilty driver is on the
stack trace (and is typically the current instruction pointer).
When possible, the guilty driver's name (Unicode string) is printed on
the bugcheck screen and saved in KiBugCheckDriver.
Arguments:
Arg1: 80501f34, Virtual address for the attempted write.
Arg2: 00501121, PTE contents.
Arg3: f6254ba4, (reserved)
Arg4: 0000000b, (reserved)

Debugging Details:
------------------

DEFAULT_BUCKET_ID:  INTEL_CPU_MICROCODE_ZERO

BUGCHECK_STR:  0xBE

PROCESS_NAME:  unpacked.exe

TRAP_FRAME:  f6254ba4 -- (.trap 0xfffffffff6254ba4)
ErrCode = 00000003
eax=fb0f7474 ebx=fb0f72d5 ecx=ffaa0990 edx=000000ad esi=ffa44718 edi=80501c80
eip=fb0f7339 esp=f6254c18 ebp=f6254c34 iopl=0         nv up ei pl nz ac pe cy
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010217
vissv+0x339:
fb0f7339 871c97          xchg    ebx,dword ptr [edi+edx*4] ds:0023:80501f34={nt!NtQuerySystemInformation (80608852)}
Resetting default scope

LAST_CONTROL_TRANSFER:  from 804f7bc3 to 80527d2c

STACK_TEXT:  
f62546e0 804f7bc3 00000003 f6254a3c 00000000 nt!RtlpBreakWithStatusInstruction
f625472c 804f87b0 00000003 00501121 00000000 nt!KiBugCheckDebugBreak+0x19
f6254b0c 804f8cdb 000000be 80501f34 00501121 nt!KeBugCheck2+0x574
f6254b2c 8051cd43 000000be 80501f34 00501121 nt!KeBugCheckEx+0x1b
f6254b8c 80540760 00000001 80501f34 00000000 nt!MmAccessFault+0x8e7
f6254b8c fb0f7339 00000001 80501f34 00000000 nt!KiTrap0E+0xcc
WARNING: Stack unwind information not available. Following frames may be wrong.
f6254c34 804ee199 ffaa0990 ffa446a8 806d2070 vissv+0x339
f6254c44 80574f50 ffa44718 80e8ec38 ffa446a8 nt!IopfCallDriver+0x31
f6254c58 80575e0b ffaa0990 ffa446a8 80e8ec38 nt!IopSynchronousServiceTail+0x70
f6254d00 8056e65e 0000005c 00000000 00000000 nt!IopXxxControlFile+0x5e7
f6254d34 8053d854 0000005c 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
f6254d34 7c91e514 0000005c 00000000 00000000 nt!KiSystemServicePostCall
0012f944 7c91d28a 7c801675 0000005c 00000000 ntdll!KiFastSystemCallRet
0012f948 7c801675 0000005c 00000000 00000000 ntdll!ZwDeviceIoControlFile+0xc
0012f9a8 0040a560 0000005c 00001800 00000000 kernel32!DeviceIoControl+0xdd
0012f9e8 00408f6d 0033f430 00914ab0 009102f0 unpacked+0xa560
00000000 00000000 00000000 00000000 00000000 unpacked+0x8f6d

STACK_COMMAND:  kb

FOLLOWUP_IP: 
vissv+339
fb0f7339 871c97          xchg    ebx,dword ptr [edi+edx*4]

SYMBOL_STACK_INDEX:  6

SYMBOL_NAME:  vissv+339

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: vissv

IMAGE_NAME:  vissv.sys

DEBUG_FLR_IMAGE_TIMESTAMP:  4566d59a

FAILURE_BUCKET_ID:  0xBE_vissv+339

BUCKET_ID:  0xBE_vissv+339

Followup: MachineOwner
---------

By looking at the stack output, we can see everything went fine until the driver causes the system error. The code which causes the error is also shown as "xchg ebx,dword ptr [edi+edx*4]". That's the operation where the address to the original NtQuerySysteminformation is changed to the routine inside the driver (hooking). A little searching in the Internet lead me to the following statement (http://uninformed.org/index.cgi?v=8&a=2&p=10):

"Considerations: On certain versions of Windows XP, the SSDT is marked as read-only. This must be taken into account when attempting to write to the SSDT across multiple versions of Windows."

That's exactly the problem of the driver, it doesn't check if the SSDT is marked as read-only, thus it risks to cause a BSOD (or endless booting, like on my system).


That's all! Thanks to TouchMyMalware for collaboration on reversing!


Appendix

Decrypted strings:
/0001
http://85.255.120.26
http://85.255.120.28
http://85.255.120.29
http://85.255.120.30
http://85.255.120.26
%s\rdpslip.exe
%s\rsoprov.exe
%s\svc332.dll
%s\s0ct0001.tmp
%s\s0ct0002.tmp
%s\s0ct0003.tmp
Software\Microsoft\Windows\CurrentVersion\Run
Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\realsearch.cc
SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\StandardProfile\AuthorizedApplications\List
:*:Enabled:QoS SRVSP
\win32.exe
\sys32.exe
\svc332.dll
%s\sescmgr.exe
kernel32.dll (gets never decrypted)
Microsoft Internet Explorer
vissv.sys
ExitThread (gets never decrypted)
LoadLibraryA (gets never decrypted)
wininet.dll
InternetOpenA
InternetOpenUrlA
InternetReadFile
InternetCloseHandle
InternetCheckConnectionA
InternetQueryDataAvailable (gets never decrypted)

Additional samples (SHA-1):
251fd0028509cb4bc13caad29e602c8aabf264c4
9f4fa181c5bced70056e07638a0cfe7a213d7660
f18803def56bf6bfb067459ee6a9589d9f135c29
b2d2a91ce2f47f402b97fff317bd019d86765405
5c7c41d1270ef388bfb19388646357e75d26959a
Share:

1 comment:

  1. This comment has been removed by a blog administrator.

    ReplyDelete