저번 포스팅에 이어 드림핵에서 리버싱 워게임 문제 rev-basic-2도 풀어보기로 했다.
문제는 아래와 같다. correct를 출력하는 입력값을 찾으면 된다.
Detect It Easy라는 프로그램에 넣어보면, 이 파일이 PE64 파일이고 따로 압축은 되어있지 않다고 나온다. IDA64로 바로 열어보자.
IDA64에 해당 파일을 올려보았다. 그럼 이런 그래프가 나온다.
이 그래프만 해석해보면 어떤 input 값을 넣으면 Correct 혹은 Wrong을 출력한다는 것 같다.
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;
}
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;
}
일단 아래의 정보는 알았다.
Comp4re_the_ar4y
이다.(더블클릭해서 들어가보니까 그랬음) 👉 아니었음. 스펠링 잘못봤다.. 삽질의 시작그런데 if ( *(_DWORD *)&aC[4 * i] != *(unsigned __int8 *)(a1 + i) )
이부분이 진짜 뭔지 모르겠다! 예전에 풀었을 때 이게 배열이고.. (a1 + i) 이부분에 i가 0부터 들어가므로 배열을 인덱스 순서대로 하나씩 순회하는 거라는 말을 들었던 것 같긴 한데...
aC[4 * i]가 인덱스가 4의 배수일 때를 의미하는 건가?? 잘 모르겠다!! 아무래도 디버깅을 하면서 알아봐야 할 것 같다.
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]
의 의미를 파고들 수 있었던 것 같다.
다음번에는 코드를 잘 읽자!! 그리고 모르는 건 검색하거나 주변에 질문해서 알아가자😇