When a programmer wants to start programming using Windows Forms he is usually lost in a sea of his own unanswered questions.
In C# the leap is quite small when compared to, say, C++, but it can still be challenging for a knowledge-seeker to find answers for all his enquiries...
This article is aimed at those, who are quite familiar with basic programming procedures, but need a little help with understanding everything windows programing has to offer.
I will try to explain the basic idea behind window's messages with a interesting example where messages are essential to the process: a password finder.
This basic password finder will work on the brute force principle - it will try every combination until it finds the right password. Windows works because of it's message system, and even if C# try's to protect the programmer from all the hard work which is needed for proper understanding of the system, there are situations when one has to do at least some of the "dirty work".
This article shows one of such problems, where we want our application to "write" in other application's entry field and then "click" the confirm button. In order to do this, we need to find out the controls handle so we can send the message to it.
And here is where the fun starts, since all the low level message sending functions are hidden deep in the core of C#, and in order to use them directly we need to load them from a dll - "User32.dll" to be exact. We do this with the help of "DllImport", for which we need to use System.Runtime.InteropServices.
The code for loading the needed functions is:
using System.Runtime.InteropServices;
[DllImport("user32.dll", SetLastError = true)]
private static extern int SendMessage(int hWnd, uint Msg, int wParam, string lParam);
[DllImport("User32.dll")]
private static extern int WindowFromPoint(Point p);
Note that we will later use GetLastError function in combination with SendMessage function, which is why it needs to be enabled in the loading call.
Now we have the basic functions we will need, we just need an application to use them in.
For the purpose of this article I designed a C# solution (you can download it from the link available at the end of this article) with two projects in it.
One will serve as an actual "password breaker", when the other one will be used as a window that requires a password. For the sake of keeping it simple I added two buttons on the password breaker form, which will be used to determine the handle of controls.
We can get the handle of the control pointed by mouse cursor by using function WindowFromPoint.
int WindowHandle = 0;
int ButtonHandle = 0;
WindowHandle = WindowFromPoint(MousePosition);
ButtonHandle = WindowFromPoint(MousePosition);
Now we get to the actual brute force algorithm.
Since we don't know what the password may be we can not assume its length or character type, so we will build our algorithm without any of those assumptions. Useful as this may be, it makes the algorithm even slower than it needs to be because we are testing each character in the password string with the whole ascii table.
We begin with the assumption that the password contains only one character and if we do not find it, we extend our length by one.
This will slowly work itself to the string of any length, but because of time consumption we limit the char array to 100. If needed this can easily be changed, however I doubt it will ever be needed.
char[] character = new char[100];
char from = (char)0;
char to = (char)128;
uint length = 0;
double try_no = 0;
DateTime begin_time = DateTime.Now;
TimeSpan time_took;
while (length < 100) {
character[0]++;
for (int i = 0; i <= length; i++) {
if (character[i] == to) {
character[i] = from;
character[i + 1]++;
if (i == length) {
length++;
break;
}
}
else break;
}
SendMessage(WindowHandle, 12, 0, new String(character));//12 = 0x000C
SendMessage(ButtonHandle, 245, 0, null); //245 = 0x00F5
try_no++;
if (Marshal.GetLastWin32Error() == 1400) {
time_took = DateTime.Now - begin_time;
textBox1.Text = "Password was found on: " + try_no.ToString() + " try. The search took: " + time_took.TotalSeconds.ToString() + " seconds, its length is: " + (length + 1).ToString();
return;
}
}
MessageBox.Show("Password is too long!");
The hart of this article is in these two lines:
SendMessage(WindowHandle, 12, 0, new String(character));//12 = 0x000C
SendMessage(ButtonHandle, 245, 0, null); //245 = 0x00F5
After calculating our (next) guess, we send it to the targer program using function called SendMessage.
First argument is the handle, which we found by using WindowFromPoint function.
The second it the value we are sending. Usually theese values are saved in integers named similar to WM_SETTEXT, however we need to send the actuall value and it doesn't need to be not saved nor in hex format.
12 or 0x000C is the Set Text value, which tells the control that the last argument will be its new text.
245 or 0x00F5 is the On Click value, which makes the control to behave as it would if it were actually clicked.
After sending those messages we need to know if our guess was correct. Now there is no guarantee that this will work in the target application, however it is reasonoble to assume that when the correct password will be entered, that form will close and the handle won't be valid any more.
That would lead to an error, which we can recognize with the GetLastError function, which is found in the form of:
Marshal.GetLastWin32Error().
It returns a viriety of values and 1400 is the one indicating that the handle is no longer valid. At this point our algorythm should stop working since we have either succeded or failed. Either way our future trys will be unsuccessfull since the controls are no longer there.
The second application is very straight forward, it only needs a textBox and a button. It should show a message box when the password is correct, but not when the password is incorrect (again because we want to maintain the simpplicity of the example).
At this point I would like to point out that this isn't an efficient algorythm and it's not ment to be one. It's main purpuse is to show the basic principle of brute force mechanisms and it can be improved in many ways.
I hope I have succeded in sheding some light on the topic!