Reversing Engineering - 3. puts("hello world!\n") → x86_64 asm
1. hello world
# hello world - 1
- "hello world!"를 출력하는 코드가 어떤식으로 어셈블리 코드로 바뀌었는지 확인
#include <stdio.h>
int main(){
puts("hello world!\n");
return 0;
}
> 소스는 visual studio code 2019를 통해 64비트 릴리즈 모드로 컴파일
# hello world - 2
- 보는 방법
1. 주소: 해당 어셈블리 코드의 시작 주소가 표시됨
2. 기계 코드
> 사람이 읽을 수 있는 어셈블리 코드의 전 단계인 기계어가 여기에 표시됨
> : 앞에 있는 값은 prefix이고 띄어쓰기 다음에 있는 부분은 어셈블리 코드의 2번쨰 인자 부분
3. 어셈블리어
> 비교적 사람이 읽기 쉬운 형태인 어셈블리 코드가 여기에 표시됨
> 주소값의 경우 x64dbg가 적절한 형태로 바꾸어서 보여주기도 함
> 세번째 줄을 보면 &puts라고 표시해주는 것을 확인할 수 있음
4. 코멘트
> x64dbg가 프로그램을 분석하여 알게 된 추가적인 정보가 여기에 표시됨
> 2번째 줄을 보면 7FF6ED802220에 있는 문자열에 대한 정보가 표시되는 것을 확인할 수 있음
> 디스어셈블리 창에 보이는 숫자는 설정에 따라 0x가 없어도 16진수로 읽어야 하는 경우가 많음
> 상단에 있는 디스어셈블 결과의 경우 0x가 없지만 전부 16진수로 표기되어 있음
2. hello-world - 디스어셈블리 결과 살펴보기
# hello-world - 디스어셈블리 결과 살펴보기 - 1
sub rsp, 28
- 해당 명령어는 rsp에서 0x28만큼 빼 함수 내부에서 사용할 스택의 용량을 확보하는 명령어
- 보통 함수에서 지역변수로 선언한 값들이 스택에 위치하게 되는데, 이 지역변수들이 저장될 공간을 컴파일러가 미리 계산하여 함수 시작 부분에 확보를 해두는 것
- 앞의 예시에서 소스코드와 디스어셈블 결과를 살펴보면 지역변수를 사용하는 곳이 없었음
> 그런데도 0x28만큼 스택을 확보한 이유는 shadow space 또는 home space라 불리는 공간을 확보하고 성능 향상을 위한 메모리 사용 최적화가 적용되었기 때문
lea rcx,qword ptr ds:[7FF6ED802220]
- 해당 명령어는 rcx에 0x7FF6ED802220 값을 저장
- 0x7FF6ED802220: 주소값이며 x64dbg가 생성한 디스어셈블 결과의 코멘트 부분을 확인해보면 puts의 첫번째 인자인 hello world!\n가 위치한 주소임을 알 수 있음
- x64에는 많은 레지스터들이 존재하는데, puts의 첫번째 인자를 rcx에 넣은 이유는 사람들이 정해둔 규칙이 있기 때문
> 이를 calling convention(함수 호출 규약)이라 함
> 함수 호출 규약은 한 가지가 아니며 여러 종류가 있음
# 64비트 windows의 함수 호출 규약
- windows의 함수 호출 규약은 다음과 같은 순서로 첫 4개의 인자를 받음
1. rcx(ecx, cx, …)
2. rdx(edx, dx, …)
3. r8(r8d, r8w, …)
4. r9(r9d, r9w, …)
> 이후 5번째 인자부터는 스택에 넣게됨
- 함수의 리턴 값은 rax(eax, ax, ...)에 저장
- 8개의 인자를 받는 함수의 디스어셈블 결과
> rcx(ecx), rdx(edx), r8(r8d), r9(r9d)에 4번째 인자까지 넣고
5~8번째 인자는 미리 확보해둔 스택 영역에 저장하는것을 확인할 수 있음
# hello-world - 디스어셈블리 결과 살펴보기 - 2
call qword ptr ds:[<&puts>]
- puts를 호출하는 명령어
xor eax,eax
- eax를 0으로 만들어주는 명령어
- main 함수의 리턴 값을 0으로 설정해놨기 때문에 리턴값을 의미하는 eax레지스터를 0으로 설정하는 것
- 이때 mov eax, 0을 쓰지 않고 xor을 통해서 하는 이유는 명령어의 길이가 짧고 CPU에서 좀 더 빠르게 실행시키기 때문
add rsp,28
- 함수 시작 시 확보해두었던 스택을 정리하는 명령어
ret
- 함수의 실행을 마치고 리턴하기 위해 사용하는 명령어
- call 명령어를 통해 스택에 저장된 return address로 들어감
'Hacking Tech > Reversing' 카테고리의 다른 글
[Dreamhack] Reversing Engineering - 6. 쉬운 crackme를 통한 디버거 사용법 - 1 (0) | 2021.12.21 |
---|---|
[Dreamhack] Reversing Engineering - 5. hello-world로 배우는 x64dbg 사용법 (0) | 2021.10.04 |
[Dreamhack] Reversing Engineering - 4. x64dbg (0) | 2021.10.03 |
[Dreamhack] Reversing Engineering - 2. x64 기초 (0) | 2021.09.19 |
[Dreamhack] Reversing Engineering - 1. 리버싱 엔지니어링이란 (0) | 2021.09.16 |