Xocery

@yd1ng· May 27, 2025 · 2 min read

1. 파일 개요

  • SHA‑256 B6D8B7A6…
  • 64‑bit PIE(ET_DYN) ELF
  • 주요 함수

    • hexStringToBytes – 128‑hex 문자열을 32‑byte 배열로 변환
    • rol, ror – 8‑bit rotate helpers
    • main – 인풋 읽기 → 길이/16진수 검증 → 바이트 단위 변환 → 변환 규칙을 통해 .data:transformed 과 비교

2. 입력 처리

// 의사코드
scanf("%199s", buf);            // 최대 199바이트 입력
if (strlen(buf) != 0x40) fail;  // 64Byte(hex 128) 확인
ok = hexStringToBytes(buf, arr, 0x20);
if (!ok) fail;                  // 16진수 값 아닌 경우

hexStringToBytes 는 두 글자씩 끊어 상위 nibble << 4 | 하위 nibble 으로 arr[32] 를 채운다. 잘못된 문자가 있으면 0을 리턴해 즉시 false.


3. 한 바이트에 적용되는 변환

byte b = arr[i];
b += i;              // step 1
b = ROL(b,3);        // step 2
b ^= 0xAA;           // step 3
b = ROR(b,2);        // step 4
b ^= (i*8 - i);      // step 5  →  b ^= (i<<3) - i = i*7

이를 최종 값 t[i] 로 두고, 프로그램은 .data:transformed[i] 와 비교한다.


4. 역‑연산으로 원본 키 복원

각 단계가 가역적 이므로, transformed[i] 로부터 arr[i] 를 구할 수 있다.

def inv(i, val):
    val ^= i*7             # step 5 invert
    val = (val << 2 | val >> 6) & 0xFF   # inverse ROR 2 == ROL 2
    val ^= 0xAA            # step 3 invert
    val = (val >> 3 | val << 5) & 0xFF   # inverse ROL 3 == ROR 3
    val = (val - i) & 0xFF # step 1 invert
    return val

32개 바이트 모두 역‑연산하면 원본 바이트 배열 arr 가 얻어지고, 이를 16진수로 직렬화하면 128‑hex 문자열(플래그 안쪽) 을 얻는다.

완성 스크립트:

transformed = [
 0x73,0x17,0xd8,0xef,0xe4,0xf6,0xb3,0x7e,
 0x7a,0xd5,0x9a,0x86,0x09,0x95,0x83,0x13,
 0x76,0xff,0x45,0x18,0x5d,0xae,0x67,0x30,
 0xaa,0xce,0x90,0x45,0xa0,0xa8,0xcc,0xfe
]

flag_bytes = [inv(i,v) for i,v in enumerate(transformed)]
flag_hex   = ''.join(f'{b:02x}' for b in flag_bytes)
print("Kuality{"+flag_hex+"}")

출력:

Kuality{ec5c3c2525ba93eb6c1731a5ef2597594600b688a9b695863ccc2c0e4bc73ca7}

5. 결론

간단한 nibble‑merge, rotate, XOR 만으로 구성된 선형·가역적 변환은 루프를 그대로 풀거나, 변환 행렬/역함수만 계산해도 손쉽게 키를 복원할 수 있다.

@yd1ng
안녕하세요. 양진영입니다.
© copyright 2025. yd1ng all rights reserved.