Перехват статически связанных зависимостей Динамически связанной библиотеки

#c #linux #mips

Вопрос:

Я пытаюсь отладить API, используемый сторонним приложением. Стороннее приложение имеет конфигурацию, которую я считал невозможной:

Двоичный файл приложения содержит экспорт, необходимый для одной из зависимостей его общей библиотеки. То есть они динамически связали свою зависимость, но зависимость этой зависимости связана статически.

Это происходит в Linux на базе MIPS с древним ядром.

Я подтвердил это, используя Ghidra для разборки исполняемой/общей библиотеки.

В основном у нас есть двоичный файл и общий объект

 file initApp
initApp: ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped

file libhyCoreSdk.so
libhyCoreSdk.so: ELF 32-bit LSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, stripped

objdump -T libhyCoreSdk.so | grep -i IMP_ISP_Open
00047900      DF *UND*  00000000 IMP_ISP_Open
 

initApp вызывает «coreAvInit» в libhyCoreSdk.so, а затем libhyCoreSdk.so вызывает IMP_ISP_Open() обратно в initApp.

Возможно, вы думаете: «Это не так уж необычно, вы можете сделать это с помощью обратных вызовов, передачи указателей, вызова dlsym и т. Д. и т. Д.». Но это не что-то из этого, это прямой импорт/экспорт символов, именно то, что вы ожидали бы увидеть, если бы Libhycore зависел от другой общей библиотеки.

Все это в стороне, моя настоящая проблема в том, что я пытаюсь выяснить, какие параметры передаются IMP_ISP_Open, и LD_PRELOAD не помогает этому странному/уникальному обстоятельству. У меня есть еще один пример приложения, которое вызывает те же API для версии API с общей библиотекой. Когда я использую LD_PRELOAD (загружаю небольшую программу-перехватчик, которую я написал) против этой версии, она отлично работает. Но когда я использую его против этой версии, которая ссылается на двоичный файл, он не работает.

Я надеюсь, что у кого-то есть идеи о том, как я могу перехватывать эти вызовы API.

Частичное Решение:

Дэниел Кляйнштейн дал мне хорошее начало. Я переименовал целевые функции из IMP_… в XMP_… (например, IMP_ISP_DisableSensor-> XMP_ISP_DisableSensor). Теперь датчик IMP_ISP_DisableSensor из моей LD_PRELOAD правильно выбран. К сожалению, я все еще сталкиваюсь с проблемами. Вызов dlsym(RTLD_DEFAULT, «XMP_ISP_DisableSensor») возвращает значение NULL без очевидной причины… Это означает, что я не могу перенаправить обратно к исходной функции.

Несмотря на то, что objdump показывает это:

 objdump -T initApp_mod | grep -i XMP
0061fb5c g    DF .text  00000338  Base        XMP_FrameSource_CreateChn
00613c6c g    DF .text  00000204  Base        XMP_ISP_DisableSensor
006097f0 g    DF .text  00000eb0  Base        XMP_Encoder_CreateChn
 

Комментарии:

1. «но зависимость этой зависимости статически связана». но file libhyCoreSdk.so показывает, что она динамически связана? Что objdump -T libhyCoreSdk.so показывает IMP_ISP_Open импорт?

2. @DanielKleinstein Я добавил то, что он показывает. Честно говоря, это мне мало о чем говорит. Глядя на вывод readelf, я вижу, что IMP_ISP_Open-это динамический символ, но в списке .dynamic нет записи «initApp». (Что имеет смысл, не знаю, как это может быть)

3. В вашей общей библиотеке есть неопределенный символ, который разрешается исполняемым файлом, а не какой-либо общей библиотекой, указанной по мере НЕОБХОДИМОСТИ в динамическом разделе. Здесь нет ничего невозможного или необычного (или действительно статически связанного). (Это невозможно в мире Windows и библиотек DLL, но общие библиотеки не являются библиотеками DLL).

4. @n.1.8e9-где-моя-доля. Похоже, что это действительно так, и, возможно, мой фон Windows сделал это таким безумным. Но эта реальность не решает моих проблем с LD_PRELOAD. Есть какие-нибудь мысли по этому поводу? Почему символ LD_PRELOAD не имеет приоритета над символом из исполняемого файла?

5. @wd40bomber27 LD_PRELOAD здесь не работает, потому что он не имеет приоритета над символами, экспортируемыми самим основным исполняемым файлом, — просто над символами, экспортируемыми общими библиотеками. Я не уверен, в чем именно заключается ваш случай (бинарное исследование? Производственный код?), Но в вашем случае я мог бы попробовать исправить сам двоичный файл, чтобы переименовать импортированный символ (или проще, переименовать экспортированный символ основного исполняемого файла), чтобы разрешить LD_PRELOAD подключение.

Ответ №1:

Ваша динамическая зависимость статически не связана с вашим основным исполняемым файлом. Когда динамическая зависимость загружается, выполняется поиск ее импорта и разрешается символом, экспортируемым исполняемым файлом — действительно, символы исполняемого файла всегда будут разрешаться раньше любых других динамических зависимостей.


К сожалению, это также препятствует вашему использованию LD_PRELOAD .

LD_PRELOAD не работает, потому что его введенная библиотека не имеет приоритета над символами, экспортируемыми самим основным исполняемым файлом, — только над символами, экспортируемыми общими библиотеками.


Если вы хотите перехватить вызов с помощью LD_PRELOAD , грубым, но эффективным решением является исправление экспортированного символа основного исполняемого файла под другим именем — таким образом, он не будет разрешен при загрузке динамической зависимости, и ваша введенная библиотека может предоставить символ.

Комментарии:

1. Еще одна проблема, с которой я столкнулся, заключалась в том, что, что бы я ни делал, я не мог разрешить исходный (теперь переименованный) символ. По какой-то причине использование API DL не работало. Это изначально помешало мне перенаправить на исходные функции после моего символа LD_PRELOAD’d. Мое решение для этого было столь же грубым. Моя (MIPS-файл, работающий на древнем ядре Linux) платформа имеет нулевой ASLR. Посмотрев символы, которые я заменял с помощью objdump, я смог напрямую заменить вызов dl на исходное смещение. Спасибо за вашу помощь!