Halloween Gremlins

This article describes a quick and easy application to play Halloween tricks on the PC.

clip_image001

Introduction

This article describes “Gremlin”, a quick and easy application that lets you play Halloween tricks. When your victim's computer is idle, Gremlin moves windows around on the screen, changes the focus window, moves your mouse, scrolls windows, and types nonsensical stuff. When there is background noise – like someone talking – it will shake the screen, even as your victim is typing away.

Deployment

Run it right away. You can download, copy theGremlin.exe executable and NAudio.dll to the victim's computer (say in c:\ directory), and then double click on the executable to run it.

Run it later. The other option is to copy the executable and dll files (or a shortcut to it) to the Startup folder on the victim's machine and watch the fun begin when they start up their machine in the morning!

If the computer you're using runs on Windows XP the path is:

C:\Documents and Settings\All Users\Start Menu\Programs\Startup

With Vista and Windows 7 the path looks like:

C:\Users\USERNAME\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup

Just remember to change USERNAME to the name of the user on your machine.

Commandline

Gremlin is compiled as a windows application, so it won't popup a terminal window if you double click on it, etc. But you can run it from the command line with flags:

-aggressive will make the gremlin's actions more obvious

-help will display the command line options

-name NAME is useful for testing. Gremlin will only use windows with this specific title or from this specific application. (Remember to drop the ".exe" from the application filename)

To stop the program, press CTRL+F2.

And now … the dodgy bits

The overall structure of the program is broken down into three kinds of functionality – actions, triggers and some interstitial glue:

Actions

  • The screen-shaker is a window that makes the monitor look like it is shaking. Sort of like a loose cable on the back of the monitor.
  • A random event might kick the windows around—either friction will slow them down, or...
  • Gremlin will type nonsensical messages from the keyboard. These messages are then sent from a virtual keyboard, or they:
  • Move the mouse around, or
  • Press the mouse buttons, or
  • Randomly switch the focus to another window

Triggers

  • An audio module listens for sounds that trigger the module that shakes your screen.
  • Otherwise, the software uses a p/invoke to GetLastInputInfo() and waits for the user to be idle for a minute or two. When it detects that the user is inactive, it randomly selects and carries out actions.

Other

  • A hidden window receives key press events. I tend to reuse this module a lot, as a way to stop experimental programs that may have made my machine unusable.

For fun, I'll describe a couple of these modules below.

Screen shaker

My favorite bit is the screen shaker. It grabs a picture of the screens, creates a window that spreads across them, and then moves that image back and forth a few pixels every 30ms or so, with a little bit of random rotation. (Faster computers, of course, get a better effect).

The screen shaker is special in four ways:

  • It is a top-level window – no other windows are allowed to go over it.
  • This top-level window never becomes the focus window (the window that gets the keyboard events).
  • Mouse button events (e.g. clicks and double-clicks) are passed through to the windows and desktop underneath. This gives the illusion that this is the "real" desktop shaking, by allowing a person to click on a button or text that passes the click thru to the real button or text.
  • It shakes each of the monitor's screens independently

Some background: to create a window that looks like the shaking screen, I used two classes. The first is ScrShake (in ScreenShake.cs), which derives from the second class UnfocusableForm.  I'll describe ScrShake first.

The screen shaking process requires five instance variables:

  • animTimer is a System.Windows.Forms.Timer used to force painting of a new frame on the screen.
  • bx, and by are how far the screen has shaken up or down, left or right.
  • angle is how much the screen has twisted during shaking.
  • screenBitmap is an array of bitmaps, one for each of the monitors.

This creates a window without a border or other trappings, then makes it the topmost window and sets a flag in the method variable ExStyle to ignore mouse clicks. More on this flag in a little while.

C#

public partial class ScrShake : UnfocusableForm
{
   public ScrShake(double ShakeCoef, double AngleCoef) : base(true)
   {
      this.SuspendLayout();
      … other setup code …
      // This is needed since we're over the whole display, and we don't
      // want the other areas to be blurry
      TransparencyKey =  BackColor = ForeColor = System.Drawing.Color.Fuchsia;
      DoubleBuffered = true;
      TopMost = true;
      FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;

      ClientSize = new System.Drawing.Size(300, 300);
      Name = "topimage";
      ResumeLayout(false);

      // This is need to pass mouse clicks thru to lower layers
      ExStyle |= (int) WS . EX_TRANSPARENT;

      … More code that will be described later…
   }
}


When the timer has done a given number of animations, it will call the Stop() method. This will stop the animation, clean it up, and hide the window:

C#

void Stop()
{
   animTimer . Stop();
   Hide();
   screenBitmap = null;
}

When the main loops that start the animated screen shaking process, it calls the Screens() method. This grabs an image of the screens, determines the shape of each monitor, and starts the animation for 10 frames.

C#

internal void Screens()
{
   if (Visible)
   {
      Stop();
      return ;
   }
   // Grab the screens
   screenBitmap = Program.GrabScreens();
   CountDown = 10;

   animTimer.Start();
   angle = 0.0f;
   … code to display the window and get shape of monitors (see below)…
}


The screen capture portion is in ScreenCapture.cs. The method GrabScreens() creates an individual bitmap for each monitor and returns them as an array.

C#

internal void Screens()
{
   if (Visible)
   {
      Stop();
      return ;
   }
   // Grab the screens
   screenBitmap = Program.GrabScreens();
   CountDown = 10;

   animTimer.Start();
   angle = 0.0f;
   … code to display the window and get shape of monitors (see below)…
}


The code below determines the bounds of each screen and builds up a size of all of the screens put together. The window will be set to be this size.

C#

Screen[] AllScreens = Screen.AllScreens;

// full width/height of all monitors combined
Rectangle fullSize = AllScreens[0].Bounds;

// find a rectangle that will encompass all monitors on the system
// (assuming the primary monitor is on the left/top!)
for (int i = 1; i < AllScreens.Length && i < screenBitmap.Length; i++)
{
    Rectangle Bounds = AllScreens[i].Bounds;

    if (Bounds.Left < fullSize.Left)
        fullSize.X = Bounds.X;

    if (Bounds.Right > fullSize.Right)
        fullSize.Width = Bounds.Right - fullSize.X;

    if (Bounds.Top < fullSize.Top)
        fullSize.Y = Bounds.Y;

    if (Bounds.Bottom > fullSize.Bottom)
        fullSize.Height = Bounds.Bottom - fullSize.Y;
}

The code to show the window, fill the whole screen, and move it to the top looks like:

C#

Show();
WindowState = FormWindowState.Normal;
// cover all monitors with one gigantic window
Location = new Point(fullSize.Left, fullSize.Top);
Size = new Size(fullSize.Width, fullSize.Height);

// bring it to the top
BringToFront();

The constructor also created a timer that drives the screen shaking effect. The timer has a delegate that randomly selects the angle of rotation and the offset of the image, and triggers a repaint of the window. (The amount of shaking is controlled by two external variables called AngleCoef and ShakeCoef).

C#

animTimer = new System.Windows.Forms.Timer();
animTimer.Tick += delegate(object A, EventArgs E)
{
    if (--CountDown < 1)
        Stop();

    angle += (float)((Program.Rnd.NextDouble() - 0.5) * AngleCoef);
    bx = (float)((Program.Rnd.NextDouble() - 0.5) * ShakeCoef);
    by = (float)((Program.Rnd.NextDouble() - 0.5) * ShakeCoef);
    Invalidate();
};

// Sets the timer interval to 30 milliseconds.
animTimer.Interval = 30;

Although each monitor shifts up & down, left & right by the same amount, and rotates by the same angle, they are painted independently. This gives the illusion that each monitor has a shaky image. Paint the window is using the following code.

C#

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);
    Graphics g = e.Graphics;
    g.CompositingQuality = CompositingQuality.HighQuality;

    // for each monitor, draw the effect
    Screen[] AllScreens = Screen.AllScreens;
    for(int i = 0; i < screenBitmap.Length; i++)
    {
        if (null == screenBitmap[i])   continue;
        g.SmoothingMode = SmoothingMode.HighQuality;

        // grab the size of the current monitor
        Rectangle region = AllScreens[i].Bounds;

        double ImWidth = screenBitmap[i].Width  * 
           e.Graphics.DpiX / screenBitmap[i].HorizontalResolution; double ImHeight= screenBitmap[i].Height *
           e.Graphics.DpiY / screenBitmap[i].VerticalResolution; Matrix m = new Matrix(); m.Translate( (float)(- ImWidth /2), (float)(- ImHeight /2), MatrixOrder.Append); // rotate the bitmap about the center m.RotateAt(angle, new Point(0,0), MatrixOrder.Append); // center the image no matter what its size is m.Translate( region.Width /2 - bx, region.Height/2 - by, MatrixOrder.Append); // assign our transformation matrix g.Transform = m; // draw it g.DrawImage(screenBitmap[i], region.Left, region.Top); }

The Form that does nothing!

The ScrShaker class uses a help class called UnfocusableForm (in UnfocusableForm.cs) to create a window that never becomes the focus window – it never receives key presses, etc.

This window has no trappings – no border, no resize gripper, no icon, no minimize / maximize buttons, no title bar.

C#

public partial class UnfocusableForm : Form
{
   public UnfocusableForm(bool X) : base()
   {
      if (X)
        {
           ControlBox = false;
           FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
           ShowInTaskbar = false;
           ShowIcon = false;
           MinimizeBox = false;
           SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
           StartPosition = System.Windows.Forms.FormStartPosition.Manual;
        }
   }

Then it overrides the ShowWithoutActivation method so that the window will not become the active when it is shown.

C#

protected override bool ShowWithoutActivation
{ get {  return true; } }

The UnfocusableForm class also overrides the CreateParams() method to set extra styles when creating the window. I haven't found a way to set these styles flexibly. Instead, the UnfocusableForm uses a method variable called ExStyle that allows derived classes to specify what flags they desire. In this case, The ScrShake class used the method variable to set a flag that ignore mouse clicks:

C#

protected override CreateParams CreateParams
{
  get
  {
     CreateParams cp=base.CreateParams;
     cp . ExStyle |= ExStyle;
     return cp;
  }
}


Finally, it captures a couple of events that ask a window if it would like to become the active window. (These usually happen when the user clicks on an inactive window):

C#

internal const int MA_NOACTIVATE = 0x0003;
protected override void WndProc(ref Message m)
{
  if (m.Msg == (int) WM.MOUSEACTIVATE)
  {
     m.Result = (IntPtr) MA_NOACTIVATE;
     return;
  }
  if (m.Msg == (int) WM.FOCUS)
  {
     m.Result = (IntPtr)1;
     return;
  }
  base.WndProc(ref m);
}

Sending Mouse Events

Sending Mouse Events is simple, but not trivial. The wiki at Pinvoke.net provides the signature to the procedures and structures we need to pass to it. (Note: these structures are a bit different, based on a blog posting by Raymond Chen)

C#

[DllImport("user32.dll", EntryPoint = "SendInput", SetLastError = true)]
static extern uint SendInput(uint nInputs, INPUT[] Inputs, int cbSize);
[DllImport("user32.dll", EntryPoint = "GetMessageExtraInfo", SetLastError = true)]
static extern IntPtr GetMessageExtraInfo();

[StructLayout(LayoutKind.Sequential)]
struct INPUT
{
   internal INPUTTYPE   type;
   internal INPUT_UNION i;
}

 // This generates the anonymous union
[StructLayout(LayoutKind.Explicit)]
struct INPUT_UNION
{
   [FieldOffset(0)]
   public MOUSEINPUT mi;
   [FieldOffset(0)]
   public KEYBDINPUT ki;
   [FieldOffset(0)]
   public HARDWAREINPUT hi;
};

[StructLayout(LayoutKind.Sequential)]
struct MOUSEINPUT
{
   public int    dx;
   public int    dy;
   public int    mouseData;
   public MOUSEEVENTF dwFlags;
   public int    time;
   public IntPtr dwExtraInfo;
}

[Flags]
enum MOUSEEVENTF : int
{
   MOVE       = 0x01,
   LEFTDOWN   = 0x02,
   LEFTUP     = 0x04,
   RIGHTDOWN  = 0x08,
   RIGHTUP    = 0x10,
   MIDDLEDOWN = 0x20,
   MIDDLEUP   = 0x40,
   ABSOLUTE   = 0x8000
}


Each of these pieces go together in a specific way. To do a mouse movement, a mouse event structure needs to be created. This involves setting dwFlags to the kind of mouse event (a relative movement in this case), dx and dy to the number of pixels moved. It is also important to set dwExtraInfo to whatever GetMessageExtraInfo() is set to.

C#

MOUSEINPUT MEvent = new MOUSEINPUT();
MEvent.dwFlags = MOUSEEVENTF.MOVE;
MEvent.dx = Rnd . Next(-8, 8) ;
MEvent.dy = Rnd . Next(-8, 8);
MEvent.dwExtraInfo = GetMessageExtraInfo();
Send(MEvent);

Sending the event takes a few more steps that are all wrapped in a helper methdo called Send(). Send these human interface device events via the SendInput() procedure (earlier). The procedure takes an array of events, for different kinds of devices. We have to create the array, set the event type, copy the event data, and then make the call:

C#

public virtual bool Send(MOUSEINPUT Event)
{
  INPUT[] Events = new INPUT[1];
  Events[0] . type = INPUTTYPE . MOUSE;
  Events[0] . i.mi = MEvent;
  return SendInput((uint)Events.Length, Events, Marshal.SizeOf(Events[0])) > 0; 
}


From here, sending a mouse button click is pretty straight forward. A mouse click is really a mouse button press event, followed by a mouse button release event. To make things interesting the mouse button is choosen at random. The “ugly” part is that each of the mouse buttons is assigned a bit, so a binary shift is used to convert a button number to its bit. And the button release is yet another bit, so the second message shifts the flags, to move the bit from the “button pressed” state to the “button released state”.

C#

MOUSEINPUT MEvent = new MOUSEINPUT();
MEvent.dwFlags = (MOUSEEVENTF) (1 << (2*Rnd.Next(0, 3)+1)) ;
MEvent.dwExtraInfo = GetMessageExtraInfo ();
Send(MEvent);

MEvent.dwFlags = (MOUSEEVENTF)((int) MEvent.dwFlags << 1);
MEvent.dwExtraInfo = GetMessageExtraInfo ();
Send(MEvent);


Generating deranged text

The gremlin can also type deranged sentences that will appear in editors, if the user left one open. The SendWait() method in the SendKeys class does the typing itself:

C# 

SendKeys . SendWait(GenerateSentence());
SendKeys . SendWait("{ENTER}");

clip_image001[6]

Generating the sentences is not difficult; I used a simplistic Markov generator. This generator starts by randomly selecting a word that can start a sentence. The Starts variable is array which holds just these words. Then, in the Transition method, this word is used to find the next word that can be included in the sentence. It does this by using a dictionary, called NonStart, which given the word as a key, will return a list of all the words that can come after it. This process then repeats, appending the words onto the end of a string. It stops if it finds a word that can end a sentence.

C#

static Dictionary<string,string[]> NonStart ;
static string[] Starts;
static Dictionary<string,string> Terminal ;

static string GenerateSentence()
{
  StringBuilder SB = new StringBuilder();
  string Word = Starts[ Rnd.Next(0, Starts.Length) ];

  Transition(SB, Word);
  return SB.ToString();
}

static void Transition(StringBuilder SB, string Word)
{
  while (true)
  {
     SB.Append(Word);
     SB.Append(' ');

     // Look up word after this
     string[] Nexts;
     if (!NonStart.TryGetValue(Word, out Nexts))
       break;
     int Idx = Rnd.Next(Terminal . ContainsKey(Word) ? -1 :0, Nexts.Length);
     if (Idx < 0)
       break;
     Word = Nexts[Idx];
  }
}


Building these two dictionaries and array is a pretty simple process. The BuildSuffixTree() method takes a string and splits it up into sentences. Then it splits each sentence into (lower case) words. The first word of the sentence goes onto the end of the Starts array. Otherwise, the previous word is used to look up a list in a dictionary, and the current word is appended on to the list. This dictionary will become the NonStarts dictionary. The last word of the sentence is also placed into the Terminal dictionary, to indicate that this might be the end of a sentence.

C#

static void BuildSuffixTree()
{
  // First, build up a list of words that start sentence, and transitions
  List<string> Starts1 = new List<string>();
  Dictionary<string,List<string>> Trans = new Dictionary<string,List<string>>();
  foreach(string S1 in S.Split(new char[]{'.','?','!'}))
  {
     string Prev=null;
     foreach(string S2 in S1.Split(new char[]{' ','\n','\r','\t',',',';'}))
     {
        if (S2 . Length < 1)
          continue;
        if (null == Prev)
          {
             Starts1.Add(string.Intern(S2.ToLower()));
             Prev = string.Intern(S2.ToLower());
             continue;
          }
        List<string> Nextsa;
        if (! Trans.TryGetValue(Prev, out Nextsa))
          Trans[Prev] = Nextsa = new List<string>();
        Prev = string.Intern(S2.ToLower());
        Nextsa.Add(Prev);
     }
     if (null != Prev)
       Terminal[Prev] = Prev;
 }

 // Next, flatten the list of words that start a sentence
 Starts = Starts1.ToArray();

 // Flatten the transition table
 foreach (string S3 in Trans.Keys)
  NonStart[S3] = Trans [S3].ToArray();
}


The things that trigger action

The audio trigger

The audio module (in file AudioTrigger.cs) listens in on all of the microphones. It uses NAudio, with a basic setup and delegate structure swiped from Mark Heath's article “.NET Audio Recording”. The first difference is that it registers all audio input devices:

C#

static WaveIn[] StartMics()
{
  int NumDevices = WaveIn.DeviceCount;
  WaveIn[] AudIns = new WaveIn[NumDevices];
  for (int waveInDevice = 0; waveInDevice < NumDevices ; waveInDevice++)
  {
     AudIns[waveInDevice] = new WaveIn();
     AudIns[waveInDevice].DeviceNumber = waveInDevice;
     AudIns[waveInDevice].DataAvailable += waveIn_DataAvailable;
     AudIns[waveInDevice].WaveFormat = new WaveFormat(8000, 1);
     AudIns[waveInDevice].StartRecording();
  }
  return AudIns;
}

The real magic in the trigger is a modified version of the waveIn_DataAvailable delegate. Instead of saving the audio, it checks for any sound activity. It starts by checking to see if any of the sound amplitudes are greater than a pre-defined, very high threshold. Then the samples are squared and summed up, and the result is compared with a threshold. If it exceeds the threshold, the trigger is set. These two are good at catching the kind of sound made when a person is talking, futzing on the desk, or typing.

clip_image002

C#

static double AudioThresh  = 0.8;
static double AudioThresh2 = 0.09;

static void waveIn_DataAvailable(object sender, WaveInEventArgs e)
{
  bool Tr = false;
  double Sum2  = 0;
  int Count = e.BytesRecorded / 2;
  for (int index = 0; index < e.BytesRecorded; index += 2)
  {
     double Tmp = (short)((e.Buffer[index + 1] << 8) | e.Buffer[index + 0]);
     Tmp /= 32768.0;
     Sum2 += Tmp*Tmp;
     if (Tmp > AudioThresh)
       Tr = true;
  }
  Sum2 /= Count;

  // If the Mean-Square is greater than a threshold, set a flag to indicate that noise has happened
  if (Tr || Sum2 > AudioThresh2)
    Interlocked.Exchange(ref AudioTrigger, 1);
}


This sets a flag – AudioTrigger – which will be seen (and reset) in the main loop, with a bit of code that looks like:

C#

while (0 == Shutdown)
{
    // Do some lovely events
    Application . DoEvents();
    Thread . Sleep (20);

    //… do some other stuff ..

    // Check for a kick from the sound system
    if (0 != AudioTrigger)
    {
        Interlocked . Exchange(ref AudioTrigger, 0);
        …
        ScreenShaker . Screens();
        continue;
    }
    //… more checks for the user idle trigger…
}

Waiting for the user to be idle

The check to see if the user is not doing anything, the main loop uses a helper method called LastInputTime(), which returns the number of milliseconds the user did any input activity. The loop ensures that the user has been idle for long enough, and then calls the method that selects random gremlin actions:

C#

uint LastTime = Win32.LastInputTime();
if ((uint) Environment.TickCount < IdleTimeTrigger + LastTime)
    continue;

The LastInputTime() helper method uses a p/invoke call to the GetLastInputInfo() API call. The wiki at Pinvoke.net provides the signature to the procedure, and a suitable structure that we need to pass to it:

C#

[DllImport("User32.dll")]
static extern bool GetLastInputInfo(ref LASTINPUTINFO LastInfo);

[StructLayout(LayoutKind.Sequential)]
struct LASTINPUTINFO
{
  public uint cbSize;

  /// <summary>
  /// Number of system tickes
  /// </summary>
  public uint dwTime;
}

Then, these two structures are wrapped up into the LastInputTime() helper procedure, which does the dirty work of allocating and initializing a structure.

C#

internal static uint LastInputTime()
{
  LASTINPUTINFO lastInput=new LASTINPUTINFO();
  lastInput.cbSize = (uint)Marshal.SizeOf(lastInput);
  GetLastInputInfo(ref lastInput);
  return lastInput . dwTime;
}

Conclusion

The tricks gremlin plays are intended to be somewhat subtle. There is an aggressive option to make it react more, and move windows around more visibly.

If you want to try this out, the download link for the executable and source code are at the top of the article!

Resources and References

This article is a blatant grab bag of experimental and reused code from earlier experiments and other demo programs. Below are some of the projects I lifted code examples from:

About The Author

Randall Maas writes firmware for medical devices, and consults in embedded software. Before that he did a lot of other things… like everyone else in the software industry. You can contact him at randym@acm.org.

Tags:

Follow the Discussion

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.