가로 채기를 원하는 라이브러리 호출을 알고있는 경우 LD_PRELOAD
을 통해로드 된 공유 개체를 사용하여 호출을 삽입 할 수 있습니다.
shortread.c : 다음
gcc -shared [-m32|-m64] shortread.c -o libshortread.so
: 같은과
#include <sys/types.h>
#include <dlfcn.h>
#define MAX_FDS 1024
static int short_read_array[ MAX_FDS ];
// #define these to match your system's values
// (need to be really careful with header files since
// getting open() declared would make things very
// difficult - just try this with open(const char *, int, ...);
// declared to see what I mean...)
#define O_RDONLY 0
#define O_WRONLY 1
#define O_RDWR 2
// note that the mode bits for read/write are
// not a bitwise-or - they are distinct values
#define MODE_BITS 3
// it's much easier to *NOT* even deal with the
// fact that open() is a varargs function
// but that means probably having to do some
// typedef's and #defines to get this to compile
// typedef some function points to make things easier
typedef int (*open_ptr_t)(const char *name, int flags, mode_t mode);
typedef ssize_t (*read_ptr_t)(int fd, void *buf, size_t bytes);
typedef int (*close_ptr_t)(int fd);
// function points to the real IO library calls
static open_ptr_t real_open = NULL;
static read_ptr_t real_read = NULL;
static close_ptr_t real_close = NULL;
// this will return non-zero if 'filename' is a file
// to cause short reads on
static int shortReadsOnFd(const char *filename)
{
// add logic here based on the file name to
// return non-zero if you want to do
// short reads on this file
//
// return(1);
return(0);
}
// interpose on open()
int open(const char *filename, int flags, mode_t mode)
{
static pthread_mutex_t open_mutex = PTHREAD_MUTEX_INITIALIZER;
int fd;
pthread_mutex_lock(&open_mutex);
if (NULL == real_open)
{
real_open = dlsym(RTLD_NEXT, "open");
}
pthread_mutex_unlock(&open_mutex);
fd = real_open(filename, flags, mode);
if ((-1 == fd) || (fd >= MAX_FDS))
{
return(fd);
}
int mode_bits = flags & MODE_BITS;
// if the file can be read from, check if this is a file
// to do short reads on
if ((O_RDONLY == mode_bits) || (O_RDWR == mode_bits))
{
short_read_array[ fd ] = shortReadsOnFd(filename);
}
return(fd);
}
ssize_t read(int fd, void *buffer, size_t bytes)
{
static pthread_mutex_t read_mutex = PTHREAD_MUTEX_INITIALIZER;
if ((fd < MAX_FDS) && (short_read_array[ fd ]))
{
// read less bytes than the caller asked for
bytes /= 2;
if (0 == bytes)
{
bytes = 1;
}
}
pthread_mutex_lock(&read_mutex);
if (NULL == real_read)
{
real_read = dlsym(RTLD_NEXT, "read");
}
pthread_mutex_unlock(&read_mutex);
return(real_read(fd, buffer, bytes));
}
int close(int fd)
{
static pthread_mutex_t close_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&close_mutex);
if (NULL == real_close)
{
real_close = dlsym(RTLD_NEXT, "close");
}
pthread_mutex_unlock(&close_lock);
if (fd < MAX_FDS)
{
short_read_array[ fd ] = 0;
}
return(real_close(fd));
}
컴파일
export LD_PRELOAD=/path/to/libshortread.so
같은 LD_PRELOAD에 특히 조심 - 프로세스 트리의 모든 프로세스 라이브러리를로드해야합니다. 64 비트 라이브러리를로드해야하는 경우 32 비트 프로세스가 실행되지 않으며 32 비트 라이브러리를로드하려고 시도하는 64 비트 프로세스도 실행되지 않습니다. 위의 소스에 LD_PRELOAD
환경 변수를 제거하는 init 함수를 추가 할 수 있습니다 (또는 무언가로 설정 함).
open()
에 O_DIRECT
플래그를 사용하는 응용 프로그램이 있으면주의해야합니다. 읽기되는 바이트 수를 수정하면 페이지 크기 IO 조작 만 지원 될 수 있으므로 일부 Linux 파일 시스템 및/또는 구현에서는 직접 입출력이 중단 될 수 있습니다.
그리고이 코드는 read()
만 처리합니다. creat()
을 처리해야 할 수도 있습니다. 또한 pread()
, readat()
, aio_read()
및 lio_listio()
(어쩌면 내가 지금은 기억할 수없는 몇 가지 다른 것들도 있습니다). 또한 대용량 파일을 처리하는 32 비트 프로세스에주의하십시오. 내가 그것들을 다루었으니 꽤 오랜 시간이 걸렸지 만, 그건 내가 기억하는 것처럼 추악해질 수있다.
또 다른주의해야 할 점은 open()
및 read()
라이브러리 호출을 호출 할 수 있으며, 직접 관련 시스템 호출을 발행 할 수있다 등 fopen()
및 fread()
로 호출합니다. 이 경우 해당 통화의 동작을 쉽게 수정할 수 없습니다. fgets()
과 같은 데이터를 읽을 수있는 STDIO 기반 호출 전체 제품군에 끼어 들기는 매우 어려운 일입니다.
이을 알고 있으면 응용 프로그램이 단일 스레드이므로 뮤텍스를 삭제할 수 있습니다.
가장 쉽거나 가장 유연한 것은 아마도 mkfifo() 또는 mknod()로 명명 된 파이프를 만드는 것일 것입니다. – Will
일반적으로 관련 'read()'변형을 호출하고 전체 크기를 반환하는 '표지'기능을 호출하지만 요청시 짧은 금액을 반환하도록 구성 할 수 있습니다. 'ssize_t tst_read (void * buffer, size_t size, int fd) {ssize_t nbytes = 읽기 (버퍼, 크기, fd); if (... 적절한 테스트 조건 ...) nbytes - = 13; return nbytes; }'. 테스트 할 필요가있는 각 읽기와 같은 기능에 대해 린스하고 반복하십시오. –
어, 그래, 만약 당신이 그냥 @ JonathanLeffler 제시대로 * 읽기 호출 자체를 캡슐 수 있습니다 * 그 * 물론 최선의 것입니다 :) – Will