본문 바로가기
étude/reverse engineering

dreamhack : rev_basic_2

by mummoo 2023. 8. 5.

저번에 남강성보고 칭구들한테 콘솔창 바로 꺼지는거 설명 못해줘따

근데 몰랐는걸ㅇㅅㅇ 일부러 안 알려준 거 아님...

 

cmd창을 관리자 권한으로 키는 건 맞는데, 그 후에 

프로그램 경로를 복사할 때 마우스 오른쪽 버튼 누르고 경로로 복사 를 눌러야 한다.

단축키 : Ctrl + Shift + C

 

생각해보니까 관리자 권한으로 열면 파일 그냥 갖다 붙이는거 안 되는데 왜 기억이 안 났는지 모르겠음

=>

왜냐하면, 관리자 권한을 요구하는 작업에 대해서는

사용자의 승인을 요청하는 Windows 사용자 계정 제어 (UAC) 라는 기능이 적용됨

그래서 cmd창을 관리자 권한으로 실행하면 UAC를 통해 보호되니까

일반적인 사용자는 cmd창에 키 입력 또는 붙여넣기가 안 됨 

UAC에 의해 제한되기 때문이다.

 

아무튼 위에 있는 그림은 윈도우 파워쉘로 연 거고,

 

이건 cmd창을 관리자 권한으로 실행한 화면이다!

 

프로그램이 output을 출력하지 않고 바로 꺼지는 걸 해결하기 위해 관리자 권한으로 cmd를 실행시키는 이유는

특정 파일이나 시스템 리소스에 접근하기 위해 관리자의 권한이 필요해서 output이 나오지 않았던 것일 수도 있고

또 위에서 설명했던 UAC가 프로그램 실행을 제한하는 경우도 있기 때문에, 그 제한을 우회해 프로그램을 실행하기 위해서이다. 

 

아무튼 이번에도 Correct를 도출하는 플래그값을 찾아내야 한다.

 

디버거로 chall2를 열면

아무튼 이번에도 1175 주소에서 점프하면 Wrong이 출력되니까, 

1173의 결과가 0이면 안 된다. 

eax를 반환하는 함수인 116E주소의 함수, 즉 1000에 들어가보면

 

위에서부터 해석해보도록 한다.

 

sub rsp, 18 // 최상단 스택의 주소인 rsp를 18만큼 뺀다 = 스택은 아래로 자라니까 스택을 18만큼 확장함

 

mov dword ptr ss :[rsp], 0 // rsp 주소에 0을 저장한다.

 

jmp 어쩌구 // 이거 누르면 mov rax, dword ptr ss:[rsp]로 이동한다.

 

=> 즉 rsp 주소에 저장된 값을 rax에 저장한단 얘긴데, 일단 아직 rsp에는 0이 저장된 상태

=> rax에 0을 저장했음을 알 수 있다.

 

cmp rax, 12 

=> 여기서 12는 0x12니까, 십진수로 따지면 18이다. 

= rax에 18이 저장될 때까지 계산을 해야됨을 유추할 수 있다.

 

jae 어쩌구 // rax >= 0x12이면 점프

 

*jae 에서 ae 가 above equal의 줄임말이기 때문에,

위의 연산에서 op1 >= op2 면 점프하라는 얘기다.

 

=> 지금은 rax 에 0이 저장된 상태라 점프할 수 없지만, 만약 rax >= 12라면? 점프하면 어떻게 되는지, 그 큰 틀이 궁금해서

점프시켜보면  eax에 1을 넣고 스택 다시 줄이고 끝난다.

 

=> 즉, rax == 12일 때 연산값이 반환된다!

반복문을 이용했음을 알 수 있다. 

 

=> 그러면 내가 해석하지 않은, rax < 0x12일 때의 경우에 어떠한 코드들을 거치는지 확인해야 플래그값을 구할 수 있다.

 

jae에서 점프하지 않고 스킵할 것이므로, 그 밑의 코드부터 해석하면 된다.

 

mov rax, dword ptr ss:[rsp] // rsp에 저장된 값 (0)을 rax에 저장한다. 

 

lea rcx, qword ptr ds:[7FF~] // 7FF~에 저장된 값을 rcx에 넣는다. 

=> 뭐지? 궁금하니까 덤프에서 따라가기 눌러서 해당 주소에 뭐가 저장되어 있는지 보기로 한다. 

 

=> 해당 주소에는 0x43이 저장되어 있다! rcx에 0x43의 값을 저장한다.

 

mov rdx, dword ptr ss :[rsp] // rsp에 저장된 값 (0)을 rdx에 저장한다 

 

mov r8, qword ptr ss : [rsp + 20] // rsp+20 주소에 저장되어 있던 값을 r8에 저장한다.

 

=> 이때, 1000함수 들어오면서 rcx에 있던 값을 rsp+8에 저장하고, 스택을 18만큼 늘렸기 때문에 rcx에 있던 값이 현재엔 rsp+20 주소에 저장되어 있음을 이용한다.

=> 즉 rsp+20 주소에는 현재 사용자 입력값이 저장되어 있다!

=> 사용자 입력값을 r8에 넣는거임

 

mov edx, byte ptr ds : [r8 + rdx] // r8 + rdx 주소에 저장되어 있는 값을 edx에 저장한다.

=> 이때 rdx에는 0이, r8에는 사용자 입력값이 저장되어 있다.

=> rev basic 1과 마찬가지로, 이번에도 사용자 입력값 (r8)에 인덱스 (rdx)가 붙은 형태로, 사용자 입력값의 한 문자씩 비교하는 흐름일 것임을 예측할 수 있다.

=> 일단 그 주소를 edx에 저장한 후에

 

cmp dword ptr ds : [rcx + rax*4], edx // rcx + rax*4 주소에 들어 있는 값과, 사용자 입력값의 특정 문자들을 &&연산해 비교한다.

=> 여기에서 rcx[0], rcx[4], ..., 의 문자와 edx의 값을 비교해 밑의 je에서 점프를 할 것임을 알 수 있다. 

점프를 하지 않으면 xor eax, eax를 통해 eax = 0 이 되어 Wrong이 출력된다. 

 

je // 1046 주소로 이동해서 또 점프를 준비한다.

jmp ~ // 1012 주소로 이동한다.

 

1012 주소의 함수에서는 rsp의 값을 eax에 넣고

 

inc eax // eax에 저장된 값을 1 증가시킨 후

 

mov dword ptr ss : [rsp], eax // eax에 저장된 값 (1)을 rsp에 넣는다.

=> rsp == 1

 

mov rax, dword ptr ss : [rsp] // rsp에 저장된 값 (1)을 rax에 저장한다.

=> rax == 1

 

cmp rax, 12 // rax와 0x12를 && 연산하는 코드로 돌아왔다.

 

이 기조가 반복될 텐데, 이를 통해서 

rax에 0x12의 값이 저장될 때까지 코드는 eax를 1 증가시키면서 반복될 것이며

rax == 0x12인 순간 eax=1을 저장하고 함수를 반환할 것이라는 것을 알 수 있다. 

 

따라서 연보라색 코드에서 0x43, 0x6F, ..., 0X79까지 총 17가지의 문자와 사용자 입력값을 비교하고, 

18번째, 즉 rax == 0x12가 되는 순간 jae로 이동해 eax = 1 저장 후 함수가 반환되는 구조임을 알 수 있다. 

 

따라서 플래그 = Comp4re_the_arr4y

 

*연보라색 코드 추가 설명

: 왜 rax가 인덱스인가요

 

=>

rcx에는 7FF~ 덤프의 값들이 있고, rax에는 0이 저장된 상태

r8에는 사용자 입력값이, 그리고 rdx에는 0이 저장된 상태

 

=> 그니까

이게 7FF 어쩌구 그 덤프를 따라가면 보이는 화면이다.

 

코드를 해석하다보면, rax는 0, 1, ...이렇게 증가한다

그리고 rcx(덤프의 값들)에 rax*4를 더한 값이 주소라면, rcx의 주소에 rax*4의 값을 더한다고 생각하면 된다.

만약에 rcx 주소가 1이었고 rax가 0, 1, 2 이렇게 증가하면 

위의 코드에서 1의 주소, 2의 주소, 3의 주소에 있는 값이 저장되는 것이다.

 

아무튼 그래서,

rcx + rax*4 : 7FF~의 주소, 7FF ~ + 4의 주소, 7FF~ + 8, ...의 주소에 저장된 값들과 

r8 + rdx : 사용자 입력값의 첫 번째 문자, 두 번째 문자, 세 번째 문자, ...에 저장된 값들을 && 연산을 통해서 같은지 비교하는 코드인 것이다.

 

그래서 위 덤프에 저장된 C, o, m, ..., y까지의 문자들이 사용자 입력값의 첫번째, 두번째, ..., 마지막 문자가 되어야 함

그래야 xor eax, eax가 계산되지 않아서 Wrong이 뜨지 않아여

 

*아 그리고 1 증가한다고 할 때, 증가하는 수는 십진수 형태로 증가한다고 생각하면 된다.

그니까 코드에서는 rax == 12일 때 당연히 0x12로 해석했지만

inc rax에서 rax를 1 증가시킬 때에는 그냥 평소에 연산하듯이 1 더하면 된다.

 

 

'étude > reverse engineering' 카테고리의 다른 글

dreamhack : rev_basic_7  (0) 2023.11.04
dreamhack : rev_basic_3  (0) 2023.08.06
dreamhack : rev_basic_1  (0) 2023.01.12
dreamhack : rev_basic_0  (0) 2023.01.10
easy_crackme1  (0) 2023.01.07