문제 설명
문제 풀이(x64dbg)
문제에서 내려받은 파일을 x64dbg로 열었을 때의 모습이다. 먼저 문자열 참조 검색 기능을 사용하여 main 함수를 찾아보자.
여기서 분기문을 찾아보자. 당연히 'Correct' 문자열을 출력하는 부분 위에 있지 않겠는가?
노란 하이라이트 부분에 커서를 올려보며 cmp 명령어가 포함되었는지 확인해본다.
140001000에 커서를 두고 미리보기를 했을 때, cmp 명령어가 포함되어 있으니 클릭하여 들어가보자.
함수의 시작 주소가 140001000이고 ret 주소가 14000106E까지라서 살짝 길지만,,, 모든 줄을 한번 분석해보자.
1. mov qword ptr ss:[rsp+8],rcx : rcx(첫번째 함수 인자)값을 rsp+8(스택)에 저장
2. sub rsp,18 : rsp 값을 0x18(24)만큼 감소시켜 스택 프레임 확보
3. mov dword ptr ss:[rsp],0 : rsp가 가리키는 메모리를 0으로 초기화
4. jmp chall4.14000101A : 14000101A로 jump
5. mov eax,dword ptr ss:[rsp] : [rsp]를 eax에 넣기(초기값은 0)
6. inc eax : eax++
7. mov dword ptr ss:[rsp],eax : 증가된 eax 값을 다시 [rsp]에 저장
8. movsxd rax,dword ptr ss:[rsp] : 길이가 일치하지 않아도 rsp값을 rax로 이동
9. cmp rax,1C : rax와 1C(10진수로 28) 비교
10. jae chall4.140001065 : 결과가 크거나 같으면 즉, rax >= 0x1C라면 반복문 종료
11. movsxd rax,dword ptr ss:[rsp] : 길이가 일치하지 않아도 rsp값을 rax로 이동
12. mov rcx,qword ptr ss:[rsp+20] : rcx = [rsp + 20]
13. movzx eax,byte ptr ds:[rcx+rax] : eax = *(rcx + rax) 즉, rcx가 가리키는 문자열의 rax번째 문자를 가져옴
14. sar eax,4 : eax 값을 오른쪽으로 4비트 shift(상위 4비트만 유지)
15. movsxd rcx,dword ptr ss:[rsp] : rsp값을 rcx로 변환
16. mov rdx,qword ptr ss:[rsp+20] = rdx = [rsp + 20]
17. movzx ecx,byte ptr ds:[rdx+rcx] : ecx = *(rdx + rcx) 즉, rdx가 가리키는 문자열의 rcx번째 문자를 ecx에 저장
18. shl ecx,4 : ecx값을 왼쪽으로 4비트 shift(하위 4비트는 모두 0이 된다)
19. and ecx,F0 : ecx의 하위 4비트를 0으로 유지
20. or eax,ecx : eax |= ecx 즉, 상위 4비트와 하위 4비트를 결합
21. movsxd rcx,dword ptr ss:[rsp] : rsp값을 rcx로 변환
22. lea rdx,qword ptr ds:[140003000] : rdx에 특정 메모리 주소 0x140003000 로드(비교용 데이터)
23. movzx ecx,byte ptr ds:[rdx+rcx] : ecx = *(rdx + rcx) 즉, 비교 대상 문자 가져오기
24. cmp eax,ecx : eax와 ecx 비교
25. je chall4.140001063 : 값이 같으면 140001063으로 jump, 루프 반복
26. xor eax,eax : eax값을 0으로 초기화(비교 실패 시)
27. jmp chall4.14000106A : 14000106A로 점프(종료)
28. jmp chall4.140001012 : 140001012로 점프(루프 재실행)
29. mov eax,1 : eax = 1(성공 플래그 설정)
30. add rsp,18 : rsp 원래대로 복구
31. ret : 함수 종료 및 반환
여기서 우리가 눈여겨봐야 할 부분은 문자열 비교를 수행하는 11번째 줄부터 20번째 줄까지이다.
이를 간단히 나타내면 다음과 같은 식이 나온다.
140003000번_주소의_값[i] >> 4 | 140003000번_주소의_값[i] << 4
= 상위 4비트를 하위 4비트로 이동 | 하위 4비트를 상위 4비트로 이동
결국, 140003000번 주소로부터 28개의 문자들의 상위 4비트를 하위 4비트로, 하위 4비트를 상위 4비트로 이동시키면 FLAG를 얻을 수 있다는 것이다.
덤프창에서 140003000번 주소가 가리키는 문자들은 다음과 같다.
140003000번부터 28개의 문자를 16진수로 나타낸 값은 다음과 같다.
0x24, 0x27, 0x13, 0xC6, 0xC6, 0x13, 0x16, 0xE6, 0x47, 0xF5, 0x26, 0x96, 0x47, 0xF5, 0x46, 0x27, 0x13, 0x26, 0x26, 0xC6, 0x56, 0xF5, 0xC3, 0xC3, 0xF5, 0xE3, 0xE3
이를 역순으로 계산하여 FLAG 값을 찾아보자.
0x24 : 0x2 >> 4 | 0x4 << 4 = 0x42 = 66 = 'B'
0x27 : 0x2 >> 4 | 0x7 << 4 = 0x72 = 114 = 'r'
0x13 : 0x1 >> 4 | 0x3 << 4 = 0x31 = 49 = '1'
0xC6 : 0xC >> 4 | 0x6 << 4 = 0x6C = 108 = 'l'
0xC6 : 0xC >> 4 | 0x6 << 4 = 0x6C = 108 = 'l'
0x13 : 0x1 >> 4 | 0x3 << 4 = 0x31 = 49 = '1'
0x16 : 0x1 >> 4 | 0x6 << 4 = 0x61 = 97 = 'a'
0xE6 : 0xE >> 4 | 0x6 << 4 = 0x6E = 110 = 'n'
0x47 : 0x4 >> 4 | 0x7 << 4 = 0x74 = 116 = 't'
0xF5 : 0xF >> 4 | 0x5 << 4 = 0x5F = 95 = '_'
0x26 : 0x2 >> 4 | 0x6 << 4 = 0x62 = 98 = 'b'
0x96 : 0x9 >> 4 | 0x6 << 4 = 0x69 = 105 = 'i'
0x47 : 0x4 >> 4 | 0x7 << 4 = 0x74 = 116 = 't'
0xF5 : 0xF >> 4 | 0x5 << 4 = 0x5F = 95 = '_'
0x46 : 0x4 >> 4 | 0x6 << 4 = 0x64 = 100 = 'd'
0x27 : 0x2 >> 4 | 0x7 << 4 = 0x72 = 114 = 'r'
0x13 : 0x1 >> 4 | 0x3 << 4 = 0x31 = 49 = '1'
0x26 : 0x2 >> 4 | 0x6 << 4 = 0x62 = 98 = 'b'
0x26 : 0x2 >> 4 | 0x6 << 4 = 0x62 = 98 = 'b'
0xC6 : 0xC >> 4 | 0x6 << 4 = 0x6C = 108 = 'l'
0x56 : 0x5 >> 4 | 0x6 << 4 = 0x65 = 101 = 'e'
0xF5 : 0xF >> 4 | 0x5 << 4 = 0x5F = 95 = '_'
0xC3 : 0xC >> 4 | 0x3 << 4 = 0x3C = 60 = '<'
0xC3 : 0xC >> 4 | 0x3 << 4 = 0x3C = 60 = '<'
0xF5 : 0xF >> 4 | 0x5 << 4 = 0x5F = 95 = '_'
0xE3 : 0xE >> 4 | 0x3 << 4 = 0x3E = 62 = '>'
0xE3 : 0xE >> 4 | 0x3 << 4 = 0x3E = 62 = '>'
따라서 FLAG는
Brl1ll1ant_bit_drlbble_<<_>>
라고 구할 수 있다.
문제 풀이(IDA)
문제 파일을 IDA로 열면 다음과 같은 화면이 나온다.
바로 디컴파일 기능을 사용해보자.
여기서 비교 연산을 수행하는 sub_140001000 메소드를 클릭하면 다음과 같은 코드가 나온다.
이를 조금 쉬운 코드로 바꿔서 FLAG 값을 구해보자.
byte_140003000 = [
0x24, 0x27, 0x13, 0xC6, 0xC6, 0x13, 0x16, 0xE6, 0x47, 0xF5,
0x26, 0x96, 0x47, 0xF5, 0x46, 0x27, 0x13, 0x26, 0x26, 0xC6,
0x56, 0xF5, 0xC3, 0xC3, 0xF5, 0xE3, 0xE3
]
a1 = []
for b in byte_140003000:
high = b >> 4
low = b & 0xF
a1.append((low << 4) | high)
print(a1)
FLAG :
Brl1ll1ant_bit_drlbble_<<_>>
'Security > Reverse Engineering' 카테고리의 다른 글
rev-basic-7 풀이 (0) | 2025.02.28 |
---|---|
rev-basic-5 풀이 (0) | 2025.02.24 |
rev-basic-6 풀이 (0) | 2025.02.23 |
rev-basic-3 풀이(IDA) (0) | 2025.02.20 |
rev-basic-3 풀이 (0) | 2025.02.05 |