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