안녕하세요. Demon 팀의 c0nstant입니다. 틈틈히 공부중인 syscall에 대해 간단하게 설명해보고자 합니다.

제가 이것을 공부하게 된 계기는 pwnable.kr의 문제를 풀기 위함 이었습니다.
하지만, 공부 해두니 정말 알아야 하는 정보였기에 복습 차원에서 적어보려 합니다.
아직 공부중인 내용이라 부족함이 있을 수도 있습니다. ^.^

시작합니다 !!

이놈은 도대체 뭐하는 녀석일까요? 고민을 한번 해봅시다. !!

대부분 프로그램에 쓰이는 단어들은 영어의 조합으로 이루어져 있음을 눈치챌 수 있을 것입니다.
이 녀석도 system과 call이라는 단어의 합성어라는 사실을 인지할 수 있게 됩니다.

그렇다면, 시스템 호출에 대한 것이라는 것이겠죠?

잠시 자가 질의응답 시간을 가져보겠습니다.

Q : SystemCall과 LibraryCall 이 두 녀석은 다를까요?

정답은 다르다 입니다.

SystemCall의 경우는 OS의 KERNEL에 서비스를 요청할 때 호출하는 함수입니다.
대표적인 아이들은 다음과 같습니다.
[ 1. OPEN, WRITE, READ , CLOSE ]
[ 2. FORK, EXECVE, KILL ]

제 나름대로 기준을 정해서 1과 2로 나누어 보았습니다. 해당 분류는 유사점이 존재합니다.
[1] open,write,read,close함수는 모두 저수준 파일 입출력입니다. 여기서의 저수준이라는 표현은 지능이 떨어지는 저능아 이런 느낌이 아니라는 것을 인지하셔야 합니다.

저수준 파일 입출력의 정의는 '커널의 시스템을 호출하여 파일 입출력을 수행한다'입니다.
그리고 "특수 파일을 읽고 쓸 수 있다"라는 특징도 지니고 있습니다.

[2] 3가지의 명령은 모두 '프로세스'와 연관이 있습니다.
[2-1]fork라는 것은 자식 프로세스를 생성합니다.
[2-2]execve라는 것은 다른 프로그램을 프로세스로 만들어주고, 자신은 종료됩니다.
중요하다고 생각되어 언급하고자 하는게 한가지 있습니다.
프로그램과 프로세스는 다른 말입니다.
프로그램이라는 것은 메모리에 올라가기 전에 하드디스크에 머물고 있는 것이며,
프로세스는 운영체제에게 자원을 할당 받아 메모리에 적재 되어야 합니다.
[2-3]리눅스 운영체제에는 쉘에서 사용할 수 있는 명령어 kill이 있습니다. 이는 프로세스를 종료시키는 역할입니다. systemcall 상의 kill함수 역시 같은 역할을 수행합니다. 프로세스 아이디(pid)를 인수로 사용하여 SIGKILL이라는 시그널을 전송할 수 있습니다.

다음으로 LibraryCall입니다.
우선 알아두어야 하는 개념 한가지가 있습니다.
LibraryCall도 "내부적"으로는 SystemCall을 사용한다는 것입니다.
C 표준 함수들이 라이브러리 함수입니다.
대표적인 아이들은 다음과 같습니다.
[1. fopen, fwrite, fclose, fseek ]
[2. fgets, fprintf, fscanf ]

이 친구들은 모두 파일의 어떠한 행동에 관여를 할 수 있기에 굳이 분류를 하지 않아도 됩니다.
하지만 systemcall open과 librarycall의 open 이런 것들의 차이점을 알기 위하여 분류를 해보았습니다.
SystemCall의 1과 LibraryCall의 1의 차이점은 [반환 형]입니다.

systemcall의 경우 파일 디스크립터를 반환하고, librarycall의 경우 파일 포인터를 반환하게 됩니다.

syscall을 설명하려했는데, 적다보니 Systemcall과 LibraryCall의 차이점이 더 많네요.
하지만 꼭 알아야 하는 개념이라고 생각해서 적어보았습니다 !

syscall은 상당히 많은 종류가 있습니다.
syscall에 대해 궁금하신 분을 위하여 linux syscall reference 사이트를 공유합니다.
[ https://syscalls.kernelgrok.com/ ]

제 우분투 환경에서 syscall 관련 된 헤더파일은 아래의 경로에 있습니다.
경로 : /usr/src/linux-headers-4.13.0-43/include/uapi/asm-generic/unistd.h
path

이러한 것들을 구경해볼 수 있습니다.
syscall

이 두개의 의미에 대해서는 미니 과제로 두겠습니다.
[1] commit_creds
[2] prepare_kernel_cred

ROP 중에 SROP라고 있습니다. 대부분 사람들이 처음 접하는 ROP는 Retrun Oriented Programming 이지요. PIE(Position Independent Executable)에 의해 쉘코드를 고정 주소에 올리지 못할 때 사용하는 훌륭한 기술입니다. system에도 이 ROP가 있었습니다.

이는 저번주에 알게 된 개념인데, System Call을 이용하는 ROP라고 합니다.
ROP에서는 사용하고자 하는 함수의 인자에 맞게 popN - ret가 됩니다.
소위 PPR 가젯이라고 표현하죠. 하지만 인자의 N갯수로 판별하기 때문에 무조건 ROP할 때 PPR을 사용하는 것은 아니라는 것을 기억해야 합니다.

SROP에서도 마찬가지로 가젯을 이용하게 되는데, 그 가젯은 int 0x80입니다.
0x80을 호출하면 sigreturn이 시그널을 통해 호출됩니다.
그리고 SROP에서 중요한 사항은 EAX(RAX)에 의해 호출 됩니다.
만약 자신이 실행하고자 하는 시그널을 알고 있다면 쉽게 제어가 가능하겠죠?

아까 전에 Kill함수 역시 시그널을 통해 호출되는데 이 역시 같은 원리를 지니고 있는 것으로 보아 커널에 서비스를 요청하는 녀석이란 것을 한번 더 인지할 수 있겠습니다.

SROP는 아직 저도 많이 공부하지 않은 상태라 적을게 마땅히 없는 것 같습니다.
또 하나 이거 공부하면서 알게 된 것은 SIGCONTEXT 구조체가 어떻게 생겼는지 알게 되었습니다.

뭔가 더 자세히 쓰면 개념 설명이 아닌 라이트업이 될 수도 있을 것 같아 이만 줄이도록 하겠습니다.

조금 더 자세히 공부하고 싶은 분들은 "execve의 여러 친구들", "프로세스 생명주기", "저수준과 고수준" 그리고 미니과제를 공부해보는 것을 추천합니다. 끝!!