Вопрос или проблема
Для контекста
Я использую этот скрипт на Python для выполнения шеллкода, который найден в
loader.bin
#!/usr/bin/env python3 import ctypes import ctypes.wintypes as wt import logging import platform # Настройка логирования logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s") class ShellcodeExecute: # EXE файл PyInstaller, преобразованный в шеллкод с использованием Donut try: shellcode = open('loader.bin', 'rb').read() logging.info(f'Длина шеллкода составляет: {len(shellcode)}') except FileNotFoundError: logging.critical('Файл loader.bin не найден. Пожалуйста, убедитесь, что файл находится в правильном месте.') raise except Exception as e: logging.critical(f'Ошибка при чтении loader.bin: {e}') raise HEAP_CREATE_ENABLE_EXECUTE = 0x00040000 HEAP_ZERO_MEMORY = 0x00000008 PAGE_READWRITE_EXECUTE = 0x40 PAGE_READ_EXECUTE = 0x20 @staticmethod def configure_ctypes(): try: # CloseHandle() ShellcodeExecute.CloseHandle = ctypes.windll.kernel32.CloseHandle ShellcodeExecute.CloseHandle.argtypes = [wt.HANDLE] ShellcodeExecute.CloseHandle.restype = wt.BOOL # CreateRemoteThread() ShellcodeExecute.CreateRemoteThread = ctypes.windll.kernel32.CreateRemoteThread ShellcodeExecute.CreateRemoteThread.argtypes = [ wt.HANDLE, wt.LPVOID, ctypes.c_size_t, wt.LPVOID, wt.LPVOID, wt.DWORD, wt.LPVOID] ShellcodeExecute.CreateRemoteThread.restype = wt.HANDLE # CreateThread() ShellcodeExecute.CreateThread = ctypes.windll.kernel32.CreateThread ShellcodeExecute.CreateThread.argtypes = [ wt.LPVOID, ctypes.c_size_t, wt.LPVOID, wt.LPVOID, wt.DWORD, wt.LPVOID ] # HeapCreate() ShellcodeExecute.HeapCreate = ctypes.windll.kernel32.HeapCreate ShellcodeExecute.HeapCreate.argtypes = [wt.DWORD, ctypes.c_size_t, ctypes.c_size_t] ShellcodeExecute.HeapCreate.restype = wt.HANDLE # HeapAlloc() ShellcodeExecute.HeapAlloc = ctypes.windll.kernel32.HeapAlloc ShellcodeExecute.HeapAlloc.argtypes = [wt.HANDLE, wt.DWORD, ctypes.c_size_t] ShellcodeExecute.HeapAlloc.restype = wt.LPVOID # OpenProcess() ShellcodeExecute.OpenProcess = ctypes.windll.kernel32.OpenProcess ShellcodeExecute.OpenProcess.argtypes = [wt.DWORD, wt.BOOL, wt.DWORD] ShellcodeExecute.OpenProcess.restype = wt.HANDLE # RtlMoveMemory() ShellcodeExecute.RtlMoveMemory = ctypes.windll.kernel32.RtlMoveMemory ShellcodeExecute.RtlMoveMemory.argtypes = [wt.LPVOID, wt.LPVOID, ctypes.c_size_t] ShellcodeExecute.RtlMoveMemory.restype = wt.LPVOID # VirtualAllocEx() ShellcodeExecute.VirtualAllocEx = ctypes.windll.kernel32.VirtualAllocEx ShellcodeExecute.VirtualAllocEx.argtypes = [wt.HANDLE, wt.LPVOID, ctypes.c_size_t, wt.DWORD, wt.DWORD] ShellcodeExecute.VirtualAllocEx.restype = wt.LPVOID # VirtualProtectEx() ShellcodeExecute.VirtualProtectEx = ctypes.windll.kernel32.VirtualProtectEx ShellcodeExecute.VirtualProtectEx.argtypes = [ wt.HANDLE, wt.LPVOID, ctypes.c_size_t, wt.DWORD, wt.LPVOID] ShellcodeExecute.VirtualProtectEx.restype = wt.BOOL # WaitForSingleObject ShellcodeExecute.WaitForSingleObject = ctypes.windll.kernel32.WaitForSingleObject ShellcodeExecute.WaitForSingleObject.argtypes = [wt.HANDLE, wt.DWORD] ShellcodeExecute.WaitForSingleObject.restype = wt.DWORD # WriteProcessMemory() ShellcodeExecute.WriteProcessMemory = ctypes.windll.kernel32.WriteProcessMemory ShellcodeExecute.WriteProcessMemory.argtypes = [ wt.HANDLE, wt.LPVOID, wt.LPCVOID, ctypes.c_size_t, wt.LPVOID] ShellcodeExecute.WriteProcessMemory.restype = wt.BOOL # GetExitCodeThread() ShellcodeExecute.GetExitCodeThread = ctypes.windll.kernel32.GetExitCodeThread ShellcodeExecute.GetExitCodeThread.argtypes = [wt.HANDLE, wt.LPDWORD] ShellcodeExecute.GetExitCodeThread.restype = wt.BOOL logging.info('ctypes успешно настроены.') except Exception as e: logging.critical(f'Ошибка при настройке ctypes: {e}') raise def __init__(self, shellcode=None): logging.info(''' _______________________________________________________ shellcode.py: Простое выполнение шеллкода на Python3 куча процесса. Версия 1.0 (c) Joff Thyer Black Hills Information Security LLC River Gum Security LLC _______________________________________________________ ''') try: if shellcode is None and platform.architecture()[0] == '64bit': logging.info('[*] 64-битный интерпретатор Python') self.shellcode = self.shellcode self.execute() except Exception as e: logging.critical(f'Ошибка инициализации: {e}') raise def execute(self): try: heap = self.HeapCreate( self.HEAP_CREATE_ENABLE_EXECUTE, len(self.shellcode), 0) if not heap: logging.error('HeapCreate не удался.') return self.HeapAlloc(heap, self.HEAP_ZERO_MEMORY, len(self.shellcode)) logging.info('[*] Успешно выделена память с помощью HeapAlloc() на: {:08X}'.format(heap)) self.RtlMoveMemory(heap, self.shellcode, len(self.shellcode)) logging.info('[*] Шеллкод скопирован в память.') thread = self.CreateThread(0, 0, heap, 0, 0, 0) if not thread: logging.error('CreateThread не удался.') return logging.info('[*] CreateThread() в том же процессе.') self.WaitForSingleObject(thread, 0xFFFFFFFF) # Проверьте, была ли успешной выполнение потока exit_code = wt.DWORD() result = self.GetExitCodeThread(thread, ctypes.byref(exit_code)) if not result: logging.error('Не удалось получить код выхода потока.') else: if exit_code.value == 0: logging.info('[*] Шеллкод выполнен успешно.') else: logging.error(f'Выполнение шеллкода завершилось с кодом выхода: {exit_code.value}') except Exception as e: logging.critical(f'Ошибка выполнения: {e}') raise if __name__ == '__main__': try: ShellcodeExecute.configure_ctypes() ShellcodeExecute() except Exception as e: logging.critical(f'Фатальная ошибка: {e}') raise
И я также использую
donut
для генерации шеллкода из моего EXE.
Теперь, когда я использую donut
с общими исполняемыми файлами (например, ./donut -i .\calc.exe
) и запускаю скрипт выполнения шеллкода, он работает без проблем.
Однако, когда у меня есть EXE, скомпилированный с использованием PyInstaller --onefile
, и я генерирую его шеллкод с помощью ./donut -i PYINSTALLER_EXECUTABLE.exe
, когда я пытаюсь выполнить сгенерированный шеллкод, используя скрипт выполнения шеллкода, вот что происходит:
2024-11-05 04:58:39,014 - INFO - Длина шеллкода составляет: 34565956
2024-11-05 04:58:39,014 - INFO - ctypes успешно настроены.
2024-11-05 04:58:39,014 - INFO -
_______________________________________________________
shellcode.py: Простое выполнение шеллкода на Python3
куча процесса.
Версия 1.0 (c) Joff Thyer
Black Hills Information Security LLC
River Gum Security LLC
_______________________________________________________
2024-11-05 04:58:39,014 - INFO - [*] 64-битный интерпретатор Python
2024-11-05 04:58:39,014 - INFO - [*] Успешно выделена память с помощью HeapAlloc() на: 1926D150000
2024-11-05 04:58:39,029 - INFO - [*] Шеллкод скопирован в память.
2024-11-05 04:58:39,029 - INFO - [*] CreateThread() в том же процессе.
[PYI-17660:ERROR] Не удалось загрузить встроенный архив PKG PyInstaller из исполняемого файла (C:\Users\zaid2\AppData\Local\Programs\Python\Python311\python.exe)
Несмотря на то, что когда я запускаю независимый EXE, он работает.
Почему это происходит? И есть ли способ правильно сгенерировать шеллкод для исполняемых файлов PyInstaller?
Ответ или решение
Для корректной генерации шелкода из исполняемого файла, созданного с помощью PyInstaller, необходимо учитывать несколько ключевых моментов, которые связаны с особенностями работы PyInstaller и механизмами, которые он использует для упаковки программ. Давайте разберёмся в деталях.
Что такое PyInstaller и как он работает?
PyInstaller — это популярный инструмент, позволяющий превращать Python-скрипты в автономные исполняемые файлы (EXE) для Windows, Linux и macOS. Он фиксирует всю среду выполнения приложения, включая используемые библиотеки и ресурсы, и включает их в собранный EXE. Этот процесс значительно отличается от создания обычных исполняемых файлов, таких как calc.exe, что может вызывать проблемы при извлечении шелкода.
Проблемы при генерации шелкода из PyInstaller-исполняемых файлов
Из вашего описания видно, что вы успешно генерируете и запускаете шелкод для стандартных исполняемых файлов, но сталкиваетесь с ошибками при использовании файлы, созданного PyInstaller. Сообщение об ошибке [PYI-17660:ERROR] Could not load PyInstaller's embedded PKG archive from the executable
указывает на то, что шелкод не может найти встраиваемую часть, необходимую для корректного выполнения.
Причина этого кроется в том, что PyInstaller использует специальную упаковку, включая дополнительные метаданные и файлы во время сборки. Поэтому, когда вы создаёте шелкод с использованием Donut, он не может корректно захватить все необходимые для выполнения элементы, которые включает в себя исполняемый файл PyInstaller.
Решения и рекомендации
Для успешной генерации шелкода, который может быть исполнен корректно, можно попробовать следующее:
-
Модификация исполняемого файла перед упаковкой: Убедитесь, что ваш скрипт, который вы собираетесь упаковать, не требует внешних ресурсов, которые не могут быть загружены динамически. Попробуйте упаковать все необходимые модули или статические ресурсы в один файл.
-
Использование альтернативных инструментов: Некоторые инструменты, такие как
pyarmor
, могут создать исполняемые файлы, которые легче преобразовать в шелкод. Попробуйте изменить подход к упаковке вашего Python-кода. -
Анализ зависимости файлов: Используйте утилиты, такие как
Dependency Walker
, чтобы изучить, какие зависимости ваш PyInstaller EXE требует для корректной работы. Возможно, вам придется учесть эти зависимости при генерации шелкода. -
Общий подход к созданию шелкода: Если вы по-прежнему сталкиваетесь с проблемами, рассмотрите возможность использования других методов кодирования и упаковки, которые могут быть более совместимыми с созданием шелкода.
-
Тест на простых приложениях: Начните с простых Python-программ и попробуйте создать шелкод для них, используя PyInstaller. Постепенно вводите более сложные зависимости, чтобы выявить, где начинается проблема.
-
Обратитесь за помощью в сообщество разработчиков: Если проблема не решается, вы можете обратиться на форумы, такие как Stack Overflow или GitHub, где другие разработчики могут поделиться опытом решения подобных вопросов.
Возможно, вам потребуется провести дополнительные эксперименты, чтобы найти наилучшее решение. Удачи в вашей работе!