[드림핵] rev-basic-2 풀이

비얌·2022년 12월 8일
0

어셈블리 게임

목록 보기
14/15
post-thumbnail

개요

저번 포스팅에 이어 드림핵에서 리버싱 워게임 문제 rev-basic-2도 풀어보기로 했다.



rev-basic-2 풀이

1. 문제

문제는 아래와 같다. correct를 출력하는 입력값을 찾으면 된다.


2. Detect It Easy 사용

Detect It Easy라는 프로그램에 넣어보면, 이 파일이 PE64 파일이고 따로 압축은 되어있지 않다고 나온다. IDA64로 바로 열어보자.


3. IDA64 사용

(1) 전체적인 그래프 파악하기

IDA64에 해당 파일을 올려보았다. 그럼 이런 그래프가 나온다.

이 그래프만 해석해보면 어떤 input 값을 넣으면 Correct 혹은 Wrong을 출력한다는 것 같다.


(2) 디컴파일하기

F5 단축키를 눌러 디컴파일해보았다. 그럼 아래와 같은 코드가 나타난다.

sub_1400013E0 함수로 Input : 을 출력하고, sub_140001440 함수로 입력값을 받는 것 같다.

그리고 sub_140001000 함수에 입력값을 넣고 맞으면 Correct, 틀리면 Wrong을 출력한다.

sub_140001000함수가 중요해보이니 이 함수를 분석해보기로 했다.

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4[256]; // [rsp+20h] [rbp-118h] BYREF

  memset(v4, 0, sizeof(v4));
  sub_1400011B0("Input : ", argv, envp);
  sub_140001210("%256s", v4);
  if ( (unsigned int)sub_140001000(v4) )
    puts("Correct");
  else
    puts("Wrong");
  return 0;
}

(3) sub_140001000 함수 분석하기

sub_140001000 함수를 더블클릭해서 들어가보았다. 그럼 아래와 같은 코드가 뜬다.

__int64 __fastcall sub_140001000(__int64 a1)
{
  int i; // [rsp+0h] [rbp-18h]

  for ( i = 0; (unsigned __int64)i < 0x12; ++i )
  {
    if ( *(_DWORD *)&aC[4 * i] != *(unsigned __int8 *)(a1 + i) )
      return 0i64;
  }
  return 1i64;
}

일단 아래의 정보는 알았다.

  • 18번 반복한다(0x12번) --> 글자가 18개인가?
  • aC는 Comp4re_the_ar4y이다.(더블클릭해서 들어가보니까 그랬음) 👉 아니었음. 스펠링 잘못봤다.. 삽질의 시작
  • return 0i64는 return 0을 의미하고, 찾아보니 true의 의미로 성공적인 반환을 의미한다고 한다. 반대로 return 1i64는 return 1을 의미하고, false의 의미로 다른 결과나 에러를 의미한다고 한다. 따라서 for문 안에서 aC[4 * i]와 a1 + i가 다를 때의 a1 값을 구해야 하는 것 같다.👉 아니었음. 반대라고 한다. return 0이 false, return 1이 true!!!

그런데 if ( *(_DWORD *)&aC[4 * i] != *(unsigned __int8 *)(a1 + i) ) 이부분이 진짜 뭔지 모르겠다! 예전에 풀었을 때 이게 배열이고.. (a1 + i) 이부분에 i가 0부터 들어가므로 배열을 인덱스 순서대로 하나씩 순회하는 거라는 말을 들었던 것 같긴 한데...

aC[4 * i]가 인덱스가 4의 배수일 때를 의미하는 건가?? 잘 모르겠다!! 아무래도 디버깅을 하면서 알아봐야 할 것 같다.


4. x64dbg 사용

x64dbg를 이용하여 디버깅해보기로 했다. 먼저 파일을 올린 후 input값을 입력하는 부분으로 가기 위해 문자열 검색을 했다. (마우스 우클릭 - 다음을 찾기 - 모든 모듈 - 문자열 참조)

"Input : "가 쓰인 부분을 더블클릭해서 들어갔다.

그럼 아래와 같이 뜨는데, Input 값을 넣고 Correct인지 Wrong인지 판별하는 흐름 사이에 call chall2.7FF6E51E1000 이부분이 Input값을 판별하는 명령인 것을 짐작할 수 있다. 그래서 이곳에 단축키 F2를 눌러 브레이크포인트를 걸고, 이 안으로 들어가 보려고 한다.

들어가보면 cmp 부분에서 글자를 비교한 후 je로 분기하는 것을 알 수 있다. 일치하면 위로 올라가서 같은 동작을 반복하고(for문 같다.), 아니면 비교를 멈춘 후 wrong을 출력한다.

그러니까, 모든 cmp를 통과하면 된다. 디버깅을 하며 종합해보니, Comp4re_the_arr4y의 한글자 한글자와 input 값의 한글자 한글자를 비교하고 있었다. 그래서 답에 Comp4re_the_arr4y를 넣었더니, correct를 출력했다!!



정답

성공했다!



하지만.. 여전히 코드가 무슨 말인지 모르겠다.

그렇다. 코드를 해석해서 푼게 아니라 디버깅을 일일이 해보면서 풀었다. 여전히 이 코드가 무슨 말인지는 모르는 상태이다.

if ( *(_DWORD *)&aC[4 * i] != *(unsigned __int8 *)(a1 + i) )

이게 무슨 말일까? 잘 모르겠으니 드림핵에 정답을 제출한 후 풀이를 보기로 했다.

아니 이게 말이 되나??? 내가 잘못 본 거였음

아니...답이 이렇게 멀쩡하게 나와있는데 내가 잘못보고 ... 오타를 낸 거였음... 그니까 이거 자체가 그냥 답이었음

그럼 이 코드의 의미는 대체 뭐야??

if ( *(_DWORD *)&aC[4 * i] != *(unsigned __int8 *)(a1 + i) )

지인에게 도움을 구했다... 의미를 알아낸 것 같음!!! 아래를 자세히 보면, 주소 140003000에 char 'C'가 있다. 그리고 140003001 ~ 140003003까지는 비어있다가 140003004가 되어서야 char 'o'가 들어있다. 즉, 4바이트마다 글자가 들어있으므로 거기서 하나씩 문자열을 뽑은 후 입력값인 a1과 비교하는 것이었다!!!!!



🐹 회고

흑흑 잘못 읽어서... 삽질을 하다니... 조금 어이가 없지만, 그래도 잘못 읽어서 바로 답을 찾지 못했고, 그래서 if ( *(_DWORD *)&aC[4 * i] != *(unsigned __int8 *)(a1 + i) )에서 [4 * i]의 의미를 파고들 수 있었던 것 같다.

다음번에는 코드를 잘 읽자!! 그리고 모르는 건 검색하거나 주변에 질문해서 알아가자😇

profile
🐹강화하고 싶은 기억을 기록하고 공유하자🐹

0개의 댓글