Buuctf - findKey

Reverse Engineering을 통해 키를 찾는 방법

LRESULT __stdcallWndProc(HWND hWndParent, UINT Msg, WPARAM wParam, LPARAM lParam)
{
  // 각종 변수와 버퍼 선언
  HDC hdc;
  struct tagPAINTSTRUCT Paint;
  CHAR Buffer[100];
  struct tagRECT Rect;

  // 문자열 로드
  LoadStringA(hInstance, 0x6Au, Buffer, 100);

  if (Msg > 273) {
    if (Msg == 517) {
      if (strlen(String1) > 6) ExitProcess(0);
      if (strlen(String1)) {
        // 문자열 복사 및 MD5 인코딩
        memcpy(v17, String1, strlen(String1));
        md5_encode(String1, strlen(String1), (LPSTR)String1);
        
        // 고정 문자열 설정
        strcpy(Str, "0kk`d1a`55k222k2a776jbfgd`06cjjb");
        memset(&Str[33], 0, 220u);
        
        // XOR 연산
        strcpy(v11, "SS");
        *(_DWORD *)&v11[3] = 0;
        v12 = 0;
        v13 = 0;
        xor(v11, Str, strlen(Str));
        
        // 비교 및 유효성 검사
        if (_strcmpi(String1, Str)) {
          SetWindowTextA(hWndParent, "flag{}");
          MessageBoxA(hWndParent, "Are you kidding me?", "^_^", 0);
          ExitProcess(0);
        }
        
        // 추가 XOR 및 메시지 출력
        memcpy(str2, &unk_423030, 0x32u);
        str2_len = strlen(str2);
        xor(v17, str2, str2_len);
        MessageBoxA(hWndParent, str2, 0, 50u);
      }
      ++dword_428D54;
    }
    else if (Msg != 520) {
      return DefWindowProcA(hWndParent, Msg, wParam, lParam);
    }
    else {
      if (dword_428D54 == 16) {
        SetWindowTextA(hWndParent, "ctf");
        MessageBoxA(hWndParent, "Are you kidding me?", Buffer, 0);
      }
      ++dword_428D54;
    }
  }
  else {
    switch (Msg) {
      case 0x111u:
        v27 = (unsigned __int16)wParam;
        v26 = HIWORD(wParam);
        if (v27 == 104) {
          DialogBoxParamA(hInstance, (LPCSTR)0x67, hWndParent, (DLGPROC)DialogFunc, 0);
        }
        else if (v27 == 105) {
          DestroyWindow(hWndParent);
        }
        break;
      case 2u:
        PostQuitMessage(0);
        break;
      case 0xFu:
        hdc = BeginPaint(hWndParent, &Paint);
        GetClientRect(hWndParent, &Rect);
        DrawTextA(hdc, Buffer, strlen(Buffer), &Rect, 1u);
        EndPaint(hWndParent, &Paint);
        break;
      default:
        return DefWindowProcA(hWndParent, Msg, wParam, lParam);
    }
  }
  return 0;
}

키 찾기 로직 분석

  1. MD5 인코딩: String1을 MD5로 인코딩
  2. XOR 연산: 고정 문자열과 XOR 후 비교
  3. 조건 검사: _strcmpi를 통해 값을 비교
  4. 최종 출력: str2를 통해 플래그 출력

Python을 사용한 키 복구

import hashlib
from tqdm import tqdm

# 고정 문자열
a = "0kk`d1a`55k222k2a776jbfgd`06cjjb"
b = "SS"

# XOR 후 복호화
a = list(a)
for i in range(len(a)):
    a[i] = chr(ord(a[i]) ^ ord(b[i % 2]))
a = "".join(a)

# MD5 해시 비교
for i in tqdm(range(10000, 9999999)):
    encrypted = hashlib.md5(str(i).encode()).hexdigest()
    if encrypted == a:
        tqdm.write(str(i))

예제 XOR 연산

a = "123321"
b = [0x57, 0x5E, 0x52, 0x54, 0x49, 0x5F, 0x01, 0x6D, 0x69, 0x46, 0x02, 0x6E, 0x5F, 0x02, 0x6C, 0x57, 0x5B, 0x54, 0x4C]

for i in range(len(b)):
    b[i] = chr(ord(a[i % 6]) ^ b[i])
    print(b[i], end="")

이 코드들은 최종적으로 플래그 값을 출력하기 위해 사용됩니다.

태그: reverse-engineering MD5 XOR C x86

7월 15일 03:36에 게시됨