시프 06- Linking2

강준호·2024년 6월 2일

시스템프로그래밍

목록 보기
4/18

라이브러리 인터포지셔닝

라이브러리 인터포지셔닝이란?

  • 라이브러리 인터포지셔닝은 프로그래머가 임의의 함수 호출을 가로챌 수 있게 해주는 강력한 링킹 기법입니다.
  • 인터포지셔닝은 다음과 같은 시점에서 발생할 수 있습니다:
    • 컴파일 시간: 소스 코드가 컴파일될 때
    • 링크 시간: 재배치 가능 객체 파일이 실행 가능 객체 파일로 정적으로 링크될 때
    • 로드/런타임: 실행 가능 객체 파일이 메모리에 로드되고 동적으로 링크된 후 실행될 때

인터포지셔닝 응용 프로그램

보안

  • 컨파인먼트 (sandboxing): 특정 환경에서 프로그램 실행을 제한.
  • 암호화: 프로그램 실행 중 암호화 작업을 수행.

디버깅

  • 예: 2014년 Facebook 엔지니어들이 인터포지셔닝을 사용하여 iPhone 앱의 오래된 버그를 디버깅.
  • 잘못된 위치에 데이터를 쓰는 코드 문제를 해결하기 위해 POSIX 쓰기 함수(write, writev, pwrite)를 가로챔.

모니터링 및 프로파일링

  • 함수 호출 횟수 계산.
  • 함수 호출 위치와 인수 특성화.
  • 메모리 할당 추적(malloc tracing) 및 메모리 누수 감지.

인터포지셔닝 예시 프로그램

목표

  • 할당되고 해제된 블록의 주소와 크기를 추적.
  • 프로그램을 중단시키지 않고, 소스 코드를 수정하지 않고 수행.

컴파일 시간 인터포지셔닝

  1. 컴파일 타임 인터포지셔닝 코드

    #ifdef COMPILETIME
    #include <stdio.h>
    #include <malloc.h>
    
    void *mymalloc(size_t size) {
        void *ptr = malloc(size);
        printf("malloc(%d)=%p\n", (int)size, ptr);
        return ptr;
    }
    
    void myfree(void *ptr) {
        free(ptr);
        printf("free(%p)\n", ptr);
    }
    #endif
  2. 컴파일 타임 인터포지셔닝 매크로

    #define malloc(size) mymalloc(size)
    #define free(ptr) myfree(ptr)
    
    void *mymalloc(size_t size);
    void myfree(void *ptr);
    
    gcc -Wall -DCOMPILETIME -c mymalloc.c
    gcc -Wall -I. -o intc int.c mymalloc.o
    ./intc
  3. 출력 결과

    malloc(32)=0x1edc010
    free(0x1edc010)

링크 시간 인터포지셔닝

  1. 링크 타임 인터포지셔닝 코드

    #ifdef LINKTIME
    #include <stdio.h>
    
    void *__real_malloc(size_t size);
    void __real_free(void *ptr);
    
    void *__wrap_malloc(size_t size) {
        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
  2. 링크 타임 인터포지셔닝 컴파일

    gcc -Wall -DLINKTIME -c mymalloc.c
    gcc -Wall -c int.c
    gcc -Wall -Wl,--wrap,malloc -Wl,--wrap,free -o intl int.o mymalloc.o
    ./intl
  3. 출력 결과

    malloc(32) = 0x1aa0010
    free(0x1aa0010)

로드/런타임 인터포지셔닝

  1. 런타임 인터포지셔닝 코드

    #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");
        if ((error = dlerror()) != NULL) {
            fputs(error, stderr);
            exit(1);
        }
        void *ptr = mallocp(size);
        printf("malloc(%d) = %p\n", (int)size, ptr);
        return ptr;
    }
    #endif
  2. 런타임 인터포지셔닝 컴파일 및 실행

    gcc -Wall -DRUNTIME -shared -fpic -o mymalloc.so mymalloc.c -ldl
    gcc -Wall -o intr int.c
    LD_PRELOAD="./mymalloc.so" ./intr
  3. 출력 결과

    malloc(32) = 0xe60010
    free(0xe60010)

인터포지셔닝 요약

  • 컴파일 시간

    • malloc/free 호출이 매크로 확장을 통해 mymalloc/myfree로 변경됨.
  • 링크 시간

    • 링커 트릭을 사용하여 특수 이름 해결 방식을 사용.
    • malloc -> __wrap_malloc
    • __real_malloc -> malloc
  • 로드/런타임

    • 동적 링크를 사용하여 라이브러리 malloc/free를 다른 이름으로 로드.

결론

  • 링커는 정적 링킹과 동적 링킹을 처리하며, 라이브러리 인터포지셔닝을 통해 다양한 목적으로 함수 호출을 가로챌 수 있습니다.
  • 이러한 기술을 통해 보안, 디버깅, 모니터링 및 프로파일링 등의 작업을 효율적으로 수행할 수 있습니다.

이 설명은 라이브러리 인터포지셔닝의 개념과 다양한 시점에서의 구현 방법을 구체적으로 다룹니다.

0개의 댓글