main +0: 스택에 rbp를 스택에 넣는다. rbp는 함수의 경계를 구분할 때, 함수와 함수의 맨 아래 경계를 가리킨다.
main +1: 옮긴 rbp에 rsp를 대입한다. rsp도 함수의 경계를 구분할 때 사용되는데, rbp가 맨 아래 경계를 가리킨다면,
rsp는 맨 위 경계를 가리킨다.
main +4: rsp의 값에서 0x10만큼 뺀 값을 rsp에 저장한다. 0x10는 10진수로 10이다.
main +8: 0x28은 10진수로 40이다.
main +17: rbp에서 0x8(10진수로: 8)만큼 뺀 주소에 rax의 값을 QWORD(8byte)만큼 복사한다는 뜻이다. ptr은 포인터의 약자이다.
<스택 카나리 기법이다>
main: 21: eax와 eax를 xor한 값을 eax에 저장한다. 0이 저장된다. eax는 산술연산과 함수의 리턴값을 저장하는 용도로 사용된다.
main 23: edi에 0x4007d4값을 저장한다. edi는 eax와 같은 역할을 하지만 함수의 리턴값을 저장하는 용도로는 사용하지 않고, edi는 복사할 데이터가 "어디에" 저장될지, 그 주소값을 저장하는 용도로 쓰인다.
main 28: 0x4004f0에 있는 <puts@plt>함수를 호출한다. puts함수를 호출한다고 이해하면 되는데, puts함수는 문자열을 출력하는 함수이다.
main 33: rbp-0xc의 값이 유효한 주소라면, rax에 저장한다.
main 37: rax의 값을 rsi에 저장한다.
main 40: 0x4007e5의 값을 edi에 저장한다.
main 45: eax에 0x0을 저장한다.
main 50: 0x400530에서 <__isoc99_scanf@plt>함수를 호출한다. scanf함수를 호출한다고 이해하면 되는데, scanf함수는 입력을 받는 함수이다.
main 55: eax에서 rbp-0xc의 주소의 해당되는 값을 eax에 DWORD(4byte)만큼 복사한다.
main 58: eax에서 0xdeadbeef를 빼서 대소관계와 같은지를 비교한다. ZF와 CF값을 정하기 때문이다. eax와 0xdeadbeef의 값은 변화가 없으며 ZF는 두 값을 뺐을 때 0이 되면 1, 아니면 0을 저장하고 CF는 두 값을 뺐을 때 자리내림이 발생하면 1, 아니면 0이 된다.
main 63: main 58과 같이 봐야 되는데, main 58에서 cmp로 비교했던 두 값이 같지 않다면 0x400733주소에 위치한 main+93으로 점프하라는 뜻이다.
main 65: edi에 0x4007e8을 저장한다.
main 70: 0x4004f0에 있는 <puts@plt>함수를 호출한다.
main 75: eax에 0x0을 저장한다. 0x0은 10진수로 0이다.
main 80: 0x400646에 있는 <flag_generator>라는 함수를 호출한다.
main 85: rdi에 rax를 저장한다. rdi는 문자열을 "어디에" 복사할건지, 즉 목적지 주소값을 저장하는 레지스터이다.
main 88: 0x4004f0에 있는 <puts@plt>함수를 호출한다.
main 93: eax에 0x0을 저장한다. 0x0은 10진수로 0이다.
main 98: rdx에 rbp에서 0x8만큼 뺀 주소부터 QWORD만큼의 값을 복사한다. QWORD의 크기는 8byte이다.
main 102: rdx와 fs:0x28부터 QWORD(8byte)만큼에 해당되는 값을 xor연산한다. xor연산 같으면 0, 다르면 1이다.
main 111: 위 비교 결과가 같다이면, 0x40074c에 있는 <main+118>로 점프한다.
main 113: 0x400500에 있는 <__stack_chk_fail@plt>함수를 호출한다.
main 118: mov esp, ebp와 pop ebp를 합친 명령어로, ebp를 esp에 옮기고 ebp를 pop한다.
main 119: pop eip와 jmp eip를 합친 명령어로, 다음 명령어에 해당하는 eip를 pop하고 eip에는 ret 주소가 들어간다.
그 다음 그 주소로 점프한다. 즉, 함수가 끝나고 원래 시작된 주소로 돌아가는 것이다.
*flag_generator는 flag를 생성하는 함수이다.
이 문제는 어셈블리어로 프로그램을 살펴본 후에, 입력값으로 0xdeadbeef를 넣으면 flag가 나온다는 것을 이해해야 하는 문제이다. (단, 입력할 때는 10진수 형태로 고쳐서 입력해야 한다. 0xdeadbeef의 10진수 형태는 3735928559이다)
즉, '공격 기법을 사용한다는 성격보다는 어셈블리어를 읽음으로써 프로그램을 이해할 수 있느냐?'라는 성격의 문제이다.
prob1을 실행시키면,
input any number라고 출력되면서 숫자를 입력받는다.
이때 아무 숫자나 입력하면,
flag가 출력되지 않고, 그냥 종료된다.
하지만 만약 0xdeadbeef를 10진수로 고친 값을 넣는다면,
correct! 라고 출력되면서 flag값이 출력된다.
flag는 Layer7{y0u_are_g00d_at_a55emb1y} 였다.
'Layer7 과제 > 리버싱' 카테고리의 다른 글
[리버싱] prob3, prob4, prob5 (0) | 2022.08.01 |
---|---|
[리버싱] 3차시 과제2 (0) | 2022.07.27 |
[리버싱] 2차시 과제 (2) (0) | 2022.07.25 |
[리버싱] 2차시 과제 (0) | 2022.07.25 |
[리버싱] 1차시 과제 (2) - 리눅스 명령어, vim 명령어 (0) | 2022.07.20 |