문제 : 이 문제는 사용자에게 문자열 입력을 받아 정해진 방법으로 입력값을 검증하여 correct 또는 wrong을 출력하는 프로그램이 주어집니다. 해당 바이너리를 분석하여 correct를 출력하는 입력값을 찾으세요.
< 전체 진행 방향 >
1. ‘문자열찾기’로 메인 함수 찾기
: 입력받는 "Input:" 부분을 통해 메인함수를 찾을 수 있음.
2. 메인함수
3. 메인 함수(그래프)
: 첫번째 블록 아래의 두 블록을 보면, 첫번째 블록의 조건이 만족되면 왼쪽 블록(Wrong)으로
점프하고, 만족되지 않으면 오른쪽 블록(Correct)로 진행됨을 알 수 있음.
아래의 메인 함수 8, 9번째 줄을 보면 eax 값을 확인한 후, eax값이 0이면 chall0.7FF6576F1166
주소로 점프하는 것을 알 수 있음. (chall0.7FF6576F1166 은 wrong)
따라서 test 위의 7번째 줄의 함수가, 입력받은 문자열이 맞는지 비교하는 함수라고 예측할 수 있음.
< main 함수 >
1. | lea rcx,qword ptr ds:[7FF6576F2238] | 00007FF6576F2238:"Input : "
2. | call <chall0.sub_7FF6576F1190> |
3. | lea rdx,qword ptr ss:[rsp+20] |
4. | lea rcx,qword ptr ds:[7FF6576F2244] | 00007FF6576F2244:"%256s"
5. | call <chall0.sub_7FF6576F11F0> |
6. | lea rcx,qword ptr ss:[rsp+20] |
7. | call <chall0.sub_7FF6576F1000> |
8. | test eax,eax |
9. | je chall0.7FF6576F1166 |
10. | lea rcx,qword ptr ds:[7FF6576F2250] | 00007FF6576F2250:"Correct"
11. | call qword ptr ds:[<&puts>] |
12. | jmp chall0.7FF6576F1173 |
13. | lea rcx,qword ptr ds:[7FF6576F2258] | 00007FF6576F2258:"Wrong"
14. | call qword ptr ds:[<&puts>] |
15. | xor eax,eax |
16. | mov rcx,qword ptr ss:[rsp+120] |
17. | xor rcx,rsp |
18. | call chall0.7FF6576F12E0 |
19. | add rsp,130 |
20. | pop rdi |
21. | ret |
4. 비교 함수 내부(그래프)
: 메인 함수 7번째 줄의 call을 따라가면 아래의 그림과 같은 비교 함수가 나온다.
이곳에서 test의 조건이 만족되지 않으면 wrong으로 점프, 만족되면 correct로 진행되는 것을 알 수 있다.
< 비교 함수>
1. | mov qword ptr ss:[rsp+8],rcx |
2. | sub rsp,38 |
3. | lea rdx,qword ptr ds:[7FF6576F2220] | 00007FF6576F2220:"Compar3_the_str1ng"
4. | mov rcx,qword ptr ss:[rsp+40] |
5. | call <JMP.&strcmp> |
6. | test eax,eax |
7. | jne chall0.7FF6576F1028 |
8. | mov dword ptr ss:[rsp+20],1 |
9. | jmp chall0.7FF6576F1030 |
10. | mov dword ptr ss:[rsp+20],0 |
11. | mov eax,dword ptr ss:[rsp+20] |
12. | add rsp,38 |
13. | ret |
< 풀이 >
main 함수 8번째 줄을 보면, eax가 0인지 아닌지 검사하는 과정이 있음.
8, 9번째 줄을 통해, (je: equl, ZF=1) eax가 0이면 wrong으로 점프, eax가 0이 아니면 correct로 가는 것을 알 수 있다.
(초록선 : jcc 명령어에서 분기를 취할 경우 / 빨간 : jcc 명령어에서 분기 취하지 않는 경우)
이때 main 함수 7번째 줄의 call(비교 함수)을 따라가면, 비교 함수 6번째 줄에서 다시 eax가 0인지 아닌지 검사를 하고 있으며, 이때 (jne : not equl, ZF=0) eax가 0이면 [rsp+20]에 1을 담고, eax가 0이 아니면 [rsp+20]에 0을 담는다. 그 후, 마지막에 공통으로 eax에 [rsp+20] 값을 저장한다.
즉, 비교 함수에서 [rsp+20]에 1이 담겨야, 비교 함수의 마지막에 eax에 1이 담기게 되고, main 함수에서 correct로 점프할 수 있다.
마지막으로, 비교 함수 5번째 줄의 call 하는 함수는 두 문자열을 비교하여 동일하면 0, 다르면 1을 eax에 저장하는 함수인데, 결론적으로 correct로 가기 위해서는 비교 함수에서 [rsp+20]에 1을 담아야 하며, 그러기 위해서는 eax가 0이어야 한다. 즉, call 함수에서 비교하는 rdx와 rcx가 같은 문자열이어야 하므로, 정답은 "Compar3_the_str1ng"가 되어야 한다.
정답 : "Compar3_the_str1ng"
'Reversing > DreamHack' 카테고리의 다른 글
[DreamHack_wargame] rev_basic_5번 (0) | 2021.05.15 |
---|---|
[DreamHack_wargame] rev_basic_4번 (0) | 2021.04.13 |
[DreamHack_wargame] rev_basic_3번 (0) | 2021.04.13 |
[DreamHack_wargame] rev_basic_2번 (0) | 2021.04.12 |
[DreamHack_wargame] rev_basic_1번 (0) | 2021.04.12 |