LINUX.ORG.RU

Сайдэффект при вызове dlsym

 , ,


0

1

Доброго ВС! Дорабатывал proxychains и словил крайне интересную ошибку... Изолировал ее на сколько мог:

#undef _GNU_SOURCE
#define _GNU_SOURCE

#include <sys/types.h>
#include <sys/param.h>

#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <inttypes.h>

#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>

void *dlsy7(void *, const char *); //special load from patched libdlsy7.so

void *(*true_dlopen)(const char *filename, int flags)=NULL;
void *(*true_dlsym)(void *handle, const char *symbol)=NULL;


void *dlopen(const char *filename, int flags) {
	if(true_dlopen==NULL) {
		true_dlopen=dlsym(RTLD_NEXT,"dlopen");
	};

	void * res=true_dlopen(filename,flags);

	printf("DLOPEN %s res = 0x%" PRIx64 "\n",(char *)filename,(unsigned long int)res);
	
	return res;
}


void *dlsym(void *handle, const char *symbol) {
	printf("DLSYM %s 0x%" PRIx64,symbol,(unsigned long int)handle);

	if(true_dlsym==NULL) {
		true_dlsym=dlsy7(RTLD_NEXT,"dlsym");
	};

	void *res,*res1;

	//res1=true_dlsym(handle, symbol); //DECOMENT THIS AND PROG WILL WORK
	res=dlsy7(handle, symbol);

	printf(" res = 0x%" PRIx64 " res1 = 0x%" PRIx64 "\n",(unsigned long int)res,(unsigned long int)res1);

	return res;
};

Собираю так

gcc main.c -fPIC -shared /usr/lib/x86_64-linux-gnu/libd7.so.2 -o libdltest.so && sed -i "s|libdl.so.2|libd7.so.2|g" ./libdltest.so && echo -e "\e[32mDONE\e[0m"
libd7.so.2 - Это предварительно обработанная libdl.so.2 с измененным именем символа dlsym на dlsy7 (чтобы можно было подменять вызов dlsym) Тесты:
LD_PRELOAD=./libdltest.so xed   #Работает
LD_PRELOAD=./libdltest.so chromium-browser

Using PPAPI flash.
--disable-new-tab-first-run --enable-user-scripts --ppapi-flash-path=/usr/lib/adobe-flashplugin/libpepflashplayer.so --ppapi-flash-version=
DLSYM dlopen 0xffffffffffffffff res = 0x7f5270541f70 res1 = 0x7f5271cc4568
DLOPEN liblttng-ust-tracepoint.so.0 res = 0x0
DLOPEN liblttng-ust-tracepoint.so.0 res = 0x0
DLSYM dlopen 0xffffffffffffffff res = 0x7f588926ef70 res1 = 0x7f588a9f1568
DLOPEN liblttng-ust-tracepoint.so.0 res = 0x0
DLOPEN liblttng-ust-tracepoint.so.0 res = 0x0
DLOPEN /usr/lib/chromium-browser/libwidevinecdmadapter.so res = 0x5564cafc6510
DLOPEN /usr/lib/adobe-flashplugin/libpepflashplayer.so res = 0x5564cafc7640
DLOPEN /usr/lib/chromium-browser/libwidevinecdm.so res = 0x5564cafc7190
DLOPEN libgdk-3.so.0 res = 0x7f5271c92000
DLSYM gdk_set_allowed_backends 0x7f5271c92000 res = 0x7f526b3183d0 res1 = 0x0
DLOPEN (null) res = 0x7f5271cc7168
DLSYM gtk_progress_get_type 0x7f5271cc7168 res = 0x0 res1 = 0x7f5271c97000
DLSYM localtime 0xffffffffffffffff res = 0x7f5270d1f930 res1 = 0x7ffd2e955040
DLSYM localtime64 0xffffffffffffffff res = 0x0 res1 = 0x7ffd2e955040
DLSYM localtime_r 0xffffffffffffffff res = 0x7f5270d1f920 res1 = 0x7ffd2e955040
DLSYM localtime64_r 0xffffffffffffffff res = 0x0 res1 = 0x7ffd2e955040
[13398:13398:0102/154843.197714:ERROR:browser_main_loop.cc(293)] Gtk: GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in the same process is not supported

В хроме возникла ошибка... Теперь раскоментируем строчку, помеченную //DECOMENT THIS AND PROG WILL WORK И опять проверяем
LD_PRELOAD=./libdltest.so chromium-browser

Using PPAPI flash.
--disable-new-tab-first-run --enable-user-scripts --ppapi-flash-path=/usr/lib/adobe-flashplugin/libpepflashplayer.so --ppapi-flash-version=
DLSYM dlopen 0xffffffffffffffff res = 0x7fb079af2f70 res1 = 0x7fb079af2f70
DLOPEN liblttng-ust-tracepoint.so.0 res = 0x0
DLOPEN liblttng-ust-tracepoint.so.0 res = 0x0
DLSYM dlopen 0xffffffffffffffff res = 0x7f6c2d6baf70 res1 = 0x7f6c2d6baf70
DLOPEN liblttng-ust-tracepoint.so.0 res = 0x0
DLOPEN liblttng-ust-tracepoint.so.0 res = 0x0
DLOPEN /usr/lib/chromium-browser/libwidevinecdmadapter.so res = 0x5587d9ed3510
DLOPEN /usr/lib/adobe-flashplugin/libpepflashplayer.so res = 0x5587d9ed4640
DLOPEN /usr/lib/chromium-browser/libwidevinecdm.so res = 0x5587d9ed4190
DLOPEN libgdk-3.so.0 res = 0x7fb07b243000
DLSYM gdk_set_allowed_backends 0x7fb07b243000 res = 0x7fb0748c93d0 res1 = 0x7fb0748c93d0
DLOPEN (null) res = 0x7fb07b278168
DLSYM gtk_progress_get_type 0x7fb07b278168 res = 0x0 res1 = 0x0
DLOPEN libgail.so res = 0x0
DLSYM gtk_progress_get_type 0x7fb07b278168 res = 0x0 res1 = 0x0
DLOPEN libatk-bridge.so res = 0x0
DLSYM gtk_progress_get_type 0x7fb07b278168 res = 0x0 res1 = 0x0
DLOPEN /usr/lib/x86_64-linux-gnu/gio/modules/libgvfsdbus.so res = 0x558143a37180
DLSYM g_module_check_init 0x558143a37180 res = 0x0 res1 = 0x0
DLSYM g_module_unload 0x558143a37180 res = 0x0 res1 = 0x0
DLSYM g_io_module_load 0x558143a37180 res = 0x7fb06a1b7e20 res1 = 0x7fb06a1b7e20
DLSYM g_io_module_unload 0x558143a37180 res = 0x7fb06a1b7f70 res1 = 0x7fb06a1b7f70
DLOPEN /usr/lib/x86_64-linux-gnu/gio/modules/libgiognomeproxy.so res = 0x558143a38c00
DLSYM g_module_check_init 0x558143a38c00 res = 0x0 res1 = 0x0

#Дальше длинный лог, а за ним нормальный запуск хрома....
Тоесть записав результат true_dlsym в никуда мы получили совсем другое выполнение программы, хотя res и res1 ничем не отличаются... Получается, что dlsym имеет какойто сайдэффект, связанный с регионом памяти, в которой она находится??? Подскажите. как такое может быть? Как gtk связан с libdl? Почему такое происходит только в хроме?

Ответ на: комментарий от annulen

libdl - это компонент libc, с ним иного чего связано

Не объясняет такое поведение. Это всеровно, что при работе в Libre office Writer в документе изменился заголовок после того, как ты пропинговал DNS гугла из консоли....

cyber_eagle
() автор топика

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

Iron_Bug ★★★★★
()
Ответ на: комментарий от Iron_Bug

Я ведь даже не возвращаю результат оригинальной dlsym. Это значит, что либо dlsym изменяет какойто параметр во время своего выполнения. А это может произойти потому, что хром в свою очередь тоже подменяет dlsym???

cyber_eagle
() автор топика

Потому что ты делаешь неправильно. Не патчи библиотеку, тебе должно быть достаточно одного LD_PRELOAD. ВООБЩЕ НЕ ТРОГАЙ ФАЙЛЫ СИСТЕМНЫХ БИБЛИОТЕК.

Чтобы не возникало проблемы курицы или яйца(чем должен твой dlsym dlsym-ать стандартный dlsym, если это он же и есть?), можно либо воспользоваться расширением линкера для врапа. Он переименует настоящую в __real_dlsym при линковке, а твою __wrap_dlsym переименует в бинарнике в dlsym. Помню -wrap ключ назывался.

Или второй вариант — снимать mprotect(), переписывать первых джва байта dlsym(), чтобы jmp-алась в твой, а когда надо вызвать оригинальный можно оригинальные байты вернуть на место.

a1batross ★★★★★
()
Ответ на: комментарий от a1batross

Чтобы не возникало проблемы курицы или яйца(чем должен твой dlsym dlsym-ать стандартный dlsym, если это он же и есть?), можно либо воспользоваться расширением линкера для врапа. Он переименует настоящую в __real_dlsym при линковке, а твою __wrap_dlsym переименует в бинарнике в dlsym. Помню -wrap ключ назывался.

Спасибо. Наверно это я и пытался найти до того, как начал патчить вручную)

Да, он dlsym вроде как подменяет, для песочницы для плагинов.

Очень похоже на то...еще с проверкой выполнения кода каким нибудь флагом...

cyber_eagle
() автор топика

Скорее твоя dlsy7 неправильно работает. Судя по

Gtk: GTK+ 2.x symbols detected.

Он просто проверяет какой-то специфический вызов. А твоя заглушка возвращает ответ будто он есть или формирует неправильное последующее поведение dlerror.

anonymous
()
Ответ на: комментарий от anonymous

А твоя заглушка возвращает ответ будто он есть или формирует неправильное последующее поведение dlerror.

С заглушкой все впорядке. Моя функция и оригинальная (res и res1) возвращают абсолютно одинаковые значения.

res1=true_dlsym(handle, symbol); 
res=dlsy7(handle, symbol);

printf(" res = 0x%" PRIx64 " res1 = 0x%" PRIx64 "\n",(unsigned long int)res,(unsigned long int)res1);

return res;
Данный код работает нормально.

cyber_eagle
() автор топика
Ответ на: комментарий от cyber_eagle

А dlerror после них одинаковый?

Суть в том, что если в хроме свои либы используются, то твоя заглушка вообще не вызывалась бы. Если там заглушки или вообще нет подмен, то вызываются (что мы и видим) и разница только в dlsy7.

Так что как не крути с заглушкой не всё в порядке.

anonymous
()
Ответ на: комментарий от cyber_eagle

Кстати где одинаковые-то?

DLSYM gdk_set_allowed_backends 0x7f5271c92000 res = 0x7f526b3183d0 res1 = 0x0

...

DLSYM gtk_progress_get_type 0x7f5271cc7168 res = 0x0 res1 = 0x7f5271c97000

DLSYM localtime 0xffffffffffffffff res = 0x7f5270d1f930 res1 = 0x7ffd2e955040

DLSYM localtime64 0xffffffffffffffff res = 0x0 res1 = 0x7ffd2e955040

...

anonymous
()
Ответ на: комментарий от anonymous

Это запуск с закоментированым res1. Те он даже не инициализирован.

Если в res1 записывать результат true_dlsym, то :

DLSYM gdk_set_allowed_backends 0x7fb07b243000 res = 0x7fb0748c93d0 res1 = 0x7fb0748c93d0 DLOPEN (null) res = 0x7fb07b278168 DLSYM gtk_progress_get_type 0x7fb07b278168 res = 0x0 res1 = 0x0 DLOPEN libgail.so res = 0x0 DLSYM gtk_progress_get_type 0x7fb07b278168 res = 0x0 res1 = 0x0 DLOPEN libatk-bridge.so res = 0x0 DLSYM gtk_progress_get_type 0x7fb07b278168 res = 0x0 res1 = 0x0 DLOPEN /usr/lib/x86_64-linux-gnu/gio/modules/libgvfsdbus.so res = 0x558143a37180 DLSYM g_module_check_init 0x558143a37180 res = 0x0 res1 = 0x0 DLSYM g_module_unload 0x558143a37180 res = 0x0 res1 = 0x0 DLSYM g_io_module_load 0x558143a37180 res = 0x7fb06a1b7e20 res1 = 0x7fb06a1b7e20 DLSYM g_io_module_unload 0x558143a37180 res = 0x7fb06a1b7f70 res1 = 0x7fb06a1b7f70 DLOPEN /usr/lib/x86_64-linux-gnu/gio/modules/libgiognomeproxy.so res = 0x558143a38c00

cyber_eagle
() автор топика
Ответ на: комментарий от cyber_eagle

С dlerror-то что? Даже в манах проверка идёт так:

dlerror();  /* Clear any existing error */

cosine = (double (*)(double)) dlsym(handle, "cos");

error = dlerror();
if (error != NULL) {
 fprintf(stderr, "%s\n", error);
 exit(EXIT_FAILURE);
}

А в какой-нибудь обёртке на c++ сам бох велел так проверять.

Т.е. на твой результат всем насрать. Выполнение по dlerror проверяется.

anonymous
()
Ответ на: комментарий от cyber_eagle

Кстати что вообще делает твоя загадочная функция? В идеале ты должен просто дополнить выводом сообщения (хотя на кой оно тебе, если есть *trace?) и в итоге вызвать штатную.

Потому что если ты хочешь дополнить функционал конкретной функции из какой-то библиотеки, то необязательно перегружать всю инфраструктуру. Достаточно только эту функцию заместить. В смысле не dl*, а именно ту что нужно. И, кстати, она тоже должна, после отлова своего сочетания аргументов, вызывать замещённую функцию!

Не вижу никакого смысла перегружать dl*.

anonymous
()
Ответ на: комментарий от anonymous

Я дописываю proxychains. Его проблема в том, что он замещает socket только в том случае, когда она указана в заголовке программы. Но если программа попытается подгрузить socket через dlsym, то весь трафик раскроется.

Осознаю, что это не панацея...но думаю, что будет лучше, чем было...

Если вам интересно - могу выложить ссылочку на даное решение.

cyber_eagle
() автор топика
Ответ на: комментарий от cyber_eagle

Его проблема в том, что он замещает socket только в том случае, когда она указана в заголовке программы. Но если программа попытается подгрузить socket через dlsym, то весь трафик раскроется.

Подгрузить через dlsym что? socket(2)? это же функция libc, ее нельзя подгружать потому что она уже загружена. А еще можно ей не пользоваться и дергать сисколлы напрямую. Твою проксю в ядро надо втыкать, или использовать только с «хорошими» приложениями.

annulen ★★★★★
()
Ответ на: комментарий от anonymous
void *res,*res1;

	//res1=true_dlsym(handle, symbol); //DECOMENT THIS AND PROG WILL WORK
	res=dlsy7(handle, symbol);

	printf(" res = 0x%" PRIx64 " res1 = 0x%" PRIx64 " dlerror = %s\n",(unsigned long int)res,(unsigned long int)res1,dlerror());

	return res;
DLOPEN libgdk-3.so.0 res = 0x7fd79a243000
DLSYM gdk_set_allowed_backends 0x7fd79a243000 res = 0x7fd7938c93d0 res1 = 0x0 dlerror = (null)
DLOPEN (null) res = 0x7fd79a278168
DLSYM gtk_progress_get_type 0x7fd79a278168 res = 0x0 res1 = 0x7fd79a248000 dlerror = (null)
DLSYM localtime 0xffffffffffffffff res = 0x7fd7992d0930 res1 = 0x7ffc6b145ac0 dlerror = (null)
DLSYM localtime64 0xffffffffffffffff res = 0x0 res1 = 0x7ffc6b145ac0 dlerror = (null)
DLSYM localtime_r 0xffffffffffffffff res = 0x7fd7992d0920 res1 = 0x7ffc6b145ac0 dlerror = (null)
DLSYM localtime64_r 0xffffffffffffffff res = 0x0 res1 = 0x7ffc6b145ac0 dlerror = (null)
[8314:8314:0106/192347.707053:ERROR:browser_main_loop.cc(293)] Gtk: GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in the same process is not supported

Очистка dlerror после заполнения true_dlsym и true_dlopen также не помогла.

Дело не в dlerror. Тоесть если хром вызывает dlerror(), то он вызывает тот экземпляр, что был загружен в первую очередь (те тот, что в dlsy7). Получается, что с последним загруженным dlerror (своим) он не работает вовсе.

cyber_eagle
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.