LD_PRELOAD를 이용하여 고정 인자 함수를 후킹하는 방법의 경우에는 여기저기 설명이 잘 된곳이 많으므로 생략하겠습니다.

이런 블로그 글들을 참고하시면 되겠습니다.


 LD_PRELOAD를 이용하여 함수들을 후킹하는 도중, 인자의 개수가 정해진 것이 아니라 가변적인 함수라면 어떻게 후킹을 해야 하는지 고민을 한 적이 있습니다. 대표적인 예가 printf, sprintf류의 포맷팅 함수들입니다. 이런 함수들은 포맷 문자의 개수에 따라 뒤따라 들어가는 인자의 개수가 계속 늘어날 수 있습니다. 이 포스팅에서는 이런 함수들을 LD_PRELOAD를 이용해 후킹하는 방법에 대해서 설명합니다.


 우선 가변 인자 함수를 만드는 방법에 대하여 알아보아야 합니다. 관련된 내용은 여기에 자세히 잘 정리되어 있습니다.

위 내용을 참고하여 fprintf 함수를 후킹하는 코드를 작성하면 다음과 같이 나오게 됩니다.


1
2
3
4
5
6
7
8
9
int fprintf(FILE *fp, const char *format, ...)
{
    int ret;
    va_list ap;
    va_start(ap, format);
    // 원하는 후킹 행위
    va_end(ap);
    return ret;
}
cs


 위 코드와 LD_PRELOAD를 이용하면 바로 fprintf 함수를 후킹하는 것이 가능합니다. 하지만 아직 완전하지는 않습니다. 문제는 바로 원본 함수인 fprintf 함수를 실행시킬 수가 없기 때문입니다. 이미 스스로 fprintf 함수를 정의해버렸기 때문에 그냥은 libc 함수를 호출할 수 없고, 만약 dlsym(RTLD_NEXT, "fprintf")을 이용해 libc의 fprintf 함수 주소를 가져오면 실행은 시킬 수 있겠지만 fprintf는 말 그대로 가변 인자 함수이기 때문에 인자가 몇 개 들어갈지 알 수 없는 상황에서 사용할 수가 없습니다.


 이럴 때 사용할 수 있는 대체 함수들이 libc에 정의되어 있습니다.

fprintf의 경우에는 vfprintf라고 하며, 이 두 함수의 선언부는 다음과 같습니다.


1
2
int fprintf(FILE *fp, const char * format, ...);
int vfprintf(FILE *fp, const char * format, va_list arg );
cs


 둘 모두 비슷하지만 차이가 있다면 fprintf에서 가변 인자 방식으로 전달받는 인자를 vfprintf는 va_list 타입으로 받는다는 점입니다.

그 점을 제외하고는 두 함수는 하는 일이 동일합니다. 그렇다면 이제 이 vfprintf 함수를 사용하여 후킹하더라도 기존과 똑같이 동작하도록 위의 코드를 수정해보도록 하겠습니다.


1
2
3
4
5
6
7
8
9
10
11
int fprintf(FILE *fp, const char *format, ...)
{
    int ret
    va_list ap;
    va_start(ap, format);
    // 함수 호출 전 원하는 후킹 행위
    ret = vfprintf(fp, format, ap);
    // 함수 호출 후 원하는 후킹 행위
    va_end(ap);
    return ret;
}
cs


 위와 같이 코드를 작성하고 위아래로 함수 실행 전과 후에 원하는 후킹 행위를 추가로 작성하면 원본 함수 실행에 영향을 미치지 않고 후킹을 수행할 수 있습니다. fprintf는 vfprintf라는 함수가 있었고, 이외에도 libc에는 vfscanf, vprintf, vsprintf등 가변 인자 함수에 대응하는 va_list 인자 함수들이 정의되어 있습니다. 이런 함수들을 후킹할 일이 있다면 위 함수들을 찾아서 가져다 쓰면 되겠습니다.

블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,