615 796 2640 This file, SPIES.DOC, is the documentation for the 1.0 versions of the two programs SPY.COM, and SPY'.COM and also the accompanying source files SPY.ASM and SPY'.ASM. The programs were written for the TSR Seminar/Tutor section of the Microsoft forum of CompuServe. They are shareware programs with a $1 minimum requested donation. If you like the programs and/or the ideas presented in the source code I would be pleased if you would send me a monetary note of thanks. What do you get for your $1? Not much to be sure. In fact each $1 that you send will be a vote for an enhanced version of a SPY program that will be written contingent upon the number of $1's received. (It too would be shareware and source code would be made available to those sending in payments). You may send donations to: Charles Lazo III P. O. Box 2312 Hohenwald, TN 38462 My CompuServe user ID is 72210,17. The object of these programs is to demonstrate two methods that allow a program to detect if it has been loaded as a TSR before and if so to optionally pass parameters to the previous load. In addition to making the programs as simple as possible it was also desired to make them useful in their own right. Whether I have been successful in this endeavor will be up to you to decide. Both SPY.COM and SPY'.COM behave in exactly the same way as far as the user is concerned (except, of course, for the copyright and syntax notices). Running the SPY program without parameters (or by making an error in syntax) you will see: SPY Copyright (C) 1987 by Charles Lazo III, v1.0 SPY syntax: SPY xxxx:yyyy L zzz Where xxxx, and yyyy are hexadecimal numbers up to four digits in length and zzz is a one to three digit hexadecimal number. SPY will monitor the segment- offset region xxxx:yyyy for a length of zzz bytes and report to the user with a number of beeps equal to the number of bytes changed in that region if and when any are changed. The method of parameter setting for SPY is the same as one of the methods of specifying a range for DEBUG, i.e., segment:offset L size. After the parameter string you may optionally place comments on the same line by preceding them with a semicolon (may be useful for SPY in batch files). The parameter string may be entered in any combination of upper and lower case, and tabs or spaces may be sprinkled liberally within it except that hex numbers may not be broken up. The length of the spy region has been arbitrarily limited to three hex digits. This allows for up to 4095 bytes to be monitored at once for changes while SPY is loaded. This maximum value also determines how much memory that SPY will reserve for the spy buffer, an area of memory that will contain a copy of the region of memory to be spied upon. Each time a change occurs in the spy region chosen by the user on the command line SPY will increment a counter and update its copy of the region which it uses for comparison. This action takes place in a modified interrupt 8 (clock) handler. In the new int 8 routine if this counter is non zero, then the speaker will be turned on and the counter will be decremented. If the speaker is on then it is turned off at the next int 8. A delay counter is set after each beep and is decremented thereafter at each int 8 tick. Another beep will not occur until the delay counter is decremented to zero. Thus the beeps emitted by SPY occur at intervals which depend upon the value set into the delay counter. The maximum size of the spy region and the value of the delay interval can be changed if the constants which control them are altered in the SPY.ASM file and the program is reassembled, relinked and passed through the EXE2BIN program. One more thing that can be easily changed is the frequency of the tone emitted by SPY. The default frequency is just about 2,000 hertz. Setting SPY's sights upon a volatile region can become distracting so it is welcome knowledge that you can shut it up merely by pointing it to another region of memory. I suggest pointing it to ROM, e.g., SPY F800:0 L1. Thus to be explicit about the nature of SPY's operation after being loaded once before: SPY detects a previous load of itself as a TSR, and if there were any parameters on the command line of the current load, then the code in spy will pass these parameters to the code of the previous load and they will be acted upon as if SPY is being loaded for the first time. (This is why SPY will save a buffer of 4095 bytes [by default] even if you only ask for the monitoring of a single byte.) Keeping the program simple has lead to a number of compromises in its operation. One undesirable result is segment wrap around. If you were to run SPY as: SPY 0:ff00 L 200, then instead of monitoring the 512 bytes from ff0:0 to ff0:200 as you might expect, you would instead be keeping tabs on the 256 bytes from ff0:0 to ff0:ff and also the 256 bytes at the top of this segment from 0:0 to 0:ff. Instead enter this as: SPY ff0:0 L 200. While DEBUG will flag this sort of carelessness with an error, SPY will accept it and wrap the segment without complaint. Before I begin comment on the details of the source code that allows sensing a previous program load I would like to mention a few of the discoveries that I have made snooping around with SPY. There is a 16 byte region in the DOS data section of memory called the ICA (Intra-Application Communications Area). Not many programs use this region and one good application of SPY is to monitor it to determine which programs do use it. I was surprised to discover that BRIEF, the editor which I am using to put this stuff together, uses this region. Why I don't know. To monitor this region enter SPY 0:4f0L10. Another good place to point SPY is the interrupt table: SPY 0:0l400. I have noticed while monitoring this region that even though interrupt vectors are four bytes long I sometimes count a number of changes which is not divisible by four. I dono why. The most interesting discovery so far, however, has been the location of a byte in a section of memory used by DOS. I suppose it is in the non transient portion of COMMAND. The location is 291:1a7 in my PC DOS ver 3.20. What is interesting is that while SPY is pointed at this single byte and DOS is at the DOS prompt every keypress that places a printable character on the screen also elicits a beep from SPY. The byte is changed very many times for a long display such as a directory listing or a file typed to the screen. SPY.ASM and SPY'.ASM differ in only one respect except for the near universal replacement of SPY with SPY' in the SPY'.ASM program. This is the method that the two programs use to detect previous loads of themselves. The detection done by SPY is carried out entirely in the routine named set_es while for SPY' it is done in both set_es and newint16h (a routine chained into the ROM BIOS keyboard interrupt vector). Both programs use a set of three data values, key1, key2, and key3 that are words which are set into specific offsets when the program loads for the first time and becomes a TSR. The idea of detection in each case is to search locations in memory for the three key values in the relative locations in which they are expected to be found. SPY uses a brute force method that looks at every paragraph prior to the current value of the code segment for the presence of the keys. The value of key1 is the two byte op code for the instruction int 20h which is found at offset 0 of every PSP. It was chosen because if all of the keys were at offsets following location 100h in the code segment, then SPY could fail in its attempt to find itself in memory because it might mistake a set of data in a cache or in the buffers of DOS as a prior load if itself. SPY' uses the routine newint16h to add a new function to the ROM BIOS keyboard interrupt int 16h. The set_es routine invokes the int 16h with the function number ah = 77h. When SPY' has not been previously loaded the interrupt returns with nothing changed. However, if SPY' has been previously loaded, then the installed newint16h will service the 77h function by checking to see if the three keys are found in their respective locations (if not found, then the 77h function call must be due to another program using the same method and function number so is ignored by newint16h). If the keys are found in the right locations, then key1 is returned in ax and key2 is returned in bx while the value of cs for the newint16h routine is passed back in es. Thus set_es compares ax to key1 and bx to key2. If both equal are equal, then it can be assumed with fair confidence that es now contains the code segment of SPY' when it was first loaded as a TSR. I have thought of a few enhancements for a 2.0 version of SPY: (1) The ability to report the currently spied region of memory. (2) Allow the use of multiple spy channels (two or more spied regions at once using different tones for reporting changes in each channel). (3) Allow the use of the second type of DEBUG range specification. I.e., SPY seg1:off1 seg2:off2. (4) Preventing the wrap of a segment (a problem mentioned earlier). (5) Implementing SPY OFF and SPY ON. (6) Allowing command line setting of the delay count, maximum spy buffer size, and frequency of tone. (7) The ability to make calls to SPY from within another program. (This could be helpful in monitoring stack usage.) (8) Optional use of a popup window for on-the-fly change or monitoring of SPY parameters. Vote for any of the above or make your own suggestions when sending in your $1 minimum contribution. REFERENCES I found the idea used by SPY to find a previous TSR load of itself while taking apart the QEGA.COM program which was supplied by the QUADRAM corporation with their QUAD EGA+ EGA card. As I recall this program used only two keys and did not use the int 20h instruction as a key. I dono how it avoids making the mistake that can be caused by cache/buffers. The idea for adding another function to the int 16h keyboard routine as used in the SPY' program I got from the program PUSHDIR (used also in the companion program POPDIR) which is presented in the May 27, 1986 issue of PC Magazine. The programs' author is John Friend. John uses the same function number 77h (or rather I am using the same number as John). The reason I chose to use the same function number was so that it can be demonstrated that no conflict arrises in the use of SPY' and PUSHDIR-POPDIR together in the same machine. Other than this similarity the programs SPY' and PUSHDIR-POPDIR are very different in their inner workings. PUSHDIR-POPDIR does not use keys, but instead compares the copyright notice in a candidate for a prior load. DISCLAIMER This software SPY.COM, SPY'.COM, SPY.ASM, and SPY'.ASM and the accompanying documentation SPIES.DOC are not warranted for any purpose either expressed or implied including but not limited to merchantability or fitness of purpose. The author of the software shall have no liability or responsibility to any user of the software with respect to any liability, loss or damage directly or indirectly arising out of the use of the software, including, but not limited to any loss of business or other incidental or consequential damages. By using the software you agree to this.