Можно ли программно получить подпись функции в общей библиотеке? - PullRequest
11 голосов
/ 30 июля 2011

Заголовок понятен, мы можем загрузить библиотеку dl_open и т. Д.

Но как я могу получить в ней сигнатуру функций?

Ответы [ 6 ]

8 голосов
/ 30 июля 2011

На этот ответ нельзя ответить вообще. Технически, если вы скомпилировали свой исполняемый файл с исчерпывающей отладочной информацией (код все еще может быть оптимизированной версией выпуска), тогда исполняемый файл будет содержать дополнительные разделы, обеспечивающие некоторую отражательную способность двоичного файла. В системах * nix (вы ссылались на dl_open) это осуществляется с помощью отладки данных DWARF в дополнительных разделах двоичного файла ELF . Аналогично это работает для Mach Universal Binaries на MacOS X.

Windows PE, однако, использует совершенно другой формат, поэтому, к сожалению, DWARF не является полностью кроссплатформенным (фактически, на ранних этапах разработки моего 3D-движка я реализовал загрузчик ELF / DWARF для Windows, так что я мог использовать общий формат для У двигателей разные модули, поэтому с некоторыми серьезными усилиями такое можно сделать).

Если вы не хотите внедрять свои собственные загрузчики или отлаживать средства доступа к информации, то вы можете встраивать информацию об отражении через некоторые дополнительные символы, экспортируемые (по некоторой стандартной схеме именования), которые ссылаются на таблицу имен функций, сопоставление их подписи. В случае с исходными файлами на Си написание парсера для извлечения информации из самого исходного файла довольно тривиально. C ++ OTOH настолько сложно правильно проанализировать, что вам нужен какой-то полноценный компилятор, чтобы все было правильно. Для этой цели был разработан GCCXML, технически GCC, который испускает AST в форме XML вместо двоичного объекта. Извлеченный XML тогда намного легче разобрать.

Из извлеченной информации создайте исходный файл со своего рода связанным списком / массивом / и т. Д. структура, описывающая каждую функцию. Если вы не экспортируете символ каждой функции напрямую, а вместо этого инициализируете какое-то поле в структуре отражения с помощью указателя на функцию, вы получаете действительно хорошую и чистую аннотированную схему экспорта. Технически вы также можете поместить эту информацию в отдельный раздел двоичного файла, но размещение ее в разделе данных только для чтения тоже подойдет.


Однако, если вы получили бинарный файл третьей стороны - скажем, в худшем случае, он был скомпилирован из источника C, никакой отладочной информации и все символы, на которые нет внешней ссылки, удалены - вы в значительной степени испорчены. Лучшее, что вы могли сделать, - это применить некоторый двоичный анализ того, как функция обращается к различным местам, в которых можно передавать параметры.

Это скажет вам только количество параметров и размер каждого значения параметра, но не тип или имя / значение. При обратном проектировании какой-либо программы (например, анализ вредоносных программ или аудит безопасности) определение типа и значения параметров, передаваемых функциям, является одним из основных усилий. Недавно я наткнулся на какой-то драйвер, который мне пришлось отменить для целей отладки, и вы не можете поверить, насколько я был поражен тем, что я нашел символы C ++ в модуле ядра Linux (вы не можете использовать C ++ в ядре Linux в здравом смысле). ), но также с облегчением, потому что искажение имени в C ++ дало мне много информации.

4 голосов
/ 30 июля 2011

Нет, это невозможно. Подпись функции ничего не значит во время выполнения, это часть информации, полезная во время компиляции, чтобы компилятор мог проверить вашу программу.

3 голосов
/ 20 мая 2017

В Linux (или Mac) вы можете использовать комбинацию «nm» и «c ++ filt» (для библиотек C ++)

нм mylibrary.so | C ++ ФИЛТР

или

нм mylibrary.a | C ++ ФИЛТР

"nm" даст вам искаженную форму, а "c ++ фильт" попытается поместить их в более понятный для человека формат. Возможно, вы захотите использовать некоторые параметры в nm для фильтрации результатов, особенно если библиотека большая (или вы можете "grep" окончательный вывод, чтобы найти конкретный элемент)

1 голос
/ 30 июля 2011

Вы не можете. Либо библиотека публикует общедоступный API в заголовке, либо вам нужно узнать подпись другими способами.

0 голосов
/ 30 июля 2011

Эта информация недоступна.Даже отладчик не знает:

$ cat foo.c
#include <stdio.h>
#include <string.h>

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) 
0 голосов
/ 30 июля 2011

Параметры функции на нижнем уровне зависят от того, сколько аргументов стека в кадре стека вы рассматриваете и как вы их интерпретируете. Поэтому, как только функция скомпилирована в объектный код, получить такую ​​подпись невозможно. Одна удаленная возможность состоит в том, чтобы разобрать код и прочитать, как работает его функция, чтобы узнать число параметров, но все же тип будет трудно или невозможно определить. Одним словом, это невозможно.

...