library interpositioning
목차
- library interpositioning
- library interpositioning이란?
- 사용 예시
- 컴파일타임에 interpositioning하기
- 링크타임에 interpositioning하기
- 로드/런타임에 interpositioning하기
- 정리
목표
컴파일타임, 링크타임, 로드/런타임에 interpositioning을 할 수 있다.
library interpositioning 이란?
라이브러리 함수 호출시 호출을 가로채 추가 작업을 하는 방법이다. 특정 함수 호출시 실제 함수 대신 커스텀한 함수를 호출하도록 한다.
이는 컴파일타임, 링킹타임, 로드타임에 모두 구현 가능하다.
사용예시
- 보안
ex) sandboxing - 프로그램을 격리된 환경에서 실행시켜서 문제가 생겨도 시스템 전체에 영향을 못 미치게 하는 보안 기법이다. 즉 "가짜 환경"을 만들어 실행을 통제한다.
- 디버깅, 모니터링
ex) malloc()의 메모리 누수를 감지하고, 할당 주소를 확인할 수 있다.
interpositioning 해보기
아래 코드는 동적할당,해제하는 간단한 코드다.
example.c
#include <stdio.h>
#include <malloc.h>
int main() {
int *p = malloc(32);
free(p);
return(0);
}
이 파일을 수정하지 않고 malloc() 호출시 malloc의 할당 주소를 출력하도록 만들어보자.
컴파일 타임에 malloc 호출을 가로채 출력하는 방법,
링크타임에 malloc 호출을 가로채 출력하는 방법,
로드/런타임에 malloc 호출을 가로채 출력하는 방법,
3가지 모두 구현해보겠다.
컴파일 타임에 interpositioning 하기
mymalloc.c 생성
malloc(), free()를 커스텀한 함수다. #ifdef를 활용하여 main에서 malloc 호출시 mymalloc이 호출되도록 한다.
#ifdef COMPILETIME
#include <stdio.h>
#include <malloc.h>
void *mymalloc(size_t size){
void *ptr = malloc(size); //실제 malloc함수 호출
printf("malloc(%d)=%p\n", (int)size, ptr);
return ptr;
}
void myfree(void *ptr){
free(ptr);
printf("free(%p)\n", ptr);
}
#endif
malloc.h 생성
기존의 malloc.c 대신 mymalloc.c를 사용하라는 헤더파일이다.
즉 main코드에서 malloc()을 호출하면 mymalloc()이 호출되도록 한다.
#define malloc(size) mymalloc(size)
#define free(ptr) myfree(ptr)
void *mymalloc(size_t size);
void myfree(void *ptr);
터미널 실행
# mymalloc.c 컴파일하기
gcc -DCOMPILETIME -c mymalloc.c # -DCOMPILETIME : "#ifdef COMPILETIME"인 코드 활성화하기
# example.c 컴파일하기
gcc -I. -c example.c -o example.o
# exapmple.o, mymalloc.o 링크하기
gcc -I. -o example example.c mymalloc.o
# 실행하기
./example
실행결과
링크 타임에 interpositioning 하기
__real_malloc()과 __wrap_malloc()을 사용한 방법이다.
"--wrap" 터미널 명령어를 사용하여 malloc() 호출시 __wrap_malloc()이 호출되도록 한다.
__wrap_malloc() 함수 내부에 __reall_malloc()을 호출하여 실제 malloc()을 호출하도록 한다.
이때 __real_malloc은 링커가 자동으로 생성해주는 심볼이다.
mymalloc.c 생성
#ifdef LINKTIME
#include <stdio.h>
void *__real_malloc(size_t size); //실제 malloc()을 호출하는 함수
void __real_free(void *ptr);
void *__wrap_malloc(size_t size){ //.c의 malloc() 호출시 호출되는 함수
void *ptr = __real_malloc(size);
printf("malloc(%d) = %p\n", (int)size, ptr);
return ptr;
}
void __wrap_free(void *ptr){
__real_free(ptr);
printf("free(%p)\n", ptr);
}
#endif
그림으로 나타낸 호출 과정
터미널 실행
--wrap, malloc : ".c의 malloc()를 __wrap_malloc()로 대체해라"
두 .o 파일을 링크할때 interpositioning 됨을 알 수 있다.
# mymalloc.c 컴파일하기
gcc -DLINKTIME -c mymalloc.c
# example.c 컴파일하기
gcc -c example.c
# example.o, mymalloc.o링크하기
gcc -Wl, --wrap,malloc -Wl, --wrap,free -o example example.o mymalloc.o
# 실행하기
./example
실행결과
로드/런타임에 interpositioning 하기
mymalloc.c
#ifdef RUNTIME
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
void *malloc(size_t size) {
void*(*mallocp)(size_t size);
char *error;
mallocp = dlsym(RTLD_NEXT, "malloc"); // 실제 malloc() 가져오기
if ((error = dlerror()) != NULL){
fputs(error, stderr);
exit(1);
}
char *ptr = mallocp(size); // 실제 malloc() 호출
printf("malloc(%d) = %p\n", (int)size, ptr);
return ptr;
}
#endif
터미널
실행시에 interpositioning된다는 것을 알 수 있다.
# mymalloc.c을 .so(동적 라이브러리)로 컴파일하기
gcc -DRUNTIME -shared -fpic -o mymalloc.so mymalloc.c -ldl
# example.c 컴파일하기
gcc -o example example.c
# 실행하기
# 동적 링커에게 다른 라이브러리 보기 전에 mymalloc.so에서 먼저 찾으라고 명시
LD_PRELOAD="./mymalloc.so" ./example
실행결과
정리
이로써 컴파일시, 링크시, 로드/런타임 시에 interpositioning이 가능하다는것을 알 수 있었다.
컴파일 타임에는 전처리기 지시어 (#define, #ifdef)를 사용하고,
링크 타임에는 링커옵션인 "--wrap"을 사용하고,
로드/런타임에는 환경변수(LD_PRELOAD)를 사용하여 구현하였다.