ReadMe.txt

    This MP3 Player is limited to 1 minutes.
    You have to play more than one minute.
    
    There are exist several 1-minute-check-routine.
    After bypassing every check routine, you will see the perfect flag.

    MP3 Player 프로그램이 있는데 1분 듣기만 가능하지만,
    1분 듣기 제한을 우회하면 flag를 획득할 수 있다고 한다.

    Analysis

    .실제로 재생해서 1분이 넘어가면,
    “1분 미리듣기만 가능합니다.”라고 창이 뜨면서, 재생이 중단된다.

    rtcMsgBox 함수를 통해 저 메시지 창을 띄우는데,

    call하는 곳은 총 4군데이다.

    00403B07,
    00403C5F,
    00403E22,
    004045D8,

    4군데를 전부 다 브레이크포인트를 걸어서
    어디서 “1분 미리듣기만 가능합니다.” 창이 뜨는지 확인해본 결과,

    sub_4044C0 함수의 004045D8에서 호출하는 것을 확인할 수 있었다.

    sub_4044C0

    // bad sp value at call has been detected, the output may be wrong!
    int __stdcall sub_4044C0(int a1)
    {
      int v1; // eax
      int v2; // edi
      int v3; // eax
      int v4; // eax
      double v5; // st7
      char v6; // fps
      int v10; // ebx
      int v11; // eax
      int *v12; // edi
      int v13; // eax
      int v14; // eax
      int v15; // edi
      int v16; // eax
      int v17; // eax
      int v18; // eax
      int v19; // eax
      int v20; // eax
      _DWORD v22[3]; // [esp-Ch] [ebp-CCh] BYREF
      int v23; // [esp+0h] [ebp-C0h]
      double v24; // [esp+4h] [ebp-BCh]
      int v25; // [esp+Ch] [ebp-B4h]
      int v26; // [esp+10h] [ebp-B0h]
      int v27; // [esp+14h] [ebp-ACh]
      int v28; // [esp+18h] [ebp-A8h]
      int v29[9]; // [esp+1Ch] [ebp-A4h] BYREF
      int v30[2]; // [esp+40h] [ebp-80h] BYREF
      int *v31; // [esp+48h] [ebp-78h]
      int v32; // [esp+4Ch] [ebp-74h]
      int v33[2]; // [esp+50h] [ebp-70h] BYREF
      int *v34; // [esp+58h] [ebp-68h]
      int v35; // [esp+5Ch] [ebp-64h]
      int v36[2]; // [esp+60h] [ebp-60h] BYREF
      int v37; // [esp+68h] [ebp-58h]
      int v38; // [esp+6Ch] [ebp-54h]
      int v39[2]; // [esp+70h] [ebp-50h] BYREF
      int v40; // [esp+78h] [ebp-48h]
      int v41; // [esp+7Ch] [ebp-44h]
      int v42[2]; // [esp+80h] [ebp-40h] BYREF
      int v43; // [esp+88h] [ebp-38h]
      int v44; // [esp+8Ch] [ebp-34h]
      int v45; // [esp+90h] [ebp-30h] BYREF
      int *v46; // [esp+94h] [ebp-2Ch]
      int *v47; // [esp+98h] [ebp-28h]
      int *v48; // [esp+9Ch] [ebp-24h]
      int v49; // [esp+A0h] [ebp-20h] BYREF
      int v50; // [esp+A4h] [ebp-1Ch] BYREF
      int v51; // [esp+A8h] [ebp-18h]
      _DWORD *v52; // [esp+B4h] [ebp-Ch]
      int *v53; // [esp+B8h] [ebp-8h]
      int v54; // [esp+BCh] [ebp-4h]
      _DWORD *v55; // [esp+C8h] [ebp+8h]
    
      v52 = v22;
      v53 = dword_4011D8;
      v54 = a1 & 1;
      v55 = (_DWORD *)(a1 & 0xFFFFFFFE);
      (*(void (__stdcall **)(_DWORD *, _DWORD, _DWORD, _DWORD, int, _DWORD, _DWORD, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int *, int, int, int, int *, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int *, int *, int *))(*v55 + 4))(
        v55,
        v22[0],
        v22[1],
        v22[2],
        v23,
        LODWORD(v24),
        HIDWORD(v24),
        v25,
        v26,
        v27,
        v28,
        v29[0],
        v29[1],
        v29[2],
        v29[3],
        v29[4],
        v29[5],
        v29[6],
        v29[7],
        v29[8],
        v30[0],
        v30[1],
        v31,
        v32,
        v33[0],
        v33[1],
        v34,
        v35,
        v36[0],
        v36[1],
        v37,
        v38,
        v39[0],
        v39[1],
        v40,
        v41,
        v42[0],
        v42[1],
        v43,
        v44,
        v45,
        v46,
        v47,
        v48);
      v1 = v55[13];
      v50 = 0;
      v49 = 0;
      v45 = 0;
      v42[0] = 0;
      v39[0] = 0;
      v36[0] = 0;
      v33[0] = 0;
      v30[0] = 0;
      v29[0] = 0;
      if ( !v1 )
        _vbaNew2(dword_40186C, v55 + 13);
      v2 = v55[13];
      v3 = (*(int (__stdcall **)(int, int *))(*(_DWORD *)v2 + 68))(v2, v29);
      __asm { fnclex }
      if ( v3 < 0 )
        _vbaHresultCheckObj(v3, v2, dword_40276C, 68);
      v51 = v29[0];
      if ( v29[0] < 60000 )
      {
        if ( v29[0] != -1 )
        {
          (*(void (__stdcall **)(_DWORD *, int))(*v55 + 1784))(v55, v29[0]);
          v24 = (double)v51;
          v5 = v24;
          if ( dword_407000 )
            adj_fdiv_m64(0, 1079574528);
          else
            v5 = v24 / 100.0;
          if ( (v6 & 0xD) != 0 )
            _vbaFPException(v55);
          v10 = _vbaFpI4(v49, v50, v5);
          if ( v10 > 600 )
            _vbaStrCopy(v55 + 14, L"LI");
          if ( !v10 )
            v10 = 1;
          v11 = (*(int (__stdcall **)(_DWORD *))(*v55 + 796))(v55);
          v12 = (int *)_vbaObjSet(&v49, v11);
          v23 = *v12;
          v13 = _vbaI2I4(v10);
          v14 = (*(int (__stdcall **)(int *, int))(v23 + 188))(v12, v13);
          __asm { fnclex }
          if ( v14 < 0 )
            _vbaHresultCheckObj(v14, v12, dword_402B58, 188);
          _vbaFreeObj(&v49);
        }
        if ( !v55[13] )
          _vbaNew2(dword_40186C, v55 + 13);
        v15 = v55[13];
        v16 = (*(int (__stdcall **)(int, int *))(*(_DWORD *)v15 + 68))(v15, v29);
        __asm { fnclex }
        if ( v16 < 0 )
          _vbaHresultCheckObj(v16, v15, dword_40276C, 68);
        if ( v29[0] > 60010 )
        {
          v34 = dword_402BDC;
          v33[0] = 8;
          rtcVarBstrFromAnsi(&v45, 114);
          v30[0] = 8;
          v31 = dword_402BE4;
          v17 = _vbaVarCat(v42, &v45, v33);
          v18 = _vbaVarCat(v39, v30, v17);
          v19 = _vbaStrVarMove(v18);
          v20 = _vbaStrMove(&v50, v19);
          _vbaStrCopy(v55 + 16, v20);
          _vbaFreeStr(&v50);
          v48 = v39;
          v47 = v42;
          v46 = &v45;
          ((void (__cdecl *)(int))_vbaFreeVarList)(3);
        }
      }
      else
      {
        v4 = (*(int (__stdcall **)(_DWORD *))(*v55 + 1800))(v55);
        if ( v4 < 0 )
          _vbaHresultCheckObj(v4, v55, dword_4025C0, 1800);
        v37 = -2147352572;
        v40 = -2147352572;
        v43 = -2147352572;
        v36[0] = 10;
        v39[0] = 10;
        v42[0] = 10;
        v34 = dword_402BAC;
        v33[0] = 8;
        _vbaVarDup(&v45, v33, v49, v50);
        v48 = v36;
        v47 = v39;
        v46 = v42;
        v45 = 64;
        ((void (__stdcall *)(int *))rtcMsgBox)(&v45);
        v48 = v36;
        v47 = v39;
        v46 = v42;
        v45 = (int)&v45;
        ((void (__cdecl *)(int))_vbaFreeVarList)(4);
      }
      v54 = 0;
      v48 = (int *)&loc_4047CF;
      (*(void (__stdcall **)(_DWORD *))(*v55 + 8))(v55);
      return v54;
    }

    else 문에서 “1분 미리듣기만 가능합니다.” 창이 뜨는데,
    else 문이 아닌 항상 if문으로 가도록 패치해주면 될 것이다.

    40456B에 있는 명령어에 의해 if문으로 분기되므로,
    항상 분기되도록 jmp loc_4045FE로 명령어를 패치해주자.

    그리고 다시 스텝을 밟다보면, 0x4046B8에 있는 명령어에 의해 충돌이 발생한다.

    4046B9 함수에 있는 저 call 명령어를

    nop으로 패치시켜주면 된다.

    FLAG

    LIstenCare

    답글 남기기

    이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다