codegate2016 vntpaz

By OC | April 6, 2016

Codegate 2016 vntpaz 출제자 Write Up


인턴왕이 드디어(?) 다른 분들에게도 블로그 글을 독촉(!!) 할 수 있게 되었습니다ㅋㅋ(신남)

그 기념(?) 으로 524님이 본선에 출제한 RF 문제 롸잇업을 받아다 낭낭히 올려봅니당!





codegate 2016 예선에 참가해보신 분은 아시겠지만

eocnd(대충) 문제를 낸 놈이 만든 문제라는게 문제이름에서 진하게 풍겨오네여.

이번 본선 문제 vntpaz는 ‘푸셈ㅋ’ 되겠습니다.

문제를 낸 미친X이 컴퓨터 하는 사람들한테 RF를 물어보네여.

회사에서 해킹대회 문제는 내라고 하는데 제가 컴알못이라 RF로 문제를 냈습니다.

예선때 멘탈 많이 깨졌다는 소리를 풍문으로 들었는데 본선에선 다들 잘 푸셨더라구여.

솔직히 아무도 못풀었으면 했는데 본선에선 많이 풀어서 오히려 제 멘탈이 나갔어여.

그럼 풀이 들어가겠습니다.

일단 RF 신호를 보는 법부터 알아볼까여.

Linux에서 baudline 이라는 프로그램을 설치해볼게요.

이 프로그램은 이런데 쓰라고 만든 프로그램은 아닐텐데… 일단 그냥 써봅시다.

실행 후 파일을 읽어볼게요.



데이터는 수신되는 족족 raw 형식으로 저장이 됩니다. 따라서 file format을 raw를 설정해줍니다.



Open을 클릭하면 파라미터를 설정하는 창이 나와요. 여기서 중요한건 Sample Rate와 Channel과 Decode Fomat입니다.

Sample Rate는 신호를 어느 속도로 수신했는지를 나타내는 지표입니다.

보통 Hz 단위로 표시되며 1초에 몇 개의 신호를 수신했는지를 나타냅니다.

일반적으로 걍 2MHz 때려서 봐요. 왜 그런지는 묻지 마세요.

그냥 사이트 여기저기 돌아다니다 보니까 컴터 하는 사람들이 이걸로 해서 쓰길래 이속도로 문제 만들었어요.

channel 은 신호가 I만 들어오는가 아니면 I/Q로 들어오는가를 설정해주는 거예요.

무선신호는 보통 일반 수학에서 말하는 실수신호와 허수신호가 동시에 전송되고 수신되요.

이를 I/Q 즉, Inphase, Quadrature 신호라고 불리는데 둘을 동시에 보기 위해선 채널을 2로 설정하고 quadrature와 flip complex를 체크해줘야 합니다.

이거 설명할라면 2박3일 걸리니까 그냥 그렇게 아시면 되여.

문제 어떻게 푸는지 볼라고 하는거지 무선통신 강의 들으러 이거 보시는거 아니잖아여.

귀찮아서 이러는게 아닙니다. 진심.

decode format은 원래는 32bit complex인데 2채널로 보기 때문에 32bit float으로 설정합니다.

뭐 이래저래 옵션 바꿔서 보셔도 저거 아니면 이상하게 보일꺼에요

파워하게 실행해봅시다.



요따구 그림이 나와요. 히잌 뭐즤! 할거 없이 그냥 신호 던지고 수신기로 관측하면 저런게 떠요.

waterfall graph라고 하는데 세로축이 시간, 가로축이 주파수, 선의 밝기가 신호의 세기 되겠습니다.

이때! 직관적으로 눈치 까야해요.

가로축이 주파수였는데 일정하게 두 줄 왔다갔다 하네?! FSK(Frequency Shift Keying) 이네ㅋ

마우스를 올려봤더니 오른쪽 아래에 나오는 주파수가 ±35kHz네. FSK Frequency Deviation은 35KHz네ㅋ

이거 두 개만 알면 신호 디코딩 다 했어여ㅋ

좀 더 자세하게 있어보이게 설명하자면 현재 신호는 두 주파수를 이용해 데이터를 보내고 있고

같은 시간에 두 주파수를 동시에 사용하지 않고 있으므로

높은 주파수 대역과 낮은 주파수 대역을 번갈아가며 사용하는 FSK를 사용하고 있을 가능성이 높아 보입니다.

하지만 만약 Quadrature 신호가 상반되어 다른 신호로 수신될 경우 QAM, 혹은 어쩌구저쩌구.,,,,

부질없어요. 그냥 딱 보면 ‘아! FSK네!’ 이래야됩니다.

만약 저기에 보이는 신호가 한 줄만 나오는데 모스부호처럼 길이 차이로 전송이 된다? OOK,

혹은 신호가 한 줄인데 같은 간격으로 밝기차이만 있다? ASK.

여러개 보고 보는 눈을 기르는 수밖에 없어요. 성의 없어 보이지만 이거 말고 설명드릴 방법이 없네요ㅠ

자 이제 modulation 방법도 알았고 하니 신호를 demod 해봅시다.





GNU Radio라는 프로그램이에요.

어떤 똑똑한 놈이 만들었는진 모르겠지만 이것저것 잘 만들어놨네요.



파일 집어넣고 sample rate 설정하고 fsk demodulation 한 다음에 신호를 이쁘게 슬라이싱 해주는 과정입니다.


file source


파일 불러오는 거에요. repeat을 no로 설정해줘야 나중에 나오는 파일 사이즈가 작고 귀엽게 나옵니다.

만약 yes로 해놓고 한 시간 정도 틀어놓으면 님 SSD 사ㅋ망ㅋ


Throttle


수도꼭지라고 보시면 되요. 신호를 어떤 속도로 재생시킬건가.

아까 sample rate와 같은 말이죠? 2MHz 입력해줍시다.


quadrature demod


fsk demoulator에요 저 블록 더블클릭해서 열어보면 이상한 외계어가 써있어요.


samp_rate/(2*math.pi*fsk_deviation_hz/8.0


samp_rate 알고 math.pi는 π, fsk_deviation_hz 는 아까 눈으로 확인했으니 다 입력해주면 되겠네요ㅋ


low pass filter


보통 적분기라고 불려요.

신호를 수신하면 원하는 신호 외에 AWGN(Additive White Gaussian Noize)라고 해서 일반적으로 잡음이 같이 수신되는데

그냥 짜잘한 랜덤값이 더해진다고 보시면 되요. 이게 특징이 가우시안 분포라고 해서



요따구로 생긴 특성이 있는데(수능 변환점수 때문에 많이 보셨죠?) μ가 0이라 다 더해서 평균내주면 0이 됩니다.

그런 일을 해주는 애에요. cutoff freq. 1.5kHz, Transition Width 1kHz로 해줘볼게요.

cutoff frequency는 단어가 주는 어감이 딱 자르는 느낌이죠?

저 주파수 안에 들어오는것만 살린다는 말이에요.

Transition Width는 요 안에 들어온걸 더 잘 살린다는 소리에요.

즉 1.5kHz 안에 들어오는 신호만 남겨두되 1kHz 안에 들어오는걸 중점적으로 살린다! 이런느낌입니다.

착오를 거쳐서 알아내셔도 저 값 비슷한 값이 나옵니다.


WX GUI FFT Sink


그냥 프로세스 끝났나 안끝났나 확인하려구 붙여둔거에요.

위에랑 똑같이 만든담에 실행하시면 창 하나 뜨고 막 움직이다 정지! 하는데 디코딩 다 됐다는 알람정도로 보시면 됩니다.


file sink


디코딩이 완료된 파일을 내보냅니다.

사용하실 때 주의하실점은 블록 in/out 부분에 파란색 주황색 네모가 붙어있죠? 저게 데이터 타입을 의미해요.

입출력 데이터 형태는 같아야 합니다!

파란색은 complex, 주황색은 float을 의미해요.

연결했는데 계속 오류나면 블록 더블클릭하셔서 안에 데이터 타입 complex나 float으로 변경해주시면 됩니다.





벌써 세 번째 프로그램이네요.

Octave를 실행합니다.

Matlab이라는 어마무시하게 비싼 프로그램이 있지만 우린 돈이 없잖아요?

어떤 존잘님께서 Matlab 비슷하게 기가막히게 만들어놓은 오픈소스 프로그램입니다.

C++ 이랑 언어는 비슷하되 배열 연산이 강화되어있고 데이터를 시각적으로 보기 아주 좋게 만들어진 프로그램입니다.


f = fopen(’D:\quad_data’); signal= fread(f,‘float’); fclose(f); plot(signal);


이렇게 입력하면 이쁘장하게 생긴 그래프가 나옵니다.



뭔가 신호가 네 번 들어온다는 느낌이 낭낭하게 보이지 않나요?

보기 편하게 하기 위해 신호를 네 개로 대~충 잘라볼게요


신호 1 : 11670 ~ 110200

신호 2 : 120200 ~ 220000

신호 3 : 230000 ~ 328900

신호 4 : 337700 ~ 438400


signal1 = signal(11670:110200);

signal2 = signal(120200:220000);

signal3 = signal(230000:328900);

signal4 = signal(337700:438400);


커맨드를 설명드리자면 octave에서 : (콜론)은 구간을 의미해서 첫 번째 신호 구간이 11670에서 110200이라고 했으니까

원래 읽어들인 신호 signal의 11670에서 110200 구간을 signal1로 저장하겠다~ 라는 뜻이 됩니다.

신호 1을 plot 한 다음에 확대해서 봤어요 그래프의 + 버튼 누르고 클릭클릭하면 확대됩니다.



언제 피크가 뜨는지 확인해보니까 간격이 200이 나오네요.

이건 윗부분만 본건데 아래에도 똑같이 나오겠죠?

그래서 신호 간격은 100이 됩니다.

+ 피크를 1로 – 피크를 0으로 볼게요.

그리고 피크 시작점을 찾아보면 각각의 시작점은


signal1 피크 시작점 : 1086

signal2 피크 시작점 : 1633

signal3 피크 시작점 : 909

signal4 피크 시작점 : 2286


이 됩니다. 따라서 시작점에서부터 100 간격으로 신호를 하나씩 뽑아내고 이를 0과 1로 맵핑하면 0과 1로 된 비트를 확인할 수 있겠죠? 아래 커맨드를 입력합니다!


decision1 = signal1(1086:100:end);

decision2 = signal2(1633:100:end);

decision3 = signal3(909:100:end);

decision4 = signal4(2286:100:end);

bits1 = decision1 > 0;

bits2 = decision2 > 0;

bits3 = decision3 > 0;

bits4 = decision4 > 0;


decision1 = signal1(1086:100:end);

bits1 = decision1 > 0;


를 설명드릴게요.

아까 잘라낸 signal1을 시작점인 1086에서 100 단위로 끝까지 뽑아내서 decision1에 저장한다는 명령이에요.

그리고 0보다 크면 1로, 0보다 작으면 0으로 맵핑한다고 했으니까

추출된 decision1을 0보다 큰지 작은 논리값으로 확인하게 되면 0과 1로 맵핑되겠죠?

좌측 워크스페이스를 확인하면 아래와 같은 창이 뜹니다!



추출된 각각의 bit는 975, 982, 980, 985로 길이가 제각각이네요.

아까 신호를 대충 잘라서 signal 1, 2, 3, 4의 길이가 다르다보니 100단위로 뽑아낸다고 해도 길이가 다를 수밖에 없어요.

하지만 시작점은 정확하게 맞췄으니까 앞에서부터 신호에 해당되는 부분까진 제대로 뽑혔다고 생각할 수 있겠죠?

뭔진 모르겠으니 일단 겹쳐서 그려볼게요


plot(bits1)

hold on;

plot(bits2,‘-r’)

plot(bits3,‘-g’)

plot(bits3,‘-k’)



plot은 아까 보셨죠? 그래프 띄우는거.

이 상태에서 hold on을 입력하면 이제부터 그리는건 다 겹쳐그릴거야! 라는 뜻이 됩니다.

그리고선 bit 2, 3, 4를 그리는데 이러면 신호가 다 똑같은 색일테니까 색 변화를 줘볼게요.

plot(bits2,‘-r’)에서 ‘-r’ 옵션은 ‘–’ 연결해서 그리되 ‘r’ 빨간색으로 그려라! 라는 의미에요.

그럼 차례대로 g는 녹색, k는 검정이 되겠죠? 기본 옵션은 ‘-b’ 로 되어있어서 파란색으로 연결해서 그려집니다.

겹쳐서 그린 그래프를 보면 녹색으로 덮인 구간이 있고 여러 색이 섞여있는 구간이 있네요.

저기에 뭘 숨겨놓은듯한 느낌이 팍팍 오지 않나요? 느낌이 안와도 어쩔 수 없어요.

제가 저기에 숨겨 넣었으니까요 ^0^

그럼 다른 구간이 어딘지 확인해봅시다.


work space를 확인해보시면 bits1, 2, 3, 4는 9xx by 1 형태의 배열로 저장되어 있습니다.

배열상에 세로로 쭉 써있다는 소리죠.

그럼 이걸 가로로 9xx by 4 형태로 저장한 다음 확인해보면 어디가 어떻게 다른지 확인이 쉽겠네요.

이어 붙여보겠습니다.

아! C와는 다르게 Octave에선 첫 번째 배열의 위치는 1입니다.

즉 100 크기의 배열이 있다면 0에서 99가 아니라 1부터 100까지 인덱싱 되는 구조에요.


bits = [bits1(1:970) bits2(1:970) bits3(1:970) bits4(1:970)];


[ ]는 배열을 선언하는 문자입니다. [ ]안에 모든 비트를 1에서 970까지만 잘라 넣어주면 970 by 4 배열이 생성됩니다.



01 혹은 10이 반복되는 형태로 나오네요.

rf 데이터 특성상 데이터 길이가 변하는걸 방지하기 위해 사용되는 코딩방법인데요.

이걸 읽으려면 10을 1 혹은 01을 1로 다시 맵핑해 주어야 최종 비트를 얻을 수 있게 됩니다.

몇 번째인지 보기 어려우니 보기 편하게 하기 위해 트랜스포즈하겠습니다.


manchester_bits10 = bits(1:2:end,:).‘;

manchester_bits01 = bits(2:2:end,:).‘;


.‘ (마침표, 홑 따옴표)는 트랜스포즈를 해주는 구문입니다.

01 또는 10을 1로 추출하기 위해선 2 단위로 추출하되 첫 번째부터 추출하면 10이 1로 두 번째부터 추출하면

01이 1로 추출되므로 뭐가 맞는지 모르니까 일단 다 추출해봅시다.

bits를 1에서부터, 혹은 2에서부터 2 단위로 추출해서 1부터 추출한건 bits10이라 명명, 2에서부터 추출하면 bits01이라 하겠습니다.

커맨드 창에 manchester_bits10을 치고 엔터! 세미콜론 빼셔야 화면에 나옵니다.


manchester_bits10



쭉 읽어가다보니 141~185까지 다르네요.

총 45 bit가 다르다는 말인데 data로 전환하기 위해 8비트 단위로 확인하려면 앞 혹은 뒤 3 bit 추가되어야 하겠죠?


data1 = manchester_bits10(:,138:185);

data2 = manchester_bits10(:,141:188);


뽑아냅니다.

(:,138:185)라는건 x by y 배열이 있을 때 x는 전체구간, y는 138에서 185구간을 추출하라는 말이에요

이걸 hex로 전환하면


data1 =

[ 0x44 0x30 0x5F 0x6E 0x4F 0x54 ;

0x5f 0x34 0x43 0x65 0x53 0x35 ;

0x5f 0x54 0x6f 0x5f 0x6d 0x59;

0x5f 0x63 0x41 0x52 0x21 0x21]


가 되구요

ASCII로 전환하면


[ D0_noT;

_4CeS5;

_To_mY

_cAR!!]


가 되니까, 최종 키 값은

D0_nOT_4CeS5_To_mY_cAR!!

가 됩니다!


Access 철자를 몰라서 acess라고 한 게 아니라 때려맞추려는 사람을 방지하기 위해서는 개뿔

네. 몰랐습니다.

4CeS5라고 쓰니까 ‘이상하긴 한데 틀리진 않은거 같아’ 라는 안일한 생각이 키 값을 저따구로 만들어놨네요.

네 이것도 변명이에요.

안그럴게요.

이상 푸셈ㅋ 풀이였습니다아.

comments powered by Disqus