운영체제

library interpositioning

pobii 2025. 4. 18. 19:52

목차

  • 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)를 사용하여 구현하였다.