Dreamhack - Reversing Basic Challenge #3

·2025년 9월 30일

Dreamhack-Writeups

목록 보기
42/52

Reversing Basic Challenge #3

문제 링크

https://dreamhack.io/wargame/challenges/17

문제 설명

이 문제는 사용자에게 문자열 입력을 받아 정해진 방법으로 입력값을 검증하여 correct 또는 wrong을 출력하는 프로그램이 주어집니다.

해당 바이너리를 분석하여 correct를 출력하는 입력값을 찾으세요!

획득한 입력값은 DH{} 포맷에 넣어서 인증해주세요.

예시) 입력 값이 Apple_Banana일 경우 flag는 DH{Apple_Banana}

풀이과정

  1. 제공된 chall0.exe파일을 실행하면 input : 이라는 문자열이 출력되며 사용자의 입력을 받는 프로그램임을 알 수 있습니다. 플래그 값을 입력하면 "Correct"가 뜨는 구조입니다.

  2. x64dbg을 이용해 chall0.exe 파일을 열어봅니다.

  3. 우클릭 후 다음을 찾기 > 모든 시스템 모듈 > 문자열 참조 을 통해 "Correct" 문자열을 검색합니다.

  4. "Correct" 문자열이 출력되는 코드 근처에서 다음과 같은 흐름을 확인할 수 있었습니다.

    • 먼저 사용자에게 input : 을 출력합니다.
    • 이후 사용자의 입력을 [rsp+20] 주소에 저장합니다.
    • 00007FF6689C114E | call chall0.7FF6689C1000 는 검사함수로, 입력을 저장한 [rsp+20]을 검사합니다.
    • 입력값이 플래그 값과 다르다면, 즉 eax == 0 라면 wrong, 같다면 correct을 출력합니다.
  5. 입력한 값이 정답인지 검사하는 함수인 00007FF6689C114E | call chall0.7FF6689C1000 이 핵심함수임을 알 수 있었습니다.

  6. 더블클릭해 그 함수에 들어가 보았습니다. 하지만 드림핵의 앞선 리버싱 문제인 rev-basic-0 같이 플래그 값이 바로 나오지 않았습니다.

  7. 코드의 흐름을 확인하기 위해 우클릭 > 그래프 를 선택하여줍니다.

그래프의 화살표 색이 파란색, 녹색, 빨간색임을 확인할 수 있습니다. x64dbg에서 색은 점프 조건의 방향을 의미합니다.

  • 파란색 → 무조건 점프
  • 녹색 → 조건이 참일 때 가는 경로
  • 빨간색 → 조건이 거짓일 때 가는 경로

위 그래프에서는 녹색, 빨간색 화살표가 보이고, 파란 화살표가 한 바퀴를 돌면 다시 위로 올라가는 것을 보면 조건문과 반복문을 이용하였다고 확인할 수 있습니다.

  1. 첫 번째 조건문인 chal 13. 00007FF7E1E7101A 부터 확인해봅니다.
  • cmp rax, 18 : cmp= 비교 명령어입니다. rax와 18 비교합니다. 0x18번째, 즉 24(10진수)번을 반복합니다.
  • jae chall3.7FF7E17E71053 : jae = Jump if Above or Equal. 즉, 비교 결과에서 rax ≥24 면 chall3.7FF7E17E71053 주소로 이동합니다.
  • 비교를 24번 하는걸 보면 문자열의 길이가 24임을 유추해볼 수 있었습니다.

24번동안 반복할 반복문을 확인해 보았습니다.

  • lea rcx, qword ptr ds:[7FF7E1E73000] : LEA (Load Effective Address) = “메모리 내용을 읽지 않고, 주소값(포인터)만 계산해서 레지스터에 넣어라.” → rcx = 0x7FF7E1E73000 이라는 뜻입니다.
  • 즉, 답인지 아닌지 비교할 문자열이 0x7FF7E1E73000 에 있다는 뜻입니다.

비교할 문자열이 있는 0x7FF7E1E73000 에 더블클릭하여 이동하였습니다.

덤프를 확인해보니 16진수 24글자가 있었습니다. 어셈블리어 변환기로 변환 해 보았더니 I`gtcgBf€xii{™mˆh”ŸM¥E 라는… 알 수 없는 문자가 나왔습니다. 반목문에 추가적인 조건이 있음을 알 수 있었습니다. 이어서 확인해 보겠습니다.

  • mov rdx, qword ptr ss:[rsp+20]
    • mov = 단순 대입.
    • rdx = 64비트 레지스터.
    • [rsp+20] = 스택에서 +0x20 떨어진 위치 (여기에 함수 인자로 받은 입력 문자열 주소가 있음).
    • rdx = &flag
  • movzx ecx, byte ptr ds:[rdx+rcx]
    • ecx = flag[i]
  • xor ecx, dword ptr ss:[rsp]
    • xor = 배타적 논리합 (비트 연산). 같은 비트면 0, 다르면 1.
    • ecx = 지금 flag[i]
    • [rsp] = i
    • flag[i]와 i를 XOR해서 ecx에 저장. ecx = flag[i] ^ i
  • lea ecx, qword ptr ds:[rcx+rdx*2]
    • (대입 전) ecx = ecx + edx*2
    • ecx = (flag[i] ^ i) + 2*i

⇒ table[i] == (flag[i] ^ i) + (2*i) 가 최종 식입니다.

  1. 문자열을 알아내기 위해 table[i] == (flag[i] ^ i) + (2*i) 을 역연산 해야한다. 파이썬 코드를 이용하였습니다. (챗지피티를 활용하였습니다.)
# 주어진 table 값 (16진수)
table_hex = [
    0x49, 0x60, 0x67, 0x74, 0x63, 0x67, 0x42, 0x66,
    0x80, 0x78, 0x69, 0x69, 0x7B, 0x99, 0x6D, 0x88,
    0x68, 0x94, 0x9F, 0x8D, 0x4D, 0xA5, 0x9D, 0x45
]

flag_bytes = []
for i, val in enumerate(table_hex):
    # 역연산: flag[i] = (table[i] - 2*i) ^ i
    calc = (val - 2*i) & 0xFF   # 0~255 범위 유지
    flag_val = calc ^ i
    flag_bytes.append(flag_val)

flag = bytes(flag_bytes)
print("Flag bytes:", flag_bytes)
print("Flag string:", flag.decode(errors="ignore"))

실행하면 결과가 Flag string: I_am_X0_xo_Xor_eXcit1ng 로 나옵니다.

DH{I_am_X0_xo_Xor_eXcit1ng} 을 입력하였더니 해결할 수 있었습니다.


배운점

  • 리버싱 툴을 잘 쓰는것 뿐만 아니라 어셈블리어, 파이썬 코드 등 알아야 할 것들이 많아 어려웠습니다.
  • 특히 어셈블리어를 읽는 법을 잘 몰라 어려움을 겪었는데, 이번 기회에 리버싱 문제를 잘 해결하기 위해 공부의 필요성을 느끼게 되었습니다.

Summary (English)

  • The challenge provides a binary that takes user input and prints "Correct" if it matches the expected flag.
  • Using x64dbg, the "Correct" string reference led to the check function at call chall0.7FF6689C1000.
  • Analysis showed:
    • The flag length is 24 characters.
    • The check compares input against a table of 24 bytes at memory 0x7FF7E1E73000.
    • Core formula: table[i] == (flag[i] ^ i) + (2*i).
  • Reversing the formula gives: flag[i] = (table[i] - 2*i) ^ i.
  • A Python script reconstructed the flag as I_am_X0_xo_Xor_eXcit1ng.
  • Final solution: DH{I_am_X0_xo_Xor_eXcit1ng}.
  • Lesson learned: Understanding assembly logic and using scripting (Python) are both essential in reverse engineering challenges.
profile
CTF 풀이 및 실습 중심 학습을 기록합니다.

0개의 댓글