home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / assemblr / library / sampler0 / spy.asm < prev    next >
Assembly Source File  |  1987-05-11  |  16KB  |  386 lines

  1. name spy
  2.  
  3. rt        equ    0dh    ; return
  4. lf        equ    0ah    ; linefeed
  5. eof        equ    1ah    ; end of file
  6. ok_seg        equ    1    ; flag for segment decode check
  7. ok_off        equ    2    ; flag for offset decode check
  8. max_size    equ    4095    ; maximum size for SPY search region
  9. beep_delay    equ    4    ; number of clock ticks between beeps
  10. timer_count    equ    597    ; frequency of beep = 1,193,180 / timer_count
  11.  
  12. code        segment
  13.         assume cs:code, ds:code
  14.  
  15.         org    0
  16. key1        dw    ?    ; offset of int 20h instruction
  17.                 ;   used to verify a PSP location
  18.  
  19.         org    100h
  20.  
  21. begin:        jmp    start    ; jump to program start location
  22.  
  23. ;-------------------------------------------------------------------------------
  24. ; This copyright message appears when SPY.COM is "typed" to the screen.
  25. ;-------------------------------------------------------------------------------
  26.  
  27.         db    8,8,8,'   '
  28. copyright    db    rt,lf,'SPY Copyright (C) 1987 by Charles Lazo III, v1.0'
  29.         db    eof,8,' ',rt,lf,'$'
  30.  
  31. key2        dw    1234h    ; keys used to determine prior load of SPY
  32. key3        dw    5678h
  33.  
  34. oldint8             dd    ?    ; double word storage for old int 8 vector
  35. beeps        dw    0    ; number of beeps (notices) to send to user
  36. delay        dw    1    ; number of clock ticks 'til next beep
  37. beep_on        db    0    ; beep on/off status
  38. spy_size    dw    ?    ; number of bytes to spy on
  39. resident    db    0    ; indicates prior load of SPY (0 = none)
  40.  
  41. spy_location    label    dword
  42. spy_off        dw    ?    ; storage for value of offset for SPYing
  43. spy_seg        dw    ?    ; storage for value of segment for SPYing
  44.  
  45. ;-------------------------------------------------------------------------------
  46. ; Comparisons of the spied region and the spy buffer (set up initially as a copy
  47. ; of the spied region) are made in this addition to the timer interrupt.
  48. ; Changes to the spied region are counted and the spy buffer is updated.  The
  49. ; speaker is turned on and off here, but frequency is set during program
  50. ; initialization.
  51. ;-------------------------------------------------------------------------------
  52.  
  53. newint8        proc    near
  54.         push    ax        ; save interrupted program's registers
  55.         push    bx
  56.         push    cx
  57.         push    si
  58.         push    di
  59.         push    ds
  60.         push    es
  61.  
  62.         mov    ax,cs        ; our data lies here
  63.         mov    ds,ax
  64.  
  65.         lea    si,spy_buffer    ; point to our buffer
  66.         les    di,spy_location    ; point to spied region
  67.         mov    cx,spy_size    ; compare whole region
  68.         cld            ; forward!
  69. cmp_more:    repz    cmpsb        ; compare until no match or cx = 0
  70.         jz    cmp_done    ; if zero, then cx = 0 and we're done
  71.         inc    beeps        ; account for a change
  72.         mov    al,es:[di-1]    ; change accounted; update spy_buffer
  73.         mov    [si-1],al
  74.         or    cx,cx        ; set zero flag by cx (avoid inf loop)
  75.         jmp    short cmp_more    ; continue 'til done
  76.  
  77. cmp_done:    cmp    beep_on,0    ; is the beep on?
  78.         jz    do_beep?    ; no, shall we do a beep?
  79.         dec    beep_on        ; yes, turn it off
  80.         in    al,97        ; get speaker control bits
  81.         and    al,0fch        ; set them off
  82.         out    97,al        ; turn off speaker
  83.         jmp    short exit    ; job done; get out
  84. do_beep?:    cmp    beeps,0        ; are there beeps to be done?
  85.         jz    delay1        ; no, get out
  86.         dec    delay        ; reduce delay 'til next beep
  87.         jnz    exit        ; not zero, then exit
  88.         in    al,97        ; get speaker control bits
  89.         or    al,3        ; set them on
  90.         out    97,al        ; turn on speaker
  91.         inc    beep_on        ; signal beep is on
  92.         mov    delay,beep_delay; reinitialize delay counter
  93.         dec    beeps        ; one less beep to do
  94.         jmp    short exit    ; leave now
  95. delay1:        mov    delay,1        ; don't wait for first beep of a series
  96. exit:        pop    es        ; restore registers
  97.         pop    ds
  98.         pop    di
  99.         pop    si
  100.         pop    cx
  101.         pop    bx
  102.         pop    ax
  103.         jmp    dword ptr cs:oldint8    ; continue with interrupt
  104. newint8        endp
  105.  
  106. ;-------------------------------------------------------------------------------
  107. ; Here the region spied upon is copied to an area of the TSR that remains in
  108. ; memory after termination, the spy_buffer.  The es register is equal either to
  109. ; cs if SPY has not yet been loaded or to the value of cs when SPY was loaded
  110. ; previously (accomplished by a call to the set_es routine).
  111. ;-------------------------------------------------------------------------------
  112.  
  113. copy_spied:    lea    di,spy_buffer    ; destination of copy
  114.         mov    si,spy_off    ; the offset is source of copy
  115.         mov    cx,spy_size    ; number of bytes to copy
  116.         mov    ax,spy_seg    ; load segment of SPY region to ds
  117.         push    ds        ; SOD (save our data)
  118.         mov    ds,ax
  119.         cld            ; forward copy
  120.         rep    movsb        ; copy the SPY region to spy_buffer
  121.         pop    ds        ; RestoreOD
  122.  
  123.         cmp    resident,0    ; is SPY currently resident in memory?
  124.         je    tsr        ; no, make it so
  125.         mov    ax,4c00h    ; yes, end with error code 0
  126.         int    21h
  127.  
  128. ;-------------------------------------------------------------------------------
  129. ; SPY has not yet been loaded into memory, so we do it now.  First the 8253-5
  130. ; chip that generates the frequency of the beeps is initialized with the value
  131. ; given by the constant timer_count.  Then the new interrupt 8 routine is
  132. ; spliced in and finally the constant max_size is used to reserve enough memory
  133. ; for the largest permissible spy buffer.
  134. ;-------------------------------------------------------------------------------
  135.  
  136. tsr:        mov    delay,beep_delay; initialize delay counter
  137.  
  138.         ; set 8253-5 programmable timer to chosen frequency
  139.         mov    al,182        ; byte to initialize 8253 timer
  140.         out    67,al        ; tell timer next two bytes are count
  141.         mov    ax,timer_count    ; get timer count
  142.         out    66,al        ; output low byte
  143.         mov    al,ah
  144.         out    66,al        ; output high byte
  145.  
  146.         mov    ax,3508h    ; get the interrupt 8 (clock) vector
  147.         int    21h        ;   with DOS function 35h call
  148.  
  149. ; Retain offset and segment of interrupt 8 vector:
  150.  
  151.         mov    word ptr cs:oldint8,bx
  152.         mov    word ptr cs:oldint8+2,es
  153.  
  154.         lea    dx,newint8    ; place offset in dx
  155.         mov    ax,2508h    ; set its pointer into interrupt table
  156.         int    21h        ;   with DOS function 25h call
  157.  
  158.         lea    dx,spy_buffer    ; where SPY buffer begins
  159.         mov    cx,max_size    ; add the maximum size of the buffer:
  160.         add    dx,cx
  161.         mov    cl,4        ; compute number of paragraphs to save:
  162.         shr    dx,cl        ;   bytes to paragraphs in dx
  163.         inc    dx        ;   insure sufficient size for buffer
  164.         mov    ax,3100h    ; terminate but stay resident code = 0
  165.         int    21h
  166.  
  167. ;-------------------------------------------------------------------------------
  168. ; The following is initialization code and data that is overwritten by the data
  169. ; copied to the spy buffer when this buffer is initialized with a copy of the
  170. ; spied region.
  171. ;-------------------------------------------------------------------------------
  172.  
  173. spy_buffer:    ; this is where SPY will store a copy of the SPY region
  174.         ;   to later check for any changes to the region
  175.  
  176. syntax        db    rt,lf,'SPY syntax:  SPY xxxx:yyyy L zzz',rt,lf,rt,lf
  177.         db    'Where xxxx, and yyyy are hexadecimal numbers up to '
  178.         db    'four digits in length and',rt,lf
  179.         db    'zzz is a one to three digit hexadecimal number.  SPY '
  180.         db    'will monitor the segment-',rt,lf
  181.         db    'offset region xxxx:yyyy for a length of zzz bytes and '
  182.         db    'report to the user with a',rt,lf
  183.         db    'number of beeps equal to the number of bytes changed '
  184.         db    'in that region if and when',rt,lf
  185.         db    'any are changed.',rt,lf,'$'
  186.  
  187. progress    db    0    ; flags for progress of command line conversion
  188.  
  189. ;-------------------------------------------------------------------------------
  190. ; This routine will convert an ASCII hex digit in al (either upper or lower case
  191. ; alpha hex) into a 1-of-16 binary value in al.
  192. ;-------------------------------------------------------------------------------
  193.  
  194. make_binary    proc    near        ; hex ASCII digit in al to binary in al
  195.         cmp    al,'0'        ; less than "0", then not hex digit
  196.         jb    not_digit
  197.         cmp    al,'f'        ; greater than "f", then not hex digit
  198.         ja    not_digit
  199.         cmp    al,'9'        ; test for numeric digit
  200.         ja    not_numeric    ; not a numeric digit
  201.         sub    al,'0'        ; convert to binary
  202.         ret
  203. not_numeric:    cmp    al,'F'        ; over "F"?
  204.         ja    low_case    ; yes, test for lower case
  205.         cmp    al,'A'        ; less than "A"?
  206.         jb    not_digit    ; yes, not hex digit
  207.         sub    al,37h        ; convert to binary
  208.         ret
  209. low_case:    cmp    al,'a'        ; less than "a"?
  210.         jb    not_digit    ; yes, not hex digit
  211.         sub    al,57h        ; convert to binary
  212.         ret
  213. not_digit:    stc            ; set carry flag if not hex digit
  214.         ret
  215. make_binary    endp
  216.  
  217. ;-------------------------------------------------------------------------------
  218. ; This routine is called to allow the command line parse routines to ignore any
  219. ; space and tab characters on the command line that do not lie in hex numbers.
  220. ; If the return character at the end of the command line is encountered, then
  221. ; the carry flag is set; otherwise it is reset.
  222. ;-------------------------------------------------------------------------------
  223.  
  224. skip        proc    near        ; skip over spaces and tabs; signal
  225.                     ;   a RETURN with the carry flag
  226. more_skip:    cmp    al,' '        ; is it a space?
  227.         je    another        ; if so, get another
  228.         cmp    al,9        ; is it a tab?
  229.         je    another        ; if so, get another
  230.         cmp    al,rt        ; is it a RETURN?
  231.         je    a_rt        ; yes, set carry and return
  232.         clc            ; not one of these three so return
  233.         ret            ;   with carry clear
  234. another:    lodsb            ; get another character
  235.         jmp    short more_skip    ; and try again
  236. a_rt:        stc            ; return with carry set
  237.         ret
  238. skip        endp
  239.  
  240. ;-------------------------------------------------------------------------------
  241. ; Here we parse the command line, which by the conditions of proper syntax has
  242. ; the three hexadecimal values for segment, offset and byte size for the region
  243. ; which is to be spied.  The routine between  cnv_more:  and  cnv_error:  is run
  244. ; once each to decode segment, offset and size which are stored respectively in
  245. ; the variables spy_seg, spy_off, and spy_size unless a syntax error is found.
  246. ; The variable progress is used to keep track of which of these three numbers
  247. ; has just been decoded.  A semicolon can be used to preface comments at the end
  248. ; of the command line.
  249. ;-------------------------------------------------------------------------------
  250.  
  251. convert        proc    near        ; convert hex ASCII to binary in ax
  252.         mov    cx,16        ; for hex to binary conversion
  253. cnv_more:    xor    bx,bx        ; accumulate result here
  254.         xor    ah,ah        ; need this zero too
  255.         dec    si        ; move back to last character
  256. cycle:        lodsb            ; get possible ASCII hex digit
  257.         call    make_binary    ; if ASCII hex, then make binary in al
  258.         jc    test_seg    ; if carry set, then char not hex digit
  259.         xchg    ax,bx        ; accumulation in ax, last digit in bx
  260.         mul    cx        ; bump to next power
  261.         or    dx,dx        ; test for overflow
  262.         jnz    cnv_error    ; result can't be larger than fff0h
  263.         add    ax,bx        ; add in most recent digit
  264.         xchg    ax,bx        ; accumulation in bx, ah = 0
  265.         jmp    short cycle    ; continue conversion
  266. cnv_error:    pop    ax        ; remove return location (of call)
  267.         jmp    stax        ; display syntax and end
  268. test_seg:    test    progress,ok_seg    ; have we decoded the segment value?
  269.         jnz    test_off    ; yes, test offset
  270.         call    skip        ; skip over spaces and tabs
  271.         jc    cnv_error    ; carry flag set if RETURN was found
  272.         cmp    al,':'        ; syntax says must have colon here
  273.         jne    cnv_error
  274.         lodsb            ; get another
  275.         call    skip        ; skip over spaces and tabs
  276.         jc    cnv_error    ; carry flag set if RETURN was found
  277.         mov    spy_seg,bx    ; store value of segment for SPYing
  278.         or    progress,ok_seg    ; segment value is now decoded
  279.         jmp    short cnv_more    ; continue to convert offset and size
  280. test_off:    test    progress,ok_off    ; have we decoded the offset value?
  281.         jnz    test_size    ; yes, test size
  282.         call    skip        ; skip over spaces and tabs
  283.         jc    cnv_error    ; carry flag set if RETURN was found
  284.         and    al,0dfh        ; convert "L" or "l" to "L"
  285.         cmp    al,'L'        ; syntax says must have "l" or "L" here
  286.         jne    cnv_error
  287.         lodsb            ; get another
  288.         call    skip        ; skip over spaces and tabs
  289.         jc    cnv_error    ; carry flag set if return was found
  290.         mov    spy_off,bx    ; store value of offset for SPYing
  291.         or    progress,ok_off    ; offset value is now decoded
  292.         jmp    short cnv_more    ; continue to convert size
  293. test_size:    cmp    bx,max_size    ; size must not be over maximum
  294.         ja    cnv_error
  295.         call    skip        ; skip over spaces and tabs
  296.         jnc    comment        ; shall allow comments at cmd line end
  297. cnv_finished:    mov    spy_size,bx    ; store away size
  298.         ret
  299. comment:    cmp    al,';'        ; test for comment symbol
  300.         jne    cnv_error    ; not comment symbol, then error
  301.         jmp    short cnv_finished    ; all done
  302. convert        endp
  303.  
  304. ;-------------------------------------------------------------------------------
  305. ; This is the routine that contains the code that this program was designed to
  306. ; demonstrate.  It serves to detect if SPY has been loaded previously as a TSR.
  307. ; If it has, then the code segment at the time of the previous load will be put
  308. ; into es; if not, then es will return with the current value of cs.  The method
  309. ; used attempts to find the set of key values key1, key2, and key3 in the memory
  310. ; above the current PSP.  key1 is word cd20h which is the int 20h instruction
  311. ; found at offset 0 of every PSP.  If key1 matches, then key2 is tried and if it
  312. ; matches key3 is tried.  A triple match gives fair confidence that SPY has been
  313. ; run as a TSR once before.  It is even possible to gain further confidence or
  314. ; detect the presence of a different version of the same program by comparing
  315. ; a string in the returned es to a string in cs, say the copyright notice.
  316. ;-------------------------------------------------------------------------------
  317.  
  318. set_es        proc    near        ; es becomes cs of original SPY load
  319.         mov    cx,cs        ; initialize count register
  320.         dec    cx        ; start at the paragraph one above cs
  321. not_yet:    mov    es,cx        ; trial value for es
  322.         mov    ax,key1        ; have we a match for the first key?
  323.         cmp    ax,es:key1
  324.         je    test_2nd    ; yes, test the 2nd key
  325.         loop    not_yet        ; no, not yet
  326.         jmp    short none_found; no match for keys; no prior SPY load
  327. test_2nd:    mov    ax,key2        ; have we a match for the second key?
  328.         cmp    ax,es:key2
  329.         je    test_3rd    ; yes, test the 3rd key
  330.         loop    not_yet        ; no, not yet
  331.         jmp    short none_found; no match for keys; no prior SPY load
  332. test_3rd:    mov    ax,key3        ; have we a match for the third key?
  333.         cmp    ax,es:key3
  334.         je    match_found    ; yes, es now has cs of original load
  335.         loop    not_yet        ; no, not yet
  336.         jmp    short none_found; no match for keys; no prior SPY load
  337. none_found:    mov    ax,cs        ; no prior load of SPY; use this cs
  338.         mov    es,ax
  339.         ret
  340. match_found:    mov    resident,1    ; prior load; set resident flag
  341.         ret
  342. set_es        endp
  343.  
  344. ;-------------------------------------------------------------------------------
  345. ; Execution starts here.  The command line is decoded, new parameters are passed
  346. ; to the prior load if it exists, and the beeps variable is set to zero for a
  347. ; fresh start.  Execution is then passed to  copy_spied:  and other termination
  348. ; code that can not be overwritten by the copy process.
  349. ;-------------------------------------------------------------------------------
  350.  
  351. start:        lea    dx,copyright    ; display copyright
  352.         mov    ah,9
  353.         int    21h
  354.  
  355.         mov    bx,80h        ; get command line byte count
  356.         mov    al,[bx]
  357.         cmp    al,1
  358.         ja    parse        ; if command given, parse it
  359. stax:        lea    dx,syntax    ; display command syntax
  360.         mov    ah,9
  361.         int    21h
  362.         mov    ax,4c01h    ; and exit with error code 1
  363.         int    21h
  364.  
  365. parse:        mov    si,82h        ; address first usable character
  366.         lodsb
  367.         call    skip        ; skip over spaces and tabs
  368.         jc    stax        ; carry is set if RETURN was found
  369.         call    convert        ; convert and store hex values
  370.         call    set_es        ; set es to spy_buffer segment
  371.  
  372.         mov    ax,spy_seg    ; set SPY region to newly given values
  373.         mov    es:spy_seg,ax    ;   (this isn't necessary for first
  374.         mov    ax,spy_off    ;    time through, but it doesn't
  375.         mov    es:spy_off,ax    ;    hurt either.)
  376.         mov    ax,spy_size
  377.         mov    es:spy_size,ax
  378.  
  379.         xor    ax,ax        ; initialize beeps count
  380.         mov    es:beeps,ax
  381.  
  382.         jmp    copy_spied    ; copy that which is to be spied
  383.  
  384. code        ends
  385.         end    begin
  386.