Ghidra est génial et j'aime scripter autant que possible. Mais les scripts Python de Ghidra sont basés sur Jython, qui n'est pas dans un grand état de nos jours. L'installation de nouveaux packages est un problème, s'ils peuvent même fonctionner dans un environnement Jython, et cela ne fera qu'empirer à mesure que Python 2 est lentement éteint.
Donc, Ghidra Bridge est un effort pour contourner ce problème - au lieu d'être coincé dans Jython, configurez un proxy RPC pour les objets Python, afin que nous puissions appeler Ghidra / Jython-Land pour obtenir les données dont nous avons besoin, puis le ramener à un python plus récent avec tous les packages dont vous avez besoin pour faire votre travail.
L'objectif est d'être aussi transparent que possible, donc une fois que vous êtes configuré, vous ne devriez pas avoir besoin de savoir si un objet est local ou à partir du Ghidra distant - le pont doit gérer de manière transparente / régler / appeler contre lui.
Si vous aimez cela, vous pourriez également être intéressé par les équivalents pour d'autres outils d'ingénierie inverse:
Si vous aimez vraiment ça, n'hésitez pas à m'acheter un café: https://ko-fi.com/justfoxing
pip install ghidra_bridge
python -m ghidra_bridge.install_server ~/ghidra_scripts
Pour un meilleur shell interactif comme Ipython ou si vous avez besoin de bibliothèques Python 3 dans votre environnement interactif, vous pouvez démarrer le pont dans le contexte d'une session GUI interactive.
Sinon:
Vous pouvez exécuter Ghidra Bridge en tant que script d'analyse de post pour une analyse sans tête, puis exécuter une analyse plus approfondie du client. Utilisez le ghidra_bridge_server.py (pas _background.py) pour celui-ci, donc il ne sort pas tant que vous n'aurez pas fermé le pont.
$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
Voir le AnalyseheadlessReadme.html dans le support / répertoire de Ghidra pour plus d'informations sur la façon d'exécuter la commande Analyzeheadless, si nécessaire.
Vous pouvez démarrer le pont dans un environnement sans aucun programme chargé, par exemple si vous souhaitez accéder à une API comme le DatatypeManager qui ne nécessite pas un programme analysé
$ghidraRoot/support/pythonRun <install directory for the server scripts>/ghidra_bridge_server.py
Du client Python Environnement:
import ghidra_bridge
with ghidra_bridge . GhidraBridge ( namespace = globals ()):
print ( getState (). getCurrentAddress (). getOffset ())
ghidra . program . model . data . DataUtilities . isUndefinedData ( currentProgram , currentAddress )ou
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 )AVERTISSEMENT: Si vous exécutez en mode non-fond, évitez de cliquer sur le bouton "Annuler" sur la fenêtre contextuelle du script, car cela laissera la prise du serveur à un mauvais état, et vous devrez fermer complètement Ghidrera pour le réparer.
Pour arrêter le serveur proprement, si vous avez fait l'étape 3 dans les instructions d'installation ci-dessus, cliquez sur Tools-> Ghidra Bridge-> Arrêt. Sinon, exécutez le script ghidra_bridge_server_shutdown.py du dossier de pont.
Alternativement, vous pouvez appeler Remote_shutdown à partir de tout client connecté.
import ghidra_bridge
b = ghidra_bridge . GhidraBridge ( namespace = globals ())
b . remote_shutdown ()Sachez que lors de l'exécution, un serveur Ghidra Bridge fournit effectivement l'exécution de code en tant que service. Si un attaquant est en mesure de parler au pont de Port Ghidra, il peut trivialement gagner l'exécution avec les privilèges avec lesquels Ghidra est exécuté.
Sachez également que le protocole utilisé pour l'envoi et la réception des messages de pont Ghidra n'est pas crypté et non vérifié - une attaque personne dans le milieu permettrait un contrôle complet des commandes et des réponses, fournissant à nouveau l'exécution de code trivial sur le serveur (et avec un peu plus de travail, sur le client).
Par défaut, le serveur de pont Ghidra écoute uniquement sur LocalHost pour réduire légèrement la surface d'attaque. Écoutez uniquement sur les adresses réseau externes si vous êtes convaincu que vous êtes sur un réseau où il est sûr de le faire. De plus, il est toujours possible pour les attaquants d'envoyer des messages à LocalHost (par exemple, via un JavaScript malveillant dans le navigateur, ou en exploitant un processus différent et en attaquant le pont Ghidra pour élever les privilèges). Vous pouvez atténuer ce risque en exécutant un pont Ghidra à partir d'un serveur Ghidra avec des autorisations réduites (un utilisateur non-trajet ou à l'intérieur d'un conteneur), en l'exécutant uniquement en cas de besoin, ou en fonctionnant sur des systèmes connectés non à réseau.
Ghidrera Bridge est conçu pour être transparent, afin de permettre un portage facile des scripts non pontés sans trop de changements. Cependant, si vous êtes heureux d'apporter des modifications et que vous rencontrez des ralentissements causés par l'exécution de nombreuses requêtes à distance (par exemple, quelque chose comme for function in currentProgram.getFunctionManager().getFunctions(): doSomething() peut être assez lent avec un grand nombre de fonctions car chaque fonction entraînera un message sur le pont), vous pouvez utiliser la fonction de télécommande () pour que le résultat soit évalué sur le pont sur le pont, qui sera à distance () Fonction Ne nécessite qu'une seule aller-retour de message.
L'exemple suivant montre l'obtention d'une liste de tous les noms de toutes les fonctions d'un binaire:
import ghidra_bridge
b = ghidra_bridge . GhidraBridge ( namespace = globals ())
name_list = b . remote_eval ( "[ f.getName() for f in currentProgram.getFunctionManager().getFunctions(True)]" )Si votre évaluation va prendre un certain temps, vous devrez peut-être utiliser l'argument Timeout_override pour augmenter la durée du pont avant de décider des choses qui ont mal tourné.
Si vous devez fournir un argument pour l'évaluation à distance, vous pouvez fournir des arguments de mots clés arbitraires à la fonction Remote_eval qui sera transmis dans le contexte d'évaluation en tant que variables locales. L'argument suivant passe dans une fonction:
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 )En tant que simplification, notez également que le contexte d'évaluation a les mêmes globaux chargés dans le __main__ du script qui a commencé le serveur - dans le cas du serveur de pont Ghidra, il s'agit notamment de l'API plate et des valeurs telles que le programme actuel.
Si vous avez un appel particulièrement lent dans votre script, il peut appuyer sur le délai d'expiration de la réponse que le pont utilise pour vous assurer que la connexion n'a pas cassé. Si cela se produit, vous verrez quelque chose comme Exception: Didn't receive response <UUID> before timeout .
Il existe deux options pour augmenter le délai d'attente. Lors de la création du pont, vous pouvez définir une valeur de délai d'expiration en secondes avec l'argument Response_timeout (par exemple, b = ghidra_bridge.GhidraBridge(namespace=globals(), response_timeout=20) ) qui s'appliquera à toutes les commandes qui traversent le pont. Alternativement, si vous souhaitez simplement modifier le délai d'attente d'une commande, vous pouvez utiliser Remote_eval comme mentionné ci-dessus, avec l'argument Timeout_override (par exemple, b.remote_eval("[ f.getName() for f in currentProgram.getFunctionManager().getFunctions(True)]", timeout_override=20) . Si vous utilisez la valeur -1 pour l'un ou l'autre de ces arguments, le délai de réponse sera désactivé et le pont attendra éternellement que votre réponse reviendra - notez que cela peut entraîner la suspension de votre script si le pont rencontre des problèmes.
Si vous souhaitez importer des modules à partir de la side Ghidra (par exemple, Ghidra, Java, Acosing Espaces), vous avez deux options.
remote_module = b.remote_import("java.math.BigInteger") ). Cela a l'avantage que vous avez un contrôle exact sur l'obtention du module distant (et que vous pouvez obtenir des modules distants avec le même nom que les modules locaux) et lorsqu'il est libéré, mais cela prend un peu plus de travail.b = ghidra_bridge.GhidraBridge(namespace=globals(), hook_import=True) ). Cela ajoutera un crochet à la machinerie d'importation de telle sorte que, si rien d'autre ne peut remplir l'importation, le pont essaiera de le gérer. Cela vous permet d'utiliser simplement l' import ghidra.framework.model.ToolListener Syntaxe après avoir connecté le pont. Cela a l'avantage qu'il peut être un peu plus facile à utiliser (vous devez toujours vous assurer que les importations se produisent après la connexion du pont), mais cela ne vous permet pas d'importer des modules à distance avec le même nom que les modules locaux (les importations locales ont la priorité) et il place les modules distants dans les SYS.Modules que les importations appropriées, de sorte qu'ils et le pont resteront probablement chargés jusqu'à ce que le processus se termine. De plus, plusieurs ponts avec hook_import = true tenteront de résoudre les importations dans l'ordre où elles étaient connectées, ce qui peut ne pas être le comportement que vous souhaitez.Normalement, les scripts Ghidra obtiennent une instance de l'état de Ghidra et des variables actuels * (CurrentProgram, CurrentAddress, etc.) au début, et il ne met pas à jour pendant que le script s'exécute. Cependant, si vous exécutez l'interpréteur Ghidra Python, qui met à jour son état avec chaque commande, de sorte que CurrentAddress correspond toujours à l'interface graphique.
Pour refléter cela, Ghidrabridge tentera automatiquement de déterminer si vous exécutez le client dans un environnement interactif (par exemple, l'interprète Python, Ipython) ou tout simplement à partir d'un script. S'il s'agit d'un environnement interactif, il enregistrera un auditeur d'événements avec Ghidra et effectuera des manigances douteuses dans les coulisses pour s'assurer que l'État est mis à jour avec des changements d'interface graphique pour se comporter comme l'interpréteur Ghidra Python. Il remplacera également help() par une qui tend la main pour utiliser l'aide de Ghidra à travers le pont si vous lui donnez un objet ponté.
Vous ne devriez pas avoir à vous soucier de cela, mais si pour une raison quelconque, la détection automatique ne vous donne pas le résultat dont vous avez besoin, vous pouvez spécifier l'argument booléen interactif_mode lors de la création de votre client Ghidrabridge pour le forcer ou désactiver au besoin.
Le code RPC de pont réel est implémenté dans JFX-Bridge. Vérifiez-le et déposiez des problèmes spécifiques non Ghidira liés au pont là-bas.