Ghidra es genial, y me gusta escribir la mayor cantidad posible de mi RE. Pero la secuencia de comandos de Python de Ghidra se basa en Jython, que no está en un gran estado en estos días. Instalar nuevos paquetes es una molestia, si incluso pueden correr en un entorno de Jython, y solo empeorará a medida que Python 2 se apaga lentamente.
Entonces, Ghidra Bridge es un esfuerzo para evitar ese problema: en lugar de estar atrapado en Jython, establecer un proxy RPC para los objetos de Python, para que podamos llamar a Ghidra/Jython-Land para obtener los datos que necesitamos, luego traerlo de vuelta a un pitón más actualizado con todos los paquetes que necesita hacer su trabajo.
El objetivo es ser lo más transparente posible, por lo que una vez que esté configurado, no debe necesitar saber si un objeto es local o del ghidra remoto: el puente debe manejar sin problemas obtener/configurar/llamar contra él.
Si le gusta esto, también puede estar interesado en los equivalentes para otras herramientas de ingeniería inversa:
Si realmente te gusta esto, no dudes en comprarme un café: https://ko-fi.com/justfoxing
pip install ghidra_bridge
python -m ghidra_bridge.install_server ~/ghidra_scripts
Para un mejor caparazón interactivo como Ipython o si necesita bibliotecas Python 3 en su entorno interactivo, puede comenzar el puente en el contexto de una sesión de GUI interactiva.
De lo contrario:
Puede ejecutar Ghidra Bridge como un script de análisis posterior para un análisis sin cabeza y luego ejecutar un análisis adicional del cliente. Use el ghidra_bridge_server.py (no _background.py) para este, para que no salga hasta que cierre el puente hacia abajo.
$ghidraRoot/support/analyzeHeadless <path to directory to store project> <name for project> -import <path to file to import> -scriptPath <install directory for the server scripts> -postscript ghidra_bridge_server.py
Consulte AnalyzeheadlessReadme.html en el soporte/ directorio de Ghidra para obtener más información sobre cómo ejecutar el comando Analyzeheadless, si es necesario.
Puede iniciar el puente en un entorno sin ningún programa cargado, por ejemplo, si desea acceder a una API como el DatatyPemanager que no requiere un programa que se analice
$ghidraRoot/support/pythonRun <install directory for the server scripts>/ghidra_bridge_server.py
Del entorno de python del cliente:
import ghidra_bridge
with ghidra_bridge . GhidraBridge ( namespace = globals ()):
print ( getState (). getCurrentAddress (). getOffset ())
ghidra . program . model . data . DataUtilities . isUndefinedData ( currentProgram , currentAddress )o
import ghidra_bridge
b = ghidra_bridge . GhidraBridge ( namespace = globals ()) # creates the bridge and loads the flat API into the global namespace
print ( getState (). getCurrentAddress (). getOffset ())
# ghidra module implicitly loaded at the same time as the flat API
ghidra . program . model . data . DataUtilities . isUndefinedData ( currentProgram , currentAddress )ADVERTENCIA: si se ejecuta en modo no retacable, evite hacer clic en el botón "Cancelar" en la ventana emergente del script, ya que esto dejará el enchufe del servidor en un estado malo, y tendrá que cerrar por completo Ghidra para solucionarlo.
Para apagar el servidor limpiamente, si ha realizado el paso 3 en las instrucciones de instalación anteriores, haga clic en Herramientas-> Ghidra Bridge-> apagado. De lo contrario, ejecute el script ghidra_bridge_server_shutdown.py desde la carpeta del puente.
Alternativamente, puede llamar a Remote_Shutdown desde cualquier cliente conectado.
import ghidra_bridge
b = ghidra_bridge . GhidraBridge ( namespace = globals ())
b . remote_shutdown ()Tenga en cuenta que cuando se ejecuta, un servidor Ghidra Bridge proporciona efectivamente la ejecución del código como servicio. Si un atacante puede hablar con el puente de Port Ghidra está funcionando, puede obtener una ejecución trivial con los privilegios con los que se ejecuta Ghidra.
También tenga en cuenta que el protocolo utilizado para enviar y recibir mensajes de puente Ghidra no está certificado y no verificado: un ataque de persona en el medio permitiría un control completo de los comandos y respuestas, nuevamente proporcionando la ejecución del código trivial en el servidor (y con un poco más de trabajo, en el cliente).
Por defecto, el servidor Ghidra Bridge solo escucha en Localhost para reducir ligeramente la superficie del ataque. Solo escuche en direcciones de red externas si está seguro de que está en una red donde es seguro hacerlo. Además, todavía es posible que los atacantes envíen mensajes a localhost (por ejemplo, a través de JavaScript malicioso en el navegador, o explotando un proceso diferente y atacando el puente Ghidra para elevar los privilegios). Puede mitigar este riesgo ejecutando Ghidra Bridge desde un servidor Ghidra con permisos reducidos (un usuario no administrativo o dentro de un contenedor), solo ejecutándolo cuando sea necesario, o ejecutándose en sistemas conectados sin red.
Ghidra Bridge está diseñado para ser transparente, para permitir una fácil portada de scripts no bridados sin demasiados cambios. Sin embargo, si está contento de hacer cambios, y se encuentra con la desaceleración causada por la ejecución de muchas consultas remotas (por ejemplo, algo así como for function in currentProgram.getFunctionManager().getFunctions(): doSomething() requiere solo un mensaje de ida y vuelta.
El siguiente ejemplo demuestra obtener una lista de todos los nombres de todas las funciones en un binario:
import ghidra_bridge
b = ghidra_bridge . GhidraBridge ( namespace = globals ())
name_list = b . remote_eval ( "[ f.getName() for f in currentProgram.getFunctionManager().getFunctions(True)]" )Si su evaluación llevará algún tiempo, es posible que deba usar el argumento TimeOut_override para aumentar cuánto tiempo esperará el puente antes de decidir que las cosas salieran mal.
Si necesita proporcionar un argumento para la evaluación remota, puede proporcionar argumentos arbitrarios de palabras clave a la función remota_eval que se transmitirá al contexto de evaluación como variables locales. El siguiente argumento pasa en una función:
import ghidra_bridge
b = ghidra_bridge . GhidraBridge ( namespace = globals ())
func = currentProgram . getFunctionManager (). getFunctions ( True ). next ()
mnemonics = b . remote_eval ( "[ i.getMnemonicString() for i in currentProgram.getListing().getInstructions(f.getBody(), True)]" , f = func )Como simplificación, tenga en cuenta también que el contexto de evaluación tiene los mismos globales cargados en el __main__ del script que inició el servidor; en el caso del servidor Ghidra Bridge, estos incluyen la API plana y los valores como el Programa actual.
Si tiene una llamada particularmente lenta en su guión, puede alcanzar el tiempo de espera de respuesta que el puente usa para asegurarse de que la conexión no se haya roto. Si esto sucede, verá algo como Exception: Didn't receive response <UUID> before timeout .
Hay dos opciones para aumentar el tiempo de espera. Al crear el puente, puede establecer un valor de tiempo de espera en segundos con el argumento Response_TimeOut (por ejemplo, b = ghidra_bridge.GhidraBridge(namespace=globals(), response_timeout=20) ) que se aplicará a todos los comandos que se encuentran con el puente. Alternativamente, si solo desea cambiar el tiempo de espera de un comando, puede usar remoto_eval como se mencionó anteriormente, con el argumento TimeOut_override (por ejemplo, b.remote_eval("[ f.getName() for f in currentProgram.getFunctionManager().getFunctions(True)]", timeout_override=20) ). Si usa el valor -1 para cualquiera de estos argumentos, el tiempo de espera de respuesta se deshabilitará y el puente esperará para siempre que su respuesta regrese: tenga en cuenta que esto puede hacer que su script se cuelgue si el puente se encuentra con problemas.
Si desea importar módulos del lado de Ghidra (por ejemplo, Ghidra, Java, espacios de nombres de acoplamiento), tiene dos opciones.
remote_module = b.remote_import("java.math.BigInteger") ). Esto tiene la ventaja de que tiene un control exacto sobre obtener el módulo remoto (y puede obtener módulos remotos con el mismo nombre que los módulos locales) y cuando se libera, pero requiere un poco más de trabajo.b = ghidra_bridge.GhidraBridge(namespace=globals(), hook_import=True) Ej. Esto agregará un gancho a la maquinaria de importación de modo que, si nada más puede llenar la importación, el puente intentará manejarlo. Esto le permite usar la sintaxis de import ghidra.framework.model.ToolListener estándar. Esto tiene la ventaja de que puede ser un poco más fácil de usar (aún tiene que asegurarse de que las importaciones ocurran después de que el puente esté conectado), pero no le permite importar módulos remotos con el mismo nombre que los módulos locales (las importaciones locales toman prioridad) y coloca los módulos remotos en SYS.módulos como las importaciones adecuadas, por lo que ellos y el puente probablemente permanecerán cargados hasta que el proceso termine. Además, múltiples puentes con Hook_import = True intentarán resolver las importaciones en el orden que estaban conectados, que puede no ser el comportamiento que desee.Normalmente, los guiones de Ghidra obtienen una instancia de las variables de Ghidra State y Current* (CurrentProgram, CurrentAddress, etc.) cuando se inicia por primera vez, y no se actualiza mientras se ejecuta el script. Sin embargo, si ejecuta el intérprete Ghidra Python, que actualiza su estado con cada comando, por lo que CurrentAddress siempre coincide con la GUI.
Para reflejar esto, Ghidrabridge intentará automáticamente determinar si está ejecutando el cliente en un entorno interactivo (por ejemplo, el intérprete de Python, Ipython) o simplemente desde un script. Si es un entorno interactivo, registrará un oyente de eventos con Ghidra y realizará algunas travesuras detrás de escena para asegurarse de que el estado se actualice con cambios en la GUI para comportarse como el intérprete Ghidra Python. También reemplazará help() con una que se comunique para usar la ayuda de Ghidra en el puente si le da un objeto puenteado.
No debería tener que preocuparse por esto, pero si por alguna razón la detección automática no le da el resultado que necesita, puede especificar el argumento Boolean Interactive_Mode al crear su cliente Ghidrabridge para que lo encienda o desactive según sea necesario.
El código RPC del puente real se implementa en JFX-Bridge. Compruébelo y presente problemas específicos no ghidra relacionados con el puente allí.