블로그 이전했습니다. https://jeongzero.oopy.io/
main 함수가 호출, 종료되는 과정
본문 바로가기
보안/Linux

main 함수가 호출, 종료되는 과정

728x90

elf 파일을 보통 디버깅 할때 main문 부터 확인했었다. 하지만 문제를 풀다가 main함수가 호출되기 까지, 종료된 후 의 과정을 알아야 할 필요가 생겨서 간단하게 정리하고자 한다. 

 

1. ELF 헤더 확인

우선 readelf -h 명령어로 현재 challenge 라는 바이너리를 확인한 결과이다. 엔트리 포인트 주소를 보면 0x4006c0을 가리키고 있는데 해당 주소가 무엇인지 아이다로 확인해보자. 

 

해당 주소는 _start 함수이다. 따라서 _start 함수가 처음에 호출된다 

 

 

2. _start 함수

  • _start() 함수
void __usercall __noreturn start(__int64 a1@<rax>, void (*a2)(void)@<rdx>)
{
  int v2; // esi
  int v3; // [rsp-8h] [rbp-8h]
  __int64 _0; // [rsp+0h] [rbp+0h]

  v2 = v3;
  *(_QWORD *)&v3 = a1;
  _libc_start_main(
    (int (__fastcall *)(int, char **, char **))main,
    v2,
    (char **)&_0,
    (void (*)(void))_libc_csu_init,
    _libc_csu_fini,
    a2,
    &v3);
  __halt();
}

start 함수를 살펴보면, 바이너리 실행 과정에 필요한 여러 요소들을 초기화하기 위해_libc_start_main 함수를 호출한다. 해당 함수는 libc안에 존재하는 함수이므로, 일반적인 함수들과 같이 plt를 뒤져 got table에 먼져 등록을 한다음 호출이 된다. 인자로 _libc_csu_init, 요 함수포인터가 들어가는데, 이 함수안에서 초기화가 이뤄진다. 

 

 

 

3. __libc_start_main() 함수

__libc_start_main 을 디버깅하고 있는 화면이다. 쭉 가다보면 +125 위치에 call rbp 부분이 있다. 현재 rbp에는 아까 인자로 넣었던, __libc_csu_init 함수이다. 해당 함수안에서 초기화가 이루어진다. 

 

 

 

3.1. __libc_csu_init 함수

__libc_csu_init (int argc, char **argv, char **envp)
{
  /* For dynamically linked executables the preinit array is executed by
     the dynamic linker (before initializing any shared object).  */
#ifndef LIBC_NONSHARED
  /* For static executables, preinit happens right before init.  */
  {
    const size_t size = __preinit_array_end - __preinit_array_start;
    size_t i;
    for (i = 0; i < size; i++)
      (*__preinit_array_start [i]) (argc, argv, envp);
  }
#endif
#ifndef NO_INITFINI
  _init ();
#endif
  const size_t size = __init_array_end - __init_array_start;
  for (size_t i = 0; i < size; i++)
      (*__init_array_start [i]) (argc, argv, envp);
}

매크로로 정의된 거에 따라서 진행이 된다. 자세한 거는 모르지만, 디버깅 해본 결과 _init() 함수가 호출되고 그 아래 로직이 수행되는것을 확인했다. 

 

for문을 보면 init_array 섹션의 크기가 size 변수에 들어간다. 그 후에 해당 섹션의 사이즈를 만큼 반복문을 돌면서 .init_array 에 저장된 함수 포인터들 호출한다. 요부분을 현재 challenge 바이너리를 대상으로 확인해보자.  

 

요 부분에 저장된 함수포인터들이 for문을 돌면서 호출된다. 현 바이너리에는 _frame_dummy 머시기 하나만 호출되는 것 같다. 이 부분을 디버깅으로 확인해보자 

 

저 초록색 라인이 바로 .init_array 에 저장된 함수포인터가 호출되는 라인이다. __libc_csu_init() 함수에서 아래 라인을 말하는 것이다.  

(*__preinit_array_start [i]) (argc, argv, envp);

 

해당 값은 아이다에서 확인한 바와 같이 frame_dummy 머시기가 들어가있고 이것이 호출되는 것이다. 현재 바이너리는 저 하나만 호출하고 끝나게 된다. 어쨋든 __libc_csu_init() 함수의 호출이 끝나고 다시 __libc_start_main 로 돌아가서 쭉 진행을 하다보면 

 

' call rdx ' 를 하게된다. 이는 우리가 잘 아는 바로 main 이다!. call rax가 끝나고 그 아래 라인은 main 함수에서 ret시에 실행되는 라인이다. 이때부터는 아래에서 분석할 것이다. 

이렇게 main 함수가 호출되기 전까지의 과정을 간략히 알아보았다. 이제 main함수가 끝나고 ret이 될때의 과정을 살펴보자 

 

 

 

4. fini_array 섹션

init_array 섹션이 main 함수 호출전 초기화를 위한 영역이라면 fini_array를 main함수가 종료된후 정상적인 종료를 위해 참조되는 섹션이다. 직접 디버깅을 하면서 확인해보자 

 

main 함수에서 ret을 하게되면 libc_start_main+240 으로 오게된다. 아까 위에서 말했던 부분이다. 그다음 call __GI_exit 를 하게 된다. 이 함수에서 결국 최종 종료가 된다고 보면 된다. 해당 함수로 들어가보자. 

 

__GI_exit 함수를 따라가다 보면 __run_exit_handlers를 호출하게 된다. 해당 함수는 exit_function 구조체 멤버 변수인 flavor 값에 따라서 함수를 호출하는데, 기본적으로는 로더 라이브러리 내부에 존재하는 _dl_fini 함수를 호출한다고 한다. - 참조 

 

__run_exit_handlers 를 쭉 따라가다 보면 ' call rdx ' 가 나온다. 이 부분이 방금 말한 _dl_fini 함수이다. 해당 함수로 들어가보자 

 

_dl_fini 함수를 또 쭉 따라가다보면 __libc_csu_init 와 비슷한 로직이 있다. r12에는 현재 0x600bc0이 담겨져 있고 해당 주소는 0x400770을 가리키고 있는데 결국 0x400770이 호출된다. 

 

0x400770__do_global_dtors_aux 함수로, fini_array에 담겨져 있는 함수포인터이다. main 함수를 종료하는 소멸자 정도로 생각하면 될 것같다. 이렇게 _dl_fini 함수가 쭉쭉 실행되고 다시 __run_exit_handlers 로 돌아온다. 

 

다시 __run_exit_handlers 를 쭉쭉 실행하다가 보면 __GI__exit 함수가 호출된다. 헷갈리면 안되는게, 아까 위에서 호출한거를 또 호출하지? 라고 생각하면 안된다. 자세히 보면 exit 앞에 ' _ ' 가 2개 이다. 아까는 한개였다.ㅋ 확인해보니 해당 함수에서 syscall로 실제로 종료가 되었다.  

 

해당 함수로 들어와서 쭉쭉 디버깅을 하다보면 rax = 0xe7 을 인자로하여 syscall이 호출된다. 이는 sys_exit_group syscall 테이블 번호이다. 여기서 실제로 종료가 되버린다. 

 

 

 

5. 정리

이 모든 과정을 간략히 표현하면 다음과 같다 

 

출처 : https://www.slideshare.net/AngelBoy1/linux-binary-exploitation-basic-knowledge 

 

 

6. 참고자료

728x90

'보안 > Linux' 카테고리의 다른 글

fuzzing 이란  (3) 2020.08.26
seccomp 간단 정리  (0) 2020.07.08
fclose 분석  (0) 2020.05.01
House of Orange 분석  (0) 2020.04.29
House of Force 분석  (0) 2020.04.20