Skip navigation.
Home

Rustock B preliminary analysis

|

eaa4a3ae6f0512fa4ee9169a86684dda
I did some rudimentary analysis of rustock B.

This variant also creates a device driver .sys file and hides it in an alternate data stream,
however the file is named differently than in the previous version.
My trick of trying to unload the driver and then extract the ADS has failed so far.

// More below the cut...

- Appears to be packed with ASPROTECT
- Writes to an alternate data stream file c:\WINDOWS\System32:lzx32.sys
- Makes a HTTP connection to 208.66.194.158 and performs a
GET request for index.php?page=main
- The machine then makes a name query of
google.com
microsoft.com
gmail.com
yahoo.com
aol.com

- The GET request looks like: (NOTE I hade to remove some of the
HTML>HEAD>
TITLE>302 Found/TITLE>
/HEAD>BODY>
H1>Found/H1>
The document has moved A HREF="http://google.com/">here/A>.P>
/BODY>/HTML>

0

- I believe the web page has been removed.

- The DNS queries look like:

Request:

00 C2 01 00 00 01 00 00 00 00 00 00 03 61 6F 6C [.............aol]
03 63 6F 6D 00 00 01 00 01 [.com..... ]

Response:

00 C2 81 80 00 01 00 01 00 00 00 00 03 61 6F 6C [.............aol]
03 63 6F 6D 00 00 01 00 01 C0 0C 00 01 00 01 00 [.com............]
00 51 81 00 04 7F 00 00 01 [.Q....... ]

- Joanna's exelent system virginity verifier finds:

C:\Documents and Settings\macdaddy\Desktop\svv>svv.exe check
ntoskrnl.exe (804d4000 - 806c6980)... suspected! (verdict = 5).
tcpip.sys (f6675000 - f66c7000)... suspected! (verdict = 5).

SYSTEM INFECTION LEVEL: 5
0 - BLUE
1 - GREEN
2 - YELLOW
3 - ORANGE
4 - RED
--> 5 - DEEPRED
SUSPECTED modifications detected. System is probably infected!

- After unpacking the binary we can see some registry modification here:

ype.Start.ErrorC
.text:00401F00 6F 6E 74 72 6F 6C 00 49 6D 61 67 65 50 61 74 68 ontrol.ImagePath
.text:00401F10 00 44 69 73 70 6C 61 79 4E 61 6D 65 00 73 79 73 .DisplayName.sys
.text:00401F20 74 65 6D 5C 43 75 72 72 65 6E 74 43 6F 6E 74 72 tem\CurrentContr
.text:00401F30 6F 6C 53 65 74 5C 53 65 72 76 69 63 65 73 5C 6C olSet\Services\l
.text:00401F40 7A 78 33 32 00 5C 00 72 00 65 00 67 00 69 00 73 zx32.\.r.e.g.i.s
.text:00401F50 00 74 00 72 00 79 00 5C 00 6D 00 61 00 63 00 68 .t.r.y.\.m.a.c.h
.text:00401F60 00 69 00 6E 00 65 00 5C 00 73 00 79 00 73 00 74 .i.n.e.\.s.y.s.t
.text:00401F70 00 65 00 6D 00 5C 00 43 00 75 00 72 00 72 00 65 .e.m.\.C.u.r.r.e
.text:00401F80 00 6E 00 74 00 43 00 6F 00 6E 00 74 00 72 00 6F .n.t.C.o.n.t.r.o
.text:00401F90 00 6C 00 53 00 65 00 74 00 5C 00 53 00 65 00 72 .l.S.e.t.\.S.e.r
.text:00401FA0 00 76 00 69 00 63 00 65 00 73 00 5C 00 6C 00 7A .v.i.c.e.s.\.l.z
.text:00401FB0 00 78 00 33 00 32 00 00 00 60 56 89 E6 81 EC 28 .x.3.2..

- And a set of variables here:

.text:004020FE aDc5e72a06d4147 db '{DC5E72A0-6D41-47e4-C56D-024587F4523B}',0
.text:00402125 aAdvapi32_dll db 'advapi32.dll',0
.text:00402132 aNtdll_dll db 'ntdll.dll',0
.text:0040213C aPe386 db 'pe386',0
.text:00402142 aWin23LzxFilesL db 'Win23 lzx files loader',0
.text:00402159 aBase db 'Base',0
.text:0040215E aExplorer_exe db 'explorer.exe',0
.text:0040216B aWininet_dll db 'wininet.dll',0
.text:00402177 aLzx32_sys db ':lzx32.sys',0
.text:00402182 aLzx32_sys_0 db '\lzx32.sys',0
.text:0040218D a208_66_194_158 db '208.66.194.158',0
.text:0040219C aIndex_php?page db '/index.php?page=main',0
.text:004021B1 aZwloaddriver db 'ZwLoadDriver',0
.text:004021BE aRtlinitunicode db 'RtlInitUnicodeString',0

- The source code of the file it currently tries to GET is

html>head>meta http-equiv="content-type" content="text/html;
charset=ISO-8859-1">title>Google/title>style>!--
body,td,a,p,.h{font-family:arial,sans-serif}
.h{font-size:20px}
.h{color:#3366cc}
.q{color:#00c}
-->/style>
script defer>
!--
function sf(){document.f.q.focus();}
// -->
/script>
/head>center>div align=right nowrap style="padding-
bottom:4px" width=100%>font size=-1>a href="/url?sa=
p&pref=ig&pval=3&q=http://www.google.com/ig%3Fhl%3
Den&usg=__yvmOvIrk79QYmDkrJAeuYO8jTmo=">Personalized Home/a> | 
a href="https://www.google.com/accounts/Login?continue=
http://www.google.com/&hl=en">Sign in/a>/font>/div>img alt="Google"
height=110 src="/intl/en_ALL/images/logo.gif" width=276>br>br>
form action="/search" name=f>script defer>!--
function togDisp(e){stopB(e);var elems=document.getElementsByName
('more');for(var i=0;i
/script>table border=0 cellspacing=0 cellpadding=4>tr>td nowrap>font

size=-1>b>Web/b>    
a class=q href="http://images.google.com/imghp?ie=
ISO-8859-1&oe=ISO-8859-1&hl=en&tab=wi">
Images/a>    a class=q

href="http://video.google.com/?ie=ISO-8859-1&oe=ISO-8859-1&hl=en&tab=wv">
Video/a>    a class=q

href="http://news.google.com/nwshp?ie=ISO-8859-1&oe=ISO-8859-1&hl=en&tab=wn">
News/a>    a class=q href="/maps?ie=
ISO-8859-1&oe=ISO-8859-1&hl=en&tab=wl">Maps  
  b>a href="/intl/en/options/" class=q onclick="this.blur();
return togDisp(event)">more »/a>/b>span name=more id=more
style="display:none;position:absolute;background:#fff;border:1px solid
#369;margin:-.5ex 2ex;padding:0 0 .5ex

.8ex;width:16ex;line-height:1.9;z-index:1000" onclick="stopB(event)">
img border=0 src=/images/x2.gif
width=12 height=12 alt="Close menu" align=right hspace=4 vspace=4>/a>
a class=q href="http://blogsearch.google.com/?ie=ISO-8859-1&oe=ISO-8859-1&hl
=en&tab=wb">Blogs/a>br>a class=q

href="http://books.google.com/bkshp?ie=ISO-8859-1&oe=
ISO-8859-1&hl=en&tab=wp">Books/a>br>a class=q
href="http://froogle.google.com/frghp?ie=ISO-8859-1&oe=
ISO-8859-1&hl=en&tab=wf">Froogle/a>br>a class=q href="
http://groups.google.com/grphp?ie=ISO-8859-1&oe=
ISO-8859-1&hl=en&tab=wg">Groups/a>br>a class=q
href="http://www.google.com/ptshp?ie=ISO-8859-1&oe=
ISO-8859-1&hl=en&tab=wt">Patents/a>br>a

href="/intl/en/options/" class=q>b>even more »/b>/a>
/span>/font>/td>/tr>/table>table cellpadding=0 cellspacing=0>
tr valign=top>td width=25%> /td>td align=center nowrap>
input name=hl type=hidden value=en>input type=hidden
name=ie value="ISO-8859-1">input maxlength=2048 name=q
size=55 title="Google Search" value="">br>input name=btnG type=submit

value="Google Search">input name=btnI type=submit
value="I'm Feeling Lucky">/td>td nowrap width=25%>font size=-2>
  a href=/advanced_search?hl=en>Advanced Search

  a href=/preferences?hl=en>Preferences/a>br> 
 a href=/language_tools?hl=en>Language Tools/a>/font>/td>
/tr>/table>/form>br>br>font size=-1>a href="/intl/en/ads/">
Advertising Programs/a> - a href=/services/>Business Solutions/a>
- a href=/intl/en/about.html>About

Google/a>/font>p>font size=-2>©2006 Google/font>/p>/center>/body>/html>

- I had a hard time rebuilding the IAT but based on the strings there is a pretty good idea of whats going on:

0000004D 0040004D 0 !This program cannot be run in DOS mode.
00000178 00400178 0 .text
000001A0 004001A0 0 .idata
000001C7 004001C7 0 @.newIID
00001EF4 00401EF4 0 Start
00001EFA 00401EFA 0 ErrorControl
00001F07 00401F07 0 ImagePath
00001F11 00401F11 0 DisplayName
00001F1D 00401F1D 0 system\CurrentControlSet\Services\lzx32
000020FE 004020FE 0 {DC5E72A0-6D41-47e4-C56D-024587F4523B}
00002125 00402125 0 advapi32.dll
00002132 00402132 0 ntdll.dll
0000213C 0040213C 0 pe386
00002142 00402142 0 Win23 lzx files loader
0000215E 0040215E 0 explorer.exe
0000216B 0040216B 0 wininet.dll
00002177 00402177 0 :lzx32.sys
00002182 00402182 0 \lzx32.sys
0000218D 0040218D 0 208.66.194.158
0000219C 0040219C 0 /index.php?page=main
000021B1 004021B1 0 ZwLoadDriver
000021BE 004021BE 0 RtlInitUnicodeString
000021DB 004021DB 0 wInternetOpenA
000021EA 004021EA 0 InternetConnectA
000021FB 004021FB 0 HttpOpenRequestA
0000220C 0040220C 0 HttpSendRequestA
0000221D 0040221D 0 InternetCloseHandle
00002246 00402246 0 OpenSCManagerA
00002255 00402255 0 CreateServiceA
00002264 00402264 0 StartServiceA
00002272 00402272 0 RegCreateKeyA
00002280 00402280 0 RegSetValueExA
000022A3 004022A3 0 wGetSystemDirectoryA
000022B8 004022B8 0 lstrcat
000022C0 004022C0 0 _lopen
000022C7 004022C7 0 VirtualAlloc
000022D4 004022D4 0 _lread
000022DB 004022DB 0 _lclose
000022E3 004022E3 0 LoadLibraryA
000022F0 004022F0 0 GetProcAddress
000022FF 004022FF 0 lstrcmpi
00002308 00402308 0 GetVersion
00002313 00402313 0 OpenEventA
0000231E 0040231E 0 GetWindowsDirectoryA
00002333 00402333 0 _lcreat
0000233B 0040233B 0 _lwrite
00002343 00402343 0 ExitThread
0000234E 0040234E 0 GetFileSize
0000235A 0040235A 0 CreateToolhelp32Snapshot
00002373 00402373 0 Process32First
00002382 00402382 0 Process32Next
00002390 00402390 0 OpenProcess
0000239C 0040239C 0 VirtualAllocEx
000023AB 004023AB 0 WriteProcessMemory
000023BE 004023BE 0 CreateRemoteThread
000023D1 004023D1 0 GetModuleFileName
000023E3 004023E3 0 DeleteFileA
000023EF 004023EF 0 Sleep
000023F5 004023F5 0 GlobalAddAtomA
00002404 00402404 0 GlobalFindAtomA
000024D2 004024D2 0 !This program cannot be run in DOS mode.
000025FD 004025FD 0 .text
0000264C 0040264C 0 @.reloc
000084AD 004084AD 0 ntoskrnl.exe
00008508 00408508 0 KeInitializeMutex
0000851C 0040851C 0 ExAllocatePoolWithTag
00008534 00408534 0 KeInsertQueueDpc
00008547 00408547 0 IoAllocateWorkItem
0000855C 0040855C 0 IoAllocateIrp
0000856C 0040856C 0 ZwClose
00008576 00408576 0 NtQueryInformationFile
0000858F 0040858F 0 NtCreateFile
0000859E 0040859E 0 ExQueueWorkItem
000085B0 004085B0 0 KePulseEvent
000085BF 004085BF 0 ExFreePoolWithTag
000085D3 004085D3 0 IoDeleteDevice
000085E4 004085E4 0 ObfReferenceObject
000085F9 004085F9 0 IoFreeMdl
00008605 00408605 0 NtOpenProcess
00008615 00408615 0 CcFlushCache
00008624 00408624 0 NtQueryDirectoryFile
0000863B 0040863B 0 ObfDereferenceObject
00013028 00413028 0 kernel32.dll
00013083 00413083 0 HeapReAlloc
00013091 00413091 0 DeviceIoControl
000130A3 004130A3 0 FindClose
000130AF 004130AF 0 GetDriveTypeA
000130BF 004130BF 0 FindResourceA
000130CF 004130CF 0 CreateFileW
000130DD 004130DD 0 GetMailslotInfo
000130EF 004130EF 0 FindFirstFileA
00013100 00413100 0 HeapAlloc
0001310C 0041310C 0 OpenProcess
0001311A 0041311A 0 SetSystemTime
0001312A 0041312A 0 CloseHandle
00013138 00413138 0 Sleep
00013140 00413140 0 CreateMailslotA
00013152 00413152 0 SetFilePointer
00013163 00413163 0 DeleteAtom
00013170 00413170 0 CopyFileA
0001317C 0041317C 0 AddAtomA
00001F44 00401F44 0 2\registry\machine\system\CurrentControlSet\Services\lzx32

HELO. you said "My trick of

HELO. you said "My trick of trying to unload the driver and then extract the ADS has failed so far." I'm just curious: what do you mean by "extract"? and what for "unload"? for a removal-tool-like utility? ;;)

oh

you run instdrv and give it the name of the driver and tell it to unload. There are other tools for loading and unloading drivers but I like that one. Then you can copy the contents of the ADS like this:

cat.exe c:\windows\system32\:lxz32.sys > c:\lxz32.sys

You could probably copy blank data over the .sys driver to disable it as well. Basically what is happening is that the .sys driver file is being hidden in an alternate data stream and then the ADS is hidden by the driver (its a rootkit).

does that make sense ?

V.

actually it's make sense,

actually it makes sense, but that's not what I would like to find out:D I think it's my bad (my ill English). what for do you want to disable it? to gain access to :lxz32.sys? what about vmware-mount.exe? (I guess you run rustock in vmware:D)

no problem

Yes to gain access to lxz32.sys. Great tip on the vmware-mount.exe, sometimes i miss the simple stuff :)

V.

yeah.. don't we all do this

yeah.. don't we all do this from time to time? (forgetting stuff ;) ) but, just another question: how the hell can that .sys be unpacked? I mean.. a memory dump or something? 'cause it's pretty strange... and.. sis it packed? or just crypted/obfuscated?

hmm

=i havent retrieved the .sys yet but this isnt too differnt from the original rustock so I would guess that it is packed. One thing I can think of to do is to attach a kernel debugger and try to watch whats going on. Anyone else have any ideas for unpacking a device driver ?

V.

the easy way to get readable driver code

ok, not much time at the moment so i'll describe just shortly what i'have done to analyse rustock.

the file malware.exe is not packed but crippled to make the code hard to read.

1. load malware.exe into ollydbg

2. scroll down to address 00401b82, place your cursor there, right click and "find references to" "selected address"

3. select 2nd reference (push 00401b82 / retn ... at address 0040198d and press f2 (set breakpoint)

4. press f9 (run)

5. f2 (clear breakpoint)

6. after breakpoint occured, press 2 x f7

7. at address 00401b82 press CTRL+A (analyze code)

we are now at the place were code gets readable.

8. trace the code until 401c7c (_lcreat() edi=c:\windows\system32:lzx32.sys)
for easier analysis change the value in memory to: c:\windows\system32\lzx32.sys instead of saving it as ADS before executing _lcreat()

9. trace further until lzx32.sys was written and file was closed at 00401cc7. make a copy of lzx32.sys now!

if you open lzx32.sys with ida now, you'll see a similar technique we recognized before in the dropper code.

to make it short: look at 0x110ce

push offset loc_116A4
retn

this is the last stage before the driver get's readable.
here's a small trick for idiots:

patch the retn mnem with a 0xcc ---> int 3 with a hexeditor and save the driver.

we need a kernel debugger now. if you use softice, make sure "i3here on" is set.

fire up ollydbg with malware.exe again and follow the instructions above until the code wants to create, write and close the file.
we bypass this stuff, because we wanna use our patched driver with int 3, so trace until 00401c7c and set the new origin directly to 401cc7 and press F9 (run code). the driver gets installed and executed now. if nothing strange happens, softice should popup with an int 3 breakpoint occurence now. change from 0xcc to 0xc3 (retn) and trace one step further.
after being landed into the uncrippled code dump the whole driver, for instance with iceext, now.

we can repair the pe structures incl. IAT by hand now or just take a first look what strings we have after uncrippling.

here we go:

\BaseNamedObjects\{DC5E72A0-6D41-47e4-C56D-024587F4523B}
services.exe
\Driver
\registry\machine\system\CurrentControlSet\Enum\Root\LEGACY_%ws
machine\system
knlsc
\registry\machine\%ws
%ws\CurrentControlSet\Services\%ws
\SystemRoot\System32\ntdll.dll
%ws%ws
NULLPROTO
TCPIP
TCPIP_WANARP
\SystemRoot\System32\drivers\wanarp.sys
\SystemRoot\System32\drivers\tcpip.sys
\SystemRoot\System32\drivers\ndis.sys
\Device\Tcp
\Device\Udp
Rootkitrevealer
BlackLight
Rkdetector
gmer.exe
endoscope.EXE
DarkSpy Anti-Rootkit
\SystemRoot\Temp\%u.tmp
.log
\registry\machine\system
!This program cannot be run in DOS mode.
.text
INIT
@.reloc
ntoskrnl.exe
hal.dll
ExAllocatePool
ExFreePool
ZwQuerySystemInformation
_stricmp
!This program cannot be run in DOS mode.
Richy
.text
h.rdata
H.data
INIT
.reloc
ZwOpenKey
ZwEnumerateKey
ZwQueryKey
ZwCreateKey
System
PSS
svchost.exe
.data
.data
ZwSaveKey
ZwDeviceIoControlFile
ZwInitializeRegistry
ZwQuerySystemInformation
.text
.text
NdisAllocatePacketPoolEx
NdisUnchainBufferAtFront
.text
PAGE
NdisGetReceivedPacket
NdisRegisterProtocol
.text
INIT
NdisOpenAdapter
NdisCloseAdapter
.data
NdisMRegisterMiniport
.text
.text
tcpip.sys
wanarp.sys
ndis.sys
PsGetThreadTeb
ZwTerminateProcess
Rustock rootkit v 1.2
RSDS0
Z:\NewProjects\spambot\new\driver\objfre\i386\driver.pdb
LoadLibraryA
GetProcAddress
SetEvent
Init
CreateThread
SleepEx
pe386
FATAL_UNHANDLED_HARD_ERROR
klif.sys
PsTerminateSystemThread
wcschr
ZwCreateEvent
RtlInitUnicodeString
KeDelayExecutionThread
ZwClose
PsCreateSystemThread
ExAllocatePoolWithTag
_wcsicmp
ZwOpenKey
_wcsnicmp
wcsstr
_wcslwr
wcsncpy
PsGetCurrentProcessId
wcscpy
ExFreePoolWithTag
_stricmp
ZwQuerySystemInformation
_strnicmp
IoGetCurrentProcess
strncpy
ZwDeleteKey
ZwEnumerateKey
IoGetRelatedDeviceObject
ZwCreateFile
ZwReadFile
ZwWriteFile
ZwQueryInformationFile
ZwSetInformationFile
swprintf
rand
KeWaitForSingleObject
KeInsertQueueApc
KeInitializeApc
KeClearEvent
ObfDereferenceObject
PsLookupThreadByThreadId
IoFreeMdl
KeDetachProcess
MmMapLockedPages
KeAttachProcess
MmBuildMdlForNonPagedPool
IoAllocateMdl
MmUnmapLockedPages
wcstombs
KeInitializeMutex
NtSetInformationProcess
ObReferenceObjectByHandle
PsLookupProcessByProcessId
KeReleaseMutex
KeSetEvent
IofCompleteRequest
IoFreeIrp
KeInitializeEvent
IoAllocateIrp
memmove
IofCallDriver
KeBugCheckEx
ProbeForRead
MmHighestUserAddress
ZwQueryInformationProcess
KeLeaveCriticalRegion
KeEnterCriticalRegion
ObOpenObjectByName
ExInterlockedPopEntrySList
ExInterlockedPushEntrySList
ZwRestoreKey
NtWaitForSingleObject
ZwLoadKey
ZwUnloadKey
wcscat
ObQueryNameString
PsSetCreateProcessNotifyRoutine
KeInitializeSpinLock
ExInitializeNPagedLookasideList
KeInsertQueueDpc
KeSetTargetProcessorDpc
KeInitializeDpc
KeNumberProcessors
KeServiceDescriptorTable
KeGetCurrentThread
KeAddSystemServiceTable
MmUserProbeAddress
KeGetPreviousMode
MmProbeAndLockPages
PsGetVersion
ObfReferenceObject
SeDeleteAccessState
RtlCopyUnicodeString
SeSetAccessStateGenericMapping
RtlMapGenericMask
SeCreateAccessState
ObCreateObject
IoFileObjectType
ZwOpenFile
wcslen
IoReuseIrp
IoGetDeviceObjectPointer
KefReleaseSpinLockFromDpcLevel
KefAcquireSpinLockAtDpcLevel
ExfInterlockedInsertTailList
MmGetPhysicalAddress
ProbeForWrite
ntoskrnl.exe
_except_handler3
KfReleaseSpinLock
KfAcquireSpinLock
KfLowerIrql
KeRaiseIrqlToDpcLevel
ExReleaseFastMutex
ExAcquireFastMutex
HAL.dll
NdisDeregisterProtocol
NdisRegisterProtocol
NdisFreeMemory
NdisFreePacket
NdisAllocateBuffer
NdisAllocatePacket
NdisAllocateMemory
NdisAllocateBufferPool
NdisAllocatePacketPool
NdisOpenAdapter
NdisCloseAdapter
NDIS.SYS
ntoskrnl.exe
KeInitializeMutex
ExAllocatePoolWithTag
KeInsertQueueDpc
IoAllocateWorkItem
IoAllocateIrp
ZwClose
NtQueryInformationFile
NtCreateFile
ExQueueWorkItem
KePulseEvent
ExFreePoolWithTag
IoDeleteDevice
ObfReferenceObject
IoFreeMdl
NtOpenProcess
CcFlushCache
NtQueryDirectoryFile
ObfDereferenceObject

hope that helps a little.

VERY COOL

I especially like changing the file to output to a normal file instead of an ADS. Thats a great idea.

PLEASE keep posting!

V.

8. trace the code until

8. trace the code until 401c7c (_lcreat() edi=c:\windows\system32:lzx32.sys)

could you explain to the readers what you mean by trace and also why you picked 00401b82.

Thanks for the great work!

V.

valsmith: i've chosen

valsmith: i've chosen 00401b82 because i've noticed that ollydbg wasn't able to analyze this code. this is often a hint that an area is packed or crippled. so i thought it's a good idea to search for a reference to this area and further if there's a jmp to it, which was the case. ;)
btw. under tracing i understand we debug the code until the address where the lzx32.sys gets created.

taking the 2nd barrier!

after playing a little with the drivers pe-header i found another way to bypass the need of a ring0 debugger.

so let's see what i've done.

load pe-tools 1.5 ---> tools ---> pe-editor ---> select lzx32.sys
select "file header" ---> characteristics ---> unmark "dll" bit ---> press "ok"
leave the "image file header editor"
select "image optional header editor" and change "Subsystem" value to "2" (windows gui) ---> press "ok"
select "directories" ---> "import directory" and set its "RVA" and "Size" to 00000000 ---> press "ok"
(remember the old values!, we have to reset them later in order to have a working file)
on my system they were RVA=00010000 and SIZE=000001CB
press "ok" in the main "PE Editor" window again, thus leaving our pe editing session.

now we are able to load this file into ollydbg! ;)

after loading our fixed lzx32.sys into ollydbg our starting address should be 00011000.
before tracing the code now scroll down until you reach address 000116a4.
while observing the code a little bit we notice that rustock uses a similar crippling technique like before in the dropper code.
after reaching address 000116a4 we see that ollydbg wasn't able to analyse it. so why not selecting our cursor at this position
and trying the trick that worked before? ;) right click "find reference to" --> selected address (000116a4)
olly shows us 3 hits and if we look at the first one at 000110ce (push 000116a4 / retn) there's a good chance that
these mnems are the last ones before the uncrippled code at 00116a4 get's disclosed.
so now set breakpoint using f2 and run (f9) the code. after breakpoint occured clean the breakpoint again (f2) and
press f7 (step into) 2 times.
we should be at address 000116a4 now and after a pressing CTRL+A (analyse code) it seems that we have uncrippled code. ;)
now dump the binary with ollydump, but remember to unmark "rebuild import" before.
after saving the dumpfile load it into pe-tools 1.5 again and reset the old values.

select "file header" ---> characteristics ---> mark "dll" bit ---> press "ok"
leave the "image file header editor"
select "image optional header editor" and change "Subsystem" value to "1" (windows native) ---> press "ok"
select "directories" ---> "import directory" and reset its "RVA" to "00100000" and Size to "000001cb" ---> press "ok"

now we load lzx32.sys in ida and we see that our new entry point is at 000116a4 and the clean code should look like this:

.text:000116A4 ; BOOL __stdcall DllEntryPoint(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpReserved)
.text:000116A4 public DllEntryPoint
.text:000116A4 DllEntryPoint proc near ; CODE XREF: .text:000110D3j
.text:000116A4 ; DATA XREF: .text:loc_110CEo ...
.text:000116A4
.text:000116A4 var_44 = dword ptr -44h
.text:000116A4 hinstDLL = dword ptr 4
.text:000116A4 fdwReason = dword ptr 8
.text:000116A4 lpReserved = dword ptr 0Ch
.text:000116A4
.text:000116A4 pusha
.text:000116A5 call $+5
.text:000116AA pop ebp
.text:000116AB sub ebp, 6
.text:000116AE mov eax, large fs:38h
.text:000116B4 mov eax, [eax+4]
.text:000116B7 xor al, al
.text:000116B9
.text:000116B9 loc_116B9: ; CODE XREF: DllEntryPoint+1Fj
.text:000116B9 ; DllEntryPoint+2Cj
.text:000116B9 sub eax, 100h
.text:000116BE cmp word ptr [eax], 5A4Dh ; MZ
.text:000116C3 jnz short loc_116B9
.text:000116C5 movzx ebx, word ptr [eax+3Ch]
.text:000116C9 cmp dword ptr [eax+ebx], 4550h ; PE
.text:000116D0 jnz short loc_116B9
.text:000116D2 mov edx, eax
.text:000116D4 lea esi, [ebp+41Ah]
.text:000116DA lea edi, [ebp+457h]
.text:000116E0 call sub_11A2E
.text:000116E5 lea esi, [ebp+46Bh]
.text:000116EB push esi
.text:000116EC push 0
.text:000116EE push esi
.text:000116EF push 0Bh
.text:000116F1 call dword ptr [ebp+45Fh]
.text:000116F7 add dword ptr [esi], 4
.text:000116FA push dword ptr [esi]
.text:000116FC push 0
.text:000116FE call dword ptr [ebp+457h]
.text:00011704 push dword ptr [esi]
.text:00011706 pop dword ptr [eax]
.text:00011708 add eax, 4
.text:0001170B mov [ebp+467h], eax
.text:00011711
.text:00011711 loc_11711: ; DATA XREF: sub_115C0+8o
.text:00011711 mov edi, eax
.text:00011713 push 0
.text:00011715 push dword ptr [esi]
.text:00011717 push edi
.text:00011718 push 0Bh
.text:0001171A call dword ptr [ebp+45Fh]
.text:00011720 test eax, eax
.text:00011722 jnz loc_117CA
.text:00011728 add edi, 4
.text:0001172B movzx eax, word ptr [edi+1Ah]
.text:0001172F lea eax, [edi+eax+1Ch]
.text:00011733 mov dword ptr [eax], 736F746Eh
.text:00011739 mov dword ptr [eax+4], 6C6E726Bh
.text:00011740 mov dword ptr [eax+8], 6578652Eh ; ntoskrnl.exe
.text:00011747 mov dword ptr [eax+0Ch], 0
.text:0001174E add edi, 11Ch
.text:00011754 movzx eax, word ptr [edi+1Ah]
.text:00011758 lea eax, [edi+eax+1Ch]
.text:0001175C mov dword ptr [eax], 2E6C6168h
.text:00011762 mov dword ptr [eax+4], 6C6C64h ; hal.dll
.text:00011769 mov edi, [ebp+473h]
.text:0001176F add edi, 4
.text:00011772 push edi
.text:00011773 push 0
.text:00011775 call dword ptr [ebp+457h]

so do we have the native driver code now?
unfortunately not because if you scroll down to address 00011afa, you'll see lots of unrecognized code.

text:00011ABE aExallocatepool db 'ExAllocatePool',0
.text:00011ACD aExfreepool db 'ExFreePool',0
.text:00011AD8 aZwquerysystemi db 'ZwQuerySystemInformation',0
.text:00011AF1 a_stricmp db '_stricmp',0
.text:00011AFA align 4
.text:00011AFC dd 6 dup(0)
.text:00011B14 dd 80000000h, 4D000088h, 38905A38h, 4026603h, 81FF7109h
.text:00011B14 dd 191C2B8h, 0C615C240h, 0E1C09E0h, 0F8BA1Fh, 21CD09B4h
.text:00011B14 dd 0C04C01B8h, 6968540Ah, 700E2073h, 67676F72h, 63876D61h
.text:00011B14 dd 4F1F6E47h, 6562E774h, 5F75CFAFh, 44066998h, 3537E4Fh
.text:00011B14 dd 65646F6Dh, 0A890D2Eh, 3D444C24h, 762DA401h, 2543C579h
.text:00011B14 dd 782A044Eh, 44427C08h, 0E63E8303h, 0BF7E215Ah, 0F0A31854h
.text:00011B14 dd 866BF85Fh, 52107E54h, 68636914h, 0A1A44634h, 4C004550h
.text:00011B14 dd 47E00501h, 5362983Dh, 10E83B8h, 8107930Bh, 1B947180h
.text:00011B14 dd 76891414h, 9A20112h, 0D2E6880h, 0CA21001h, 2B74DF04h

this is the last barrier we have to take.
but not now. it's new year's eve today and i'm going to pardey tonight and i haven't slept that much, so i'll get some kip now to surive the evening. ;)

i'm also planing to write a paper with screenshots and so forth for better understanding.
so watch out for more.

cheers,
frank boldewin

you are awesome.

Thanks for the great post and happy new year.

V.

the last stage

i'm currently writing on a paper how all this debugging and uncrippling stuff works until we have the native drivercode which can be loaded into ida for a detailed analysis. the paper will have lots of snapshots, the repaired binaries and ida 5 .idb files of the several stages, so reproducing all the stuff disussed in the paper should be no problem.

mainly the last stage was:

running the driver, then switching to softice incl. iceext with setting "!protect on"

map32 lzx32

gives us the drivers map incl. imagebase (here it was mapped to 0xf5fee000 and of size 0x12000).

then we dump the whole stuff:

!dump \??\c:\rustock-analysis\lzx32-dumped-2ndstage.sys f5fee000 12000

the interesting thing in this last stage is that binary consists of 2 PE-files.

f5fee000-f5fefb1a ---> stub for uncrippling the native driver code
f5fefb1b-f6000000 ---> the native driver

OEP of native driver was: f5feff91

so after dumping, the last job we have to do is stripping the stub (f5fee000-f5fefb1a) e.g. with ultraedit and then repairing the PE file.

the unstripped native driver then has the size of 66789 bytes

first thing i've noticed, were some important missing PE characteristics:

e_magic (offset 00h) ---> MZ
e_lfanew (offset 3ch) ---> 0xe0h
PE-Signature (offset e0h) ---> PE

so after setting them, PE-tools accepts the dump as valid pe file and the last few changes can be made.

OEP ---> 0x476 (should already be ok)
IMAGEBASE ---> YOURIMAGEBASEOFLZX32+1b1b (here 0xf5fefb1b)

in "sections" right click and use "dumpfixer"

IAT should be ok.

ok, that's it. we have the real and native driver of the rustock rootkit now and further analysis is just reverse engineering work as usual.

happy reversing,
frank boldewin

you might try

x86emu.

its kind of painful to use sometimes but once i got the driver partially unpacked x86emu seemed to be working ok to clear up the rest of it. I havent finished since you have to hit "step" about 100,000 times. :)

V.