继续挑战
第21题为第20题对unreal.jpg用特定的Range请求得到的压缩包内容
- 压缩包里面有一个package.pack文件,题目readme.txt内容为:- We used to play this game when we were kids
- When I had no idea what to do, I looked backwards.
 
先重复上一题的步骤把package.pack解压出来看看:
from io import BytesIO
from zipfile import ZipFile
import requests
with requests.Session() as sess:
    sess.auth = ('butter', 'fly')
    header = {'Range': 'bytes=1152983631-'}
    response = sess.get('http://www.pythonchallenge.com/pc/hex/unreal.jpg', headers=header)
with ZipFile(BytesIO(response.content), 'r') as f:
    with f.open('package.pack', 'r', pwd=b'invader'[::-1]) as f_pack:
        package = f_pack.read()
        
print(package[:20])
b'x\x9c\x00\n@\xf5\xbfx\x9c\x00\x07@\xf8\xbfx\x9c\x00\x06@\xf9'
查了下b'x\x9c\x00开头的是zlib压缩格式,我们来解包看看:
import zlib
temp = zlib.decompress(package)
print(temp[:20])
b'x\x9c\x00\x07@\xf8\xbfx\x9c\x00\x06@\xf9\xbfx\x9c\x00\xff?\x00'
又玩这种循环迭代的游戏了!那我们继续:
import zlib
data = package
while True:
    try:
        data = zlib.decompress(data)
    except Exception as e:
        print(data[:20])
        print(f'{e!r}')
        break
b'BZh91AY&SY\x91\xe8/+\x00v\xa9\x7f\xff\xff'
error('Error -3 while decompressing data: incorrect header check')
咦?切换到了BZh开头的bzip2压缩格式了,我们改一下继续:
import bz2
import zlib
data = package
while True:
    try:
        data = zlib.decompress(data)
    except:
        try:
            data = bz2.decompress(data)
        except Exception as e:
            print(data[:20])
            print(f'{e!r}')
            break
b'\x80\x8d\x96\xcb\xb5r\xa7\x00\x06Xz\xdafO\x19\xee\x84k\xa4d'
OSError('Invalid data stream')
这回不知道是什么东西了。。。来,我们开始读题。
说这是我们小时候会玩的游戏,我们刚才是在反复解压同一个东西,估计这个游戏就像是一个东西在小伙伴里面不断地传递,每个人会给它用某种方式(压缩)包装一层再继续。我们在做的事情就是解压拿到最原始的内容。没毛病,但是现在我们卡壳了。
再看看第二句话,当我们卡壳的时候,会试着倒过来看:
print(data[::-1][:20])
b'x\x9c\x00\x0c@\xf3\xbfx\x9c\x00\x05@\xfa\xbfx\x9c\x00\x05@\xfa'
果然有用!!
我们改一下继续:
import bz2
import zlib
data = package
try_count = 0
while True:
    try:
        data = zlib.decompress(data)
    except:
        try:
            data = bz2.decompress(data)
        except:
            data = data[::-1]
            try_count += 1
            if try_count == 3:
                print(data[:20])
                break
            continue
    try_count = 0
print(data.decode())
b'look at your logs'
look at your logs
解压出来最原好的内容了!但是叫我们看日志,看来要加上一些打印来记录我们的解压操作了。
在我们继续之前,首先是我发现了一个叫python-magic的库,可以知道文件内容的具体格式,不用我们总是去查找。至少可以优化一下上面那段那么丑的代码吧。
from magic import Magic
magic_t = Magic(mime=True)
print(magic_t.from_buffer(package))
application/zlib
其次是我们有三种不同的操作,需要定义其打印的字符:
| 操作 | 打印字符 | 
|---|---|
| zlib | ’.’ | 
| bz2 | ‘0’ | 
| 倒序 | ‘\n’ | 
import bz2
import zlib
from magic import Magic
magic_t = Magic(mime=True)
data = package
while True:
    mime = magic_t.from_buffer(data)
    if mime in ('application/zlib', 'application/x-tex-tfm'):
        data = zlib.decompress(data)
        print('.', end='')
    elif mime == 'application/x-bzip2':
        data = bz2.decompress(data)
        print('0', end='')
    else:
        data = data[::-1]
        print()
        if mime == 'text/plain':
            break
print(data.decode())
......000..........000......00000000....00000000....0000000000..00000000
....0000000......0000000....000000000...000000000...000000000...000000000
...00.....00....00.....00...00......00..00......00..00..........00......00
..00...........00.......00..00......00..00......00..00..........00......00
..00...........00.......00..000000000...000000000...00000000....000000000
..00...........00.......00..00000000....00000000....00000000....00000000.
..00...........00.......00..00..........00..........00..........00...00.
...00.....00....00.....00...00..........00..........00..........00....00.
....0000000......0000000....00..........00..........000000000...00.....00.
......000..........000......00..........00..........0000000000..00......00
look at your logs
好大一个COPPER!将地址改为copper.html,来到了下一题。
 
      