Let’s put away the serious stuff for a while and let’s have some fun. What about some hacking pranks!. Let’s start with something simple, the so called nervous mouse.
Note: The code is a modification of some example from internet. I cannot recall where I got it, but it is, let’s say, the default example you will find when searching for uinput tutorials.
Nervous Mouse
Nervous Mouse is a simple program that abuses the uinput
device to inject fake mouse events in a linux box and move the mouse randomly every five seconds. It is a pretty stupid prank program but a funny way to get introduced to this useful device.
The uinput
device is pretty straightforward to use.
- Configure the events we want to generate
- Create a device for that configuration
- Write events to the device
Let’s see how to write your own
Opening and Configuring the Device
This part of the program is quite standard, we open the /dev/uinput
device, execute a bunch of ioctl
syscalls to configure it and we are good to go.
Something like this:
if ((fd = open ("/dev/uinput", O_WRONLY | O_NONBLOCK)) < 0) die ("error: open");
/* And we also want to produce mouse events */
if (ioctl (fd, UI_SET_EVBIT, EV_REL) < 0) die ("error: ioctl");
if (ioctl (fd, UI_SET_RELBIT, REL_X) < 0) die ("error: ioctl");
if (ioctl (fd, UI_SET_RELBIT, REL_Y) < 0) die ("error: ioctl");
/* Time to register our virtual device */
memset (&uidev, 0, sizeof(uidev));
snprintf (uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-sample");
uidev.id.bustype = BUS_USB;
uidev.id.vendor = 0x1;
uidev.id.product = 0x1;
uidev.id.version = 1;
if (write (fd, &uidev, sizeof(uidev)) < 0) die ("error: write");
if (ioctl (fd, UI_DEV_CREATE) < 0) die ("error: ioctl");
The first part of the program opens the uinput
device and then configures the events we want to inject. In this case we are using EV_REL
to inject mouse movement events.
After that we have to create the device. We are kind of defining a USB mouse and as for any USB device we have to provide vendor and user ides as well as a version number. Basically just enter the values in the code to get it running. Honestly I haven’t when deep enough on this to be able to tell you the importance of these values.
The we write the struct into our uinput
device and call UI_DEV_CREATE
ioctrl to create our virtual input device.
Now we just have to inject our events
Moving the Mouse
In order to move the mouse, the main function of Nervous Mouse, we have to inject EV_REL
events. This events represent a relative movement of a pointing device. So, let’s write a function to move our mouse:
int
move_mouse (int fd, int dx, int dy)
{
struct input_event ev;
memset (&ev, 0, sizeof(struct input_event));
ev.type = EV_REL;
ev.code = REL_X;
ev.value = dx;
if (write (fd, &ev, sizeof(struct input_event)) < 0) die ("error: write");
memset (&ev, 0, sizeof(struct input_event));
ev.type = EV_REL;
ev.code = REL_Y;
ev.value = dy;
if (write (fd, &ev, sizeof(struct input_event)) < 0) die("error: write");
memset (&ev, 0, sizeof(struct input_event));
ev.type = EV_SYN;
ev.code = 0;
ev.value = 0;
if(write(fd, &ev, sizeof(struct input_event)) < 0) die("error: write");
usleep(15000);
return 0;
}
I think you can figure out how does this work, just looking to the code, but in case you don’t.
Well, events are sent to the system writing into our uinput
device an event structure. The event structure has the following fields:
-
type
. Indicates the type of event. EV_REL (relative movement), EV_KEY (key press including mouse buttons), EV_SYN (the synchronization event),… -
code
. Each kind of event supports multiple codes. For instance, for theEV_REL
event (that we are using) we have a code to move the mouse on the X coordinate (REL_X
) and another event to move it in the Y coordinateREL_Y
. -
value
. Some codes, requires a value. For ourEV_REL
event, the value will indicate the numbers of pixels to move in the direction indicated by thecode
field
So, the function above, takes two values dx
and dy
and use them to move the mouse cursor dx
pixel in the X coordinate and dy
pixels in the Y coordinate. Some events, to be interpreted correctly, requires us to send an extra event of type EV_SYNC
.
Nervous Mouse
By now, you should already be able to figure out how to make your mouse look nervous… I guess so. But otherwise, this is a way of doing it.
while (1)
{
for (i = 0; i < 100; i++)
{
move_mouse (fd, rand() % 10 -5 , rand()%10 - 5);
}
sleep (5);
}
Sure, every 5 seconds the mouse moves a maximum of 5 pixels away from its last position in each direction 100 hundred times.
Not just a Prank
Now, seriously. I have used this technique in the past to easily interface special devices to standard applications in an easy way. An example was a small keyboard composed of two buttons, connected to two RPi GPIOs, used to interact with some kiosk application.
A small program in the Rpi read the GPIO pins, and produced uinput
events. The main application just have to read the keyboard. This technique will allow us to control standard programs using special devices in a very easy way…
You can get the whole code from my github, as usual. The code in github also includes a click after the mouse movement so you may get windows or menus activated in unexpected ways.
The program has to be executed as root, by the way.
Hack fun!