[Dreamhack] patch

김성진·2022년 8월 11일
0

Dreamhack_Reversing

목록 보기
11/13

📒 Description

그래픽 문제를 많이 접해보지는 못해서 좀 힘들긴 했다. 저 가리는 모션을 패치하자.


📒 C code

int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
  HCURSOR v6; // rax
  HWND v7; // rax
  HWND v8; // rbx
  HACCEL v9; // 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 = 0i64;
  v11.hInstance = hInstance;
  v11.hIcon = LoadIconW(hInstance, (LPCWSTR)0x6B);
  v6 = LoadCursorW(0i64, (LPCWSTR)0x7F00);
  *(__m128i *)&v11.hbrBackground = _mm_load_si128((const __m128i *)&xmmword_1400053F0);
  v11.hCursor = v6;
  v11.lpszClassName = ClassName;
  v11.hIconSm = LoadIconW(hInstance, (LPCWSTR)0x6C);
  RegisterClassExW(&v11);
  qword_140007880 = (__int64)&unk_1400078A0;
  v7 = CreateWindowExW(0, ClassName, WindowName, 0xC80000u, 0x80000000, 0, 600, 200, 0i64, 0i64, hInstance, 0i64);
  v8 = v7;
  if ( v7 )
  {
    hWnd = v7;
    dword_140007920 = 600;
    dword_140007924 = 200;
    GdiplusStartup(&unk_1400078A0, &dword_1400078A8, 0i64);
    ShowWindow(v8, nShowCmd);
    UpdateWindow(v8);
    v9 = LoadAcceleratorsW(hInstance, (LPCWSTR)0x6D);
    while ( GetMessageW(&Msg, 0i64, 0, 0) )
    {
      if ( !TranslateAcceleratorW(Msg.hwnd, v9, &Msg) )
      {
        TranslateMessage(&Msg);
        DispatchMessageW(&Msg);
      }
    }
    LODWORD(v7) = Msg.wParam;
  }
  return (int)v7;
}

뭐가 많이 복잡하긴 하다.
RegisterClassExW(&v11); 이 부분을 보자. 콜백함수이ㅏㄷ.
v11을 분석해보자 ...?
v11.lpfnWndProc = (WNDPROC)sub_1400032F0; 주소는 32F0을 보면 되겠다.

📖 sub_1300032F0

LRESULT __fastcall sub_1400032F0(HWND a1, UINT a2, WPARAM a3, LPARAM a4)
{
  LRESULT result; // rax
  _QWORD *v5; // rbx
  __int64 v6; // rbx
  __int64 v7; // [rsp+20h] [rbp-18h] BYREF

  switch ( a2 )
  {
    case 2u:
      PostQuitMessage(0);
      result = 0i64;
      break;
    case 0xFu:
      qword_140007910 = (__int64)BeginPaint(hWnd, &Paint);
      v5 = (_QWORD *)GdipAlloc(16i64);
      if ( v5 )
      {
        *v5 = 0i64;
        v5[1] = 0i64;
        v7 = 0i64;
        *((_DWORD *)v5 + 2) = GdipCreateFromHDC(qword_140007910, &v7);
        *v5 = v7;
      }
      else
      {
        v5 = 0i64;
      }
      qword_140007918 = (__int64)v5;
      sub_140002C40();
      v6 = qword_140007918;
      if ( qword_140007918 )
      {
        GdipDeleteGraphics(*(_QWORD *)qword_140007918);
        GdipFree(v6);
      }
      EndPaint(hWnd, &Paint);
      result = 0i64;
      break;
    case 0x202u:
      InvalidateRect(hWnd, 0i64, 1);
      UpdateWindow(hWnd);
      result = 0i64;
      break;
    default:
      result = DefWindowProcW(a1, a2, a3, a4);
      break;
  }
  return result;
}

beginPaint와 endPaint 부분 사이에 플래그를 출력할 것 같다.

📖 sub_140002C40

begin과 end사이에서 호출하는 함수가 있어서, 한 번 확인해보고자 했다.

char __fastcall sub_140002C40(__int64 a1, int a2)
{
  int v2; // ebx
  int v3; // edx
  int v4; // edx
  int v5; // edx
  int v6; // edx
  int v7; // edx
  int v8; // edx
  int v9; // edx
  int v10; // edx
  int v11; // edx
  int v12; // edx
  int v13; // edx
  int v14; // edx
  int v15; // edx
  int v16; // edx
  int v17; // edx
  int v18; // edx
  int v19; // edx
  int v20; // edx
  int v21; // edx
  int v22; // edx
  int v23; // edx
  int v24; // edx
  int v25; // edx
  int v26; // edx
  __int64 v27; // rbx
  __int64 v28; // r8
  __int64 v29; // r8
  __int64 v30; // rdx
  __int64 v31; // r8
  __int64 v32; // rdx
  __int64 v33; // r8
  __int64 v34; // rdx
  __int64 v35; // r8
  __int64 v36; // rdx
  __int64 v37; // r8
  __int64 v38; // rdx
  __int64 v39; // r8
  __int64 v40; // rdx
  __int64 v41; // r8
  __int64 v42; // r8
  __int64 v43; // rdx
  __int64 v44; // r8
  __int64 v45; // r8
  __int64 v46; // rdx
  __int64 v47; // r8

  v2 = qword_140007880;
  sub_140002B80(qword_140007880, a2, 30, 470, 80, -16777216);
  sub_140002B80(v2, v3, 35, 470, 75, -16777216);
  sub_140002B80(v2, v4, 40, 470, 70, -16777216);
  sub_140002B80(v2, v5, 45, 470, 65, -16777216);
  sub_140002B80(v2, v6, 50, 470, 60, -16777216);
  sub_140002B80(v2, v7, 55, 470, 55, -16777216);
  sub_140002B80(v2, v8, 60, 470, 50, -16777216);
  sub_140002B80(v2, v9, 65, 470, 45, -16777216);
  sub_140002B80(v2, v10, 70, 470, 40, -16777216);
  sub_140002B80(v2, v11, 75, 470, 75, -16777216);
  sub_140002B80(v2, v12, 80, 400, 60, -16777216);
  sub_140002B80(v2, v13, 30, 470, 90, -16777216);
  sub_140002B80(v2, v14, 35, 470, 30, -16777216);
  sub_140002B80(v2, v15, 40, 470, 35, -16777216);
  sub_140002B80(v2, v16, 45, 470, 50, -16777216);
  sub_140002B80(v2, v17, 50, 470, 40, -16777216);
  sub_140002B80(v2, v18, 55, 400, 90, -16777216);
  sub_140002B80(v2, v19, 60, 470, 60, -16777216);
  sub_140002B80(v2, v20, 65, 470, 30, -16777216);
  sub_140002B80(v2, v21, 70, 470, 80, -16777216);
  sub_140002B80(v2, v22, 75, 470, 70, -16777216);
  sub_140002B80(v2, v23, 80, 470, 60, -16777216);
  sub_140002B80(v2, v24, 80, 470, 80, -16777216);
  sub_140002B80(v2, v25, 80, 470, 70, -16777216);
  sub_140002B80(v2, v26, 90, 470, 90, -16777216);
  v27 = qword_140007880;
  sub_1400017A0(qword_140007880, 40i64, v28, 4278190080i64);
  sub_140001C80(v27, 80i64, v29, 4278190080i64);
  sub_140002640(v27, v30, v31, 4278190080i64);
  sub_1400020F0(v27, v32, v33, 4278190080i64);
  sub_140002390(v27, v34, v35, 4278190080i64);
  sub_140001240(v27, v36, v37, 4278190080i64);
  sub_140001F20(v27, v38, v39, 4278190080i64);
  sub_140001560(v27, v40, v41, 4278190080i64);
  sub_140001C80(v27, 360i64, v42, 4278190080i64);
  sub_1400019D0(v27, v43, v44, 4278190080i64);
  sub_1400017A0(v27, 440i64, v45, 4278190080i64);
  sub_140002870(v27, v46, v47, 4278190080i64);
  return 0;
}

뭘 자꾸 그린다. v27값을 설정해주는 부분을 기준으로 위 함수, 아래 함수를 분석해보고싶다.

📖 sub_140002B80

__int64 __fastcall sub_140002B80(__int64 a1, __int64 a2, unsigned int a3, int a4, int a5, unsigned int a6)
{
  int v9; // eax
  __int64 v10; // rsi
  int v11; // eax
  __int64 v12; // rbx
  int v13; // eax
  __int64 v15; // [rsp+30h] [rbp-38h] BYREF
  __int64 v16; // [rsp+38h] [rbp-30h]

  v16 = 0i64;
  v15 = 0i64;
  v9 = GdipCreatePen1(a6, a2, 0i64, &v15);
  v10 = *(_QWORD *)(a1 + 120);
  LODWORD(v16) = v9;
  v11 = GdipDrawLineI(*(_QWORD *)v10, v15, 150i64, a3, a4, a5);
  if ( v11 )
    *(_DWORD *)(v10 + 8) = v11;
  v12 = *(_QWORD *)(a1 + 120);
  v13 = GdipSetSmoothingMode(*(_QWORD *)v12, 4i64);
  if ( v13 )
    *(_DWORD *)(v12 + 8) = v13;
  return GdipDeletePen(v15);
}

펜1?을 만들고, DrawLine을 하는 점으로 보아 정말 무엇인가를 그린다고 생각할 수 있겠다.
실제로 이렇게 그림을 그려나가는 것을 디버깅을 통해 확인할 수 있다.
그렇다면 sub_140002B80을 nop 해줘야겠다.


📒 Exploit

📖 patch

함수를 nop으로 바꾸는 것 보다, 실행되자마자 ret하도록 바꾸는 것이 더 편하다.

profile
Today I Learned

0개의 댓글