Click here to Skip to main content
Click here to Skip to main content

How to make keyloggers life difficult

By , 20 Jan 2013
 

Introduction  

If you usually typing a password in a desktop application, it may be that a keylogger spies out your secrets. This is obviously not good. Screen keyboards might be a good solution, but again, there could be a screen capture program which watches effortlessly your passwords. Furthermore, screen keyboards are relative unhandily.

The following article presents a relatively simple principle, which prevents the keylogger to write down passwords entered. Basically, the used system is surprisingly easy and can therefore be transferred to other programming / operating systems / platforms, although under a small limitation.

Background 

The first question is: How can a program hide keystrokes? Perhaps there are some difficult ways to do this, but most probable this is not possible. We create an assumption: Entered characters necessarily mean the keylogger sees them. And that's what we use against the keylogger.

The second question is: How can a program generate keystrokes? This is normally possible. For example, we use in C# the class SendKeys, which provides methods for sending keystrokes. By the way, there can be the mentioned limitation because a website has not the authorization to produce keystrokes.

The third question is: How can we combine these two statements? At every time when the user types a character, the program generates some keytrokes more. The keylogger write down all characters both from user and program, but only the user and the program know the entire password. Unauthorized third parties see only letter salad and they can not decrypt the main password.

The fourth question is: Is this main system 100 % secure? Surprisingly and unfortunately no. The prinziple has many weak points, but there are also many solutions to close these gaps. I advise every developer to think about it before they add this concept to their code. Let me explain you the vulnerabilities and the solutions:

  1. Creating random keystrokes after every character allows attackers to reproduce the typed password. Therefore the program must create identical keystrokes. Then again the produced keystrokes should not be identical for all passwords. In summary, we need a algorithm, which produces for every character always the same keystrokes. In addition to this, the length of the generated keystrokes should vary.

  2. For all that, an attacker can create a table with all characters and their hash result either by reverse engineering or by testing. Using this table, he can decrypt the password relatively easy. To prevent this, the generated keystrokes should depend on a password identity, such as account name, account number, e-mail or computer specification. Unfortunately, this is only an obstacle, but no blockage for attackers.

Using the code

At first, the create a new component SecureTextBox with some properties:

public class SecureTextBox : TextBox
{
     /// <summary>
     /// Gets the typed password.
     /// </summary>
     public string Password
     {
          get;
          private set;
     }
 
     /// <summary>
     /// Sets or gets the password ID.
     /// </summary>
     public string ID
     {
          get;
          set;
     }
}

The next step is to implement a constructor for initializing important events:

public SecureTextBox()
{
     this.TextChanged += new EventHandler(SecureTextBox_TextChanged);
     this.KeyDown += new KeyEventHandler(SecureTextBox_KeyDown);
     this.KeyUp += new KeyEventHandler(SecureTextBox_KeyUp);
}    

The methods SecureTextBox_KeyDown and SecureTextBox_KeyUp should ensure that no key is pressed, otherwise characters are inserted incorrectly or even not.  The boolean variable IsTriggering declares if the user entered a character while he is holding another key.

private int KeysPressed = 0;
private bool IsTriggering = false;
 
void SecureTextBox_KeyDown(object sender, KeyEventArgs e)
{
     KeysPressed++;
}
 
void SecureTextBox_KeyUp(object sender, KeyEventArgs e)
{
     KeysPressed--;
     if (KeysPressed == 0 & IsTriggering)
          this.SecureTextBox_TextChanged(null, null);
}

Now consider the random functions. For this example, I used Random combined with a given seed. The seed is created from the ID and the last entered character from user.

Random _NextSaltLength, _NextSaltChar;
// TODO: Extend the CharContent with all important characters!
string CharContent = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
 
private int NextSaltLength(bool CreateNew)
{
	// TODO: Replace this code with your own function!
	if (CreateNew)
		_NextSaltLength = new Random(ID.GetHashCode() - Password[Password.Length - 1].GetHashCode());
	return _NextSaltLength.Next(1, 4);
}
 
private string NextSaltChar(bool CreateNew)
{
	// TODO: Replace this code with your own function!
	if (CreateNew)
		_NextSaltChar = new Random(ID.GetHashCode() + Password[Password.Length - 1].GetHashCode());
	return CharContent[_NextSaltChar.Next(CharContent.Length)].ToString();
}

Finally, we can create the main method which manage the generation of the keystrokes:

private int RemainingSaltChars = 0;
private int LastTextLength = 0;
 
void SecureTextBox_TextChanged(object sender, EventArgs e)
{
     if (KeysPressed > 0)
     {
          IsTriggering = true;
          return;
     }
     IsTriggering = false;
     if (LastTextLength < this.TextLength)
     {
          LastTextLength = this.TextLength;
          if (RemainingSaltChars > 0)
          {
               if (RemainingSaltChars > 1)
                    SendKeys.Send(this.NextSaltChar(false));
               RemainingSaltChars--;
          }
          else
          {
               this.Password += this.Text[this.TextLength - 1];
               RemainingSaltChars = this.NextSaltLength(true);
               SendKeys.Send(this.NextSaltChar(true));
          }
     }
     else
     {
          this.ResetText();
          LastTextLength = 0;
     }
}

Here is a short description of the implementation: If no keys are pressed and the user entered a character in the TextBox, the char is saved, the quantity of the next generated characters are randomly calculated and the first character is send through SendKeys.Send(). Now the program is in a complicated loop and generates the specified keystrokes. This state is interrupted, if RemainingSaltChars is zero. Just as a footnote, if the user presses Delete or Backspace, the text will be reset because otherwise this would mix up the algorithm.

public override void ResetText()
{
     base.ResetText();
     this.Password = String.Empty;
}

Points of Interest 

Originally I have this prinziple from a software, which polls for a password at startup. At first I wondered why more masked characters apperared in the textbox than typed until I figured it out. I implemented my thoughts and experimented with my code using a keylogger. I was very surprised about the effectivity. Then I wanted to analyse how good the other application works while using a keylogger. But the program produced no keystrokes. Unbelievable! I found this very amusing.

In the introduction I said that this prinziple could not be implemented by a website. A solution for this would be a extra Add-On for the browser, which could take on this task. 

History 

Published on 19 January 2013.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Michael Hudak (Aregeion)
Student Kaiserslautern University of Technology
Germany Germany
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberMonjurul Habib2 Feb '13 - 7:04 
nice work Smile | :)
GeneralMy vote of 5memberSergio Andrés Gutiérrez Rojas29 Jan '13 - 16:14 
Good work!!
GeneralMy vote of 5memberEdo Tzumer29 Jan '13 - 3:23 
*****
 
Nice Smile | :)
GeneralMy vote of 5mvpMichael Haephrati מיכאל האפרתי24 Jan '13 - 7:42 
Thanks for submitting your article. Your POC works as described and your article is well explained. I don't think such approach is useful because the characters added aren't random. Another question (I may have missed something): lets say I want to set my gmail password to "123". When I type it, the text actually typed is "aNbVcK". What will be my password (lets say I want to log in form a PC which doesn't have your software on it)
AnswerRe: My vote of 5memberMichael Hudak (Aregeion)24 Jan '13 - 11:43 
First, the prinziple works for websites not in the least if you wouldn't implement the priniple in the browser itself.
Second, if you type "123", the actually typed text would never be "kydhg" but something like "1fh2osi3ksdj".
Third, assuming browser X has implemented the prinziple, but browser Y not. You can log in with both Browsers anyway.
 
Please, if you have some questions or if I did some mistakes, reply Wink | ;)
GeneralRe: My vote of 5mvpMichael Haephrati מיכאל האפרתי24 Jan '13 - 23:41 
if I set a new password "123" for website www.abc.com will the password actually be: "1fh2osi3ksdj" or "123"?
AnswerRe: My vote of 5memberMichael Hudak (Aregeion)25 Jan '13 - 8:28 
it will be "123"
Questionclose...i thinkmemberMember 322138523 Jan '13 - 5:00 
i wonder....i think this could be modified (i haven't tried the source or this modification)....
 
but could you program it so that it is a user-controlled dictionary?   for example, if i type:
pwdAmazon - the this app would actually send my Amazon password (and potentially remove pwdAmazon)?   maybe "pwd" is a trigger to the app to listen...and if it found an entry - send that instead (to include garbled message, programmed at the same speed that i can type).
 
now i get shortcut passwords (pwdAmazon, pwdiTunes, pwdCodeProject) - and really secure and unique site passwords, and keyloggers will have a real hard time.   not to mention the website hackers.
AnswerRe: close...i thinkmemberMichael Hudak (Aregeion)24 Jan '13 - 11:33 
Perhaps I does not understand your goal, but I try it:
You want to modify the program so that it listen to your passwords e.g. pwdAmazon
and then sends the right password e.g. bf93q748bf9 to Amazon?
 
Ok, this is normally not possible, because the browser must send the password (over https).
 
This is important, because only browser - server should be able to authorize each other.
 
In summary, the browser should do that you want.
But there are many security questions:
How is the password saved?
How can you verify yourself towards the browser?
...
 
And yeah, I want to highlight that there are many posibilities to modify this prinziple.
GeneralMy vote of 5memberJH6421 Jan '13 - 11:33 
Learned something new. Make keyloggers log crap is good approach.
QuestionDon't think it will workmemberHaBiX20 Jan '13 - 21:42 
If I log you entering password 10 times.. that's all I need to extract the typed characters.
Its only good if text is constantly random.
 
For passwords, etc: its better to use randomly generated virtual keyboard or similar (no mouse logging possible either)..
 
but yeah .. every protection has its attack (taking screenshots of keyboard, etc)
AnswerRe: Don't think it will workmemberMichael Hudak (Aregeion)21 Jan '13 - 23:54 
This I can't understand. Why you think, after 10 times you have the password?
The prinziple does not use random characters because this helps to extract the typed characters.
You can try it: Every time you get the same String, not more, not less.
 
Or I oversee a gap?
GeneralRe: Don't think it will work [modified]memberHaBiX22 Jan '13 - 0:06 
I said 10 as an example. When you capture repeating sequences of password typing, there will be some character in sequence repeated (with random stuff in between):
 
I'll give you a very simple example of password "Foo" from the keyloger's perspective:
FvAo3o97
F6ovxopo
Fbxo5F4o1F
Fq3oS3oV9
 
You could guess the pwd by eye.. (Only "Foo" repeats in all sequences); if you made a program to look for repeating sequences, you could extract more complex stuff.
 
Not to mention, if the keyloger got installed, it needed alot of privileges and could easy make a screenshot as well (to see the password, or at least the password length).
 

**edit
I forgot to say about time: the delay between natural key strokes will be much bigger than from the artifical ones.
 
**edit2
I read it again, sorry, I didn't see it doesn't use random characters (should have try it), but the fact that you're using typed password as random seed makes it reversable.

modified 22 Jan '13 - 6:30.

GeneralMy vote of 5memberFaithcz20 Jan '13 - 21:39 
Great idea. I have never thought about that.
QuestionInteresting: need a keylogger nowmemberBruno Tabbia20 Jan '13 - 20:48 
Hallo,
this article is interesting, and I would like to understand more in depth what happens during the keylogger-antikeylogger battle.
Does anyone know a good (and recent) keylogger to test this component ?
Even better would be having a simple C# keylogger source (I've already seen the two codeprojects "Basic Keystroke Mining" and "SpyNet").
AnswerRe: Interesting: need a keylogger nowmvpEddy Vluggen9 Feb '13 - 1:38 
Enjoy[^]
Bastard Programmer from Hell Suspicious | :suss:
If you can't read my code, try converting it here[^]

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 20 Jan 2013
Article Copyright 2013 by Michael Hudak (Aregeion)
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid