제리의 블로그

dingJMax @ Samsung CTF (SCTF) 2018 본문

CTF/reversing

dingJMax @ Samsung CTF (SCTF) 2018

j3rrry 2018. 7. 20. 17:52

dingJMax (106pts)

94 Solvers

난이도: Easy

분야: Reversing


I prepared the Rhythm game "dingJMax" for you.

This is really hard... Can you get prefect score for flag?


dingJMax

md5sum: 0a55a302e2da26f2e4cd327f056f8219


목차

  1. 실행 화면
  2. 분석
  3. gdb_command
- 실행 화면



실행해보면 4키 리듬게임으로 note  의 모양은 소문자 o  입니다.

그리고 299개의 모든 note 를 PERFECT!  를 해서 max SCORE 1000000점을 얻는게 목표란 것을 알 수가 있습니다.


- 분석

    76      key = wgetch(stdscr);
    77      if ( key == 'f' )
    78      {
              ...
    83      }
    84      if ( key > 'f' )
    85      {
    86        if ( key == 'j' )
    87        {
                ...
    92        }
    93        if ( key == 'k' )
    94        {
                ...
    99        }
   100      }
   101      else if ( key == 'd' )
   102      {
              ...
   107      }

dfjk key를 누를 때마다 FLAG 에 영향을 주고

f  눌렀을 때를 보면

    77      if ( key == 'f' )
    78      {
    79        key_f = 1;
    80        sub_401C9A('f' * time_clock);             // 
    81        sub_400C5E(dest);
    82        goto LABEL_20;
    83      }

f 와 time_clock 를 이용해서 FLAG 를 바꾼다는 것을 예측할 수 있습니다.




PERFECT!  일 조건을 알아보자면

   135      if ( key_d )
   136      {
   137        if ( note_d == 'o' )
   138        {
   139          if ( time_clock == 20 * ((unsigned __int64)(0x0CCCCCCCCCCCCCCCDLL * (unsigned __int128)time_clock >> 64) >> 4) )
   140          {
   141            show_log(window_log_obj, (__int64)"PERFECT!", 200);
   142            ++perfect_count;
   143          }
   144          else
   145          {
   146            show_log(window_log_obj, (__int64)"GREAT!", 200);
   147            ++great_count;
   148          }
   149        }
   150        else
   151        {
   152          show_log(window_log_obj, (__int64)"MISS!", 200);
   153          ++miss_count;
   154        }
   155      }

조건은 137과 139번째 줄에 있습니다.

note(o) 가 전역변수 note_d 에 있으면서 time_clock 역시 20의 배수일 때에 PERFECT!  입니다.

앞으로 139번째 줄을 PERFECT!  시간이라고 칭하겠습니다.



이번엔 note(o)  테이블 부분입니다.

   122      if ( time_clock == 20 * ((unsigned __int64)(0x0CCCCCCCCCCCCCCCDLL * (unsigned __int128)time_clock >> 64) >> 4) )
   123      {
   124        for ( k = 19; k > 0; --k )                // note 가 1칸 내려옴
   125          dword_607600[k] = dword_607600[k - 1];
   126        dword_607600[0] = *(_DWORD *)off_603280[(unsigned __int64)(0x0CCCCCCCCCCCCCCCDLL * (unsigned __int128)time_clock >> 64) >> 4];
   127      }

딱 PERFECT!  시간에 한칸씩 업데이트되고 있습니다.



앞에서 본 내용을 다시한번 짚고 넘어가자면

  1. dword_607600  은 note 정보가 들어있는 테이블이고
  2. 테이블이 업데이트되는 time_clock 은 20의 배수이며 PERFECT!  시간입니다.

그래서 저는 122번째 줄의 if 문 안에 break 를 걸고

테이블을 검증해서 key 를 자동으로 누르도록 gdb 명령을 짜봤습니다.


- gdb_command

b *0x0000000000401623
command 1
if *(int *)(0x607600+0x48) != 0x20202020
    if *(char *)(0x607600+0x48) == 'o'
        p/c $eax='d'
        end
    if *(char *)(0x607600+0x48+1) == 'o'
        p/c $eax='f'
        end
    if *(char *)(0x607600+0x48+2) == 'o'
        p/c $eax='j'
        end
    if *(char *)(0x607600+0x48+3) == 'o'
        p/c $eax='k'
        end
    p $rip=0x000000000040141A
    ignore 1 1
    end
c
end




SCTF{I_w0u1d_l1k3_70_d3v3l0p_GUI_v3rs10n_n3x7_t1m3}


Comments