Question:
Comment ajouter des fonctionnalités à un exécutable binaire existant?
asheeshr
2013-03-23 18:55:13 UTC
view on stackexchange narkive permalink

Je souhaite ajouter des fonctionnalités à un fichier binaire existant. Le fichier binaire a été créé en utilisant gcc .

  • Dois-je d'abord décompiler le binaire, même si je comprends suffisamment le fonctionnement du programme?
  • Comment dois-je procéder pour ajouter le code nécessaire?
  • Ai-je besoin d'outils pour pouvoir le faire?
pour quelle plate-forme, par exemple Windows, Linux?
Quelle est la fonctionnalité que vous souhaitez ajouter? car en fonction de cela, il existe différentes approches. Par exemple, pour automatiser une interface graphique, vous utilisez une technique différente, par exemple la modification d'un moteur de base de données.
http://stackoverflow.com/questions/4309771/disassembling-modifying-and-then-reassembling-a-linux-executable
Huit réponses:
#1
+38
Ed McMan
2013-03-23 20:47:41 UTC
view on stackexchange narkive permalink

Il existe plusieurs façons de procéder.

  1. Instrumentation dynamique

    Des outils tels que NIP, Valgrind ou DynamoRIO vous permettent de modifier dynamiquement le comportement d'un programme. Par exemple, vous pouvez ajouter des appels à de nouvelles fonctions à des adresses particulières, intercepter les appels de bibliothèque et les modifier, et bien plus encore.

    L'inconvénient est que l'instrumentation dynamique a souvent une surcharge élevée.

  2. Instrumentation statique

    Vous pouvez également essayer de modifier statiquement le programme pour ajouter le comportement souhaité. Un défi est que vous devez souvent vous débrouiller avec le format de fichier exécutable. Certains outils, comme elfsh du projet ERESI existent pour cela, mais je les ai trouvés bogués et difficiles à utiliser.

    Une autre stratégie pour la statique l'instrumentation consiste à "recompiler". Vous pouvez le faire en décompilant le programme, en modifiant le code source et en recompilant. En théorie, vous pouvez également utiliser un outil comme BAP pour élever le programme en IL, le modifier, puis le recompiler en utilisant LLVM. Cependant, la version actuelle n'est probablement pas assez mature pour cela.

  3. Chargement dynamique

    Vous pouvez utiliser LD_PRELOAD pour remplacer des fonctions qui vont être liés dynamiquement. C'est une option intéressante lorsque vous souhaitez modifier le comportement d'une fonction de bibliothèque. Naturellement, cela ne fonctionne pas sur les binaires liés statiquement, ni pour les fonctions statiques.

  4. Corrections binaires

    Vous pouvez souvent apporter de simples modifications à un binaire en éditeur hexadécimal. Par exemple, si vous souhaitez ignorer un appel de fonction ou une branche, vous pouvez souvent le remplacer par des instructions nop . Si vous devez ajouter une grande quantité de nouveau code, vous devrez probablement utiliser quelque chose comme elfsh du projet ERESI pour vous aider à redimensionner le binaire.

#2
+17
Gilles 'SO- stop being evil'
2013-03-23 19:53:18 UTC
view on stackexchange narkive permalink

Très souvent, vous pouvez changer le comportement d'un programme en vous y accrochant soigneusement. La possibilité d'ajouter les fonctionnalités souhaitées de cette manière dépend de la manière dont le programme est construit. Cela aide si le programme se présente sous la forme d'un exécutable principal plus plusieurs bibliothèques.

Vous pouvez vous connecter à n'importe quel appel que le programme fait aux bibliothèques partagées en liant d'abord votre propre bibliothèque, avec LD_PRELOAD . Écrivez une bibliothèque qui définit une fonction foo et définissez la variable d'environnement LD_PRELOAD sur le chemin de votre bibliothèque compilée ( .so ) lorsque vous démarrez le programme: alors le programme appellera votre toto au lieu de celui qu'il souhaite. Vous pouvez appeler la fonction d'origine foo depuis votre remplaçant en obtenant un pointeur vers elle avec dlsym().

Voici quelques exemples et tutoriels:

Quelques exemples de programmes utilisant LD_PRELOAD:

La limitation de LD_PRELOAD est que vous ne pouvez intercepter que les appels de fonction qui sont résolus à l'exécution (liaison dynamique ). Si vous souhaitez intercepter un appel interne, vous devrez recourir à des techniques plus lourdes (modification de l'exécutable sur disque ou en mémoire avec ptrace ).

#3
+7
Michael Anderson
2013-03-23 22:06:39 UTC
view on stackexchange narkive permalink

Je souhaite ajouter des fonctionnalités à un fichier binaire existant.

Donc, en général, ces quatre grandes questions s'appliquent à la modification d'un exécutable:

La première question de base posée: Le programme se méfie-t-il des modifications de code (auto-vérification, anti-débogage-astuces, protection contre la copie, ...)?

Si oui:

  1. Est-il même possible de supprimer / contourner ces protections (par exemple le déballage, si elle est emballée) facilement
  2. Cela vaut-il la peine de le faire?
  3. ol>

    La deuxième question est:
    Pouvez-vous savoir quel compilateur / langage a été utilisé pour produire l'exécutable?

    Plus de détails, c'est mieux, mais la plupart les constructions de base ( if et d'autres structures de contrôle) devraient être mappées de manière assez similaire sur une variété de compilateurs.

    Ceci est lié à une précédente question sur RE-Stackexchange.


    Comment l'interface utilisateur est-elle implémentée (CLI, Win32-Window Controls, Custom, ...)?

    Si cela est connu:
    Pouvez-vous déterminer le mappage des constructions HLL courantes (Menues, Dropdown-Menues, Checkboxes, ...) en conjonction avec le compilateur / langage utilisé que vous souhaitez modifier?

    La quatrième et plus grande question est:
    Comment pouvez-vous créer la fonctionnalité souhaitée dans le programme?

    En substance, cela peut nécessiter un peu d'inverse ingénierie, pour savoir comment s'intégrer au mieux au programme sans le perturber.

    Point central: Comment pouvez-vous utiliser les API internes existantes pour atteindre votre objectif, sans casser des trucs (comme CRTL + Z, gestion des versions, récupération fonctionnalités)?

  • Structures de données existantes (et comment sont-elles liées?)
  • Fonctions existantes (paramètres, format de paramètre, ...)
    • Que fait-il?
    • Que peut-il faire d'autre?
    • Que fait-il VRAIMENT?
    • ...
  • Processus existants (= Comment le programme fonctionne en interne, par étapes pour implémenter des fonctionnalités similaires)
    • Quelles fonctions sont appelées, dans quel ordre?
    • Quelles structures de données sont utilisées?
  • Où se trouve la viande de la fonction / du programme (les données, par exemple la zone de peinture principale, et comment se rapporte-t-elle en interne?)
  • Stuff to recherchez (si cela concerne la fonctionnalité souhaitée):
    • Journalisation
    • Fonctionnalités de récupération
    • Versioning
  • Comment les métadonnées sont-elles gérées (par exemple, vitesse d'obturation, f-Stops, ...), qui sont liées à la fonctionnalité souhaitée.

Exemples de projets: b>

  • Construire un nouveau type d'outil de peinture dans un programme graphique (sans plugin-API).
  • Extension de l'API plugin d'un programme.
  • Construction d'un plugin-API dans un programme sans un.
  • Ajout d'un nouveau format de sauvegarde / export pour les fichiers (s'il n'y a aucun moyen de convertir le format de sortie dans un format souhaité, ou si des informations cruciales sont manquantes dans le f exporté iles).
  • Ajout d'un nouveau format d'importation (s'il n'y a aucun moyen de convertir le format d'entrée en un format importable ou si certaines informations ne sont pas correctement importées).
  • Extension de Mspaint avec un outil de recherche et de remplacement des couleurs (dans une sélection ou dans l'image entière)
  • Ajout de la prise en charge du proxy / de l'authentification proxy de base à un programme.
  • Ajout de ( new) La ligne de commande bascule vers un programme qui expose des fonctionnalités nouvelles / existantes.
  • Ajout d'une API pour les appels de procédure à distance pour gérer les opérations du programme en externe.
  • Ajout de la prise en charge des scripts pour automatiser les opérations souvent répétées (s'il n'y a pas d'API de plugin / script pour commencer) ou de prendre en charge le traitement par lots.

Concernant les décompilateurs de code & encapsulés: Je ne parlerai pas du code enveloppé dans d'autres langages qui est emballé avec une VM / un interpréteur (Py2Exe, Java 2 Exe, ...), ou en utilise un installé (JVM, C #). Il existe de très bons décompilateurs pour certains de ces cas. Après une décompilation réussie, cela revient à vaincre l'obfuscation du code (s'il y en a un).

Concernant C / C ++ - Décompilateurs:
Je ne peux pas parler de C / C ++ - Décompilateurs, même si cela se résumerait à un remappage HLL au mieux (pour les choses que le décompilateur n'a pas obtenu) et à la désobfuscation du code (s'il était compilé sans symboles) à condition qu'il n'y ait pas de protection supplémentaire dans l'exécutable.

Recommandation concernant le mappage HLL:
Essentiellement, une grande partie de cette question concerne le "mappage HLL" (mappage de langage de haut niveau (en code machine)) et la modification de ces constructions dans le code machine correspondant.

J'ai trouvé un excellent cours de départ téléchargeable, qui utilise "IDA Free", sur ce sujet ici (binary-auditing.com).

#4
+7
Ange
2013-03-26 12:49:26 UTC
view on stackexchange narkive permalink

(Légèrement obsolète, mais comme cela n'a pas été mentionné précédemment dans ce fil)

Il y a longtemps, j'ai passé des mois à étendre un logiciel avec uniquement le binaire.

  • J'ai utilisé IDA pour l'analyse et SoftICE pour le débogage en direct. La décompilation n'est pas nécessaire si vous pouvez comprendre la cible au niveau de l'opcode / bytecode.
  • Ensuite, comme il s'agissait d'un binaire PE x86, j'ai utilisé le Code Snippet Creator strong de Tasm et Iczelion >: Ce n'est plus un outil célèbre, mais il a permis d'utiliser Tasm de manière transparente et de réinjecter du code, avec des transformations PE, etc ...

    Il a ajouté du code à EntryPoint, donc j'ai fait mes propres correctifs manuellement , puis est passé à EntryPoint d'origine.

Un peu old-school maintenant - j'injecterais probablement une DLL ces jours-ci - mais cela fonctionnait certainement.

Et au moins, cela vous donne un contrôle total via ASM, tout en gardant la maintenabilité via des correctifs automatisés.

#5
+6
Andrew
2013-03-23 19:30:43 UTC
view on stackexchange narkive permalink

Vous n'avez pas besoin de décompiler le binaire. Si vous comprenez les modifications que vous souhaitez apporter et que ces modifications peuvent être apportées en modifiant uniquement le fichier binaire ou ses dépendances, vous pouvez simplement effectuer ces modifications sur le disque ou en mémoire.

Vous avez quelques choix sur la façon d'effectuer la modification elle-même.

Vous pouvez utiliser LD_PRELOAD pour que l'éditeur de liens charge un objet partagé avant l'exécution du binaire. Ensuite, vous n'avez pas du tout besoin de modifier le binaire sur le disque. C'est un peu ce que fait valgrind, il se charge en tant qu'objet partagé mais commence ensuite l'instrumentation binaire dynamique.

Vous pouvez utiliser valgrind. Valgrind vous permettrait de réécrire dynamiquement le programme et de modifier son comportement de manière arbitraire. Valgrind est un programme d'instrumentation binaire dynamique qui permet à ses outils d'éditer le programme pendant son exécution. Si vous voulez juste changer le comportement du programme, cela pourrait fonctionner, mais valgrind subit également un ralentissement global et si vous vouliez patcher et redistribuer un programme, ce n'est probablement pas idéal.

Vous pouvez également utiliser des outils comme elfsh / eresi pour insérer un nouveau code dans le programme. Ces outils devraient prendre soin d'injecter votre code par rapport à des éléments tels que l'en-tête du programme ELF. Il existe un concept d '«infecteur ELF» que vous pourriez rechercher sur Google, où votre code injecté devient le nouveau point d'entrée du programme, fait quelque chose, puis saute vers l'ancien point d'entrée du programme.

#6
+6
0xC0000022L
2013-04-07 03:19:50 UTC
view on stackexchange narkive permalink

Faire cela sous Windows

Bien que cette question se concentre sur Linux, où personnellement j'irais avec la méthode simple LD_PRELOAD comme indiqué dans d'autres réponses, Windows connaît un mécanisme similaire qui en fait, a été abusé dans un passé plus récent (voir également les approches alternatives ci-dessous). J'ai utilisé cette méthode pour "cracker" un système de dongle.

Entrez ...

Attaques de placement de DLL (alias préchargement, alias détournement)

Le nom a a été donnée à la méthode assez récemment quand il s'est avéré que placer des DLL sur des partages distants, puis naviguer vers des partages, par exemple dans un lecteur multimédia, entraînerait le chargement de la DLL distante par le lecteur multimédia au lieu d'une version locale. C'est par conception. Le changer maintenant casserait des centaines sinon des milliers d'applications.

Ce problème a été résolu par Microsoft de certaines manières, bien que la seule vraie solution soit une mise en œuvre correcte du côté des applications. Mais alors, de nombreux développeurs n'ont même pas compris la sécurité NT même si nous devons y faire face depuis que Windows 2000 est devenu le premier OS grand public basé sur la plate-forme NT.

Qu'est-ce que cela a à voir avec votre Objectif décrit?

L'ajout de fonctionnalités n'implique pas nécessairement que vous corrigiez l'exécutable sur le disque. Vous pouvez également le faire en mémoire.

Comment pouvez-vous en tirer parti?

Chaque fois qu'une application utilise une DLL, et vous pouvez indiquer l'ordre de chargement avec Dependency Walker ou sous un débogueur, vous pouvez choisir l'une des DLL qu'il importe et la remplacer (à son emplacement actuel) ou placer une autre DLL dans un chemin qui précède la DLL existante dans l'ordre de chargement.

Un Une autre méthode consiste à changer le nom des DLL importées. Dans de rares cas (DLL bien connues, par exemple), c'est la seule méthode viable pour charger une DLL alternative et peut encore échouer dans certains cas particuliers.

Limitations

Si la DLL utilisée existe au premier emplacement de l'ordre de recherche des DLL, vous devrez littéralement remplacer le fichier sur le disque, sauf si vous renommez l'importation comme brièvement mentionné ci-dessus.

Implémentations

Une approche manuelle peut être utilisée pour les DLL avec seulement quelques symboles exportés. Le plus simple serait de créer un fichier de définition de module à partir de la DLL et de créer une DLL avec uniquement des redirecteurs de fonctions. De cette façon, votre DLL placée serait déjà chargée et passerait simplement par les appels.

Cependant, cette approche échouera avec les variables exportées (par opposition aux fonctions).

Voici un simple Script Python basé sur pefile que j'ai écrit pour une autre réponse sur StackOverflow:

  import osimport sysimport redef main (pename): depuis pefile import PE print "Parsing% s"% pename pe = PE (pename) modname = os.path.basename (pename) libname = re.sub (r "(? i) ^. *? ( [^ \\ /] +) \. (?: dll | exe | sys | ocx) $ ", r" \ 1.lib ", modname) defname = libname.replace (". lib "," .def ") print "Ecriture du fichier de définition du module% s pour% s"% (defname, modname) f = open (defname, "w") # veux qu'il soit renvoyé, pas de gestion d'erreur sophistiquée ici f.write ("LIBRARY% s \ n \ n "% modname) f.write (" EXPORTS \ n ") numexp = 0 pour exp dans pe.DIRECTORY_ENTRY_EXPORT.symbols: si exp.name: numexp + = 1 f.write (" \ t% s \ n "% exp .name) print "A écrit% s avec% d exportations "% (defname, numexp) print" \ n \ nUtilisez ceci pour créer la librairie d'exportation: \ n \ tlib / def:% s / out:% s "% (defname, libname) si __name__ == '__main__': if len (sys.argv)! = 2: sys.stderr.write ("ERREUR: \ n \ tSyntax: fakelib <dllfile> \ n") sys.exit (1) sys.exit (main (sys.argv) [1]))  

Vous pouvez l'ajuster pour créer des redirecteurs de fonctions au lieu d'une simple définition de module avec des noms exportés.

Donc ceci façon dont vous pouvez transférer votre code dans l'application cible et partir de là.

Approches alternatives

L'instrumentation et l'accrochage ont déjà été mentionnés. Detours est un exemple souvent mentionné d'accrochage avec un CLUF peu pratique pour la plupart des raisons pratiques. Reportez-vous aux réponses existantes pour ce type d'approche.

Vous pouvez également utiliser la valeur de registre AppInit_DLL pour injecter une DLL au début. Ou vous pouvez écrire un petit lanceur avec une boucle de débogage et utiliser Options d'exécution de fichier image pour que votre cible lance d'abord votre débogueur. Un débogueur peut également influencer le chargement de la DLL ou simplement intercepter - de manière pratique - les appels à la frontière entre l'exécutable et les DLL.

Trivia: voici ( Options d'exécution de fichier image ) comment Process Explorer remplace le Gestionnaire de tâches lorsque vous choisissez l'option dans Process Explorer.


Vous remarquerez comment vous pouvez classer ces approches dans les catégories Ed McMan mentionnées dans sa réponse déjà. Cependant, je vais laisser cela comme un exercice au lecteur :)

#7
+3
jyz
2013-03-23 20:36:48 UTC
view on stackexchange narkive permalink

J'ai fait cela avec Notepad.exe sous Windows. Je voulais ajouter un élément du menu supérieur pour ouvrir calc.exe juste pour le plaisir (je sais que votre question est étiquetée Linux et gcc compilateur, mais l'idée est probablement la même).

J'ai donc utilisé Outil Resource Hacker pour ajouter le menu Calc et ouvrir notepad.exe sur Immunity Debugger à la recherche d'un espace dans le code où je pourrais mettre mon shellcode WinExec. Au départ, je n'ai pas changé l'exécutable, j'ai dû regarder le programme en mémoire pour trouver un espace où je pourrais coller mes instructions d'assemblage sans planter le bloc-notes.

Une fois que j'ai trouvé assez d'espace (en changeant le code d'origine en en éliminant certaines instructions d'assemblage inutiles ou même en les optimisant) J'ai ouvert notepad.exe sur XVI Hex Editor et j'ai recherché les opcodes qui s'exécutaient sur Immunity. Je veux dire, le débogueur exécutait des opcodes, non? J'ai juste cherché une séquence d'opcodes pour être sûr que j'étais au bon morceau du logiciel que je voulais changer et l'ai pacthé avec mon shellcode (maintenant ce n'est pas du code d'assemblage mais l'assemblage "compilé" - code machine)

Encore une fois: je sais que votre question est étiquetée Linux et compilateur gcc, mais peut-être que quelqu'un pourrait indiquer quelques outils sous Linux pour obtenir la même chose que j'ai fait sur Windows. L'idée est probablement la même.

#8
+1
Peter Teoh
2014-11-15 13:38:19 UTC
view on stackexchange narkive permalink

"ptrace ()" a été mentionné avec désinvolture par Giles. Mais je pense qu'il méritait une section entière à lui seul. "ptrace ()" est une API d'appel système fournie par OS (Linux et tous les UNIX l'ont, et Windows aussi) pour exercer un contrôle de débogage sur un autre processus. Lorsque vous avez utilisé PTRACE_ATTACH (dans le cadre de ptrace ()) pour vous attacher à un autre processus, le noyau suspendra complètement le processeur exécutant ce processus, vous permettant ainsi d'apporter des modifications à N'IMPORTE QUELLE partie du processus: CPU, tous les registres, toute partie de cela mémoire de processus, etc. C'est ainsi que fonctionne le hooking dynamique en ligne. (ptrace () attach, modifie le binaire en mémoire, puis ptrace () unattached). Pour autant que je sache, toute modification dynamique d'un autre processus doit utiliser ptrace () - car c'est le seul mécanisme fourni par le noyau pour garantir l'intégrité via un appel système à ce stade.

Mais récemment, une API similaire comme utrace () apparaît, et donc le raccordement en ligne est également théoriquement possible:

http://landley.net/kdocs/ols/2007/ols2007v1-pages-215-224.pdf

Pour le hooking du noyau, il existe de nombreuses méthodes: syscall, interruption et inline hooking. Ceci est pour interrompre le hooking:

http://mammon.github.io/Text/linux_hooker.txt



Ce Q&R a été automatiquement traduit de la langue anglaise.Le contenu original est disponible sur stackexchange, que nous remercions pour la licence cc by-sa 3.0 sous laquelle il est distribué.
Loading...