J – 1
Demain, le reveillon, c’est ici !
En comparant le projet qui m’obsède jour et nuit et les outils similaires déjà existants (crunchgen(1), rescue), j’en suis venu à me poser des questions sur le cas d’un mode “full static”. Pour mémoire, BeastieBox “trouve” la fonction à appeler fonction de argv[0], et je pars du principe que chaque nom de fonction doit être construit dynamiquement. Ce tour de passe-passe est facilement geré par les fonctions dlopen(3) / dlsym(3) dans le cas d’un binaire compilé dynamiquement, mais quid d’un binaire beastiebox compilé à l’aide du swtich -static ? Point de ld.so_elf à la rescousse ici, la seule solution qui m’est apparue… c’est d’attaquer le binaire comme le fait précisemment ld.so_elf, en mmap‘ant le binaire et en l’adressant via les structures ELF.
J’ai posté l’explication dans la Mollacademy, et le code associé de BeastieBox est visible ici, ici et là.
On oublie le post ci dessous. En effet, après avoir posté le resultat de mes travaux sur tech-userlevel@, j’ai appris une astuce des plus magiques. Arnaud Lacombe me dit dans une réponse :
Just looking quickly at the code, you can avoid the “#ifdef BBOX commant_
Je regarde donc comment s’y prend le gaillard de crunchgen(1) pour eviter les conflits de symboles et je vois ceci :
${NM} -ng cat/cat.ro | awk '/^ *U / { next }; /^[0-9a-fA-F]+ C/ { next }; / main$$/ { print "main _crunched_cat_stub"; next }; { print $3 " " $3 "$$from$$cat" }' > cat.cro.syms
${OBJCOPY} --redefine-syms cat.cro.syms cat/cat.ro cat.cro
Et ça, ça va m’apprendre à lire les manpages en entier.
En clair, à l’aide de nm(1), on liste les symboles exportés par les objets, on leur associe un nouveau nom avec awk(1) puis on redefinit les noms des symboles en passant à objcopy(1) le fichier de correspondances fraichement créé.
Magnifique.
Dans ma tentative de conquete du monde, je suis confronté à un problème auquel je n’avais pas immédiatement pensé. En effet, une foule d’outils partagent sans vergogne certains noms de fonction (usage(), help(), error()…) et de variables globales. Cet ennuyeux constat aboutit evidemment à des problèmes de linkage et faisait lamentablement foirer la compilation de mon BeastieBox cheri.
Une solution evidente était de renommer ces fonctions et leurs appels. mais…
imil@obana:~/src/beastiebox/beastiebin/sh$ grep 'error(' *.c|wc -l
95
Flemme quoi.
Je me suis donc fendu de même pas 10 lignes de shell/perl qui serviront peut-être au voyageur perdu :
#!/bin/sh
usage()
{
echo "usage: $0 <type> <function|variable> <prefix>"
echo "type : <func|var>"
exit 1
}
[ $# -lt 3 ] && usage
type=$1
item=$2
prefix=$3
preprx="^|\s+|=+\s*|\(.+?\)\s*|\(\s*"
for file in *.[ch]
do
if [ "$type" != "var" ]; then
perl -pi.bkp -e "s/(${preprx})${item}(\s*\()/\1${prefix}_${item}\2/g" $file
else
perl -pi.bkp -e "s/(${preprx}|[\+\-\*\/\>\< \%\^\|\!\&\~\[\.]+)${item}(\s*[^a-z0-9\-_\(])/\1${prefix}_${item}\2/gi" $file
fi
done
L’outil s’utilise de cette façon :
$ commonfunc.sh func pouet prefixe
ou
$ commonfunc.sh var variable prefixe
Chaque appel et déclaration de la fonction pouet sera remplacé par prefixe_pouet. Même principe pour les variables. Un backup suffixé "bkp" sera créé pour chaque fichier modifié, permettant ainsi de réaliser un petit diff de verification.
Recent Comments