1. 준비 : x64dbg 설치 및 Hello World 컴파일
해당 링크에서 다운로드 할 수 있다. 32비트/ 64비트 모두 지원한다.
x64dbg
Built on open-source libraries x64dbg uses Qt, TitanEngine, Zydis, Yara, Scylla, Jansson, lz4, XEDParse, asmjit and snowman.
x64dbg.com
다운을 받고 압축을 풀면 release\x64\x64dbg.exe 를 실행하면 된다.
(32비트는 64->32)
기능은 제쳐두고 다음 C언어 코드를 디버깅해 보자
#include <stdio.h>
int main() {
printf("Hello, World!");
return 0;
}
Hello World! 를 출력하는 C를 빌드했다.
2. 분석 시작 : main 함수를 찾아보자.
명령에 "main"을 입력해 보면 해당 심볼의 주소를 찾을 수 있다.
* 심볼(Symbol)은 컴파일러가 코드에 붙여준 이름표다, 그 덕분에 기계어 속에서 main을 쉽게 찾을 수 있다.
더블클릭하여 찾아가보자
3. main() 함수의 시작
해당 디스어셈블리를 번역해 보면
push rbp
push rdi
sub rsp, E8
lea rbp, qword ptr ss:[rsp+20]
push rbp : rbp의 레지스터의 값을 스택에 푸시
push rdi : rdi의 레지스터의 값을 스택에 푸시
sub rsp, E8 : 스택 포인터(rsp)를 0xE8 (232)만큼 공간 확보
lea rbp, qword ptr ss:[rsp+20] : 확보한 공간의 안쪽(rsp+20)을 기준점 (rbp)로 설정
main 함수의 시작점이라고 보면 될 것 같다.
4. 함수 분석 : 디버깅 함수
lea rcx,qword ptr ds:[<__1182F9CB_FileName@cpp>]
call project1.7FF7DE50136B
이 부분은 함수 호출 부분인데 project1.7FF7DE50136B를 타고 가보니
이런 함수가 나왔는데 컴파일러(Visual Studio)에서 디버깅을 위해 추가한 함수라고 한다.
nop
CPU에게 건너뛰라고 지시하는 명령이다.
5. 함수 분석 : printf("Hello, World!")
lea rcx,qword ptr ds:[<"Hello, World!"...>]
call project1.7FF7DE501195
printf("Hello, World!");
를 드디어 찾았다.
lea rcx,qword ptr ds:[<"Hello, World!"...>] : rcx라는 곳에 64비트의 포인터 "Hello, World!"라는 문자열의 주소를 담는다.
call project1.7FF7DE501195 : project1.7FF7DE501195를 호출한다.
여기서 project1.7FF7DE501195를 더블클릭 해서 보면
project1.printf 로 점프하라는 어셈블리가 나오고 또 들어가 보면
printf의 함수도 나온다.
6. main() 함수의 마무리
xor eax,eax
lea rsp,qword ptr ss:[rbp+C8]
pop rdi
pop rbp
ret
main 함수의 마지막 부분이다.
xor eax,eax : eax 레지스터를 0으로 만든다. (return 0;) , (xor 연산, 서로 같은 값이면 0이 된다)
lea rsp,qword ptr ss:[rbp+C8] : sub로 확보했던 스택 공간을 해제
pop rdi : 함수시작에서 push rdi 했던 것을 복원
pop rbp : 함수시작에서 push rbp 했던 것을 복원
ret : 함수를 호출한 곳으로 되돌아간다.
입문할 때 배우는 간단한 출력 코드도 어셈블리로 번역하니까 하루 종일 걸리는 것 같다.
다음에는 printf가 출력한 hello world! 의 문자열을 바꾸는 메모리 변조를 해봐야겠다.
'Reversing' 카테고리의 다른 글
[리버싱] 어셈블리로 Hello, World! 변경해보기 (0) | 2025.10.01 |
---|