[MISC]

안녕하세요. SCANCODE_BOX 출제를 맡았던 c0nstant입니다.

해당 문제는 어떻게 접근을 하면 되는지에 대해 알려드리려고 합니다.

SCANCODE라고 혹시 들어보셨는가요?
스캔코드와 아스키코드의 차이를 보면서 설명해드릴게요.

스캔코드
키보드는 키가 눌리거나(KEYDOWN), 키가 떨어질 때(KEYUP) 키 별로 할당 된 특수한 값을 키보드 컨트롤러로 전달하는 것을 의미합니다.

아스키코드
숫자나 문자를 대응시키는 인코딩 방식 중 하나입니다.

스캔코드가 있는 이유는 다양한 언어를 단 하나의 키보드로 표현할 수 있기 때문입니다.

아스키코드로 문제를 만들지 않은 이유는 문제 명을 보면서, 구글링을 통해 조금이나마 스캔코드에 대한 지식을 얻게 하기 위함 이었습니다.

모든 글에는 제목과 주제가 따라오게 됩니다. 저는 프로그램 파일 즉, 바이너리 역시 이렇게 짜여져 있다고 생각을 하는 편입니다. 따라서 scancode_box라는 문제 명에서 scancode가 뭐지? 라는 의문점을 가지고, 구글링을 하면서 지식을 하나 습득하게 하기 위한 의도 였습니다.

해당 테이블은 MS에서 제공하는 문서파일에 수록되어 있습니다.
https://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/scancode.doc

이것으로 저희는 1단계 시나리오를 완성하였습니다.
"scancode table의 정보를 이용하라"

다음으로 왜 Table이라는 단어가 문제 명에 포함되었는지를 알아볼 시간입니다.
저희가 생각하는 테이블 혹은 표는 행과 열로 구성되어 있습니다.

저는 테이블을 어떻게 표현할지 고민하다가 문득 AES 나무위키를 보게 되었습니다.
여기에서 나오는 알고리즘은 다양합니다.
[SubBytes, InvSubBytes, ShiftRows, InvShiftRows, MixColumns, InvMixColumns, AddRoundKey]

이 중 저는 레인달 알고리즘 중 SubBytes라는 방법을 커스텀 했습니다.
https://namu.wiki/w/AES

이로써, 저희는 2단계 시나리오를 완성하였습니다.
"Table의 의미를 파악하라"

어떻게 커스텀 했는지를 설명해보고자 합니다.
problem

문제에서 첫번째로 찾아라고 제시한 것이 98이었습니다.
98의 의미는 "9행 8열" 입니다. 9행 8열을 보게 되면 A3이 나오게 됩니다.
이 A3은 상기에서 알려드린 scancode table 정보 중 하나가 됩니다.

이런 식으로 하나하나 코딩을 하거나, 여유를 갖고 테이블을 보면서 퍼즐 맞추기를 진행하면 플래그를 획득할 수 있습니다.

☆ find를 가만히 들여다 보면 중복되는 숫자들이 보입니다. 왠지 이런것은 _라는 생각이 들게 되지요.

문제 설계 정보를 업로드 하였습니다.

NON ASCII &&S- Box Custom Table의 조건 : 값이 겹치면 안 된다.

Prob : NON ACSII && S-BOX Custom

-> 아스키 코드가 들어가야 한다. 
-> 중복되면 안되며, 랜덤으로 들어가줘야 한다.

행 : 9
열 : 9

즉, 2차원 배열 9x9을 만들어야 함.

중복되지 않게 하되 조금 특이한 로직을 이용해보고 싶음.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <Windows.h>
#define MAX (100)
// essential : \xA3\xAE\x9E\xB2\x99\x9A\x9F\xB1\x98\xA0\x8C\xB0\xAD\x94\x85\xA6

// 19EA 
const unsigned int esential[] = {0xA3,0xAE,0x9E,0xB2,0x99,0x9A,0x9F,0xB1,0x98,0xA0,0x8C,0xB0,0xAD,0x94,0x85,0xA6,0x92,0x84,0x95};
unsigned int arr[100] = {0};
unsigned int tmp = 0;

int main(int argc, char *argv[])
{

	unsigned int data = 0;
	int cnt = 0;
	int index = 0;
	int i = 0;
	int j = 0;
	int row = 0;
	int col = 0;
	//srand(time(NULL));

	// 81개의 배열안에 essential은 반드시 들어가야하고 모든 배열은 중복되면 안 된다.

	// 9 x 9 generated
	printf("Let's Shuffle\n");
	COMBACK:
	while (i < MAX)
	{

		data = rand() % 100 + 100;
		
		arr[i] = data;

		while (1)
		{
			for (j = 0; j < i; j++)
			{
				while (arr[i] == arr[j])
				{
					//printf("중복\n");
					data = rand() % 100 + 100;
					//data = rand() % 10;
					arr[i] = data;
				}
			}
			for (j = 0; j < i; j++)
			{
				if (arr[i] != arr[j])
					cnt++;
			}
			if (cnt == (i))
				break;
			cnt = 0;
		}
		i++;
	}
	
	for (int i = 0; i < MAX; i++)
	{
		if (arr[i] == esential[index])
		{
			row = i / 10;
			col = i % 10;
			printf("%x는 %d,%d에 있다\n", esential[index],row,col );
			index++;
		}
	}

	if (index != 19)
	{
		goto COMBACK;
	}
	else
	{
		int color = 0;
		index = 0;
		j = 0; // 필요한 값 인덱스 체크 
		for (int i = 0; i < MAX; i++) // 100번 돈다.
		{
			if (index == 9)
			{
				printf("%5X\n", arr[i]);
				index = 0;
			}
			else
			{
				printf("%5X", arr[i]);
				index++;
			}
		}
	}
}