Corriger un binaire avec dd

32

J'ai lu cette citation (ci-dessous) à plusieurs reprises, dont la plus récente ici , et je suis toujours perplexe quant à la manière dont ddon peut utiliser pour patcher n'importe quoi, sans parler d'un compilateur:

Le système Unix que j'avais utilisé à l'école, il y a 30 ans, était très limité en RAM et en espace disque. En particulier, le /usr/tmpsystème de fichiers était très petit, ce qui posait problème lorsque quelqu'un essayait de compiler un programme volumineux. Bien entendu, les étudiants n'étaient pas censés écrire de "gros programmes" de toute façon; les grands programmes étaient généralement des codes sources copiés "quelque part". Beaucoup d' entre nous copiés /usr/bin/ccà /home/<myname>/cc, et utilisé ddpour patcher le binaire à utiliser au /tmplieu de/usr/tmp , qui était plus grande. Bien sûr, cela ne faisait qu'aggraver le problème: l'espace disque occupé par ces copies importait de nos jours et se /tmpremplissait maintenant régulièrement, empêchant les autres utilisateurs de modifier leurs fichiers. Après avoir découvert ce qui s’est passé, les administrateurs système ont fait unechmod go-r /bin/* /usr/bin/* qui "corrige" le problème et supprime toutes nos copies du compilateur C.

(Souligné par moi)

La ddpage de manuel ne dit rien sur les correctifs et ne pense pas qu'il pourrait être modifié pour le faire de toute façon.

Les binaires pourraient-ils vraiment être corrigés dd? Y at-il une signification historique à cela?

Amziraro
la source
3
Bien sûr - juste odun fichier pour les codes hexadécimaux, trouvez le décalage dont vous avez besoin, décidez de votre édition et de bs=$patchsize count=1 seek=$((offset/bs)) conv=notruncvotre correctif directement dans.
mikeserv
3
Quelqu'un n'a jamais écrasé un secteur de démarrage. ;)
Parthe
@ParthianShot En fait, j'ai écrasé une fois le premier ~ 260 Mo de mon lecteur de démarrage (+ racine) avec une partie d'un LiveCD Debian. O_o Mais je ne pense pas que ce soit vraiment correctif, hehehe ...
Amziraro
1
Ou plutôt, voilà le comportement attendu et tout à fait normal du Destructeur de disques: D
Amziraro

Réponses:

73

Essayons. Voici un programme C trivial:

#include <stdio.h>
int main(int argc, char **argv) {
    puts("/usr/tmp");
}

Nous allons construire cela dans test:

$ cc -o test test.c

Si nous l'exécutons, il affichera "/ usr / tmp".

Voyons où " /usr/tmp" se trouve dans le binaire:

$ strings -t d test | grep /usr/tmp
1460 /usr/tmp

-t d imprime le décalage en décimal dans le fichier de chaque chaîne trouvée.

Créons maintenant un fichier temporaire contenant juste " /tmp\0":

$ printf "/tmp\x00" > tmp

Nous avons maintenant le fichier binaire, nous savons où se trouve la chaîne à modifier et nous avons un fichier contenant la chaîne de remplacement.

Maintenant nous pouvons utiliser dd:

$ dd if=tmp of=test obs=1 seek=1460 conv=notrunc

Ceci lit les données de tmp(notre " /tmp\0" fichier), les écrit dans notre binaire, en utilisant une taille de bloc de sortie de 1 octet, en sautant au décalage que nous avons trouvé précédemment avant qu’il n’écrive quoi que ce soit, et ne tronque pas explicitement le fichier lorsque cela est fait.

Nous pouvons exécuter le fichier exécutable corrigé:

$ ./test
/tmp

Le littéral de chaîne que le programme affiche a été modifié. Il contient donc maintenant " /tmp\0tmp\0", mais les fonctions de chaîne s'arrêtent dès qu'elles voient le premier octet nul. Ce patch permet uniquement de raccourcir ou de prolonger la longueur de la chaîne, mais cela convient parfaitement.

Donc, non seulement nous pouvons corriger les choses en utilisant dd, nous venons de le faire.

Michael Homer
la source
1
C’est excellent… et j’espère que je ne le rencontrerai jamais dans un environnement de production! J'ai utilisé des méthodes similaires dans le passé pour obtenir des numéros de série dans des images hexadécimales destinées aux microcontrôleurs. Il est cependant trop facile de se tirer une balle dans le pied.
Michael Shaw
Si je voulais donner des instructions écrites à quelqu'un pour patcher un binaire particulier, je lui donnerais plutôt une ligne de commande pour copier / coller plutôt que de leur dire "ouvrez le fichier dans un éditeur hexadécimal, trouvez la /usr/tmpchaîne, remplacez-la par /tmp, don 'oubliez pas le dernier \0octet, sauvegardez le fichier et croisez les doigts ". Ou, mieux encore, un script shell qui vérifie d'abord la cohérence, puis appelle dd. Malheureusement, le besoin de choses comme celle-ci se pose fréquemment lorsqu'un logiciel déjà développé par un ancien fournisseur doit maintenant être migré vers un nouveau système.
Guntram Blohm soutient Monica le
Oui, Sed est mieux pour ce genre de chose. Mais vous n'avez pas tout à fait raison à propos de l'ensemble "Ce patch permet uniquement de raccourcir ou de prolonger la longueur de la chaîne". Vous supposez que vous vous souciez des données qui suivent immédiatement la chaîne que vous souhaitez modifier ou que vous ne pouvez pas avoir la chaîne suivante simplement une sous-chaîne de la chaîne d'origine. En d'autres termes, si vous êtes dans la section mémoire de .strings et que vous avez "/ usr \ 0 / bin / bash \ 0", vous pouvez le transformer en / usr / bin / bash en le modifiant simplement en premier octet nul et le rendant "/ usr // bin / bash" (par exemple).
Parthian Shot
2
@ParthianShot - ce sedn'est pas mieux pour ce genre de chose - vous ne pouvez pas limiter sedles tampons de lecture / écriture de manière aussi explicite et précise, comme vous le feriez avec dd- ce qui est la raison pour laquelle il a été utilisé pour cela à l'origine. Avec ddvous pouvez placer arbitrairement un nombre arbitraire d'octets arbitraires. On ne peut pas en dire autant de cela sed. Si ddest utilisé ici comme un scalpel, vous appliqueriez sedcomme une boule de démolition.
mikeserv
C'est un point juste (quoique assez rare!) - il y aura des occasions où vous pourrez rallonger la chaîne en ne vous souciant pas du résultat ni d'une autre donnée arbitraire, mais spécifique. Je maintiens cependant la déclaration générale.
Michael Homer
9

Cela dépend de ce que vous entendez par "patcher le binaire".

Je change les binaires en utilisant ddparfois. Bien sûr, cette fonctionnalité n’existe pas dd, mais elle peut ouvrir des fichiers, lire et écrire des choses à des décalages spécifiques, donc si vous savez quoi écrire où, voila votre patch.

Par exemple, j'avais ce fichier binaire contenant des données PNG. Utilisez binwalkpour trouver le décalage, ddpour l'extraire (généralement binwalk extrait également des choses mais ma copie était boguée), éditez-le avec gimp, assurez-vous que le fichier modifié est de la même taille ou plus petit que celui d'origine (modifier les décalages n'est pas quelque chose que vous pouvez faire facilement. ), puis utilisez-le ddpour remettre l’image modifiée en place.

$ binwalk thebinary
[…]
4194643    0x400153     PNG image, 800 x 160, 8-bit/color RGB, non-interlaced
[…]
$ dd if=nickel bs=1 skip=4194641 count=2 conv=swab | od -i
21869 # file size in this case - depends on the binary format
$ dd if=thebinary bs=1 skip=4194643 count=21869 of=theimage.png
$ gimp theimage.png
$ pngcrush myimage.png myimage.crush.png
# make sure myimage.crush.png is smaller than the original
$ dd if=myimage.crush.png of=thebinary bs=1 seek=4194643 conv=notrunc

Parfois, je souhaite également remplacer des chaînes dans des fichiers binaires (tels que des noms de chemins ou de variables). Bien que cela puisse également être fait en utilisant dd, il est plus simple de le faire en utilisant sed. Vous devez simplement vous assurer que la chaîne que vous remplacez a la même longueur que la chaîne d'origine afin de ne pas modifier les décalages.

sed -e s@/the/old/save/path@/the/new/save/path@ -i thebinary

ou pour prendre l'exemple de MichaelHomer avec un 0 octet ajouté dans:

sed -e 's@/usr/tmp@/tmp\x00tmp@' -i test

Bien sûr, vous devez vérifier si cela fonctionne réellement après.

Frostschutz
la source
... en supposant que vous avez un système sedqui gère bien les fichiers binaires, ce qui semble être le cas avec gnu sed, mais pas avec la plupart des anciens seds qui travaillaient uniquement sur des fichiers ascii, ont été confondus avec autre chose (en particulier \0s dans l'entrée), et avait des restrictions sur la longueur maximale de la ligne.
Guntram Blohm soutient Monica le
1
busybox sedsemble être capable de changer les fichiers binaires sans problème, mais cela ne comprend pas \x00la chaîne de remplacement comme le fait GNU sed. Cela nécessite des tests, mais même dans ce cas, je pense que cela vaut la peine d'être mentionné car c'est beaucoup plus simple que dd, dans certains cas. Corriger les fichiers binaires est une entreprise floconneuse dans les deux cas.
frostschutz