Introduction
Overview
This example demonstrates how to use a UDP client, and a UDP server. The example is a useful application which can be used to spread fun around many corporate environments. However be sure to use it with care. Havoc has been known to ensue when used inappropriately.
The example is named "Remote BSOD Invocator", or simply RBSOD for short. RBSOD can be used to trigger fake BSODs on your colleagues (or enemies) computers. The BSODs that are triggered are not real, and will not cause the person to lose any data. However they give them a startle. The BSODs can also be cleared remotely.
Note
- This example uses the open source Indy library for its UDP client and server. Indy can be obtained freely at The Indy Project
- I�ve not had time to translate the server into C# or VB yet. I will update the article later, until then I�ve provided a precompiled executable for the server as well as the original source.
Applications
RBSOD consists of two programs. The server which is to be run on the remote machine, and the client which is used to control and trigger the BSODs. The client is available for C#, Delphi, and Visual Basic. The server currently is only available in Delphi, but precompiled Win32 versions of both client and server are provided as well.
Many options are provided. Depending on the options that are selected, the BSOD can be made to appear quite authentic, or it can be made to appear as a joke. However when they are made to appear as a joke it will take the user a few seconds to understand this and provide them with an initial startle.
Usage
The following options are provided:
IP Address
Specifies the IP address or host name of the computer that you wish to trigger the BSOD. The server must be installed and running on the remote computer.
If this field is left empty, the message will be broadcast across the local subnet (in most cases your local LAN) and all computers which have the server installed and running will display the BSOD.
Message
Message is the error message that will be displayed to the user in the BSOD screen. The default message is:
A fatal exception OE has occurred at 0028:C0011E36 in VXD VMM(01)00010E36.
The current application will be terminated.
This text was taken from a real BSOD, and will appear quite real to the user.
Many Japanese Haiku's (A special form of a Japanese poem) are also included for fun. There are many very funny ones to choose from. Here two of my favorites:
- Windows crashed again. I am the Blue Screen of Death. No one hears your screams.
- Three things are certain: Death, taxes, and lost data. Guess which has occurred.
Imagine the look on your colleagues faces after they realize they have been fooled. Be very careful when you perform this prank on Dilbert type bosses or Visual Basic programmers however. They may not realize that it is a prank.
These messages are contained in messages.dat, and you can add your own as well.
Use a custom message
If this option is checked, another text box will appear and you can enter a custom message. This option is useful for providing interactive or relevant BSOD messages. For example if your boss is wearing an unusually tacky suit one day you might trigger this message:
Ugly brown suit error. I cannot continue in such company.
Show any key
This option can be used to give additional humor to the prank. The BSOD will initially prompt the user with "Press any key to continue _". This is the same as a normal BSOD. However if this option is checked, after they press a key it will then further prompt them with flashing text "Not that key, press the ANY key!"
This option is sure to keep Dilbert bosses busy for hours hunting for the Any key. This option is best used just prior to leaving for the airport on a long business trip, or when you need to keep them busy for a while.
Show trademark
If this option is used, in the bottom corner of the screen the following text will be displayed in small but readable text:
* The BSOD is a trademark of the Microsoft Corporation.
Show
The show button will trigger the BSOD on the remote computers.
Clear
Clear can be used to remotely clear the triggered BSODs. Normally you will let the end user clear their own BSOD, but in some cases you may wish to clear it remotely.
Client
The RBSOD client is even simpler than the server. The RBSOD client consists of one form: Main.pas. Main.pas contains several events but most of them are related to the user interface and should be self explanatory.
The relevant Indy code in the RBSOD client is this excerpt which is taken from the OnClick
of the Show button.
C#
private void SendMsg(string aMsg) {
using (UDPClient xClient = new UDPClient()) {
xClient.Host = textHost.Text.Trim();
xClient.Port = 6001;
xClient.Send(aMsg);
}
}
Delphi
IdUDPClient1.Host := editHost.Text;
IdUDPClient1.Send(s);
Visual Basic
Private Sub SendMsg(ByVal aMsg As String)
Dim xClient As UDPClient = New UDPClient
xClient.Host = textHost.Text.Trim()
xClient.Port = 6001
xClient.Send(aMsg)
End Sub
The first line sets the host that the UDP packet will be sent. In Delphi, the port has already been set at design time using the property inspector and matches that of the server with the value of 6001. For C# and Visual Basic the port is set in code because the client is created in code also.
The next line uses the Send
method to send the UDP packet. Since UDP is connectionless, any data must either be sent as multiple packets, or packaged into a single packet. If multiple packets are sent, it is the developers responsibility to coordinate and reassemble them. This is not as trivial a task as it appears, so unless you are sending large amounts of data it is much easier to assemble the data into a single packet.
The argument passed to send will be immediately sent as a UDP packet and thus when it is called, all data that you want to be sent must be passed in a single call.
Indy also contains an overloaded SendBuffer
method to send data using buffers. In the case of RBSOD the protocol simply consists of two characters that specify options to show the trademark, and show any key, followed by the actual message to display.
The only other Indy code in the RBSOD client is in the OnClick
for the Clear button and it is nearly identical to the previous excerpt.
Server
Let's take a look at the server first.
Installation
The server is named svchost instead of RBSODServer or some other sensible name. This is so because you can install it easily on other computers while hiding it. svchost is a normal Windows executable of which normally multiple copies are executed. If you look in task manager now, you are likely to see four entries for this executable. Since you will put this special version in its own directory, it will not interfere with the Windows one, but will appear the same as the normal when viewed in task manager.
The server does not have any windows and will not appear in the system tray or task tray. If you want to stop it, use the task manager and select the svchost that is running as the logged on user. The system svchosts will be running as System. When you have selected your version, you can use END TASK.
For most installations simply copy the compiled version of the server to the target computer and run it. It will stay in memory until the user restarts their computer. After they restart, the program will not reload. If you want the program to automatically reload you can add it to the users start up group or use registry entries for a stealthier start.
Source code
The server consists of two units, Server.pas and BSOD.pas. BSOD.pas contains a form that is used to display the BSOD screen. BSOD.pas does not contain any Indy code and thus will not be covered here.
Server.pas is the main application form and contains a single UDP server. The port property has been set to 6001 and the active property has been set to True
. When the application runs, it will immediately begin listening on port 6001 for incoming UDP packets.
As discussed previously UDP is similar to a pager. Because of this there are no connections required to receive data. Data packets simply arrive as one piece. For each UDP packet that is received, the UDP server will fire the OnUDPRead
event. No other events are needed to implement a UDP server. When the OnUDPRead
event is fired, the complete packet would have been received and is now available for use.
The OnUDPRead
event passes in three arguments:
ASender: TObject
- This is the component which fired this event. This is only useful for multiple UDPServers that have been created and are sharing a single method as an event. This is rarely used or needed.
AData: TStream
- This is the main argument and it contains the packet. UDP packets can contain text and/or binary data. Because of this Indy represents them as a stream. To access the data, simply use the read methods of the TStream
class.
ABinding: TIdSocketHandle
- This is useful for advanced options to retrieve information about the binding that was used to receive the packet. This is only useful if you have created bindings.
Here is what the OnUDPRead
event looks like for the RBSOD server:
procedure TformMain.IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
var
LMsg: string;
begin
if AData.Size = 0 then begin
formBSOD.Hide;
end else begin
// Move from stream into a string
SetLength(LMsg, AData.Size);
AData.ReadBuffer(LMsg[1], Length(LMsg));
//
formBSOD.ShowBSOD(Copy(LMsg, 3, MaxInt)
, Copy(LMsg, 1, 1) = 'T'
, Copy(LMsg, 2, 1) = 'T');
end;
end;
Notice that there is an if
statement that checks to see if the size is 0. It is legal to send and receive empty UDP packets. In this case it is used to signal the server to clear the BSOD.
If the size is not 0, the data is read into a local string using TStream.ReadBuffer
.
The UDP server does not use an individual thread for each packet, so OnUDPRead
events occur sequentially. By default OnUDPRead
is fired in the main thread so forms and other GUI controls can be accessed safely.