Python/Python Challenge

[Python Challenge 21] 압축효율 끝판왕

Python challenge 21은 웹을 통해 푸는 문제가 아니다. 있지 않다. 저번 시간 풀었던 packer.pack을 계산해서 푸는 문제이다.


구성(준비물)

다음과 같다.

  • packer.pack : 저번시간 풀고 나온 거
  • readme.txt : 안내문

일단 readme.txt부터 보자

번역하면 다음과 같다. 

 

"좋아요! 여기가 레벨 21입니다.

그리고 당연하게도 당신이 풀고 나면 22단계에 가있을 거예요!

 

이 레벨을 풀기 위한 것들은 다음과 같습니다.

 

* 우리는 어릴 때 이 게임을 하곤 했어요

* 어떻게 해야 될지 모를 땐, 전 거꾸로 바라보곤 했습니다."

 

?? 일단 pakcer.pack의 확장자를 특정하기 위해 hxd로 까 보자

시작 헤더는 89 9C이다. 이는 zlib의 확장자 헤더이다. 일단 까 볼까

### 21_1.py

import zlib

if __name__=="__main__" :
    with open("package.pack","rb") as f:
        data = f.read()

    data2 = zlib.decompress(data)
    
    with open("1.dat","wb") as f:
        f.write(data2)

??? 실행결과로 나온 1.dat은 똑같은 89 9C파일에 234KB로 달라진 게 없는 거 같다. 어떻게 해결해야 되는 것일까


해결 아이디어

안 바뀐 거 같아 보여도 바뀌었다.

### 21_2.py

import zlib

if __name__=="__main__" :
    with open("package.pack","rb") as f:
        data = f.read()

    data2 = zlib.decompress(data)
    print(data2 == data)
    
    with open("1.dat","wb") as f:
        f.write(data2)

결과는 "FALSE"이다. 일단 반복될 느낌이 드니까 무한루프 안에 위에 코드를 걸어두자

### 21_3.py

import zlib

if __name__=="__main__" :
    with open("package.pack","rb") as f:
        data = f.read()

    while(True) :
        try :
            data = zlib.decompress(data)
            print(data[0:2])
        except :
            with open("1.dat","wb") as f:
                f.write(data)
            break
        

결과로 나온 1.dat은 이번에는 42 5A의 헤더를 가진다. 얘는 bz2를 이용해서 decompress를 걸 수 있다. 두 개가 반복될 느낌이 심하게 드니까 다음과 같은 코드를 짜자

### 21_4.py

import zlib, bz2

if __name__=="__main__" :
    with open("package.pack","rb") as f:
        data = f.read()

    while(True) :
        if(data.startswith(b"x\x9c")) :
            data = zlib.decompress(data)
            print(data[0:2])
        elif(data.startswith(b"BZ")) :
            data = bz2.decompress(data)
            print(data[0:2])
        else :
            with open("1.dat","wb") as f:
                f.write(data)
            break

결과는 아래와 같이 끝난다.

...


b'BZ'
b'BZ'
b'BZ'
b'BZ'
b'BZ'
b'BZ'
b'BZ'
b'BZ'
b'\x80\x8d'
>>> 

으흠; 80 8D라는 헤더는 없는데.... 힌트를 한번 빌리자.

 

"어떻게 해야 될지 모를 땐, 전 거꾸로 바라보곤 했습니다."

 

파일의 맨 뒤를 보면 9C 78로 끝난다. 그러니까 파일이 뒤집혀 있다는 것이다. 

### 21_5.py

import zlib, bz2

if __name__=="__main__" :
    with open("package.pack","rb") as f:
        data = f.read()

    while(True) :
        if(data.startswith(b"x\x9c")) :
            data = zlib.decompress(data)
            print(data[0:2])
        elif(data.startswith(b"BZ")) :
            data = bz2.decompress(data)
            print(data[0:2])
        elif(data.endswith(b"\x9cx")) :
            data = data[::-1]
        else :
            with open("1.dat","wb") as f:
                f.write(data)
            break

완벽하다. 1.dat은 다음과 같은 파일이다.

"sgol ruoy ta kool"이라고 적혀있다. 거꾸로 읽으면 "look at your logs"이다. 여기서 필자는 한참 헸갈렸는데, 압축해 재를 할 때마다 타입에 따라 문자열을 지정하면 아스키 아트를 발견할 수 있다. 확실하다.

### 21_6.py

import zlib, bz2

if __name__=="__main__" :

    ans = ""
    
    with open("package.pack","rb") as f:
        data = f.read()

    while(True) :
        if(data.startswith(b"x\x9c")) :
            data = zlib.decompress(data)
            ans += "1"
        elif(data.startswith(b"BZ")) :
            data = bz2.decompress(data)
            ans += "2"
        elif(data.endswith(b"\x9cx")) :
            data = data[::-1]
            ans += "\n"
        else :
            with open("1.dat","wb") as f:
                f.write(data)
            break

    print(ans)

그렇다. 아스키 아트는 다음과 같다.

구리다. 찾았다.

Answer Url : http://www.pythonchallenge.com/pc/hex/copper.html