실행파일을 다운로드하여 확인해 보자.
잘 가려놨네..
IDA를 이용해서 코드를 확인해 보자.
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
HCURSOR CursorW; // rax
HWND Window; // rax
HWND v8; // rbx
HACCEL AcceleratorsW; // rbx
WNDCLASSEXW v11; // [rsp+60h] [rbp-A8h] BYREF
struct tagMSG Msg; // [rsp+B0h] [rbp-58h] BYREF
LoadStringW(hInstance, 0x67u, &WindowName, 100);
LoadStringW(hInstance, 0x6Du, &ClassName, 100);
v11.cbSize = 80;
v11.style = 3;
v11.lpfnWndProc = (WNDPROC)sub_1400032F0;
*(_QWORD *)&v11.cbClsExtra = 0LL;
v11.hInstance = hInstance;
v11.hIcon = LoadIconW(hInstance, (LPCWSTR)0x6B);
CursorW = LoadCursorW(0LL, (LPCWSTR)0x7F00);
*(__m128i *)&v11.hbrBackground = _mm_load_si128((const __m128i *)&xmmword_1400053F0);
v11.hCursor = CursorW;
v11.lpszClassName = &ClassName;
v11.hIconSm = LoadIconW(hInstance, (LPCWSTR)0x6C);
RegisterClassExW(&v11);
qword_140007880 = (__int64)&unk_1400078A0;
Window = CreateWindowExW(0, &ClassName, &WindowName, 0xC80000u, 0x80000000, 0, 600, 200, 0LL, 0LL, hInstance, 0LL);
v8 = Window;
if ( Window )
{
hWnd = Window;
dword_140007920 = 600;
dword_140007924 = 200;
GdiplusStartup(&unk_1400078A0, &dword_1400078A8, 0LL);
ShowWindow(v8, nShowCmd);
UpdateWindow(v8);
AcceleratorsW = LoadAcceleratorsW(hInstance, (LPCWSTR)0x6D);
while ( GetMessageW(&Msg, 0LL, 0, 0) )
{
if ( !TranslateAcceleratorW(Msg.hwnd, AcceleratorsW, &Msg) )
{
TranslateMessage(&Msg);
DispatchMessageW(&Msg);
}
}
LODWORD(Window) = Msg.wParam;
}
return (int)Window;
}
WinMain을 찾아 디컴파일한 코드들이다.
자세히 보면 윈도의 그리기 방식을 정의하는 애들이 있다.
v11.cbSize = 80;
v11.style = 3;
v11.lpfnWndProc = (WNDPROC)sub_7FF7DE7D32F0;
v11.hInstance = hInstance;
v11.hIcon = LoadIconW(hInstance, (LPCWSTR)0x6B);
v11.hCursor = LoadCursorW(0LL, (LPCWSTR)0x7F00);
v11.lpszClassName = &ClassName;
v11.hIconSm = LoadIconW(hInstance, (LPCWSTR)0x6C);
RegisterClassExW(&v11);
- cbSize: 구조체의 크기.
- style: 윈도우 클래스의 스타일(여기서는 3).
- lpfnWndProc: 윈도우 프로시저 함수의 포인터. 이 함수는 메시지를 처리합니다.
- hIcon: 큰 아이콘을 로드.
- hCursor: 커서를 로드.
- lpszClassName: 클래스 이름을 설정.
- hIconSm: 작은 아이콘을 로드
이 친구들이다 보면 프로시저 함수의 포인터는 'sub_7 FF7 DE7 D32 F0'이라는 주소값을 할당되어 있으니
자세히 들여다보도록 하자.
LRESULT __fastcall sub_1400032F0(HWND a1, UINT a2, WPARAM a3, LPARAM a4)
{
_QWORD *v5; // rbx
__int64 v6; // rbx
__int64 v7; // [rsp+20h] [rbp-18h] BYREF
switch ( a2 )
{
case 2u:
PostQuitMessage(0);
return 0LL;
case 0xFu:
qword_140007910 = (__int64)BeginPaint(hWnd, &Paint);
v5 = (_QWORD *)GdipAlloc(16LL);
if ( v5 )
{
*v5 = 0LL;
v5[1] = 0LL;
v7 = 0LL;
*((_DWORD *)v5 + 2) = GdipCreateFromHDC(qword_140007910, &v7);
*v5 = v7;
}
else
{
v5 = 0LL;
}
qword_140007918 = (__int64)v5;
sub_140002C40();
v6 = qword_140007918;
if ( qword_140007918 )
{
GdipDeleteGraphics(*(_QWORD *)qword_140007918);
GdipFree(v6);
}
EndPaint(hWnd, &Paint);
return 0LL;
case 0x202u:
InvalidateRect(hWnd, 0LL, 1);
UpdateWindow(hWnd);
return 0LL;
default:
return DefWindowProcW(a1, a2, a3, a4);
}
}
BeginPaint로 그리기 작업을 시작하고 EndPaint로 그리기 작업을 종료한다.
그렇다면 그 사이에 있는 함수가 중요하다.
눈에 띄는 것은 'sub_14002C40' 함수가 정의되어있다.
확인해 보자.
2개의 묶음(?)으로 나눠져 있는 함수가 있다.
하나는 'sub_140002B80' 이 여러 번 호출이 되고 다른 하나는 서로 다른 함수들이 호출된다.
breakpoint [F2]를 잡아 디버깅 모드로 확인해 보자.
일단 같은 함수만 호출하는 'sub_140002B80' 만 호출해 보자.
'
누가 봐도 flag를 못 보게 만드는 함수인걸 알 수 있다.
그러면 서로 다른 함수들을 호출한 게 flag 안에 내용인 거 같다.
'sub_140002 B80'
.
'sub_140002B80' 에 대한 주소값을 찾아 ret로 수정한 후 저장해서 프로그램을 실행해 보면...
flag 값이 잘 나온다.
'DreamHack > Reverising' 카테고리의 다른 글
rev-basic-6 (1) | 2024.10.17 |
---|---|
rev-basic-4 (1) | 2024.10.09 |
rev-basic-2 (1) | 2024.09.26 |
rev-basic-3 (0) | 2024.09.11 |
rev-basic-1 (0) | 2024.09.11 |