Уроки Разработка малвари - 5. Изучаем динамические библиотеки (1 Viewer)

Пользователи, которые просматривают: тема


X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
5 848
Репутация
7 947
1692450669523.png


В этой статье предлагаю рассмотреть создание динамических библиотек, в винде это всем наверное известные DLL.)

И .exe, и .dll файлы считаются исполняемыми файлами, в формате PE, сам PE уже описан много где, нет не времени не желание описывать архитектуру, если интересно всё в сети есть и очень разжованно.)

Что такое DLL?

DLL - это общие библиотеки исполняемых функций или данных, которые могут использоваться несколькими приложениями одновременно. Они используются для экспорта функций, которые будут использоваться процессом. В отличие от EXE файлов, DLL файлы не могут исполнять код самостоятельно. Вместо этого библиотеки DLL необходимо загрузить другими программами для выполнения кода.

Например функция createFile экспортирована из kernel32.dll, поэтому если процесс хочет вызвать эту функцию, ему сначала нужно загрузить kernel32.dll в свое адресное пространство.

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

Несколько примеров таких DLL: ntdll.dll, kernel32.dll и kernelbase.dll.

В PocessExplorer показанно какие dll загружены в процесс explorer.exe:

1692451166356.png


Системный Базовый Адрес DLL

ОС Windows использует системный базовый адрес DLL, чтобы загружать некоторые DLL по одному и тому же базовому адресу в виртуальном адресном пространстве всех процессов на данной машине для оптимизации использования памяти и улучшения производительности системы.

Следующее изображение показывает, как kernel32.dll загружается по одному и тому же адресу (0x7fff9fad0000) среди нескольких работающих процессов.

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

1692451264860.png


Зачем использовать DLL?

Есть несколько причин, почему DLL так часто используются в Windows:
  1. Модульность кода - вместо одного огромного исполняемого файла, содержащего всю функциональность, код делится на несколько независимых библиотек, каждая из которых фокусируется на конкретной функциональности. Модульность упрощает работу разработчиков во время разработки и отладки.
  2. Повторное использование кода - DLL способствуют повторному использованию кода, так как библиотеку можно вызывать из нескольких процессов.
  3. Эффективное использование памяти - когда несколько процессов нуждаются в одной и той же DLL, они могут экономить память, разделяя эту DLL, вместо того чтобы загружать ее в память процесса.
Точка входа в DLL

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

Есть 4 возможности для вызова точки входа:
  1. Загрузка процессом DLL.
  2. Создание процессом нового потока.
  3. Нормальный выход потока.
  4. Выгрузка процессом DLL.
Пример кода DLL

Код ниже показывает типичную структуру кода DLL.

Код:
BOOL APIENTRY D11Main(
HANDLE hModule, // Handle to DLL module
DWORD ul_reason_for_call, // Reason for calling function
LEVOID lpReserwved // Reserved
)
{
switch (ul_reason_for_call)

case DLL_PROCESS_ATTACH: //Load to process
// Do something here
break;

DLL_THREAD_ATTACH: // A a new thread.
// Do socmething here
break;

case DLL_THREAD_DETACH // А thread exits normally.
// Do something here
break;

case DLL_PROCESS_DETACH: // A process unloads the DLL.
// Do something here
break;

return TRUE;
}

Экспорт функции

DLL-файлы могут экспортировать функции, которые могут быть использованы вызывающим приложением или процессом. Чтобы экспортировать функцию, она должна быть определена с использованием ключевых слов extern и __declspec(dllexport). Приведен ниже пример экспортированной функции HelloWorld.

C:
extern _ declspec(dllexport) void HelloWorld() {
// Function code here
}

Динамическое связывание

Можно использовать WinAPI, такие как LoadLibrary, GetModuleHandle и GetProcAddress, чтобы импортировать функцию из DLL. Этот процесс называется динамическим связыванием.
Это метод загрузки и связывания кода (DLL) во время выполнения, а не связывания их на этапе компиляции с помощью компоновщика и таблицы адресов импорта.

Существует несколько преимуществ использования динамического связывания, их подробное описание можно найти в документации Microsoft.

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

Загрузка DLL

Вызов функции, например MessageBoxA, в приложении заставит ОС Windows загрузить DLL, экспортирующую функцию MessageBoxA, в адресное пространство памяти вызывающего процесса, в данном случае это user32.dll. Загрузка user32.dll была выполнена автоматически ОС при запуске процесса, а не кодом.

Однако в некоторых случаях, эта DLL может не быть загружена в память. Чтобы приложение могло вызвать функцию, ему сначала нужно получить дескриптор DLL, экспортирующий эту функцию. Для этого потребуется использовать функцию WinAPI LoadLibrary, как показано ниже.

Код:
HMODULE hModule = LoadLibraryA("sampleDLL.d11"); // hMedule now contain sampleDLL.dll's handle

Получение адреса функции

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

Код:
PVOID pHelloWorld = GetProcAddress(hModule, "HelloWorld");

Вызов функции

После сохранения адреса HelloWorld в переменной pHelloWorld, следующим шагом является приведение типа этого адреса к указателю функции HelloWorld. Этот указатель на функцию требуется для вызова функции.

Код:
typedef void (WINAPI* HelloWorldFunctionPointer) ();
HelloWorldFunctionPointer HelloWorld = (HelloWorldFunctionPointer)pHelloWorld;
HelloWorld();

Пример динамического связывания

Ниже представлен еще один простой пример динамического связывания, где вызывается MessageBoxA. Код предполагает, что user32.dll экспортирующая эту функцию не загружена в память. Напоминаю, что если DLL не загружена в память, для загрузки этой DLL в адресное пространство процесса требуется использование LoadLibrary.

Код:
typedef int (WINAPI* MessageBoxAFunctionPointer)(HWND, LPCSTR, LPCSTR, UINT);
MessageBoxAFunctionPointer pMessageBoxA = (MessageBoxAFunctionPointer)GetProcAddress(LoadLibrary("user32.dll"), "MessageBoxA");
if (pMessageBoxA) {
    pMessageBoxA(NULL, "Текст MessageBox", "Заголовок MessageBox", 0);
}

Указатели на функции

На протяжении оставшегося курса типы данных указателей на функции будут иметь именование, которое использует имя WinAPI с префиксом fp, что означает "указатель на функцию". Например, вышеуказанный тип данных MessageBoxAFunctionPointer будет представлен как fpMessageBoxA. Это используется для упрощения и повышения ясности на протяжении курса.

Rundll32.exe

Существует несколько способов запуска экспортированных функций без использования программного метода.
Одна из общеизвестных техник - использование бинарного файла rundll32.exe. Rundll32.exe - это встроенный бинарник Windows, который используется для запуска экспортированной функции DLL. Для запуска экспортированной функции используйте следующую команду:

Код:
rundll32.exe <имя_dll>, <экспортированная функция для запуска>

Создание файла DLL с помощью Visual Studio

Чтобы создать файл DLL, запустите Visual Studio и создайте новый проект. Когда вам будут предложены шаблоны проектов, выберите опцию "Dynamic-Link Library (DLL)".

1692452618767.png


Далее будут сгенерированы шаблоны, в которых уже можно писать код (dllmain.cpp):

1692452667576.png


Предоставленный шаблон DLL поставляется с framework.h, pch.h и pch.cpp, которые известны как предварительно скомпилированные заголовки. Эти файлы используются для ускорения компиляции проекта для больших проектов. Вряд ли они понадобятся в этой ситуации, поэтому рекомендуется удалить эти файлы. Для этого выделите файл и нажмите клавишу удаления, затем выберите опцию "Удалить".

1692452719622.png


1692452761257.png


После удаления предварительно скомпилированных заголовков необходимо изменить настройки компилятора по умолчанию, чтобы подтвердить, что в проекте не следует использовать предварительно скомпилированные заголовки.

1692452883649.png


1692452911470.png


Перейдите к вкладке C/C++.

Измените параметр "Предварительно скомпилированный заголовок" на "Не использовать предварительно скомпилированные заголовки"и нажмите "Применить".

1692453021103.png


Наконец, можно изменить файл dllmain.cpp на dllmain.c. Это необходимо, если вы используете C вместо C++. Для компиляции программы выберите Сборка > Собрать решение, и DLL будет создан в папке Release или Debug, в зависимости от конфигурации компиляции.
 
Последнее редактирование:

Spectrum735

Просветленный
Просветленный
Регистрация
21.02.2019
Сообщения
204
Репутация
100
Пытался как-то использовать технику Dll hijack proxing, но так и не понял как она работает.
Изначально ищется уязвимое приложение через Process Explorer, которое ищет библиотеку рядом с собой, а потом уже в системных каталогах. Затем пишется dll, которая кладется рядом с уязвимым приложением и полученный результат будет проксирование вызовов всех экспортируемых функций легальной dll из системного каталога (System32 например). В итоге получаем приложение, зависящее от искомой ею библиотеки, при этом вызывая Payload при инициализации.

Подробности тут
Вам нужно авторизоваться, чтобы просмотреть содержимое.


Dll вроде как вызывается, но само приложение никак не открывается. Как сделать чтобы основное приложение не умирало, увы, не знаю
 

X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
5 848
Репутация
7 947
Как сделать чтобы основное приложение не умирало, увы, не знаю
Нужно глянуть какие функции импортирует приложение из оригинальной библиотеки.

Их экспортировать в своей библиотеке.

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

У тебя краш скорей-всего происходил, т.к библиотека не экспортировала нужные оригинальные функции, а приложению они нужны.

Таким образом кстати можно подменять данные из необходимых экспортируемых функций.)
 

Spectrum735

Просветленный
Просветленный
Регистрация
21.02.2019
Сообщения
204
Репутация
100
У тебя краш скорей-всего происходил, т.к библиотека не экспортировала нужные оригинальные функции, а приложению они нужны.
делал как по инструкции по ссылке выше, но всё равно почему-то не проходит
 

X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
5 848
Репутация
7 947
делал как по инструкции по ссылке выше, но всё равно почему-то не проходит
Там собирать надо i686-w64-mingw32-gcc.
Хотя в вижуалке тоже наверное можно настроить.

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

Spectrum735

Просветленный
Просветленный
Регистрация
21.02.2019
Сообщения
204
Репутация
100
Там собирать надо i686-w64-mingw32-gcc.
аа, вон чё) Надо глянуть.
def-файл генерил через питон-скрипт, который там приводится.
Для visual studio есть целое приложение для генерации проекта - spartacus, пробовал его, не канает. Возможно даже причина в коде инициализации. Нужно как-то запустить сторонний софт таким вот методом
 

X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
5 848
Репутация
7 947
Важно что-бы в твоей библиотеки были экспортированы функции оригинальной библиотеки, их можно написать вручную, как вариант из своей библиотеки вызывать оригинальные.
Можно автоматизировать, как это сделано выше...

В целом можно проверить потом что они там есть, любой программой для анализа DLL.

Например dumbin:

Что-то такое:

dumpbin /exports C:\path\to\my.dll
 

Purple

Пользователь
Форумчанин
Регистрация
11.09.2023
Сообщения
14
Репутация
5
Пытался как-то использовать технику Dll hijack proxing, но так и не понял как она работает.
я делал такое. смотрел у exe, какие функции импортируются из оригинальной dll, потом писал свою dll.
В своей dll приходилось объявлять все функции из оригинальной dll, помимо этого, еще нужно было перенаправлять вызов к оригинальной dll (что-то вроде заглушек).
А уж в одной из функций до перенаправления выполнял свой код)

Проблемы у меня заключались только при обработке типов переменных, которые передаются в dll, но их я решил

Если хочешь, могу покопаться и дать тебе пример проксирования одной функции из DLL :)
Правда, пример будет реализован на мертвом Delphi =D Я от этой среды разработки, к счастью, давно отошел
 
Автор темы Похожие темы Форум Ответы Дата
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 1
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 2
X-Shar Введение в разработку вредоносных программ 1
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 4
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 3
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 1
X-Shar Введение в разработку вредоносных программ 2
X-Shar Введение в разработку вредоносных программ 2
X-Shar Введение в разработку вредоносных программ 1
Похожие темы
Уроки Разработка вирусов-29. Предельная техника-2. Практика. Реализуем техники инъекции через сисколы
Уроки Разработка вирусов-28. Предельная техника. Разборка с сисколами
Уроки Разработка вирусов-27.Кунгфу-2.Изучаем API Hooking
Уроки Разработка вирусов-26. Изучаем кунгфу-1. Скрытие таблицы импорта
Уроки Разработка вирусов-25. Скрытие строк
Уроки Разработка вирусов-24. Изучаем технику Spoofing
Уроки Разработка вирусов-23. Контроль выполнения полезной нагрузки
Уроки Разработка малвари-18.Определение PID нужного процесса, или перечисления процессов
Уроки Разработка малвари-14. Размещаем Payload удаленно на сервере
Уроки Разработка малвари-13.Инъекция шелл-кода в процесс
Уроки Разработка малвари-12. Иньекция в процесс
Уроки Разработка малвари-11. Локальный запуск Payload
Уроки Разработка малвари-10. Обфускация Payload
Уроки Разработка малвари-9. Шифруем Payload
Уроки Разработка малвари-8. Куда класть нагрузку ?
Уроки Разработка малвари-7. Виды детектов
Уроки Разработка малвари-6. Процессы Windows
Уроки Разработка малвари - 4. Шпаргалка по архитектуре винды
Уроки Разработка малвари - 3. Так какой-же язык выбрать !?
Уроки Разработка малвари - 2. Изучаем инструменты
Верх Низ