일반적인 리버싱 문제의 형태인 입력 값 검증 문제다.
하지만 값을 입력하면 종료된다.
원인을 찾기 위해 ida와 xdbg로 분석한다.
WinMain은 단순하다.
콜백 함수인 DialogFunc만 보면 된다.
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
DialogBoxParamA(hInstance, (LPCSTR)0x65, 0, DialogFunc, 0);
return 0;
}
check 버튼을 누르면 a3 == 0x3EB을 만족하게 된다.
0x3EA에는 입력한 값이 있으며, GetDlgItemInt 함수로 가져올 수 있다.
즉, dword_4084D0에 입력 값이 저장된다.
(0x3EA, 0x3EB는 다이얼로그 박스의 id 값으로 활용된다)
INT_PTR __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4)
{
if ( a2 != 0x111 )
return 0;
if ( (unsigned __int16)a3 == 2 )
{
EndDialog(hDlg, 2);
return 1;
}
else if ( (unsigned __int16)a3 == 0x3EB )
{
dword_4084D0 = GetDlgItemInt(hDlg, 0x3EA, 0, 0);
sub_40466F();
sub_404689(&loc_40469F);
*(_DWORD *)sub_40466F = 0xC39000C6;
sub_40466F();
sub_40466F();
*(_DWORD *)sub_40466F = 0x6E8;
return 1;
}
else
{
return 0;
}
}
이제부턴 어셈으로 보는 것이 좋다.
(디버거를 활용해도 좋음)
GetDlgItemInt 함수 호출 이후부터 살펴보면 된다.
0x40466F를 호출한 뒤 0x404690으로 점프한다.
.text:0040105A call ds:GetDlgItemInt
.text:00401060 mov dword_4084D0, eax
.text:00401065 call sub_40466F
.text:0040106A xor eax, eax
.text:0040106C jmp loc_404690
0x40466F을 보면 opcode가 다 해석되지 않고 깨져있다.
단축키 'c'를 통해 해결할 수 있다.
0x40467A를 호출한 뒤, 0x404689를 호출한다.
.text:0040466F ; int sub_40466F(void)
.text:0040466F sub_40466F proc near ; CODE XREF: DialogFunc+45↑p
.text:0040466F ; DialogFunc+3689↓p ...
.text:0040466F call loc_40467A
.text:0040466F ; ---------------------------------------------------------------------------
.text:00404674 dd 84D00581h
.text:00404678 db 40h, 0
.text:0040467A ; ---------------------------------------------------------------------------
.text:0040467A
.text:0040467A loc_40467A: ; CODE XREF: sub_40466F↑j
.text:0040467A mov dword_406014+2, 619060EBh
.text:00404684 call $+5
.text:00404684 sub_40466F endp ; sp-analysis failed
0x404674를 클릭한 뒤 'c'를 누르면 다음과 같이 바뀐다.
입력 값이 저장된 0x4084D0에 +0x601605C7을 수행한다.
.text:0040466F sub_40466F proc near ; CODE XREF: DialogFunc+45↑p
.text:0040466F ; DialogFunc+3689↓p ...
.text:0040466F call near ptr loc_404674+6
.text:00404674
.text:00404674 loc_404674: ; CODE XREF: sub_40466F↑p
.text:00404674 add dword_4084D0, 601605C7h
.text:0040467E inc eax
.text:0040467F add bl, ch
.text:00404681 pusha
.text:00404682 nop
.text:00404683 popa
.text:00404684 call $+5
.text:00404684 sub_40466F endp
0x404689에선 입력 값이 저장된 0x4084D0에 +1을 수행한다.
.text:00404689 ; int __cdecl sub_404689(_DWORD)
.text:00404689 sub_404689 proc near ; CODE XREF: DialogFunc+367A↓p
.text:00404689 inc dword_4084D0
.text:0040468F retn
.text:0040468F sub_404689 endp
이제 0x40466F를 호출한 뒤 점프하는 0x404690을 분석한다.
입력 값이 저장된 0x4084D0를 eax에 저장하고 0x404689를 호출한다.
(0x4084D0에 +1이 된다)
이후 0x40466F를 여러 번 호출하는데
mov를 사용해서 opcode를 수정하는 루틴이 있다.
(중간에 0x4084D0에 +1하는 부분도 있다)
마지막에 0x401071로 점프한다.
.text:00404690 ; START OF FUNCTION CHUNK FOR DialogFunc
.text:00404690
.text:00404690 loc_404690: ; CODE XREF: DialogFunc+4C↑j
.text:00404690 mov eax, dword_4084D0
.text:00404695 push offset loc_40469F
.text:0040469A call sub_404689
.text:0040469F
.text:0040469F loc_40469F: ; DATA XREF: DialogFunc+3675↑o
.text:0040469F mov dword ptr ds:sub_40466F, 0C39000C6h
.text:004046A9 call sub_40466F
.text:004046AE inc eax
.text:004046AF call sub_40466F
.text:004046B4 mov dword ptr ds:sub_40466F, 6E8h
.text:004046BE pop eax
.text:004046BF mov eax, 0FFFFFFFFh
.text:004046C4 jmp loc_401071
.text:004046C4 ; END OF FUNCTION CHUNK FOR DialogFunc
0x40469F에선 다음과 같이 바뀐다.
c6 00 90 mov BYTE PTR [eax],0x90
3c ret
이후 0x4046B4에서 다시 원래대로 돌린다.
E8 06 00 00 00 call near ptr loc_404674+6
마지막 점프하는 0x401071은 다음과 같다.
"Correct!"를 출력해줘야 하는데 0x401084로 점프해서 끝나버린다.
.text:00401071 loc_401071: ; CODE XREF: DialogFunc+36A4↓j
.text:00401071 jmp short loc_401084
.text:00401073 ; ---------------------------------------------------------------------------
.text:00401073 push offset String ; "Correct!"
.text:00401078 push 3E9h ; nIDDlgItem
.text:0040107D push esi ; hDlg
.text:0040107E call ds:SetDlgItemTextA
.text:00401084
.text:00401084 loc_401084: ; CODE XREF: DialogFunc:loc_401071↑j
.text:00401084 mov eax, 1
.text:00401089 nop
.text:0040108A nop
.text:0040108B nop
.text:0040108C nop
.text:0040108D nop
.text:0040108E nop
.text:0040108F nop
.text:00401090 pop esi
.text:00401091 pop ebp
.text:00401092 retn 10h
0x40469F에서 바뀌는 opcode를 이용해서
EB 11을 90 90으로 바꿔주면 되겠다.
c6 00 90 mov BYTE PTR [eax],0x90
3c .byte 0x3c
.text:00401071 EB 11 jmp short loc_401084
디버깅 해보면 dword_4084D0은 다음 식을 만족해야 한다.
dword_4084D0 + 0x601605C7 + 1*4 = 0x401071
계산 결과인 2687109798을 입력하면 Correct!가 출력된다.
'write-up(rev) > reversing.kr' 카테고리의 다른 글
[reversing.kr] Position write-up (1) | 2024.06.15 |
---|---|
[reversing.kr] ImagePrc write-up (2) | 2024.06.06 |
[reversing.kr] Music Player write-up (0) | 2024.05.31 |
[reversing.kr] Easy ELF write-up (0) | 2023.08.30 |
[reversing.kr] Easy Unpack write-up (0) | 2023.08.30 |