## 이미 작년에 끝난 대회문제 풀이를 올려놓는건데 문제되는건 없겠지요?
## 혹시나 문제되는게 있거나 문의사항이 있으면 댓글이나 메일 부탁드립니다 :p
간만에 아는 지인분들의 블로그들을 돌아다니다가
작년에 비스트랩에서 개최했던 JFF(Just For Fun!!) 대회문제를 발견했습니다..
( 2008년 JFF 문제중 하나. : http://maj3sty.tistory.com/607 )
작년에 동생분(A군)과 함께 이것저것 끄적대면서 풀었던 기억이 새록새록 나더군요.
하아.. 목욕재계하고 펌프나 뛰러 가려고 했는데..
후딱 풀어놓고 가야겠네요.
##
음,, 파일 자체는 평범한 avi 포맷 형식의 (배트맨 다크나이트) 2분 7초짜리 동영상 파일인데요.

헥사에디터로 열어보면
RIFF 헤더로 시작해서 여러개의 LIST로 나열되어있는걸 알수 있습니다.

(AVI 파일포맷 참조 : http://home.postech.ac.kr/~lionbaeg/cs499/research.htm)
MAJ3STY 님 말대로 출제자의 의도만 파악한다면 그리 어렵지는 않은 문제입니다.
(실제 다른 대회문제라던가 워게임들도 그렇죠.)
파일명은 mirror.avi
그리고 특이점은 파일의 맨 아래부분에 보면 다음과 같이 문자열이 뒤집혀져 있는듯한 내용이
보입니다. (ex: LIST -> TSIL)

그래서 파일 이름의 mirror처럼 파일 내용 전체를 뒤집는 간단한 코드를 작성했습니다.
//rev1.c/////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
//coded by BlueH4G
FILE *Fp1 = fopen("mirror.avi", "rb");
FILE *Fp2 = fopen("rv.avi", "wb");
char buf;
int size,i;
char *ad,*rv;
fpos_t pos;
fseek(Fp1, 01, SEEK_END);
size = (ftell(Fp1)); //mirror.avi파일의 크기를 구함
rewind(Fp1);
ad=(char *)malloc(sizeof(char)*size); //원본파일의 내용을 저장할 메모리 할당
rv=(char *)malloc(sizeof(char)*size); //원본파일의 내용을 뒤집어 저장할 메모리 할당
fread(ad,1,size,Fp1); //파일 내용을 읽어서 ad 메모리에 저장
for(i=0;i<=size;i++){
memset(rv+i-1,*(ad+size-i),1);
}
//ad메모리 내용을 뒤집어서 rv메모리에 저장
fwrite(rv,1,size,Fp2); //rv메모리 내용(뒤집어진 내용)을 rv.avi에다가 씀
free(ad);
free(rv); // 메모리 해제
}
//////////////////////////////////////////////////////////////////////////////////////
해당 소스를 컴파일하고 실행 후 생성된 rv.avi의 헥사코드를 보니

다음과 같군요.. 그런데 실행(재생)하지는 못합니다.
cuz, 앞의 RIFF 헤더부분이 사라졌기 때문이죠.
헤더의 형식에 맞춰주기 위해 뒤집은 소스의 맨 앞부분을 보면 LIST 가 있는게 보이는군요.
그 LIST 블록의 ListType이 'strl'인걸 보니, 이부분이 헤더 리스트이고
헤더의 DATA 부분이 오디오/비디오 스트림 헤더이고
이걸 mirror.avi 의 헤더에 핀트만 맞춰주면 될거 같네요.
mirror.avi의 헥사코드중 헤더 리스트의 위치가 '\x57' 부터 시작이니까, 위의 소스를
조금만 수정해서 헤더리스트부터 뒤집어 넣으면 되겠군요.
// rev2.c/////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
//coded by BlueH4G
FILE *Fp1 = fopen("mirror.avi", "rb");
FILE *Fp2 = fopen("rv.avi", "wb");
char buf;
int size,i;
char *ad,*rv;
fpos_t pos;
fseek(Fp1, 01, SEEK_END);
size = (ftell(Fp1)); //mirror.avi파일의 크기를 구함
rewind(Fp1);
ad=(char *)malloc(sizeof(char)*size); //원본파일의 내용을 저장할 메모리 할당
rv=(char *)malloc(sizeof(char)*size); //원본파일의 내용을 뒤집어 저장할 메모리 할당
fread(ad,1,size,Fp1); //파일 내용을 읽어서 ad 메모리에 저장
for(i=0;i<='\x57';i++){
memset(rv+i,*(ad+i),1);
}
//헤더리스트 이전부분은 그대로 유지
for(i='\x57';i<=size;i++){
memset(rv+i-1,*(ad+size-i+'\x57'),1);
}
//헤더리스트 이후에 ad메모리 내용을 뒤집어서 rv메모리에 저장
fwrite(rv,1,size,Fp2); //rv메모리 내용(뒤집어진 내용)을 rv.avi에다가 씀
free(ad);
free(rv); // 메모리 해제
}
//////////////////////////////////////////////////////////////////////////////////////
그리고 컴파일 후 실행.
그리고 다시 헥사로 열어보면 헤더리스트가 정위치에 바르게 들어가있는걸 확인할 수 있습니다.
그리고 rv.avi파일을 재생시켜보면 처음에 재생되던 배트맨 영상과는 다르게

윤하누님께서 노래하는 영상이 재생되고 마지막에 패스워드가 출력됩니다.

전 당시에 avi 포맷 헤더범위랑 파일오픈할때 모드를 텍스트 모드로 해서 삽질을 좀 많이 했던.... C 책에는 텍스트모드만 여는 예제가 있어서 ㅋㅋㅋㅋㅋㅋㅋ heap을 이용하셨네염 ㅎㄷㄷ 전 그냥 배열배울때 배열 뒤집기 하던 방식으로 했눈뎁 ㅋㅋ
답글삭제http://www.fastgraph.com/help/avi_header_format.html
답글삭제전 참고로 위 URL 보고 했답니당 ^^ ㅋ
(저보다 풀이를 먼저 올리시다닝!! 나도 올릴려 했는데 ㅋㅋ)
@MaJ3stY - 2009/08/27 15:09
답글삭제헐.. ㅋㅋ
난 C언어는 책을 한권도 산게 없어서;;
인터넷에 워낙 자료가 많아서 책사는게 아까웠다는..
(책 한권이면 술을 두번을 마신다구!!)
@MaJ3stY - 2009/08/27 15:13
답글삭제ㅋㅋ 이거야 말로 선공!! ㅎㅎ
나도 하드디스크 정리하다가 이것저것 찾은거 있는데
그거 같이 풀자구!!ㅋ 뭐, 그게 윈윈 아니겠어? ㅎ
어떤 문제인데요??? ㅎㅎㅎ
답글삭제@MaJ3stY - 2009/08/28 16:15
답글삭제그냥 이것저것 잡다한거 모아놓은거지 뭐.. ㅋㅋ
비밀 댓글 입니다.
답글삭제@Anonymous - 2009/11/02 18:47
답글삭제뭔가 비밀댓글이라 대답도 비밀로 해야할것같은 필이.. ㅎ
메일주소라도 주셨으면 답메일로 드렸을텐데~ 일단은 댓글로 달아드릴게요 ㅋ
/********************************************************/
[ avi 헤더 ] - 파일 시작
[배트맨 영상]
[정답 영상] - 파일 끝
하하님이 문제를 출제하실때 대략 이렇게 끊어서 만드셨는데 중요한건 avi 헤더라고 해서 헤더가 하나로 이루어져 있는게 아니구요,
헤더 안에서도 여러가지 부분으로 나뉩니다.
제가 본문에 링크해둔 주소를 따라가 보시면 기본적인 avi 파일의 포맷이 나오는데 그중 RIFF 헤더와 여러개의 chunk와 list로 구성되어 있다고 되어있네요.
Maj3sty님이 링크해주신 주소는 그 헤더의 부분 중에서도 audio/video data list 의 부분만 나와있는 부분입니다.
간단히 얘기하면 위에서 두번째 이미지를 보시면 문제파일의 맨 마지막 부분(정답 영상으로 삽입할 첫부분)의 뒤집어져 있는 문자열을 볼수 있는데요.
해당 부분을 보면 .LISTt...strlstrh8... 이라고 되어있는데요.
그 부분이 뒤집어졌을때 첫 화면에 있는 부분에서 \x57부분이랑
핀트가 맞죠? 그래서 \x57부터 시작한거랍니다~
그 외에 헤더부분은 건드리지 않기위해 그대로 둔거구요.
사실 저 핀트 맞추기만 본다면 avi 헤더파일 관련 레퍼런스 없이도
쉽게 풀수 있죠.. ㅋ 그 외에 -1 등은 그냥 더하기빼기 수학이라
뭐라 설명할만한게 없네요aa
해당 위치를 정확히 맞추기 위해 앞뒤 핀트맞추는 과정이라서요 ㅎ
더더더더더더 풀이를 원하거나 심심하면 연락주세요ㅕ :p
비밀 댓글 입니다.
답글삭제@Anonymous - 2009/11/04 01:07
답글삭제별말씀을 ㅎ
혹시 이번 POC 오시나요~?
비밀 댓글 입니다.
답글삭제@Anonymous - 2009/11/04 21:39
답글삭제헤에,, ㅠ ㅋㅋㅋ
님 소속에 XX형님 한분만 오신거 같던데 aa
다음번엔 같이 놀아요 ㅋㅋ
(비밀댓글의 비밀댓글이 안되서 실명 지움;; ㅋㅋ)
@nesk - 2009/11/26 12:18
답글삭제으하하;; 지금 답변달아도 거의 일주일이 지난듯... ㅠ_ㅠ
홈피나 메일이라도 있으면 바로 답변 드릴텐데aa
일단 그냥 댓글 달게요 허허;;;
fseek 에서 01번째부터 끝까지를 찾는 이유는..
제가 코딩하면서 이것저것 테스트해보느라 삽질한다고 0에서 01로 바꿔놓은걸 그대로 둬서 그렇답니다 :)
허무하죠... 0으로 해도 실행되구요.. 대신 밑에 소스도 '약간'은 바뀌지만요~~
fseek을 0으로 했을때의 소스는
@nesk - 2009/11/26 12:18
답글삭제#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
//coded by BlueH4G
FILE *Fp1 = fopen("mirror.avi", "rb");
FILE *Fp2 = fopen("rv02.avi", "wb");
char buf;
int size,i;
char *ad,*rv;
fpos_t pos;
fseek(Fp1, 0, SEEK_END);
size = (ftell(Fp1)); //mirror.avi파일의 크기를 구함
rewind(Fp1);
ad=(char *)malloc(sizeof(char)*size); //원본파일의 내용을 저장할 메모리 할당
rv=(char *)malloc(sizeof(char)*size); //원본파일의 내용을 뒤집어 저장할 메모리 할당
fread(ad,1,size,Fp1); //파일 내용을 읽어서 ad 메모리에 저장
for(i=0;i<='\x57';i++){
memset(rv+i,*(ad+i),1);
}
//헤더리스트 이전부분은 그대로 유지
for(i='\x57';i<=size;i++){
memset(rv+i,*(ad+size-i+'\x57'),1);
}
//헤더리스트 이후에 ad메모리 내용을 뒤집어서 rv메모리에 저장
fwrite(rv,1,size,Fp2); //rv메모리 내용(뒤집어진 내용)을 rv.avi에다가 씀
free(ad);
free(rv); // 메모리 해제
}
@nesk - 2009/11/26 12:18
답글삭제memset의 두번째 인자는 int c 이죠...
void *memset(void *s, int c, size_t n);
첫번째 파라미터(*s) 부터
두번째 파라미터(c) 의 값을
세번째 파라미터(n) 만큼 써라.
라는건 아시죠 :)
제가 두번째인자에 포인터로 쓴건 다른게 아니구 어느값을 쓸거냐에서 앞서 있는 mirror.avi 의 값을 읽어와서 써야하니까, mirror.avi의 값을 읽어오는 포인터로 쓰는게 맞지요:p
아하하 그렇군요 시간이야 수능끝나고 남아돌아서 괜찮 -_-
답글삭제어쨋건 답변 감사합니다 열심히 공부해야 할듯 ㅜ
안녕하세요 bluh4g님 maj3sty님 블로그에서 보고 문제 다운받아서 풀어보려고 하다가 찾앗는데
답글삭제풀이에서 궁금한게 몇가지가 -_- 초보라서 ;;;
우선요 fseek에서 01번째부터 끝까지를 찾는이유가 뭔가요 ??? 0부터 찾기를 해보니깐 실행이 안되긴 안되는데 왜 저렇게 해야하는거죠 ?_?
2번째 memset사용에서 2번째 인자는 왜 포인터로 넘겨줘야 하는거죠 memset의 레퍼런스를 새로 찾아보니깐 void *memset(void *s, int c, size_t n);
이렇게 되어있던데 왜그렇게 해야 하는지 설명좀해주세요 ㅜㅜ
죄송해요 프로그래밍 초보라서 이상한질문이 많음
비밀 댓글 입니다.
답글삭제@nesk - 2009/11/26 12:17
답글삭제홧팅입니다 :)
저도 공부해야하는데... (맨날 해야하는데.. 에서 게임한다고 빠지지만.. ㅠ) 아무튼 자주 뵈요 ㅎㅎ
@Anonymous - 2009/11/26 12:30
답글삭제네에 ㅠ
일단 학교레포트부터 해결하고 ㅠ
빠른시일내에 해볼것을 약속드려요 :)
와우 매너 좋으시군요 감사합니다 ^^
답글삭제@nesk - 2009/11/26 20:46
답글삭제으하하하하;;;; 저 매너 별로 안좋아요 ㅜ_ㅜ ㅋㅋ
암튼 감사합니다 ㅎㅎ
@MaJ3stY - 2009/08/27 15:09
답글삭제아, 그리고 이제 하나 더 추가하는데 ㅋㅋ
그렇게 하는게 더 간단하고 소스도 짧고 편하긴 하지만
나중에 파일안의 데이터 하나하나를 검사 및 비교, 수정 등의 작업을
중복으로 두세번씩 하고 복잡해지면 메모리 할당하고 처리하는게
더 편해지니까 ㅎ, 사실 단순 뒤집기에서는 나처럼 하는게
어떻게보면 비효율적일지도... ㅠ
잘보고 가요~ ㅋㅋ 나도 전에 저거 문제 봤을때 캐 삽질 했었는데...헤더부분을 몰라서.. 난 재윤이 임 ㅋ 알겠지 누군지?!
답글삭제@hermezJY - 2010/03/10 17:39
답글삭제yo~ ㅋㅋㅋㅋㅋ
당연히 알지 ㅋㅋ 또 보아 ;)
Hi mate would it be ok if i used some information from here to use on one of my websites? cheers mate.
답글삭제