LINUX.ORG.RU

перехват open

 


1

2

Здравствуйте создал библиотеку для перехвата open

#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
#include <fcntl.h>

#ifndef RTLD_NEXT
#define RTLD_NEXT ((void *) -1l)
#endif /* RTLD_NEXT */


int open(const char *filename, int flags, mode_t mode)
{
    if (strstr(filename,"/openlog")==NULL)
    {
        char buf[256];
        FILE *f=fopen("/openlog","a");
        if (f!=NULL)
        {
            sprintf(buf,"файл %s успешно открыт",filename);
            fwrite(buf,sizeof(buf),1,f);
        }
        fclose(f);
    }

    int (*open_orig)(const char *filename,int flags,mode_t mode)=(int (*)(const char*, int, mode_t))dlsym(RTLD_NEXT, "open");
    return open_orig(filename, flags, mode);
}
начинаю компилировать
[root@maks mylib]# gcc -fPIC -c -Wall main.cpp
[root@maks mylib]# gcc -shared main.o -ldl -o main.so

устанавливаю LD_PRELOAD

[root@maks mylib]# LD_PRELOAD="main.so" /usr/bin/mc
но у меня появляется вот это
ERROR: ld.so: object 'main.so' from LD_PRELOAD cannot be preloaded: ignored.

1) все либы указывать после ключа -o

2) Просто собери $(CC) -shared -fPIC ./main.c -o main.so -ldl

3) Указывай относительный путь с ./, т.е. LD_PRELOAD="./main.so" . Хотя, может это и ни при чём.

Ещё может быть у тебя какие-нить патчи безопасности, хотя это врядли.

С open есть ещё засада что на самом деле тебе нужно будет переопределять open64.

true_admin ★★★★★
()
Последнее исправление: true_admin (всего исправлений: 1)
Ответ на: комментарий от omnomnomnus
LD_LIBRARY_PATH="`pwd`" LD_PRELOAD="/dinlibrary/mylib/main.so"/usr/bin/mc

/dinlibrary/mylib/main.so---путь где лежит библиотека

все равно ошибка

ERROR: ld.so: object '/dinlibrary/mylib/main.so' from LD_PRELOAD cannot be preloaded: ignored.

просто я запускаю команду из папки /dinlibrary/mylib/ мб в этом дело?

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

Они хоть одной архитектуры? Что за ОС? Ещё у ld есть дебаговых выхлоп, смотри man ld.so раздел «Environment variables». Ну и я бы через strace глянул что там творится.

true_admin ★★★★★
()

Из твоего open вызывается fopen, который использует open.

i-rinat ★★★★★
()
Ответ на: комментарий от true_admin

ось мсвс 5.7 64 бита

[root@maks mylib]# gcc -shared -fPIC ./main.cpp -o main.so -ldl
[root@maks mylib]# LD_LIBRARY_PATH="`pwd`" LD_PRELOAD="/dinlibrary/mylib/main.so" /usr/bin/mc
/usr/bin/mc: symbol lookup error: /dinlibrary/mylib/main.so: undefined symbol: __gxx_personality_v0 

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

Ну судя по всему main.so теперь нормально загружается. Но слинкована она как-то не очень правильно. Попробуй слинковать с помощью g++, а не gcc.

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

вообщем в итоге код

#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
#include <fcntl.h>


#ifndef RTLD_NEXT
#define RTLD_NEXT ((void *) -1l)
#endif /* RTLD_NEXT */
int open(const char *filename, int flags, mode_t mode)
{
    int (*open_orig)(const char *filename,int flags,mode_t mode)=(int (*)(const char*, int, mode_t))dlsym(RTLD_NEXT, "open"); 
    if (strstr(filename,"/openlog")==NULL)  // ÅÓÌÉ ÜÔÏ ÎÅ openlog ÆÁÊÌ
    {
        char buf[256];
        FILE *f=fopen("/openlog","a");
        if (f!=NULL)
        {
            sprintf(buf,"файл %s открыт для чтения",filename);
            fwrite(buf,sizeof(buf),1,f);
             fclose(f);
        }

        return open_orig(filename, flags, mode);

    }


    return open_orig(filename, flags, mode);
}

int open64(const char *__file, int __oflag)
{
    int (*open64_orig)(const char *__file,int __oflag)=(int (*)(const char *,int))dlsym(RTLD_NEXT,"open64");
    if (strstr(__file,"/openlog")==NULL) 
    {
        char buf[256];
        FILE *f=fopen("/openlog","a");
        if (f!=NULL)
        {
            sprintf(buf,"файл %s открыт для чтения",__file);
            fwrite(buf,sizeof(buf),1,f);
            fclose(f);
        }


        return open64_orig(__file,__oflag);
    }
    return open64_orig(__file,__oflag);
}

компилирую его так

[root@maks mylib]# gcc -shared -fPIC ./main.cpp -o main.so -ldl
запускаю
[root@maks mylib]# LD_LIBRARY_PATH="`pwd`" LD_PRELOAD="/dinlibrary/mylib/main.so" /usr/bin/mc
запускается mc.... хожу по папкам открываю разные файлы но файл логов (/Openlog) пустой почему то....

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

У тебя феерическое кол-во проблем в коде. Например, нет логгирования ошибок. И да, всякие fwrite тоже умеют возвращать ошибки.

open(«/openlog»,«a»)

Ты работаешь из-под рута и пишешь в корень? No way... Хотя бы корень не захломляй.

sprintf

snprintf и sizeof(buf) ...

И зачем define RTLD_NEXT? Он у тебя не определён?

dlsym(RTLD_NEXT,«open64») я бы вызывал один раз и сохранял значение. Гугли void __attribute__((constructor)) _initializer (void)

Плюс смотри через strace что у тебя там происходит.

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

файл логов (/Openlog) пустой почему то....

Буферизация.

true_admin ★★★★★
()

Программа почти правильная :)

Из-за расширения .cpp gcc компилирует код как с++ код в котором разрешены перегрузки функций. Без extern «C» символ будет иметь имя:

$ nm main.so  | grep open
0000000000000840 T _Z4openPKcij

$ c++filt _Z4openPKcij
open(char const*, int, unsigned int)

Это неправильный прототип libc функции open().

man 2 open говорит, что С функция бывает в двух вариантах:

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

В С перегрузок функци нет и реальный прототип glibc:

// /usr/include/fcntl.h
extern int open (const char *__file, int __oflag, ...) __nonnull ((1));

Подправленый пример:

#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <dlfcn.h>
#include <fcntl.h>

static const char * log_file = "./openlog";

extern "C" int open(const char *filename, int flags, ...)
{
    if (strstr(filename,"openlog")==NULL)
    {
        FILE *f = fopen(log_file,"a");
        if (f)
        {
            fprintf (f, "файл '%s' успешно открыт\n",filename);
            fclose(f);
        }
    }

    va_list va;
    va_start(va, flags);
    mode_t mode = va_arg(va, mode_t);
    va_end(va);

    int (*open_orig)(const char *filename, int flags, ...);
    open_orig = (int (*)(const char*, int, ...))dlsym(RTLD_NEXT, "open");
    return open_orig(filename, flags, mode);
}

/*

# cat run.sh

#!/bin/bash
set -e
g++ -fPIC -shared main.cpp -ldl -o main.so -Wl,--no-undefined
LD_PRELOAD="./main.so" /usr/bin/mc

*/

Как сама glibc разбирает аргументы: https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/gene...

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

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

я в итоге решил сделать так

#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <unistd.h>

static const char * log_file = "/openlog";

extern "C" int open(const char *filename, int flags, ...)
{
    int (*open_orig)(const char *filename, int flags, ...);
    open_orig = (int (*)(const char*, int, ...))dlsym(RTLD_NEXT, "open");


    if (strstr(filename,"openlog")==NULL)
    {
        char buf[256];
        snprintf(buf,sizeof(buf),"файл %s успешно открыт для чтения",filename);
        int opis=open_orig("/openlog",O_APPEND);
        if (opis>0)
        {
            write(opis,(void *)buf,sizeof(buf));
            close(opis);
        }
//        FILE *f = fopen(log_file,"a");
//        if (f)
//        {
//            fprintf (f, "файл '%s' успешно открыт для чтения\n",filename);
//            fclose(f);
//        }
    }

    va_list va;
    va_start(va, flags);
    mode_t mode = va_arg(va, mode_t);
    va_end(va);

    return open_orig(filename, flags, mode);
}

смысл в том что мне нужно открытие каждого файла писать в лог... компилирую

g++ -fPIC -shared main.cpp -ldl -o main.so -Wl,--no-undefined

запускаю

LD_PRELOAD="./main.so" /usr/bin/mc
если я правильно понимаю при открытии файлов в mc(горячей клавишей F3) должен писаться мой лог(openlog)?

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

Мне кажется, нельзя va_start вызывать, если реально были переданы два аргумента, это undefined behaviour. Надо проверять mode (в glibc это __OPEN_NEEDS_MODE) и делать две ветки выполнения.

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

лог почему то пишется какой то странный когда запускаю саму библиотеку LD_PRELOAD="./main.so" /usr/bin/mc

файл '/dev/tty' успешно открыт для чтения
файл '/root/.tmp/0-0/mc-root/.mc/ini' успешно открыт для чтения
файл '/root/.tmp/0-0/mc-root/.mc/panels.ini' успешно открыт для чтения
файл '/usr/share/mc/mc.lib' успешно открыт для чтения
файл '/etc/mc/mc.keymap' успешно открыт для чтения
файл '/usr/share/mc/skins/default.ini' успешно открыт для чтения
файл '/root/.tmp/0-0/mc-root/.mc/history' успешно открыт для чтения
файл '/root/.tmp/0-0/mc-root/.mc/history' успешно открыт для чтения
файл '/root/.tmp/0-0/mc-root/.mc/history' успешно открыт для чтения
файл '/root/.tmp/0-0/mc-root/.mc/Tree' успешно открыт для чтения
файл '/dev/tty' успешно открыт для чтения
файл '/root/.tmp/0-0/mc-root/.mc/ini' успешно открыт для чтения
файл '/root/.tmp/0-0/mc-root/.mc/panels.ini' успешно открыт для чтения
файл '/usr/share/mc/mc.lib' успешно открыт для чтения
файл '/etc/mc/mc.keymap' успешно открыт для чтения
файл '/usr/share/mc/skins/default.ini' успешно открыт для чтения
файл '/etc/mc/filehighlight.ini' успешно открыт для чтения
файл '/root/.tmp/0-0/mc-root/.mc/history' м
файл '/usr/share/mc/hints/mc.hint.ru_RU.KOI8-R' успешно открыт для чтения
файл '/usr/share/mc/hints/mc.hint.ru' успешно открыт для чтения
файл '/usr/share/mc/hints/mc.hint.ru_RU.KOI8-R' успешно открыт для чтения
файл '/usr/share/mc/hints/mc.hint.ru'успешно открыт для чтения
файл '/usr/share/mc/hints/mc.hint.ru_RU.KOI8-R' успешно открыт для чтения
файл '/usr/share/mc/hints/mc.hint.ru' успешно открыт для чтения
файл '/usr/share/mc/hints/mc.hint.ru_RU.KOI8-R' успешно открыт для чтения
файл '/usr/share/mc/hints/mc.hint.ru' успешно открыт для чтения
файл '/usr/share/mc/hints/mc.hint.ru_RU.KOI8-R' успешно открыт для чтения

я как понимаю тут возникает проблемка небольшая что из

//        FILE *f = fopen(log_file,"a"); 
вызывается собственно
extern "C" int open(const char *filename, int flags, ...)
я так понял что файл нужно открыть не fopen а open_orig?

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

все правильно пишется )
mc открывает указанные файла сам, для своей работы
можно представить какой мусор будет в логе от всей системы )
но open перехвачен, задача формально выполнена

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

врят ли такое возможно только перехватом open, ведь для открытия «твоего» файла используется тотже open

можно фильтрануть потом получившийся лог, криво, но чуть ближе к цели

както иначе нужно делать

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

ну в общем то масло маслянное почему то логи пишутся при такой конструкции

        FILE *f = fopen(log_file,"a");
        if (f)
        {
            fprintf (f, "файл '%s' успешно открыт для чтения\n",filename);
            fclose(f);
        }
а вот при такой когда я работаю напрямую с системными вызовами
        int opis=open_orig("/openlog",O_APPEND);
        if (opis>0)
        {
            write(opis,(void *)buf,sizeof(buf));
            close(opis);
        }
почему то ничего не пишется и сам файл логов не создается те грубо говоря делаю unset LD_PRELOAD

потом LD_PRELOAD="./main.so" /usr/bin/mc

и через сисколы вообще ничего нет.. ведь поидее можно записть лог не через библиотечные функции fopen.... fwrite.... а через сисколы как open_orig,write,close?

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

то, что лог не пишется это другой вопрос

важно что перехватом open ты не можешь знать «кто читеает» файл: сам mc свои настройки или пользователь свои файлы т.к. вызов в обоих случаях един - open

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

вопрос решил с открытием лога через сискол... логи открываются и пишутся вопрос в следующем

когда я допустим определяю переменную окружения LD_PRELOAD

LD_PRELOAD="./main.so" /usr/bin/mc
я ее как понимаю определяю для конкретного приложения в данном случае /usr/bin/mc те грубо говоря будут перехватываться все openы которые буду иди из mc а можно определить LD_PRELOAD как бы «глобально» для всех приложений? чтобы openы перехватывались из всех приложений?

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