2015 Layer7 CTF ReverseMe

로꾸꺼 는 2015년 Layer7 CTF에서라는 리버싱 150점짜리 문제이다.

ReverseMe.mp3 라는 파일이 주어졌다. 근데 이 mp3를 열어보면 로꾸꺼 노래가 나오고 정말 수상햇다.

f = open('ReverseMe.mp3','rb')
f2 = open("ReverseMe.exe","wb")
data = f.read()
f.close()
f2.write(data[::-1])
f2.close()

hex 값을 보니까 PE 헤더가 다 로꾸꺼하게 되있어서 우선 파일의 값을 다 로꾸꺼해주었다.

int __cdecl main(int argc, const char **argv, const char **envp)
{
  printf("input : ");
  scanf("%s", &hostlong);
  if ( sub_401060() )
  {
    printf("Correct !\n");
    printf("flag is %s\n", &hostlong);
  }
  else
  {
    printf("InCorrect ..");
  }
  return 0;
}

main의 흐름은 입력받아 입력 받은 값이 맞는지 비교해주고 Correct ! 떠서 맞으면 입력한 값이 플래그다.

BOOL sub_401060()
{
  u_long v1; // edi
  u_long v2; // ebx
  signed int v3; // esi
  int v4; // edi
  unsigned int v5; // eax
  int v6; // eax

  if ( strlen(&hostlong) != 8 )
    return 0;
  v1 = dword_40336C;
  v2 = htonl(hostlong);
  v3 = 0;
  v4 = htonl(v1);
  do
  {
    switch ( v3 )
    {
      case 0:
        v5 = sub_401110(v4);
        goto LABEL_9;
      case 1:
        v5 = sub_401160(v4);
        goto LABEL_9;
      case 2:
        v5 = sub_4011B0(v4);
        goto LABEL_9;
      case 4:
        v5 = sub_401200(v4);
LABEL_9:
        v2 ^= v5;
        break;
      default:
        break;
    }
    v6 = v2;
    ++v3;
    v2 = v4;
    v4 = v6;
  }
  while ( v3 < 4 );
  return v6 == 0x72659830 && v2 == 0x64C38B40;
}

우선 8바이트를 input 받는다는걸 알았다. 그리고 htonl 함수를 써서 4바이트씩 나눠서 연산하는 것 같다.

  • 참고
u_long htonl(u_long hostlong); 
unsigned int a = 0x12345678;
printf("%#x %#x\n",a, htonl(a));
>> 0x12345678 0x56781234

그래서 AAAABBBB 를 입력해주고 마지막 리턴해줄 때 참을 만들어야한다.

앞에 AAAA 4바이트를 입력한건 어떠한 연산을 하고 eax에 저장한 후 v6와 비교한다.

뒤에 BBBB 4바이트를 입력한건 어떠한 연산을 하고 ebx에 저장한 후 v2와 비교한다.

디버깅해보면서 마지막에 비교할 때 eax 값을 보니까 0x4141BE14 였는데

앞에 두 글자는 그대로 들어가고 뒤에 두 글자는 어떠한 연산을 해서 나온다는 걸 알 수 있다.

그리고 ebx 값을 보면 0x42E8BD42 이런식으로 들어가는데

첫 글자와 마지막 글자만 입력한 그대로 들어가는 것 같다.

이번에는 BBBBAAAA 를 넣게되면 eax는 0x4242BD17 , ebx는 0x41EBBE0x41 이렇게 들어가있다.

그래서 현재까지 알아낸건 아래와 같다.

flag[0] = 0x72
flag[1] = 0x65
flag[4] = 0x64
flag[7] = 0x40 
flag = 're??d??@'

현재까지 re??d??@ 4글자 알아냈다.

나머지는 xor 연산을 해주는걸 알게되었다.

0x4141 2바이트 입력하게되면 0xBE14 가 나온다. 그러면 역연산을 하면 된다.

0xBE14 ^ 0x4141 = 65365
0xBD16 ^ 0x4242 = 65365

그러면 이제 입력한 값과 65365와 xor한 값이 0x9830이 나와야한다.

0x9830 ^ 65365 = 0x6765 

그러므로 2번째 인덱스의 값은 0x67(g), 3번째 인덱스의 값은 0x65(e)이다.

현재까지 reged??@ 이만큼 구했다. 이제 5,6번째 인덱스의 값만 구해주면 된다.

아까처럼 역연산해주면 된다.

0xE8BD ^ 0x4242 = 43775
0xEBBE ^ 0x4141 = 43775

이제 입력한 값과 43775와 xor한 값이 0xC38B이 나오면 된다.

0xc38b ^ 43775 = 0x6974

5번째 인덱스는 0x69(i), 6번째 인덱스는 0x74(t) 이다.

그러면 이제 다 구했다.

regedit@ 을 입력하면 Correct가 뜰 것이다.

FLAG : regedit@