[Dreamhack] legacyopt

chrmqgozj·2025년 1월 24일

DreamHack

목록 보기
15/39
  1. main
__int64 __fastcall main(int a1, char **a2, char **a3)
{
  int v3; // eax
  int i; // [rsp+4h] [rbp-8Ch]
  _BYTE *ptr; // [rsp+8h] [rbp-88h]
  char s[104]; // [rsp+10h] [rbp-80h] BYREF
  unsigned __int64 v8; // [rsp+78h] [rbp-18h]

  v8 = __readfsqword(0x28u);
  ptr = malloc(0x64uLL);
  fgets(s, 100, stdin);
  s[strcspn(s, "\n")] = 0;
  v3 = strlen(s);
  encrypt(ptr, s, v3);
  for ( i = 0; i < strlen(s); ++i )
    printf("%02hhx", (unsigned int)(char)ptr[i]);
  free(ptr);
  return 0LL;
}
  1. encrypt
unsigned __int64 __fastcall encrypt(_BYTE *a1, char *a2, int a3)
{
  int v3; // eax
  int v4; // edx
  unsigned __int64 result; // rax
  char *v6; // rax
  char v7; // cl
  _BYTE *v8; // rax
  char *v9; // rax
  char v10; // cl
  _BYTE *v11; // rax
  char *v12; // rax
  char v13; // cl
  _BYTE *v14; // rax
  char *v15; // rax
  char v16; // cl
  _BYTE *v17; // rax
  char *v18; // rax
  char v19; // cl
  _BYTE *v20; // rax
  char *v21; // rax
  char v22; // cl
  _BYTE *v23; // rax
  char *v24; // rax
  char v25; // cl
  _BYTE *v26; // rax
  char *v27; // rax
  char v28; // cl
  int v32; // [rsp+20h] [rbp-4h]

  v3 = a3 + 7;
  v4 = a3 + 14;
  if ( v3 < 0 )
    v3 = v4;
  v32 = v3 >> 3;
  result = (unsigned int)(a3 % 8);
  switch ( (int)result )
  {
    case 0:
      goto LABEL_4;
    case 1:
      goto LABEL_11;
    case 2:
      goto LABEL_10;
    case 3:
      goto LABEL_9;
    case 4:
      goto LABEL_8;
    case 5:
      goto LABEL_7;
    case 6:
      goto LABEL_6;
    case 7:
      while ( 1 )
      {
        v9 = a2++;
        v10 = *v9;
        v11 = a1++;
        *v11 = v10 ^ 0x66;
LABEL_6:
        v12 = a2++;
        v13 = *v12;
        v14 = a1++;
        *v14 = v13 ^ 0x44;
LABEL_7:
        v15 = a2++;
        v16 = *v15;
        v17 = a1++;
        *v17 = v16 ^ 0x11;
LABEL_8:
        v18 = a2++;
        v19 = *v18;
        v20 = a1++;
        *v20 = v19 ^ 0x77;
LABEL_9:
        v21 = a2++;
        v22 = *v21;
        v23 = a1++;
        *v23 = v22 ^ 0x55;
LABEL_10:
        v24 = a2++;
        v25 = *v24;
        v26 = a1++;
        *v26 = v25 ^ 0x22;
LABEL_11:
        v27 = a2++;
        v28 = *v27;
        result = (unsigned __int64)a1++;
        *(_BYTE *)result = v28 ^ 0x33;
        if ( --v32 <= 0 )
          break;
LABEL_4:
        v6 = a2++;
        v7 = *v6;
        v8 = a1++;
        *v8 = v7 ^ 0x88;
      }
      break;
    default:
      return result;
  }
  return result;
}

a1: ptr(output), a2: s(input), a3: s의 길이

a3의 길이를 8로 나눈 나머지에 따라 switch문을 통과한다.
그대로 구현하면 된다.

각 label이 복잡해보이지만 잘 보면 모두 일정한 형태를 띄고 있다.

s[i]에 어떤 값을 xor해서 ptr에 저장한다. 즉 output을 읽어서 같은 값을 한 번더 xor 해주면 플래그를 얻을 수 있다.

  1. 주의사항
printf("%02hhx", (unsigned int)(char)ptr[i]);

idx값을 다 넣어봐도 멀쩡한 플래그가 안 나와서 다시 코드를 살펴보니 각 문자가 하나의 플래그 문자를 뜻하는게 아니라 2개가 세트로 16진수를 나타내고 있다는 걸 알게 되었다.

  1. exploit.py
arr = [0x66, 0x44, 0x11, 0x77, 0x55, 0x22, 0x33, 0x88]
flag = ''

with open('D:\\code\\dh\\rev\\legacyopt\\output.txt', 'r') as f:
    data = f.read()
    size = len(data)
    idx = 7-((size//2)%8)

    for i in range(0, size, 2):
        h = int(data[i:i+2], 16)
        flag += chr((h^arr[idx]) & 0xff)
        idx = (idx+1) % 8

print(flag)

-> DH{Duffs_Device_but_use_memcpy_instead}

0개의 댓글