Est-il possible d’obtenir par programme la signature d’une fonction dans une bibliothèque partagée?

Le titre est clair, on peut charger une bibliothèque par dl_open etc ..

Mais comment puis-je obtenir la signature des fonctions qu’il contient?

Cette réponse ne peut pas être répondu en général. Techniquement, si vous avez compilé votre exécutable avec des informations de débogage exhaustives (le code peut toujours être une version optimisée, la version finale), l’exécutable contiendra des sections supplémentaires, fournissant une sorte de réflectivité du binary. Sur les systèmes * nix (vous avez fait référence à dl_open ), cela est implémenté via le débogage DWARF dans des sections supplémentaires du fichier binary ELF . Semblable fonctionne pour les binarys Universal Mach sur MacOS X.

Cependant, Windows PEs utilise un format complètement différent. DWARF n’est donc pas vraiment une plate-forme croisée (en fait, lors des premières étapes de développement de mon moteur 3D, j’ai implémenté un chargeur ELF / DWARF pour Windows, de sorte que je puisse utiliser un format commun pour les différents moteurs. modules, donc avec un effort sérieux tel peut être fait).

Si vous ne souhaitez pas implémenter vos propres chargeurs, ni déboguer des accesseurs d’informations, vous pouvez incorporer les informations de reflection par le biais de symboles supplémentaires exportés (par un schéma de dénomination standard) faisant référence à une table de noms de fonctions, mappés à leurs Signature. Dans le cas de fichiers source C, écrire un parsingur pour extraire les informations du fichier source lui-même est plutôt sortingvial. C ++ OTOH est si notoirement difficile à parsingr correctement que vous avez besoin d’un compilateur à part entière pour réussir. À cette fin, GCCXML a été développé, techniquement un GCC qui émet l’AST sous forme XML au lieu d’un object binary. Le XML émis est alors beaucoup plus facile à parsingr.

À partir des informations extraites, créez un fichier source avec une sorte de liste chaînée / tableau / etc. structure décrivant chaque fonction. Si vous n’exportez pas directement le symbole de chaque fonction, mais initialisez un champ dans la structure de reflection avec le pointeur de fonction, vous obtenez un schéma d’exportation annoté vraiment sympa et propre. Techniquement, vous pouvez également placer ces informations dans une section spearate du fichier binary, mais le faire dans la section des données en lecture seule fait également le travail.


Toutefois, si vous recevez un fichier binary tiers – par exemple, dans le pire des cas, il a été compilé à partir d’une source C, aucune information de débogage et tous les symboles non supprimés à la référence externe – vous êtes pratiquement foutu. Le mieux que vous puissiez faire consistait à appliquer une parsing binary de la manière dont la fonction accède aux différents emplacements dans lesquels les parameters peuvent être passés.

Cela vous indiquera seulement le nombre de parameters et la taille de chaque valeur de paramètre, mais pas le type ou le nom / signification. Lors du reverse engineering de certains programmes (par exemple, parsing de programmes malveillants ou audit de sécurité), l’identification du type et de la signification des parameters transmis aux fonctions est l’un des efforts majeurs. Récemment, je suis tombé sur un pilote que j’ai dû inverser à des fins de débogage, et vous ne pouvez pas croire à quel point je suis stupéfait par le fait que j’ai trouvé des symboles C ++ dans un module de kernel Linux (vous ne pouvez pas utiliser C ++ dans le kernel Linux de manière saine. ), mais aussi soulagé, car le nom C ++, mangling, m’a fourni beaucoup d’informations.

Non, ce n’est pas possible. La signature d’une fonction ne veut rien dire au moment de l’exécution, c’est une information utile lors de la compilation pour que le compilateur valide votre programme.

Tu ne peux pas. Soit la bibliothèque publie une API publique dans un en-tête, soit vous devez connaître la signature par un autre moyen.

Sous Linux (ou Mac), vous pouvez utiliser une combinaison de “nm” et “c ++ filt” (pour les bibliothèques C ++)

nm mylibrary.so | c ++ filt

ou

nm mylibrary.a | c ++ filt

“nm” vous donnera la forme mutilée et “c ++ filt” tente de les mettre dans un format plus lisible par l’homme. Vous voudrez peut-être utiliser certaines options dans nm pour filtrer les résultats, en particulier si la bibliothèque est volumineuse (ou vous pouvez “grep” la sortie finale pour rechercher un élément particulier)

Les parameters d’une fonction du niveau inférieur dépendent du nombre d’arguments de stack dans le cadre de stack que vous considérez et de la façon dont vous les interprétez. Par conséquent, une fois que la fonction est compilée en code object, il n’est plus possible d’obtenir la signature de cette manière. Une possibilité à distance consiste à désassembler le code et à lire son fonctionnement afin de connaître le nombre de parameters, mais que le type rest difficile ou impossible à déterminer. En un mot, ce n’est pas possible.

Cette information n’est pas disponible. Même le débogueur ne sait pas:

 $ cat foo.c #include  #include  int main(int argc, char* argv[]) { char foo[10] = { 0 }; char bar[10] = { 0 }; printf("%s\n", "foo"); memcpy(bar, foo, sizeof(foo)); return 0; } $ gcc -g -o foo foo.c $ gdb foo Reading symbols from foo...done. (gdb) b main Breakpoint 1 at 0x4005f3: file foo.c, line 5. (gdb) r Starting program: foo Breakpoint 1, main (argc=1, argv=0x7fffffffe3e8) at foo.c:5 5 { (gdb) ptype printf type = int () (gdb) ptype memcpy type = int () (gdb)