자료 조사
추천 사이트1: yeosong님의 42wiki
추천 사이트2: libasm notion
작업환경 구축
MacBook Pro (16-inch, 2019)
macOS Big Sur 11.2.1
Homebrew 설치하기
Homebrew는 Mac OS에서 기본적으로 제공되지 않는 라이브러리를 설치하는 도구입니다. Docker를 사용할 때 등 여러모로 유용하니 설치하도록 합시다.
공식 사이트에서 지시하는 대로 설치해 봅시다. 터미널에서 다음 명령어를 실행해 보세요!
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
성공하셨다면 아마 이렇게 나오셨을 것 같습니다. 정확히는 다를 수도 있지만요!
==> Checking for `sudo` access (which may request your password).
Password:
==> This script will install:
/usr/local/bin/brew
/usr/local/share/doc/homebrew
/usr/local/share/man/man1/brew.1
/usr/local/share/zsh/site-functions/_brew
/usr/local/etc/bash_completion.d/brew
/usr/local/Homebrew
Press RETURN to continue or any other key to abort
==> /usr/bin/sudo /usr/sbin/chown -R kimkwanho:admin /usr/local/Homebrew
==> Downloading and installing Homebrew...
remote: Enumerating objects: 250, done.
remote: Counting objects: 100% (250/250), done.
remote: Compressing objects: 100% (70/70), done.
remote: Total 323 (delta 195), reused 209 (delta 175), pack-reused 73
Receiving objects: 100% (323/323), 139.51 KiB | 358.00 KiB/s, done.
Resolving deltas: 100% (213/213), completed with 97 local objects.
From https://github.com/Homebrew/brew
* [new branch] dependabot/bundler/Library/Homebrew/sorbet-0.5.6287 -> origin/dependabot/bundler/Library/Homebrew/sorbet-0.5.6287
485f73a32..25d098764 master -> origin/master
HEAD is now at 25d098764 Merge pull request #10723 from Homebrew/assert_not_match
Ignoring json-2.3.1 because its extensions are not built. Try: gem pristine json --version 2.3.1
/Library/Ruby/Gems/2.6.0/gems/json-2.3.1/lib/json/version.rb:4: warning: already initialized constant JSON::VERSION
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/json/version.rb:4: warning: previous definition of VERSION was here
/Library/Ruby/Gems/2.6.0/gems/json-2.3.1/lib/json/version.rb:5: warning: already initialized constant JSON::VERSION_ARRAY
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/json/version.rb:5: warning: previous definition of VERSION_ARRAY was here
/Library/Ruby/Gems/2.6.0/gems/json-2.3.1/lib/json/version.rb:6: warning: already initialized constant JSON::VERSION_MAJOR
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/json/version.rb:6: warning: previous definition of VERSION_MAJOR was here
/Library/Ruby/Gems/2.6.0/gems/json-2.3.1/lib/json/version.rb:7: warning: already initialized constant JSON::VERSION_MINOR
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/json/version.rb:7: warning: previous definition of VERSION_MINOR was here
/Library/Ruby/Gems/2.6.0/gems/json-2.3.1/lib/json/version.rb:8: warning: already initialized constant JSON::VERSION_BUILD
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/json/version.rb:8: warning: previous definition of VERSION_BUILD was here
/Library/Ruby/Gems/2.6.0/gems/json-2.3.1/lib/json/common.rb:107: warning: already initialized constant JSON::NaN
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/json/common.rb:100: warning: previous definition of NaN was here
/Library/Ruby/Gems/2.6.0/gems/json-2.3.1/lib/json/common.rb:109: warning: already initialized constant JSON::Infinity
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/json/common.rb:102: warning: previous definition of Infinity was here
/Library/Ruby/Gems/2.6.0/gems/json-2.3.1/lib/json/common.rb:111: warning: already initialized constant JSON::MinusInfinity
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/json/common.rb:104: warning: previous definition of MinusInfinity was here
/Library/Ruby/Gems/2.6.0/gems/json-2.3.1/lib/json/common.rb:136: warning: already initialized constant JSON::UnparserError
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/json/common.rb:129: warning: previous definition of UnparserError was here
Updated 2 taps (homebrew/core and homebrew/cask).
==> New Formulae
crispy-doom projectm
==> Updated Formulae
cairo ✔ haxe perl
arduino-cli highlight phpstan
argocd ipython pipx
armadillo jetty pspg
aws-sdk-cpp jetty-runner python-markdown
azcopy jruby python@3.7
babel kotlin python@3.8
berkeley-db kubeaudit richmd
cabal-install kubectx s-nail
circleci kustomize snakemake
commitizen libgr sofia-sip
conan libgxps stella
csvprintf liblinear stress-ng
cubejs-cli libomp supervisor
dasel lmod tendermint
docker mermaid-cli tfsec
docker-compose microplane tree-sitter
docker-compose-completion minetest ugrep
dolt mosquitto vault
earthly mozjpeg vercel-cli
eccodes name-that-hash verilator
eksctl nano vim
envoy nativefier vultr
erlang newrelic-cli waffle
etcd nfpm webpack
exploitdb ocaml-findlib xorgproto
fonttools ocrmypdf yq
freerdp pdm
==> Deleted Formulae
geant4
==> Updated Casks
ableton-live dash opencore-configurator
ableton-live-intro deskreen pgadmin4
ableton-live-lite digital qgis
ableton-live-standard drawio qownnotes
ableton-live-suite exodus raven-reader
apache-directory-studio figma subethaedit
autopkgr figmadaemon teamviewer
biscuit imazing telegram
calibre little-snitch tunnelbear
cleanmymac macupdater tutanota
clover-configurator mmhmm visual-studio
cocktail nova webstorm
daedalus-mainnet objectivesharpie
==> Deleted Casks
protonmail-unofficial
You have 15 outdated formulae and 1 outdated cask installed.
You can update them with brew upgrade.
==> Installation successful!
==> Homebrew has enabled anonymous aggregate formulae and cask analytics.
Read the analytics documentation (and how to opt-out) here:
https://docs.brew.sh/Analytics
No analytics data has been sent yet (or will be during this `install` run).
==> Homebrew is run entirely by unpaid volunteers. Please consider donating:
https://github.com/Homebrew/brew#donations
==> Next steps:
- Run `brew help` to get started
- Further documentation:
https://docs.brew.sh
NASM 설치하기
NASM의 개념에 대한 정보는 여기를 확인하세요!
brew를 설치하셨으니 터미널에서 윗 줄의 명령어를 실행해 주세요!
설치가 완료되었다면 밑의 줄의 명령어를 실행해서 버전을 확인해 봅시다.
brew install nasm
nasm -ver
제 버전은 다음과 같습니다.
NASM version 2.15.05 compiled on Nov 14 2020
NASM에서 "Hello, world!" 출력하기
NASM 설치가 완료되었으니 어셈블리어 파일 hello.s 파일을 만들어 봅시다.
global _main
section .text
_main:
mov rax, 0x02000004
mov rdi, 1
mov rsi, message
mov rdx, 13
syscall
mov rax, 0x02000001
xor rdi, rdi
syscall
section .data
message:
db "Hello, World!", 10
hello.s 파일에 대한 해석은 다음과 같습니다.
번외: hello.s 파일 해석해보기
어셈블리어에 관한 자세한 내용은 여기를 참고하세요!
☎️ System Call이란?
먼저 _main에서 syscall을 기점으로 둘로 나뉘는 듯이 생겼으니 syscall의 의미에 대해 알아봅시다.
시스템 호출은 운영 체제의 커널이 제공하는 서비스에 대해, 응용 프로그램의 요청에 따라 커널에 접근하기 위한 인터페이스이다.
보통 C나 C++과 같은 고급 언어로 작성된 프로그램들은 직접 시스템 호출을 사용할 수 없기 때문에 고급 API를 통해 시스템 호출에 접근하게 하는 방법이다.
이 블로그에서도 정리를 잘 해주신 거 같네요. 읽어보면 좋을 거 같습니다!
다들 아시겠지만, 운영체제에는 Kernel Mode와 User Mode가 있습니다.
잠깐! 커널의 개념이 헷갈리신다면? 커널의 정의를 찾아보면 되죠!
커널(kernel)은 컴퓨터의 운영 체제의 핵심이 되는 컴퓨터 프로그램의 하나로, 시스템의 모든 것을 완전히 통제한다. 운영 체제의 다른 부분 및 응용 프로그램 수행에 필요한 여러 가지 서비스를 제공한다.
이처럼 커널은 사용자 명령 해석 - 파일 입출력 등 많은 역할을 담당하며,
시스템 콜은 커널 영역의 기능을 사용자 모드가 사용 가능하게 -
다시 말해서 프로세스가 자원에 직접 접근해서 필요한 기능을 사용할 수 있게 해준다고 보시면 될 것 같습니다!
mov 명령어가 뭐지..?
여기서 정리를 잘 해 놓으셨으니까 참조해 보세요! (옛날 자료지만 ㄱㅊ)
mov 명령어는 mov [destination] [source]의 형식으로 사용합니다.
[source]의 값을 [destination]으로 복사한다고 생각하시면 됩니다.
move라고 생각해서 복사가 아니라 이동이라고 생각하실 수도 있는데, 복사의 개념이 맞습니다.
xor 명령어
여기서 정리를 잘 해 놓으셨으니까 참조해 보세요! (옛날 자료지만 ㄱㅊ)
xor 명령어는 말 그대로 실제로 xor 연산을 수행하는 것입니다.
mov 명령어와 비슷하게 xor [param1] [param2].
아시겠지만, xor 연산은 두 값이 같을 때 0을 반환합니다.
param1과 param2을 xor 연산하여 연산 결과를 param1에 넣습니다.
저희 코드에서는 xor rdi, rdi로 사용하였는데,
같은 값을 xor하면 0이 되는 원리를 이용하여 rdi를 0으로 초기화한다고 생각할 수 있습니다.
파일을 만드셨다면 다음 명령어를 입력해서 실행시켜 봅시다.
두 명령어를 모두 실행하셨다면 아래와 같이 디렉토리가 구성될 겁니다.
언제나 그래왔듯이 ./hello 명령어로 출력해 봅시다.
nasm -f macho64 hello.s
gcc -o hello hello.o
본격적으로 시작해보기
공부
시작하기 전에 간단히 공부를 해봅시다.
먼저 명령어입니다. 더보기란을 참고하여 대충 공부하세요!
필요할 때마다 명령어는 찾아보면서 해도 될 거 같네요.
- 조작 명령어 -
call : 함수 호출
ret : call로 호출한 함수를 종료하고 다음 명령줄로 이동
nop : 아무것도 하지 않음
jmp : 분기(라벨) 실행
조건 점프 명령어 : cmp 연산 결과에 따라 jmp
1) je : cmp A B 에서 A == B 일때 jmp
2) jne : cmp A B 에서 A != B 일때 jmp
3) ja : cmp A B 에서 A > B일 때 jmp
4) jb : cmp A B 에서 A < B일 때 jmp
5) jae : cmp A B 에서 A >= B일 때 jmp
6) jae : cmp A B 에서 A <= B일 때 jmp
- 데이터 전송 명령어 -
push : 스택에 값 넣기
pop : 스택에서 값 가져오기
mov : mov param1 param2에서 param2의 값을 param1에 대입
lea : lea param1 param2에서 param2의 주소를 param1에 대입
조건 점프 명령어 : cmp 연산 결과에 따라 jmp
- 산술 명령어 -
inc : 인자의 값 1 증가
dec : 인자의 값 1 감소
add : add param1 param2에서 param2의 값을 param1에 더함
sub : sub param1 param2에서 param2의 값을 param1에 뺌
cmp : cmp param1 param2에서 값을 비교할 때 사용; 위의 조건 점프 명령어와 같이 사용
test : test param1 param2에서 두 인자의 값을 AND 연산함.
그 다음은 레지스터들입니다.
레지스터는 프로세서에 있는 고속 메모리입니다.
작은 데이터와 중간 결과 같은 값을 저장할 수 있기에,
어셈블리어에서는 변수 대용으로 레지스터를 사용합니다.
저희는 반환값을 rax에 저장하고, 매개변수를 rdi rsi rdx rcx r8 r9를 차례대로 사용해야 합니다.
1. 산술-논리 연산을 맡는 레지스터
EAX Accumulator Register |
가장 자주 사용하는 변수로, 사칙연산과 논리연산에서 주로 사용한다. |
EBX Base Register |
특별한 목적으로 만들어진 레지스터가 아니다. |
ECX Count Register |
C는 Count의 의미로써 사용되었다. 반복문에서의 idx 역할을 맡는다. |
EDX Data Register |
일반적으로 EAX와 함께 연동하여 사용한다. |
2. 메모리 주소를 저장하는 레지스터
EBP Base Point Register |
Stack의 첫 시작 주소를 저장한다. |
ESP Stack Pointer Register |
Stack의 끝 주소를 저장한다. |
ESI Source Index Register |
데이터 조작/복사 시 소스 데이터의 주소를 저장한다. |
EDI Destination Index Register |
데이터 복사 시 목적지의 주소를 저장한다. |
등등 다양한 레지스터들이 있네요.. 넘 많으니 여러 블로그에서 대략적으로만 보시고 일단 사용해 봅시다.
Comment