1. 파일 개요
- SHA‑256
B6D8B7A6…
- 64‑bit PIE(ET_DYN) ELF
-
주요 함수
hexStringToBytes
– 128‑hex 문자열을 32‑byte 배열로 변환rol
,ror
– 8‑bit rotate helpersmain
– 인풋 읽기 → 길이/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 만으로 구성된 선형·가역적 변환은 루프를 그대로 풀거나, 변환 행렬/역함수만 계산해도 손쉽게 키를 복원할 수 있다.