리버싱 능력의 필요성을 느껴서 공부를 다시 해보려 한다..
이번 문제는 라업 참고해 가면서 분석했다.
GUI 기반의 mp3 player exe파일이 주어진다.
문제 설명은 다음과 같다.
1분 체크 루틴을 우회하면 플래그를 얻을 수 있다고 한다.
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.
1분이 되면 이렇게 메시지 박스가 뜬다.
디버거로 어디서 이 메시지 박스를 띄우는지 확인해봐야 한다.
xdbg에서 alt+k를 누르면 콜스택을 볼 수 있다.
거기서 주 스레드를 확인해보면 다음과 같다.
여기서 music_player와 관련된 주소들을 확인해보자.
중앙을 살펴보니
music_player.004045DE와 문제 파일에 있던 dll인 msvbvm60의 rtcMsgBox가 있음을 확인할 수 있다.
아이다로 004045DE을 확인해보니 정확히 찾은 것 같다.
(rtcMsgBox도 있다)
else
{
v4 = *v55;
v47 = v55;
v5 = (*(int (**)(void))(v4 + 0x708))();
if ( v5 < 0 )
_vbaHresultCheckObj(v5, v55, dword_4025C0, 0x708);
v37 = 0x80020004;
v40 = 0x80020004;
v43 = 0x80020004;
v36[0] = 0xA;
v39[0] = 0xA;
v42[0] = 0xA;
v34 = (int *)L"1분 미리듣기만 가능합니다.";
v33[0] = 8;
_vbaVarDup(&v45, v33, v47, v48);
v48 = v36;
v47 = v39;
v46 = v42;
v45 = 0x40;
((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 **)(int *))(*v55 + 8))(v55);
return v54;
}
코드에서 볼 수 있듯이 else로 가야지 이 부분이 실행된다.
if문은 다음과 같다.
if ( v29[0] < 0xEA60 )
문제 풀 땐 몰랐는데
0xEA60을 10진수로 바꿔보니 60000라서 ms단위의 1분을 의미한 것 같다.
아무튼 값을 0xEA60에서 0xFFFFF으로 바꿔줬다.
그러고나서 실행해보면 런타임 에러를 만날 수 있다.
다시 호출 스택은 보면
도움이 안 되는 정보들만 있다.
(라업 보니까 다들 잘 나오던데 ㅋㅋ..)
어쩔 수 없이 하나씩 실행해보는 수 밖에 없었다.
실행될 부분은 다음과 같다.
if ( v30[0] < 0xFFFFF )
{
if ( v30[0] != 0xFFFFFFFF )
{
(*(void (__stdcall **)(int *, int, int *))(*v56 + 0x6F8))(v56, v30[0], v49);
v25 = (double)v52;
v6 = v25;
if ( dword_407000 )
adj_fdiv_m64(0, 0x40590000);
else
v6 = v25 / 100.0;
if ( (v7 & 0xD) != 0 )
_vbaFPException(v56);
v11 = _vbaFpI4(v50, v51, v6);
if ( v11 > 0x258 )
_vbaStrCopy(v56 + 0xE, L"LI");
if ( !v11 )
v11 = 1;
v12 = (*(int (__cdecl **)(int *))(*v56 + 0x31C))(v56);
v13 = (int *)_vbaObjSet(&v50, v12);
v24 = *v13;
v14 = _vbaI2I4(v11);
v15 = (*(int (__stdcall **)(int *, int))(v24 + 0xBC))(v13, v14);
__asm { fnclex }
if ( v15 < 0 )
_vbaHresultCheckObj(v15, v13, dword_402B58, 0xBC);
_vbaFreeObj(&v50);
}
if ( !v56[0xD] )
_vbaNew2(dword_40186C, v56 + 0xD);
v16 = v56[0xD];
v17 = (*(int (__stdcall **)(int, int *, int *))(*(_DWORD *)v16 + 0x44))(v16, v30, v49);
__asm { fnclex }
if ( v17 < 0 )
_vbaHresultCheckObj(v17, v16, dword_40276C, 0x44);
if ( v30[0] > 0xEA6A )
{
v35 = dword_402BDC;
v34[0] = 8;
rtcVarBstrFromAnsi(&v46, 0x72);
v31[0] = 8;
v32 = dword_402BE4;
v18 = _vbaVarCat(v43, &v46, v34);
v19 = _vbaVarCat(v40, v31, v18);
v20 = _vbaStrVarMove(v19);
v21 = _vbaStrMove(&v51, v20);
_vbaStrCopy(v56 + 0x10, v21);
_vbaFreeStr(&v51);
v49 = v40;
v48 = v43;
v47 = &v46;
((void (__cdecl *)(int))_vbaFreeVarList)(3);
}
}
step-over로 실행하다보면
이 부분이 문제라는 것을 알 수 있다.
__vbaHresultCheckObj 함수를 실행하면서 런타임 에러가 발생한다.
if ( v15 < 0 )
_vbaHresultCheckObj(v15, v13, dword_402B58, 0xBC);
어셈으로 보면 다음과 같다.
.text:004046AB 7D 12 jge short loc_4046BF
.text:004046AD 68 BC 00 00 00 push 0BCh
.text:004046B2 68 58 2B 40 00 push offset dword_402B58
.text:004046B7 57 push edi
.text:004046B8 50 push eax
.text:004046B9 FF 15 3C 10 40 00 call ds:__vbaHresultCheckObj
__vbaHresultCheckObj를 호출하지 않도록 jge를 jmp로 바꿔준다.
.text:004046AB EB 12 jmp short loc_4046BF
이제 1분을 넘길 수 있고
창 상단에 플래그가 등장한다.
'write-up(rev) > reversing.kr' 카테고리의 다른 글
[reversing.kr] ImagePrc write-up (2) | 2024.06.06 |
---|---|
[reversing.kr] Replace write-up (0) | 2024.06.01 |
[reversing.kr] Easy ELF write-up (0) | 2023.08.30 |
[reversing.kr] Easy Unpack write-up (0) | 2023.08.30 |
[reversing.kr] Easy Keygen write-up (0) | 2023.08.18 |