
Легко превращайте DLL-хиджининг в оружие. Внедряйте бэкдор в любую функцию любой DLL.

DllShimmer анализирует исходную DLL и извлекает информацию об экспортируемых функциях (имя, порядковый номер и сведения о форвардинге). На основе этой информации DllShimmer создает шаблонный C++-файл (.cpp). Сгенерированный файл позволяет добавить свой код в каждую функцию, экспортируемую из исходной DLL, не нарушая нормальную работу программы. Не требуется реверс-инжиниринг или инструментирование, потому что DllShimmer не полагается на сигнатуры функций (подробнее в разделе «Ограничения»).
Второй генерируемый файл — это .def файл, который гарантирует, что все DLL, экспортируемые из прокси после компиляции, будут иметь те же имена и порядковые номера, что и в исходной DLL.
После компиляции EAT в прокси-DLL является точной копией EAT исходной DLL. Все имена и порядковые номера экспортируемых функций совпадают, а перенаправленные функции также перенаправляются. DllShimmer не перенаправляет явно все функции (как большинство инструментов), создавая совершенно новую и подозрительную структуру EAT.
Скомпилируйте исходный код на Go или скачайте готовый бинарный файл.
Зависимости:
x86_64-w64-mingw32-g++x86_64-w64-mingw32-dlltoolПример:
# Backdoor version.dll (proxy to absolute path)
./DllShimmer -i version.dll -o project/ -x "C:/Windows/System32/version.dll" -m
# Backdoor random chat.dll (proxy to relative path)
./DllShimmer -i chat.dll -o project/ -x "lib/chat2.dll" -m
# Backdoor random app.dll (static linking to the original DLL)
./DllShimmer -i app.dll -o project/ -x "app2.dll" -m --static
Параметры:
-i / --input <path> [обязательный]
Исходная DLL, в которую вы хотите внедрить бэкдор.
-o / --output <path> [обязательный]
Путь к каталогу, в который DllShimmer сохранит все сгенерированные файлы.
-x / --original <path> [обязательный]
В случае динамической компоновки (по умолчанию) укажите путь, по которому прокси-DLL найдет исходную DLL в целевой системе.
В случае статической компоновки (--static) укажите только имя исходной DLL. Она будет искаться в соответствии с порядком загрузки по умолчанию в Windows.
-m / --mutex [необязательный]
Включение этой опции добавит мьютекс в исходный файл, который предотвращает выполнение вашего бэкдора более одного раза за один запуск программы. Все исходные функции продолжат работать нормально.
--static [необязательный]
Включает статическую компоновку между прокси-DLL (IAT) и исходной DLL (EAT). Это создает дополнительный файл .lib в выходном каталоге, который выступает в роли исходной DLL для статической компиляции.
У этого метода есть серьезные ограничения по сравнению с динамической компоновкой:
Однако статическая компоновка в некоторых сценариях может быть более скрытной и естественной.
По умолчанию: DllShimmer всегда использует динамическую компоновку с функциями LoadLibraryA() и GetProcAddress().
--debug-file <path> [необязательный]
Сохраняет отладочные журналы в файл. Журналы записываются в файл непрерывно во время работы программы. Если опция выбрана, журналы не выводятся в STDOUT.
По умолчанию: DllShimmer всегда записывает отладочные журналы в STDOUT.
Пример вывода отладочной информации:

Перед началом устранения неполадок:
--static). С динамической компоновкой (по умолчанию) отлаживать проще.--debug-file)..cpp я не вижу всех экспортируемых функций из исходной DLL.Функции, определенные в исходной DLL как «forwarded» (перенаправленные), не включаются в файл .cpp. Однако они видны в файле .def. После компиляции они также будут экспортироваться точно так же, как в исходной DLL.
Иногда прокси-DLL показывает ошибку при загрузке исходной DLL, и код ошибки — 126, даже если вы теоретически указали правильный относительный путь в параметре -x. Почему это не работает?!?
DLL ищутся в Current Directory (текущем каталоге). В 98% случаев это просто расположение основного EXE-файла, но есть программы (в основном старые, легаси), которые произвольно меняют Current Directory, например, с помощью SetCurrentDirectoryW(). Основная программа знает об этом изменении, поэтому корректно загружает вашу прокси-DLL, но вы об этом не знаете и пытаетесь загрузить исходную DLL относительно, хотя программа ищет её в изменённом Current Directory.
Это правило действует как для статической, так и для динамической загрузки исходной DLL. К сожалению, при статической компоновке эту проблему гораздо сложнее обнаружить, потому что у нас нет отладочной информации. Системный загрузчик просто завершается с ошибкой, и всё. Поэтому я всегда рекомендую сначала использовать динамическую компоновку по умолчанию.
В случае динамической компоновки у нас есть два варианта:
-x с учётом нового Current Directory.Current Directory, чтобы искать DLL там, где нам нужно.В случае статической компоновки у нас, по сути, только один вариант:
Current Directory.