728x90

exe파일 실행시, 음악 플레이어가 나온다.

테스트 오디오를 재생할 시, 1분 제한이 걸리며 시간이 지나면, 

해당 팝업창이 띄워지며 1분 이후로는 재생이 되지 않는다.

 

우선, 팝업창이 띄워지므로 messagebox api를 호출하는 부분을 모두 trace 해본다.

sub_4038d0, sub_4044c0 에서 호출하는 것을 확인하였다.

호출하는 모든 부분에 breakpoint를 설정한다.

이후, 프로그램을 디버깅하여 어떤 위치에서 "1분 미리듣기만 가능합니다" 라는 message box를 호출하는지 알아보자.

 

sub_4044c0

위 위치에서 호출하는것을 확인하였고, 

해당 함수의 코드를 살펴보면, 

// bad sp value at call has been detected, the output may be wrong!
int __stdcall sub_4044C0(int a1)
{
  //선언부분 생략
  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;
}

  if ( v29[0] < 60000 ) , ~~. else, ~~

구조로 이루어져 있는것을 보아, 해당 조건문은

 

  if ( v29[0] < 60000 ):

         "파일을 재생한지 1분이 지나지 않은 경우"

else

          "1분이 지난 경우"

 

이와 같은 구조로 이루어져 있는것을 확인할 수 있다. 또한 특이점으론, 

 

  if ( v29[0] < 60000 ):

         "파일을 재생한지 1분이 지나지 않은 경우"

        if if ( v29[0] > 60010 ): <<???

else

          "1분이 지난 경우"

 

이와 같이 전제 조건에 맞지 않는 조건문이 안에 들어있는것을 확인하여, 해당 부분 로직을 실행하기 위해 바이너리 패치를 하였다.

패치 전
패치 후

이후, 바이너리를 다시 실행해보면, 

노래는 1분 이후로 재생되지만, 어떠한 동작을 하는 도중 runtime error가 발생한다.

해당 error를 유발하는 함수를 찾기위해, conditional breakpoint를 설정하여 디버깅하였다.

여기서 get_reg_value는 IDC의 ida api로, ida 공식 홈페이지에서 확인할 수 있다.

또한, 'v29[0]'이 60010 초과일때, 또다른 로직이 실행되므로, 해당값 이상일 경우 break하도록 설정하였다.

 

v29[0]이 60073인 시점에 break하였고, 프로시저 하나하나 실행해보면, 

150, 159번 줄의 'vbaHresultCheckObj' 함수를 호출할 시, floating point 에러가 발생하는 것을 알 수 있다.

위 조건문을 건너뛰도록 바이너리 패치를 하면, 

 

위와 같이 flag가 messagebox의 제목으로 나오는것을 볼 수 있다.

728x90

'reversing > reversing.kr' 카테고리의 다른 글

[reversing.kr] Replace  (0) 2024.02.16
[reversing.kr] Easy Keygen  (0) 2021.04.14
[reversing.kr] Easy_CrackMe  (0) 2020.11.29

+ Recent posts