2023. 2. 22. 01:33ㆍ코딩/공부 [STUDY]
시작하기에 앞서, 본 글은 제가 공부를 하고 나서 정리하기 위해서 작성 된 글입니다.
내가 12월 말 부터 1월 말까지 약 1개월이란 시간동안 드림핵에서 리버싱과 포너블을 공부하며, 문제를
풀고 다시 웹해킹으로 넘어가서 문제를 풀다보니 리버싱,포너블 공백기가 좀 생겼다.
기본적인 부분들을 다시 복습하고 싶은 마음에 복습한 내용들을 정리 하는 글을 쓰게 되었다.
1. 어셈블리어란?
이 부분은 위키를 찾아보면 너무 잘 나와있기 때문에 내가 어느정도 알고있는지 파악하기 위해서
생각을 좀 해보았다.
고수준 언어는 컴퓨터에 명령이 불가능하다. 왜냐하면 컴퓨터는 0과 1로된 기계어밖에 모르기 때문이다.
따라서 인간은 기계어로 컴퓨터에 명령을 내려야 했는데, 기계어는 인간이 공부하고 응용하기 너무 난해했다.
이때 나온것이 바로 어셈블리어, 기계어와 1대1 대응이 되면서, 직관적이고 인간도 공부해서 쓸 수 있을 만한 수준의 난이도였지만, 어셈블리어의 특성 상 코드의 길이가 너무 길고 비효율적이다. 그렇게 인간친화적으로 개발 된 언어들이 우리가
흔히 사용하는 컴퓨터 언어들이다.
2. 시스템 콜 이란?
시스템 콜이 뭔데? 라는 질문에 분명 syscall을 알고는 있는데 정의를 딱 말하지 못해서 당황했다.
그래서 바로 위키를 찾아보았다.
시스템 호출 또는 시스템 콜(system call), 간단히 시스콜(syscall)은 운영 체제의 커널이 제공하는 서비스에 대해, 응용 프로그램의 요청에 따라 커널에 접근하기 위한 인터페이스이다.
3. ISA(명령어 집합 구조) 이란?
ISA란 instruction set architecture의 약자이다.
이는 마이크로프로세서가 인식하여 기능을 이해하고 실행 할 수 있는 기계어 명령을 말하는데,
그 종류들로는 AMD64(x86), ARM, RISC-V, MIPS, PowerPC, SPARC, AVR32 등이 있다.
참고로, 현재 가장 흔하게 사용되는 ISA는 AMD64이다.
4. nasm으로 실습
nasm은 내가 작성한 어셈블리 코드를 기계어로 변환하여 실행하게 해주는 소프트웨어이다.
sudo apt install nasm
visual studio code를 이용하여 임의의 폴더를 하나 생성한 후, 그 속에 hello.s를 작성해보자.
그리고 일단 어셈블리어로 코딩을 하기 전에 세그먼트가 무엇인지 알아야 할 필요가 있다.
(레지스터도 알아야 함)
(본인은 해당 블로그를 참고 함.)
https://hackyboiz.github.io/2022/01/14/poosic/linux-memory-layout/
hackyboiz
hack & life
hackyboiz.github.io
그 후에
section .text
global _start
_start:
mov rax, 1
mov rdi, 1
mov rsi, hello
mov rdx, helloLen
syscall
mov rax, 60
mov rdi, 0
syscall
section .data
hello: db 'Hello world!', 10
helloLen: equ $-hello
해당 코드를 작성하고
nasm -f elf64 -o hello.o hello.s
ld -o hello hello.o
를 입력하자, Hello world!가 실행 되는 것을 볼 수 있다.
자세히 살펴 보도록 하겠다.
section .text가 보이는 데 .text부터는 text 세그먼트 영역이라는 것을 의미한다.
그리고 하단의 section .data 또한 .data 세그먼트 영역이라는 것을 의미한다.
global_start는 ELF에서 프로그램이 시작되는 부분을 나타낸다.
_start는 레이블이라고 하는데 조금 더 공부가 필요한 부분같다.
db는 위의 뜻에서 알 수 있듯, 바이트를 선언 하는 것이다.
참고로 뒤의 10은 \n이다.
따라서 우리는 hello라는 이름으로 Hello world!\n이 선언 한 것을 알 수있다.
이어서, helloLen에는 equ(상수) $-hello는 현재 라인에서 hello의 라인 위치를 뺀 값을
helloLen에 넣겠다는 말이다.
즉, 이 값은 hello의 길이가 된다.
자, 마지막으로 6번째 라인에 존재하는 어셈블리어를 해석해 보도록 하겠다.
https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md#x86_64-64_bit
Chromium OS Docs - Linux System Call Table
Linux System Call Table These are the system call numbers (NR) and their corresponding symbolic names. These vary significantly across architectures/ABIs, both in mappings and in actual name. This is a quick reference for people debugging things (e.g. secc
chromium.googlesource.com
해석하기 전에 리눅스 system call table을 참고하자
(레지스터도 알아오자)
어쨋든, 프로세스는 모두 표준입력스트림, 표준출력스트림을 가진다.
예를 들어, C언어의 printf, java의 System.out.println <- 표준출력스트림
리눅스 시스템 호출 테이블을 보면 리눅스의 write syscall은 1번이다.
그리고 syscall의 번호는 rax에 들어간다.
그래서 write를 호출하기 위해, rax에 1을 집어 넣는 것이다.
다시 위 사진을 봐보자, write 시스템 콜은 rdi 레지스터를 사용하는 인자를 첫 번째로 두고 있다.
fd? 가 뭔지 궁금하다면...
(fd = 파일 스크립터)
Unix OS에서 네트워크 소켓과 같은 파일이나 기타 입력/출력 리소스에 액세스하는 데 사용되는 추상표현이다.
즉, 시스템으로 부터 할당받은 파일이나 소켓을 대표하는 정수다.
즉, 저 3가지의 숫자로 현재 상태를 표현 하고 있는 것이다.
각각 표준입력,표준출력,표준에러를 의미한다.
따라서 rdi에 표준 출력 스트림을 사용하기 위해서 1을 넣는 것이다.
그리고 8~9번 줄에서 rsi에는 *buf 값을 집어넣는데,
hello라는 변수 주소에 Hello world!\n 라는 문장이 바이트 형식으로
존재하고 있다. 따라서, rsi에는 hello를 넣는 것이다.
9번째 줄인 rdx에선, helloLen에서 write에서 출력할 문장의 길이를 받기 때문에,
helloLen에서 구한 $-hello 만큼의 값이 들어가게 되는 것이다.
마지막으로 11~12에서
rax 60은 exit 시스템 콜을 뜻하는데, 이는 해당 코드를 종료시키기 위함이다.
rdi에 0을 넣는 것은 정상 종료를 의미하여, 해당 코드는 정상 종료 된다.
'코딩 > 공부 [STUDY]' 카테고리의 다른 글
[STUDY] 어셈블리어 - 5 (0) | 2023.02.28 |
---|---|
[STUDY] 어셈블리어 - 4 (0) | 2023.02.25 |
[STUDY] 어셈블리어 - 3 (rip,rsp,rbp,스택프레임) (1) | 2023.02.23 |
[STUDY] 어셈블리어 - 2 (1) | 2023.02.23 |
[STUDY] Web - javascript prototype pollution (0) | 2022.07.18 |