
ํ์ผ์ ์ด ๋ ํ์ผ ์ ๊ทผ ์ ํ์ ๋ช ์ํด์ผ ํ๋๋ฐ, ๋ํ์ ์ผ๋ก ์ฝ๊ธฐ ๋ฐ ์ฐ๊ธฐ ๋ชจ๋๊ฐ ์๋ค.
์ฝ๊ธฐ ๋ชจ๋๋ก ํ์ผ์ ์ด๊ณ , ํ์ผ์ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๋ ค ํ๋ฉด ์๋ฌ๊ฐ ๋ฐ์ํ์ง๋ ์์ง๋ง ๊ธฐ๋ฅ์ด ์ํ๋์ง ์๋๋ค.
๋ชจ๋ ํ์ผ ํจ์๋ fopen ํจ์์์ ๋ฐํํ ํ์ผ ํฌ์ธํฐ๋ฅผ ์ธ์๋ก ์ ๋ฌ๋ฐ๊ณ , ๊ธฐ๋ฅ์ ์ํํ๊ธฐ ์ ์ ํ์ผ ํฌ์ธํฐ๋ฅผ ์ฐธ์กฐํด ํ์ผ ์ ๋ณด๋ฅผ ๋จผ์ ํ์ธํ๋ค. ํ์ผ์ ์ ๋ณด๋ก๋ ํ์ผ์ด ์ด๋ค ๋ชจ๋๋ก ์ด๋ ธ์ผ๋ฉฐ, ํ์ผ ์์ ์ ์ํํ๊ธฐ ์ํ ํจ์ ์ฃผ์๊ฐ ํฌํจ๋๋ค
-> ํ์ผ ์์ ์ด ์ด๋ป๊ฒ ์ด๋ค์ง๋์ง ์๊ธฐ ์ํด์๋ ํ์ผ ๊ตฌ์กฐ์ฒด๋ฅผ ์ดํดํ๊ณ ์์ด์ผ ํ๋ค.
_IO_FILE ์ค์ต ์์ ์ฝ๋
// Name: iofile.c
// Compile: gcc -o iofile iofile.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
void file_info(FILE *buf) {
printf("_flags: %x\n", buf->_flags);
printf("_fileno: %d", buf->_fileno);
}
int main() {
FILE *fp;
char buf[256];
strcpy(buf, "THIS IS TESTFILE!");
fp = fopen("testfile", "w");
fwrite(buf, 1, strlen(buf), fp);
file_info(fp);
fclose(fp);
return 0;
}
_IO_FILE
_IO_FILE์ ๋ฆฌ๋ ์ค ์์คํ ์ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ํ์ผ์คํธ๋ฆผ์ ๋ํ๋ด๊ธฐ ์ํ ๊ตฌ์กฐ์ฒด์ด๋ค.
-> ํ์ผ์ ์ด๊ธฐ ์ํ fopenํจ์๋ฅผ ์ฌ์ฉํ ๋ ํ ์์ญ์ ํ ๋น๋๋ค.
_IO_FILE ๊ตฌ์กฐ์ฒด
struct _IO_FILE_plus
{
FILE file;
const struct _IO_jump_t *vtable;
};
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 | ํ์ผ ๋์คํฌ๋ฆฝํฐ์ ๊ฐ |
_IO_jump_ t *vtable | ํ์ผ ๊ด๋ จ ์์ ์ ์ํํ๋ ๊ฐ์ ํจ์ ํ ์ด๋ธ |
_IO_FILE: _flags
_flags ๋ฉค๋ฒ ๋ณ์๋ ํ์ผ์ ์ฑ์ง์ ๋ํ๋ด๋ ํ๋์ด๋ค.
ํด๋น ํ๋๋ fopen ํจ์๋ก ํ์ผ์ ์ด ๋ ์ ๋ฌํ ๋ชจ๋์ ๋ฐ๋ผ ๊ฐ์ด ์ค์ ๋๋ค.
๋ค์์ _flags ๋ณ์๋ฅผ ๊ตฌ์ฑํ๋ ๊ฐ ๋นํธ๋ค์ ์งํฉ์ด๋ค.
#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
์์ ์ค์ต ์ฝ๋(iofile.c)๋ฅผ ์ปดํ์ผํ๊ณ ์คํํด๋ณด์.
0xfbad2c84: _IO_MAGIC์ด๋ผ๋ ๋งค์ง ๋๋ฒ๋ฅผ ํฌํจํ ๊ฐ ๊ถํ์ ์๋ฏธ
- ํด๋น ๊ฐ์ _flags ๋ฉค๋ฒ ๋ณ์ ๋นํธ ์งํฉ์ ํ์ธํด๋ณด๋ฉด _IO_MAGIC, _IO_NO_READS, _IO_LINKED, _IO_TIED_PUT_GET, _IO_CURRENTLY_PUTTING, _IO_IS_FILEBUF ๋นํธ๊ฐ ํฌํจ๋ ๊ฑธ ์ ์ ์๋ค.
๋ค์ ํจ์๋ fopen ํจ์๊ฐ ํธ์ถ๋ ๋ ์คํ๋๋ ๋ด๋ถ ํจ์์ธ _IO_new_file_fopen์ด๋ค.
FILE *_IO_new_file_fopen(FILE *fp, const char *filename, const char *mode,
int is32not64) {
int oflags = 0, omode;
int read_write;
int oprot = 0666;
int i;
FILE *result;
const char *cs;
const char *last_recognized;
if (_IO_file_is_open(fp)) return 0;
switch (*mode) {
case 'r':
omode = O_RDONLY;
read_write = _IO_NO_WRITES;
break;
case 'w':
omode = O_WRONLY;
oflags = O_CREAT | O_TRUNC;
read_write = _IO_NO_READS;
break;
case 'a':
omode = O_WRONLY;
oflags = O_CREAT | O_APPEND;
read_write = _IO_NO_READS | _IO_IS_APPENDING;
break;
...
}
์ฝ๋๋ฅผ ์ดํด๋ณด๋ฉด, fopen ํจ์์ ๋ ๋ฒ์งธ ์ธ์์ธ mode ๋ณ์๊ฐ 'r', 'w', 'a' ๋ฌธ์์ธ์ง ํ์ธํ๊ณ , ๊ฐ ๊ถํ์ ํด๋น๋๋ ๋นํธ๊ฐ ํ ๋น๋๋ ๊ฑธ ํ์ธํ ์ ์๋ค. ๋ํ read_write ๋ฟ๋ง์ด ์๋๋ผ omode ๋ณ์์๋ O_RDONLY, O_WRONLY ๋ฑ์ ๊ฐ์ด ์ ์ฅ๋๋ ๊ฑธ ํ์ธํ ์ ์๋ค.
fopen ํจ์๋ ๊ฒฐ๊ตญ open ์์คํ ์ฝ์ ํธ์ถํด ํ์ผ์ ์ฌ๋๋ฐ, ์ด๋ ํด๋น ์์คํ ์ฝ์ ์ธ์๋ก ์ ๋ฌ๋๋ค.
_IO_FILE: vtable
_IO_FILE_plus ๊ตฌ์กฐ์ฒด๋ฅผ ํ์ธํด๋ณด๋ฉด vtable ํฌ์ธํฐ๊ฐ ์กด์ฌํ๋ ๊ฑธ ํ์ธํ ์ ์๋ค.
Virtual function Table(vtable)์ ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์์ ํด๋์ค๋ฅผ ์ ์ํ๊ณ , ๊ฐ์ ํจ์๋ฅผ ์ฌ์ฉํ ๋ ํ ๋น๋๋ ํ ์ด๋ธ์ด๋ค.
-> ๋ฉ๋ชจ๋ฆฌ์ ๊ฐ์ ํจ์๋ฅผ ๋ด์ ์์ญ์ ํ ๋น
-> ํจ์์ ์ฃผ์๋ฅผ ๊ธฐ๋ก
๊ฐ์ ํจ์๋ฅผ ์ฌ์ฉํ๋ฉด ํด๋น ํ ์ด๋ธ์ ๊ธฐ์ค์ผ๋ก ์๋ ์ฃผ์๋ฅผ ํตํด ํธ์ถํ๋ค.
ํ์ผ ๊ตฌ์กฐ์ฒด๋ ๊ฐ ํ์ผ๋ง๋ค ํจ์ ํ ์ด๋ธ์ ๊ฐ๊ณ ์๋ค.
vtable ๋ณ์๋ ๊ฐ์ฒด ์งํฅ. ํ๋ก๊ทธ๋๋ฐ์์ ์ฌ์ฉํ๋ ํ ์ด๋ธ๊ณผ ๋น์ทํ๊ฒ ๊ตฌํ๋์ด์๊ณ , ํ์ผ ํจ์๋ฅผ ํธ์ถํ๋ฉด ํด๋น ํ ์ด๋ธ์ ์ฐธ์กฐํ๊ณ , ์ค์ ๊ธฐ๋ฅ์ ์ํํ๋ ํจ์๋ฅผ ํธ์ถํ๋ค.
๋ค์์ ํ์ผ ํจ์์ ํ ์ด๋ธ์ ์ ์ํ _IO_jump_t ๊ตฌ์กฐ์ฒด์ด๋ค.
struct _IO_jump_t
{
JUMP_FIELD(size_t, __dummy);
JUMP_FIELD(size_t, __dummy2);
JUMP_FIELD(_IO_finish_t, __finish);
JUMP_FIELD(_IO_overflow_t, __overflow);
JUMP_FIELD(_IO_underflow_t, __underflow);
JUMP_FIELD(_IO_underflow_t, __uflow);
JUMP_FIELD(_IO_pbackfail_t, __pbackfail);
/* showmany */
JUMP_FIELD(_IO_xsputn_t, __xsputn);
JUMP_FIELD(_IO_xsgetn_t, __xsgetn);
JUMP_FIELD(_IO_seekoff_t, __seekoff);
JUMP_FIELD(_IO_seekpos_t, __seekpos);
JUMP_FIELD(_IO_setbuf_t, __setbuf);
JUMP_FIELD(_IO_sync_t, __sync);
JUMP_FIELD(_IO_doallocate_t, __doallocate);
JUMP_FIELD(_IO_read_t, __read);
JUMP_FIELD(_IO_write_t, __write);
JUMP_FIELD(_IO_seek_t, __seek);
JUMP_FIELD(_IO_close_t, __close);
JUMP_FIELD(_IO_stat_t, __stat);
JUMP_FIELD(_IO_showmanyc_t, __showmanyc);
JUMP_FIELD(_IO_imbue_t, __imbue);
};
๊ตฌ์กฐ์ฒด๋ฅผ ์ดํด๋ณด๋ฉด, 16๋ฐ์ดํธ ํฌ๊ธฐ์ ๋๋ฏธ ๋ฐ์ดํธ๋ฅผ ํฌํจํด ๋ค์ํ ํจ์๊ฐ ์ ์๋ ๊ฑธ ํ์ธํ ์ ์๋ค.
๋๋ฒ๊น ํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค
gdb-peda$ p *(struct _IO_jump_t *)0x00007ffff7dca2a0
$32 = {
__dummy = 0x0,
__dummy2 = 0x0,
__finish = 0x7ffff7a6e400 <_IO_new_file_finish>,
__overflow = 0x7ffff7a6f3d0 <_IO_new_file_overflow>,
__underflow = 0x7ffff7a6f0f0 <_IO_new_file_underflow>,
__uflow = 0x7ffff7a70490 <__GI__IO_default_uflow>,
__pbackfail = 0x7ffff7a71d20 <__GI__IO_default_pbackfail>,
__xsputn = 0x7ffff7a6da00 <_IO_new_file_xsputn>,
__xsgetn = 0x7ffff7a6d660 <__GI__IO_file_xsgetn>,
__seekoff = 0x7ffff7a6cc60 <_IO_new_file_seekoff>,
__seekpos = 0x7ffff7a70a60 <_IO_default_seekpos>,
__setbuf = 0x7ffff7a6c920 <_IO_new_file_setbuf>,
__sync = 0x7ffff7a6c7a0 <_IO_new_file_sync>,
__doallocate = 0x7ffff7a601e0 <__GI__IO_file_doallocate>,
__read = 0x7ffff7a6d9e0 <__GI__IO_file_read>,
__write = 0x7ffff7a6d260 <_IO_new_file_write>,
__seek = 0x7ffff7a6c9e0 <__GI__IO_file_seek>,
__close = 0x7ffff7a6c910 <__GI__IO_file_close>,
__stat = 0x7ffff7a6d250 <__GI__IO_file_stat>,
__showmanyc = 0x7ffff7a71ea0 <_IO_default_showmanyc>,
__imbue = 0x7ffff7a71eb0 <_IO_default_imbue>
}
_IO_FILE: vtable ํธ์ถ ๊ณผ์
fread ํจ์์ ํธ์ถ ๊ณผ์ ์ ์ฝ๋๋ฅผ ํตํด ํ์ธํด๋ณด๋ฉฐ _IO_jump_t ๊ตฌ์กฐ์ฒด์ ์ด๋ป๊ฒ ์ ๊ทผํ๋์ง ์์๋ณด์.
#define fread(p, m, n, s) _IO_fread (p, m, n, s)
size_t
_IO_fread (void *buf, size_t size, size_t count, FILE *fp)
{
size_t bytes_requested = size * count;
size_t bytes_read;
CHECK_FILE (fp, 0);
if (bytes_requested == 0)
return 0;
_IO_acquire_lock (fp);
bytes_read = _IO_sgetn (fp, (char *) buf, bytes_requested);
_IO_release_lock (fp);
return bytes_requested == bytes_read ? count : bytes_read / size;
}
๋ค์ ์ฝ๋๋ฅผ ๋ณด๋ฉด fread ํจ์๋ _IO_fread ํจ์์ ๋์ผํ๊ฒ ์ ์๋ ๊ฑธ ํ์ธํ ์ ์๋ค.
ํด๋น ํจ์ ๋ด์์ _IO_sgetn ํจ์๋ฅผ ํธ์ถํ๋ค.
#define _IO_XSGETN(FP, DATA, N) JUMP2 (__xsgetn, FP, DATA, N)
#define JUMP2(FUNC, THIS, X1, X2) (_IO_JUMPS_FUNC(THIS)->FUNC) (THIS, X1, X2)
#define _IO_JUMPS_FUNC(THIS) (IO_validate_vtable ( (THIS)))
size_t
_IO_sgetn (FILE *fp, void *data, size_t n)
{
/* FIXME handle putback buffer here! */
return _IO_XSGETN (fp, data, n);
}
๋ค์์ _IO_sgetn ํจ์์ ๊ตฌํ์ฒด์ด๋ค.
์ฝ๋๋ฅผ ์ดํด๋ณด๋ฉด _IO_XSGETN์ ํธ์ถํ๋ ๊ฑธ ํ์ธํ ์ ์๋ค.
์ฝ๋ ์๋จ์ ๋ฉํฌ๋ก๋ฅผ ํ์ธํด๋ณด๋ฉด vtable ๋ณ์๋ฅผ ์ฐธ์กฐํ๋ ๊ฑธ ํ์ธํ ์ ์๋ค.
fread๋ฅผ ํฌํจํ ๋ชจ๋ ํจ์๋ ๊ฐ์ ํจ์ ํ ์ด๋ธ์ ์ฐธ์กฐํด์ ํ์ผ ์์ ์ ์๋ํ๋ค.
ํ์ง๋ง ํด๋น ํจ์ ํ ์ด๋ธ์ ๋์ ์ผ๋ก ํ ๋น๋๋ ์์ญ์ผ๋ก, ์ฐ๊ธฐ ๊ถํ์ด ์๊ธฐ ๋๋ฌธ์ ๊ณต๊ฒฉ์ ์ ์ฉ๋ ์ ์๋ค.
'DreamHack > SystemHacking' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Dreamhack System Hacking] send_sig (0) | 2022.11.14 |
---|---|
[Dreamhack System Hacking] SigReturn-Oriented Programming (0) | 2022.11.14 |
[Dreamhack System Hacking] SROP (0) | 2022.11.14 |
[DreamHack System Hacking] rtld (0) | 2022.09.22 |
[DreamHack System Hacking] __eviron (0) | 2022.09.21 |