CS/소프트웨어보안

5-1. 소프트웨어 보안을 위한 리눅스 기초

arsenic-dev 2025. 10. 17. 00:21

경희대학교 장대희 교수님의 소프트웨어보안 수업을 기반으로 정리한 글입니다.

 

시스템콜 및 파일디스크립터의 이해

시스템콜

시스템콜이 보안상 중요한 이유는?

 

시스템콜은 응용프로그램에 커널(OS)이 제공하는 함수를 호출하는 인터페이스로,

'높은 권한'이 요구되는 시스템 자원 접근의 통로이기 때문에 보안상 중요하다.

 

OS가 제공하는 기능 -> 권한 상승이 요구됨

  • H/W 접근
  • File System
  • Network
  • ...

 

커널

운영체제를 구성하는 핵심 코드

운영체제는 권한이 분리됨

 

시스템 콜 구현(권한 분리)의 보안상 의미

  • 타 애플리케이션으로부터의 메모리 접근, 하드웨어 손상, 시스템 마비 방지

 

시스템콜의 종류

  • System Information Query: getpid
  • Process Management: execve
  • Memory: mmap (not malloc)
  • Storage: open/read/write
  • Network: socket

 

※ malloc() -> mmap() -> 커널 메모리 공간 할당, malloc()은 시스템콜이 아니라 라이브러리 함수(API)이다.

  • 할당 받은 메모리를 쪼개 사용하는 건 어플리케이션의 자유이지만, 최초의 메모리(page)를 할당 받을 땐 OS에 요청해야 함

 

시스템콜의 수행 흐름

 

⭐ Code 영역: application 프로그램 -> 라이브러리 호출

libc(립씨) 영역: 보편적인 기능을 제공하는 라이브러리 -> 시스템콜 호출

  • 라이브러리에 대한 실제 assembly 구현이 있는 메모리 영역

 

low level의 개발이 아닌 이상, 보통 application을 개발할 땐 system call 보단 먼저 라이브러리를 호출한다.

 

 Code 영역에서 라이브러리 함수 호출 시, 라이브러리 코드가 있는 영역으로 jump하여 분기하는데,

이때 라이브러리 내부로 진입하는 과정이 복잡하다.

  • 리눅스에서 공유 라이브러리 호출에 관여하는 코드(PLT)와 자료구조(GOT)
    • 라이브러리 함수와, 라이브러리의 어셈블리 코드들이 존재하는 메모리의 위치를 연결하는 과정에 관여
    • PLT: code section
    • GOT: 함수 pointer들이 있는 table

 

대부분 라이브러리에 진입시, 라이브러리에서 시스템콜을 호출한다.

 

int 0x80: interrupt를 발생시켜 시스템콜에 진입하는 어셈블리 명령어 -> 권한 바뀜

  • kernel에서 할 일 다 하고 되돌아 가는 순간 권한 빠지고, 어셈블리로 시스템콜 진입한 직후로 되돌아 간다.

 

시스템콜 vs API

 

API란 Application Programming Interface의 약자로, 라이브러리가 제공하는 기능과 함수를 호출하는 것을 API를 사용한다고 한다. 그리고 시스템콜을 사용한다는 것은 보다 low level의 영역으로, API들이 보통 시스템콜을 내부적으로 많이 사용한다.

 

다음 API 중 시스템콜을 사용하지 않는 것은?

  • printf("hello"); -> write (하드웨어 access)
  • sleep(3); -> clock_nanosleep (타이머 access)
  • strcmp("abc", "def");
  • exit(0); -> exit (프로세스 access)

-> strcmp("abc", "def");

 

※ strcmp: string compare / exit: process 종료

 

파일 디스크립터 

OS가 할당해주는 리소스(e.g., 네트워크, 파일, 키보드, 모니터)에 대한 번호로,

시스템콜 사용시 리소스를 구분하기 위한 번호로 사용된다.

 

즉, 파일 디스크립터란 파일 뿐만 아니라 컴퓨터의 거의 모든 자원에 access 하기 위한

인터페이스 함수들이 사용하는 식별 번호이다.

 

모든 프로세스들은 프로세스 안에 file descriptor table을 갖고 있다. (프로세스마다 각각 따로 존재)

 

※ 리눅스에서는 모든 것을 파일로 다룬다.

 

파일 디스크립터와 OS의 연결

 

리눅스 파일 디스크립터의 특성

  • 예약된 번호가 존재
    • 0: Standard Input
    • 1: Standard Output
    • 2: Standard Error Output
  • 3번부터는 파일 만들 때마다 순차적으로 번호 할당(mapping)되는 방식으로 사용
  • 예약된 번호는 시스템 디폴트지만 수정할 수 있음: 프로그램상에서 매핑 변경 가능
    • 프로그램상에서 매핑 변경 가능 (e.g., xinet.d 프로그램, daemon)
  • 데이터 입출력에 사용
    • 데이터는 조작이 가능하기에 exploit, 악성코드 유포 측면에서 입출력은 보안상 매우 중요

 

프로세스의 다양한 I/O 채널

파라미터 인자 (Argument Vector)

명령어 형태로 프로그램 최초 실행 시, 스페이스 한 칸 띄우고 옵션들을 줄 수 있다.

이렇게 옵션들을 argument(추가적인 파라미터 옵션)라고 하는 인자들의 배열로 줄 수 있어 argument vector라고 한다.

 

터미널 (STDIO)

 

파이프: 한 프로세스의 출력(stdout)을 다른 프로세스의 입력(stdin)으로 연결하는 기능

  • 예시)
    ls | gret txt # grep은 문자열 검색 명령어 -> "txt"라는 문자열 포함된 줄만 걸러서 출력

리다이렉션: 표준 입출력의 흐름 방향을 바꾸는 기능

형태 의미 예시
> stdout을 파일로 보냄 (덮어쓰기) ls > out.txt
>> stdout을 파일에 덧붙임 echo hi >> log.txt
< stdin을 파일에서 읽음 sort < data.txt
2> stderr을 파일로 보냄 gcc test.c 2> err.txt
&> stdout + stderr 모두 파일로 보냄 ./run &> log.txt

 

파일

 

dnldhk rkxdms 함수는 파일에 대해 mode 지정이 가능하다. (access 권한 지정)

  • w: 쓰기 전용 모드

 

파일의 open 모드

  • text mode: 특정한 문자에 추가 logic 해석됨 (e.g., \n은 엔터)
  • binary mode: 파일 안에 모든 것을 바이트의 덩어리로 봄

 

⭐ 네트워크

 

리눅스에서 소켓 통신을 하면 file descriptor를 반환한다.

 

⭐ 환경변수

프로세스를 실행할 때 자동적으로 부모 프로세스로부터 상속을 받는 변수의 이름과 값의 배열이다. 

  • OS 수준에서 사용할 수 있는 변수 (조작되면 보안상 매우 위험)
  • 프로그램 실행 도중 변경되는 값이 아니라, 최초 실행 시 받게 되는 그런 변수
  • 특정 프로세스 관리 위한 옵션, 설정 값들

 

※ LD_PRELOAD: 파일 경로 지정 가능 -> 최우선 공유 라이브러리 지정

 

데이터의 포맷

 

컴퓨터 상의 모든 데이터는 결국 메모리에 들어가야 하고,

모든 메모리 값은 바이트의 집합일 뿐이고, 한 바이트는 8비트 숫자이기에 2진수로 해석이 가능하다.

 

아스키코드

 

공유 라이브러리 

Library?

라이브러리란 프로그램 제작 시 공통적으로 사용되는 코드의 모음이다. (API 함수)

  • e.g., "printf"

 

리눅스 라이브러리의 종류

  • Static(.a 파일): Code 영역 안에 libc, PLT, GOT가 다 들어오는 것 (다른 application과 공유 X)
  • Shared (.so 파일): 시스템이 공유해주는 라이브러리 사용하는 것
    • Dynamic Linking (컴파일타임): PLT, GOT는 빌드할 때 생성, libc의 실제 주소로 GOT를 채우는 건 실행 때
    • Dynamic Loading (런타임): 모든 것을 실행 때

 

정적 라이브러리

Embedded System(소형)에서 주로 사용되는 라이브러리로, 메인 프로그램의 .text에 합쳐진다. 

  • 1개의Segment: ASLR이 효과적이지 않게 됨
  • 속도가 빠름
  • 호환성이 좋음
  • 메모리 사용 면에서는 불리 (다른 어플리케이션과 공유하지 않기 때문)

 

※ ASLR: 공유 라이브러리의 위치를 랜덤화하여 ROP(Return Oriented Programming) 공격을 방지하기 위한 기술이다.

 

동적 라이브러리

일반적인 Desktop 및 범용 Computing 환경에서 사용되는 라이브러로, 실행파일 바이너리와 동이란 format이다.

 

링킹타임 vs 런타임

  • 링킹타임: 프로그램을 "빌드"하는 단계에서 사용할 라이브러리를 결정하는 방식으로, 가장 기본적인 방식이다.
  • 런타임: 프로그램 실행 도중에 언제든지 라이브러리를 불러와서 사용하는 방식으로, Windows에서 흔한 형태이다.

 

Static vs Dynamic

 

Static Linking은 라이브러리의 어셈블리 코드가 내가 만드는 프로그램에 통으로 복제되어 들어가는 것을 말한다.

  • 라이브러리 바꿔치기, 후킹(함수 입출력 바꿔치기)을 하는 등의 보안 관점에선 유리하나, ASLR 효과는 줄어듦

 

Dynamic Linking은 내가 빌드하고 컴파일한 코드에 라이브러리의 실제 어셈블리 코드가 없이,

단지 라이브러리와 연결하기 위한 PLT, GOT 자료구조만 만들어두고 런타임 때 실제 라이브러리를 찾아 사용하는 것을 말한다. 

'CS > 소프트웨어보안' 카테고리의 다른 글

6. Reversing  (0) 2025.12.06
5-2. 리눅스 사용  (0) 2025.10.17
4-3. 어셈블리 실습  (0) 2025.10.17
4-2. GDB 실습  (0) 2025.10.15
4-1. 메모리 구조  (0) 2025.10.15