공부중/시스템 해킹

레지스터의 용도와 시스템콜 이해하기

silver surfer 2024. 2. 2.

** Register

위 어셈블리어 코드에서는 크게 data 영역과 text 영역으로 나누었다.

data 영역에서는 Hello world라는 문자열을 담는 msg라는 이름의 변수를 만들어주었고,

실제로 코드를 실행하는 text 영역에서 msg 변수를 사용한 걸 볼 수 있다. 

 

이제 이러한 코드가 어떻게 동작하는지 이해하기 위해 64bit 운영체제 상에서 동작하는 갖가지 레지스터의 이름, 쓰임새와

그러한 레지스터가 실질적으로 사용되기 위해 알아야하는 system call 개념에 대해 배울 것이다. 

 

https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/x64-architecture

 

x64 Architecture - Windows drivers

The x64 architecture is a backwards-compatible extension of x86. It provides a legacy 32-bit mode, which is identical to x86, and a new 64-bit mode.

learn.microsoft.com

마이크로소프트에서 공식 문서로 제공해주는 64-bit architecture

 

bit별로 레지스터를 보여주고있다. 과거 32 bit 운영체제에서는 앞에 e로 시작하는 레지스터를 사용하곤 했다.

지금은 CPU가 한 번에 처리하는 단위가 64 bit로 늘어났기 때문에 앞에 r이 붙은 형식으로 레지스터 이름이 바뀌었다.

예를 들어

rax 시스템 콜의 실질적인 번호를 가리키는 레지스터이자, 함수가 실행된 다음 결과가 담기는 레지스터
rbx base register로, 메모리 주소를 지정할 때 사용한다.
rcx count register로, 주로 반복문에 많이 사용된다.
rdx data register로, 연산을 수행할 때 rax와 함께 많이 사용된다.

 

위 4가지를 데이터 레지스터로 분류한다. 

 

그 다음 아래의 4가지 레지스터는 포인터 레지스터이다.

rsi 메모리를 이동하거나 비교할 때 출발지 주소를 가리킨다.
rdi 메모리를 이동하거나 비교할 때 목적지 주소를 가리킨다.
rbp 함수의 파라미터나 변수의 주소를 가리킬때 많이 사용한다.
rsp 어떠한 스택이 있을때, 그 스택에 삽입 및 삭제 명령에 의해서 변경되는 스택에서 가장 위에 있는 주소를 가리키는 register  

 

r8부터 r15도 쓰임새가 존재하는데, 일반적으로 함수의 매개변수로 사용이 된다.

이러한 레지스터를 통해 어셈블리어 코딩을 할 수 있다.

 

** System Call

구글에 64bit systecm call table 입력하면 정보 많음.

그 중 하나

https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/

 

Linux System Call Table for x86 64 · Ryan A. Chapman

Linux 4.7 (pulled from github.com/torvalds/linux on Jul 20 2016), x86_64 Note: 64-bit x86 uses syscall instead of interrupt 0x80. The result value will be in %rax To find the implementation of a system call, grep the kernel tree for SYSCALL_DEFINE.\?(sysca

blog.rchapman.org

 

0번 시스템 콜 함수는 sys_read

1번 시스템 콜 함수는 sys_write

이런 식으로 각각 다양한 함수들이 기본적으로 커널 단에 마련이 되어있다.

 

%rax가 앞서서 시스템 콜 함수를 불러올 때 그 번호를 가리키는데, 만약 시스템 콜을 불러오기 전에 rax에 0이란 값이 담겨있다면 sys_read 함수를 사용한다.

갖가지 함수들에는 기본적으로 매개 변수가 따라오는데 대표적인 예로

sys_write 함수

- %rdi가 fd(file descripter) 역할을 하는 것을 알 수 있다.

- 컴퓨터에 내용을 출력(write)하는 함수이므로 정확히 어떠한 문자열을 출력할지, 그에 대한 문자열을 %rsi가 포함하게 한다.

- 출력한 문자열의 길이는 %rdx에 담아 함수를 불러온다.    

 

실제로 코딩할 때 시스템 콜 테이블을 두고 참고해서 다양한 함수를 불러올 수 있고, 기존 C언어나 자바같은 고급 언어에 비해 훨씬 빠르게 동작하는 프로그램을 작성할 수 있다.

 

section .data
	msg db "Hello World"

→ data 영역에 Hello world라는 문자열을 만들어놓고, 그 문자열의 위치를 가리키는 포인터 msg를 하나의 변수로써 마련한 다음

 

section .text
	global_start
    
_start:

→ text 영역에 가장 처음으로 실행되는 start 함수를 정의한다.

 

mov rax, 1

→ rax에 1을 담음으로써, sys_write 를 불러올거라고 컴퓨터에게 알려준다.

 

mov rdi, 1

→ rdi, 즉 파일 디스크럽터에 1을 입력해 어떠한 문자열을 출력하겠다고  syscall 함수의 매개변수로 넣어준다.

 

mov rsi, msg

→ 어떠한 문자열을 출력할건지 msg라는 포인터 변수를 rsi 값에 넣어줌으로써 Hello World가 출력될 수 있게 한다.

 

mov rdx, 12

→ Hello World를 모두 출력할 수 있는 충분한 길이인 12을 넣어줌으로써 하나의 Systemcall을 불러올 준비를 마쳤다.

 

syscall

→ 결과적으로 system call을 불러옴으로써 Hello world가 콘솔창에 출력된다.

 

밑에 있는 코드는 무엇일까?

mov rax, 60
mov rdi, 0
syscall

60은 sys_exit이라는 걸 알 수 있고, rdi에는 error 코드를 매개변수로 넣는다.

rdi에 0을 넣어주면서 코드가 안전하게 종료될 수 있도록 한다.

즉, 첫 번째 시스템콜은 Hello World를 출력해주는 콜, 두 번째 시스템콜은 프로그램을 종료하는 시스템 콜이다.   

'공부중 > 시스템 해킹' 카테고리의 다른 글

[Dreamhack] Linux memory Layout  (0) 2024.09.09
[Dreamhack]x86-64 아키텍처  (0) 2024.09.09
윈도우 환경 구축/WSL2  (0) 2024.07.13
리눅스<>로컬 pc ssh 연결  (0) 2024.06.30
메모리 구조 이해하기  (0) 2024.03.02

댓글