상세 컨텐츠

본문 제목

x86_64 assembly code

REVERSING/Reversing Study

by koharin 2021. 4. 4. 17:46

본문

728x90
반응형

Hello World


debugger로 디스어셈블 결과로 확인한 어셈블리 코드

7FF6ED801000 | 48:83EC 28       | sub rsp,28                          |
7FF6ED801004 | 48:8D0D 15120000 | lea rcx,qword ptr ds:[7FF6ED802220] | 00007FF6ED802220:"hello world!\n"
7FF6ED80100B | FF15 5F110000    | call qword ptr ds:[<&puts>]         |
7FF6ED801011 | 33C0             | xor eax,eax                         |
7FF6ED801013 | 48:83C4 28       | add rsp,28                          |
7FF6ED801017 | C3               | ret 
  • x64dbg 디버거를 사용한 디스어셈블 결과이다.
  • 주소, 기계 코드, 어셈블리어, 코멘트를 확인할 수 있다.
  • 주소로 어셈블리 코드의 시작 주소를 확인할 수 있다.
  • : 앞의 값은 prefix이다.
  • x64dbg가 프로그램 분석 통해 알게 된 추가 정보를 코멘트에 표시한다. 00007FF6ED802220:"hello world!\n"는 코멘트에 해당한다.

 

 

hello world 디스어셈블리 결과 살펴보기


디스어셈블리 결과 분석

7FF6ED801000 | 48:83EC 28       | sub rsp,28                          |
7FF6ED801004 | 48:8D0D 15120000 | lea rcx,qword ptr ds:[7FF6ED802220] | 00007FF6ED802220:"hello world!\n"
7FF6ED80100B | FF15 5F110000    | call qword ptr ds:[<&puts>]         |
7FF6ED801011 | 33C0             | xor eax,eax                         |
7FF6ED801013 | 48:83C4 28       | add rsp,28                          |
7FF6ED801017 | C3               | ret     

sub rsp, 28

  • 컴파일러는 함수 내에서 사용하는 지역변수를 위한 스택 공간을 미리 확보한다.
  • 스택은 낮은 주소로 자라나므로, 스택 공간 확보 위해 rsp - 0x28을 한 것을 알 수 있다.
  • shadow space / home space*
  • 메모리 사용 최적화로 성능 향상을 위해 shadow space 또는 home space 공간을 확보한다.
  • 따라서 위의 프로그램과 같이 지역변수를 사용하지 않아도 sub rsp, 28로 shadow space로 확보된 것이다.

lea rcx, qword ptr ds:[7FF6ED802220]

  • 0x7FF6ED802220 주소가 가지는 값의 64bit 크기(qword)를 rcx 레지스터가 가리키는 주소에 저장한다.
  • 00007FF6ED802220:"hello world!\n"으로 해당 주소에는 puts 함수의 첫 번째 인자인 문자열이 들어있음을 알 수 있다.
  • puts 함수의 첫 번째 인자를 rcx 레지스터로 가져온다. rcx 레지스터는 Window 64bit 함수 호출 규약에서 첫 번째 인자 값을 저장하는 레지스터이다.

call qword ptr ds:[<&puts>]

  • puts 함수를 호출하는 명령어

xor eax, eax

  • eax 레지스터 값을 0으로 초기화하는 명령어이다.
  • main 함수의 리턴값이 0이므로, 리턴값을 저장하는 eax 레지스터 값을 0으로 만든 것이다.
  • mov eax, 0 대신 xor eax, eax를 쓴 이유는, 명령어 길이가 더 짧고 CPU에서 더 빨리 실행되기 때문이다.

add rsp, 28

  • 0x28 크기만큼 확보해둔 스택 공간을 정리하기 위해 rsp + 0x28을 한다.

ret

  • 함수 자신을 호출한 함수로 리턴하기 위한 명령어
  • call 명령어를 통해 해당 함수로 이동 전 스택에 저장해놓은 return address로 돌아간다.

 

64bit windows 함수 호출 규약

인자 저장 레지스터

  • rcx(ecx, cx, ...)
  • rdx(edx, dx, ...)
  • r8(r8d, r8w, ...)
  • r9(r9d, r9w, ...)
  • 64bit 크기(qword) 저장 시 rcx, 32bit크기 (dword) 저장 시 ecx, 16bit 크기 저장(8byte, word) 시 cx 레지스터가 인자를 받는다.
  • 이에 따라 rdx도 64bit 크기 인자 저장, edx는 32bit(dword) 크기 인자 저장, dx는 16bit(word) 크기 저장하는 레지스터이고, r8과 r9는 64bit 크기 저장 레지스터, r8d, r9d는 32bit(dword) 크기 저장, 그리고 r8w, r9w는 16bit 크기 저장하는 레지스터이다.

리턴값 저장 레지스터

  • rax(eax, ax, ...)
  • 첫 4개 인자 이후의 5번째 인자부터는 스택에 저장된다.
7FF611801040 | sub rsp,48                            |
7FF611801044 | mov dword ptr ss:[rsp+38],8           |
7FF61180104C | mov dword ptr ss:[rsp+30],7           |
7FF611801054 | mov dword ptr ss:[rsp+28],6           |
7FF61180105C | mov dword ptr ss:[rsp+20],5           |
7FF611801064 | mov r9d,4                             |
7FF61180106A | mov r8d,3                             |
7FF611801070 | mov edx,2                             |
7FF611801075 | mov ecx,1                             |
7FF61180107A | call consoleapplication1.7FF611801000 |
7FF61180107F | xor eax,eax                           |
7FF611801081 | add rsp,48                            |
7FF611801085 | ret                                   |
  • 8개 인자 받는 함수 디스어셈블 결과로, rcx(ecx), rdx(edx), r8(r8d), r9(r9d)에 차례로 1,2,3,4 인자 값을 저장하고, 스택에 5 ~ 8까지의 인자 값을 미리 확보한 스택 영역에 저장하고 있다.
728x90
반응형

관련글 더보기