블로그 이전했습니다. https://jeongzero.oopy.io/
[CodeEngine] Advance RCE L03
본문 바로가기
워게임/CodeEngn

[CodeEngine] Advance RCE L03

728x90

1. 문제


Name이 CodeEngn 일때 Serial은 무엇인가


Author: Vallani
File Password: codeengn

키젠 문제

2. 접근방법


INT_PTR __stdcall DialogFunc(HWND hWnd, UINT a2, WPARAM a3, LPARAM a4)
{
  HICON v4; // eax
  HWND v5; // eax
  LONG v6; // eax
  INT_PTR result; // eax
  int savedregs; // [esp+0h] [ebp+0h] BYREF

  switch ( a2 )
  {
    case 0x110u:
      PlaySoundA((LPCSTR)0x7D2, hmod, 0x4000Du);
      v4 = LoadIconA(hmod, (LPCSTR)0x7D0);
      SendMessageA(hWnd, 0x80u, 1u, (LPARAM)v4);
      VirtualProtect(&byte_4011E7, 0x40u, 0x40u, &flOldProtect);
      v5 = GetDlgItem(hWnd, 1004);
      SetFocus(v5);
      v6 = GetWindowLongA(hWnd, -20);
      SetWindowLongA(hWnd, -20, v6 | 0x80000);
      result = SetLayeredWindowAttributes(hWnd, 0, 0xC8u, 2u);
      break;
    case 0x10u:
      result = EndDialog(hWnd, 0);
      break;
    case 0x111u:
      result = a3;
      if ( a3 == 1002 )
      {
        if ( GetDlgItemTextA(hWnd, 1004, Name, 32) >= 3 )// 3바이트 이상의 Name 입력 해야함
        {
          Name_ = (int)Name;
          keygen(0);
          GetDlgItemTextA(hWnd, 1005, serial, 32);
          wsprintfA(name_mutate_result, "%u", name_muation);
          name_muation = 0;
          dword_40325C = (int)&savedregs;
          lstrcmpA(name_mutate_result, serial);
        }
        result = MessageBoxA(0, "No, that is not the right answer :) ", Caption, 0x10u);
      }
      else if ( a3 == 1003 )
      {
        result = MessageBoxA(0, aKeygenme4ByVal, aAbout, 0x40u);
      }
      break;
    default:
      result = 0;
      break;
  }
  return result;
}

Name값과 Serial 값 모드 .data 영역에서 관리된다. 처음에 Name에 입력값을 세팅하고 keygen() 함수를 통해서 키젠을 진행한다. 해당 함수 내부에서 키젠이 생성되면 name_mutation에 젠된 키가 담기고 unsigned int 형으로 저장한다.

그다음 입력한 serial 값과 비교한다. 헌데 잘보면 실패 분기만 있을뿐 성공 분기가 없다. 어셈을 분석해야 할듯

3. 풀이


strcmp 함수로 키젠 값과 serial을 비교한다. 그다음 cdq 명령어를 실행한다

💡
CDQ 명령어란? 찾아보니 나눗셈 관련하여 피제수, 제수 등 이해가 잘 안가는 설명이 많다.. 결론적으로 해당 어셈은 32bit 레지스터인 eax를 64bit로 확장시키는 명령어고 확장은 edx:eax 형태로 만든다. 예를 들어 eax가 1인 상태에서 cdq가 수행되면 0x0000(edx)_0001(eax) 저런 식으로 됨

결국 키젠 알고리즘을 몰라도 저때 비교되는 값을 확인하여 입력하면 된다. 만약 두개의 비교값이 일치하면 eax에 0이 담길테고 cdq가 수행되면 edx, eax 둘다 0이 된다.

이때 idvi eax를 하게 되면 0 / 0 이 되어 예외가 발생한다.

아마 이걸 의도한듯,, 초기에 보면 seh 핸들러에 성공시에 호출되는 함수를 핸들러로 등록해놓는다

원래 seh 체인의 list head는 0x19fb90이였지만 핸들러함수를 하나 추가하여 head가 0x19fae0이 되었다

TIB 구조체의 첫 멤버는 SEH frame이다. 이는 fs레지스터로 접근할 수 있다.(fs:[0])

https://dazemonkey.tistory.com/33

따라서 해당 바이너리의 0x40102F 에서 seh 체인에 성공시 분기되는 함수를 핸들러로 등록하고, 후에 strcmp의 결과가 0이 나와 0/0 형태가 되면 아까 등록한 핸들러가 호출된다

x32dbg의 seh 창에서도 추가된 핸들러함수를 확인할 수 있다

4. 몰랐던 개념


키젠 로직을 분석할라고 했으나 복잡해서 패스.

int __stdcall keygen(char a1)
{
  char *v1; // ebx
  char *v2; // eax
  unsigned int i; // ecx
  char *v4; // ebx
  unsigned int j; // ecx
  char *v6; // ebx
  unsigned int k; // ecx
  int result; // eax

  name_muation -= 0x7F9;
  if ( _bittest(&name_muation, 1u) )
    v1 = &rand[0x40];
  else
    v1 = rand;

  v2 = (char *)&loc_4011D5 + 18;

  for ( i = 0; i < 0x1C; ++i )
    *v2++ = v1[i] ^ 0x38;

  if ( _bittest(&name_muation, 2u) )
    v4 = &rand[0x5C];
  else
    v4 = &rand[28];

  for ( j = 0; j < 0x13; ++j )
    *v2++ = v4[j] ^ 0xD4;

  if ( _bittest(&name_muation, 3u) )
    v6 = &rand[0x6F];
  else
    v6 = &rand[0x2F];

  for ( k = 0; k < 0x11; ++k )
    *v2++ = v6[k] ^ 0xAF;

  if ( a1 )
  {
    result = dword_403234;                      // 0
    *(_DWORD *)(dword_40325C + 4) = dword_403234;
  }
  else
  {
    name_muation ^= sub_401241(
                      (13 * (*(unsigned __int8 *)(Name_ + 1) + 32 * *(unsigned __int8 *)Name_ + 9000)) ^ 0x15587,
                      *(unsigned __int8 *)(Name_ + 1) ^ 0xBC614E);
    result = ++Name_ + 1;
    if ( *(_BYTE *)(Name_ + 1) )
      result = keygen(0);
  }
  return result;
}

특정 조건에 따라서 고정으로 박혀있는 rand값으로 몇개 가져온다. 그다음 가져온걸로 xor을 조지고 밑에서 또 어떤 연산을 조진다.

728x90

'워게임 > CodeEngn' 카테고리의 다른 글

[CodeEngn] Advance RCE L05  (0) 2021.01.29
[CodeEngine] Advance RCE L04  (0) 2021.01.28
[CodeEngine] Advance RCE L02  (0) 2021.01.26
[CodeEngine] Advance RCE L01  (0) 2021.01.25
[CodeEngine] Malware Analysis L08  (0) 2021.01.23