ghkdtlwns987

_IO_FILE_vtable 1 본문

시스템

_IO_FILE_vtable 1

2020/03/31 2020. 10. 10. 14:47

이번엔 _IO_FILE_vtable 에 대해 다뤄보고자 한다. 

_IO_FILE 이라 하면 파일 포인터(fp) 가 생각나는게 일반적이다. 

하지만 _IO_FILE 은 그보다 더 많은 정보를 포함하고 있다.

예를 들자면 read,write,fread,write... 와 같은 함수를 사용하면 내부적으로 _IO_FILE 구조체를 참고하게 되는 것이다.  

_IO_FILE

더보기
struct _IO_FILE
{
  int _flags;		/* High-order word is _IO_MAGIC; rest is flags. */
  /* The following pointers correspond to the C++ streambuf protocol. */
  char *_IO_read_ptr;	/* Current read pointer */
  char *_IO_read_end;	/* End of get area. */
  char *_IO_read_base;	/* Start of putback+get area. */
  char *_IO_write_base;	/* Start of put area. */
  char *_IO_write_ptr;	/* Current put pointer. */
  char *_IO_write_end;	/* End of put area. */
  char *_IO_buf_base;	/* Start of reserve area. */
  char *_IO_buf_end;	/* End of reserve area. */
  /* The following fields are used to support backing up and undo. */
  char *_IO_save_base; /* Pointer to start of non-current get area. */
  char *_IO_backup_base;  /* Pointer to first valid character of backup area */
  char *_IO_save_end; /* Pointer to end of non-current get area. */
  struct _IO_marker *_markers;
  struct _IO_FILE *_chain;
  int _fileno;
  int _flags2;
  __off_t _old_offset; /* This used to be _offset but it's too small.  */
  /* 1+column number of pbase(); 0 is unknown. */
  unsigned short _cur_column;
  signed char _vtable_offset;
  char _shortbuf[1];
  _IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

 

  • _flags

    • 파일에 대한 읽기/쓰기/추가 권한을 의미한다. 0xfbad0000가 매직 값이며 하위 2바이트는 여러 비트 플래그들입니다. 각각의 의미에 대해서는 잠시 후에 다루겠다.

  • _IO_read_ptr

    • 파일 읽기 버퍼에 대한 포인터이다.

  • _IO_read_end

    • 파일 읽기 버퍼 주소의 끝을 가리키는 포인터이다.

  • _IO_read_base

    • 파일 읽기 버퍼 주소의 시작을 가리키는 포인터이다

  • _IO_write_base

    • 파일 쓰기 버퍼 주소의 시작을 가리키는 포인터이다

  • _IO_write_ptr

    • 쓰기 버퍼에 대한 포인터이다.

  • _IO_write_end

    • 파일 쓰기 버퍼 주소의 끝을 가리키는 포인터이다.

  • _chain

    • 프로세스의 _IO_FILE 구조체는 _chain 필드를 통해 링크드 리스트를 만든다. 링크드 리스트의 헤더는 라이브러리의 전역 변수인 _IO_list_all에 저장된다.

  • _fileno

    • 파일 디스크립터의 값이다.

 

+ 예를 들자면 다음과 같을 것이다. 

  • Read buffers
    1. _IO_read_ptr
    2. _IO_read_end
    3. _IO_read_base
  • Write buffers
    1. _IO_write_ptr
    2. _IO_write_end
    3. _IO_write_base
  • Reserve buffers
    1. _IO_buf_base
    2. _IO_buf_end

위의 접은 글에 있는 내용은 드림핵에 나와 있는 내용이다. 

난 여기서 추가로 공부했던 내용도 추가로 정리해 볼 예정이다.

 

먼저, _IO_write_base, _IO_write_ptr 에 대해 설명해 보자면 _IO_write_base < _IO_write_ptr 이 된다면

_IO_overflow() 함수를 호출하게 되는데, 이는 잠시 후에 설명하도록 하겠다. (너무 길어지면 다음글에 정리)

 

우선은 flag 에 대해 설명해보고자 한다. 

#define _IO_MAGIC         0xFBAD0000 /* Magic number */
#define _IO_MAGIC_MASK    0xFFFF0000
#define _IO_USER_BUF          0x0001 /* Don't deallocate buffer on close. */
#define _IO_UNBUFFERED        0x0002
#define _IO_NO_READS          0x0004 /* Reading not allowed.  */
#define _IO_NO_WRITES         0x0008 /* Writing not allowed.  */
#define _IO_EOF_SEEN          0x0010
#define _IO_ERR_SEEN          0x0020
#define _IO_DELETE_DONT_CLOSE 0x0040 /* Don't call close(_fileno) on close.  */
#define _IO_LINKED            0x0080 /* In the list of all open files.  */
#define _IO_IN_BACKUP         0x0100
#define _IO_LINE_BUF          0x0200
#define _IO_TIED_PUT_GET      0x0400 /* Put and get pointer move in unison.  */
#define _IO_CURRENTLY_PUTTING 0x0800
#define _IO_IS_APPENDING      0x1000
#define _IO_IS_FILEBUF        0x2000
                           /* 0x4000  No longer used, reserved for compat.  */
#define _IO_USER_LOCK         0x8000

다음은 flag bit 이다. 만약 flag 가 0xfbad2488 라 한다면 _IO_MAGIC, _IO_IS_FILIEBUF, _IO_TIED_PUT_GET, _IO_LINKED, _IO_NO_WRITES 가 설정되어 있다고 볼 수 있다. 

설명할게 많기 떄문에 우선은 여기까지만 설명하고 넘어가겠다. 

 

 

 

다음으로는 _IO_FILE_vtable 에 대해서 알아보도록 하자. 

이는 _IO_FILE_plus 라고도 불린다. 즉, _IO_FILE_plus 는 vtable을 가리킨다라고 생각하면 된다. 

stdin, stdout, stderr 도 이 구조체를 사용하고, 모든 파일 관련된 작업들은 이 _IO_FILE_plus 를 사용한다.

struct _IO_FILE_plus
{
  _IO_FILE file;
  const struct _IO_jump_t *vtable;
};

(디버깅을 할 때는 _IO_file_jumps 라고 한다. 실제 명칭도 그렇다.)

const struct _IO_jump_t _IO_file_jumps libio_vtable =
{
  JUMP_INIT_DUMMY,
  JUMP_INIT(finish, _IO_file_finish),
  JUMP_INIT(overflow, _IO_file_overflow),
  JUMP_INIT(underflow, _IO_file_underflow),
  JUMP_INIT(uflow, _IO_default_uflow),
  JUMP_INIT(pbackfail, _IO_default_pbackfail),
  JUMP_INIT(xsputn, _IO_file_xsputn),
  JUMP_INIT(xsgetn, _IO_file_xsgetn),
  JUMP_INIT(seekoff, _IO_new_file_seekoff),
  JUMP_INIT(seekpos, _IO_default_seekpos),
  JUMP_INIT(setbuf, _IO_new_file_setbuf),
  JUMP_INIT(sync, _IO_new_file_sync),
  JUMP_INIT(doallocate, _IO_file_doallocate),
  JUMP_INIT(read, _IO_file_read),
  JUMP_INIT(write, _IO_new_file_write),
  JUMP_INIT(seek, _IO_file_seek),
  JUMP_INIT(close, _IO_file_close),
  JUMP_INIT(stat, _IO_file_stat),
  JUMP_INIT(showmanyc, _IO_default_showmanyc),
  JUMP_INIT(imbue, _IO_default_imbue)
};

다음은 _IO_FILE_vtable 이다. _IO_FILE_vtable 이라 함은 _IO_FILE 에서 내부적으로 호출하는 table 이라 할 수 있다. 

만약 read() 가 실행이 된다면 vtable은 read 를 가리킬 것이고, fclose() 함수가 호출이 되면 close() 가 호출 될 것이다. 

이는 직접 디버깅을 통해 보여주겠다.

다음 그림은 read() 함수가 실행되었을 때의 파일 포인터이다. 

vtable 은 빨간색으로 체크 해 놓은곳에 존재한다. 

다음을 보면 _IO_file_jumps 가 있고, 특정 주소가 들어가 있다. 이를 확인해보자.

다음과 같이 file_finish, file_overflow... 을 가리키는 주소가 들어가 있다.

 

그림으로 표현하자면 다음과 같다. 

 

이번 글에서는 _IO_FILE 구조체, _IO_FILE_Plus 구조체, file_jumps 를 공부해 봤다. 

다음글에서는 _IO_FILE_vtable 을 가지고 어떻게 Exploit 하는지 알아보도록 하겠다.

'시스템' 카테고리의 다른 글

FSOB(_IO_flush_all_lockp )  (0) 2020.10.10
flose() 분석  (0) 2020.10.10
FSOB(File Stream Oriented Programming) 1  (0) 2020.10.10
_IO_FILE_vtable_check  (0) 2020.10.10
_IO_FILE_vtable 2  (0) 2020.10.10
Comments