StevenPZChan
StevenPZChan
4 min read

Categories

Tags

继续挑战


第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,来到了下一题。

总结:这一题是一些常用的压缩格式的应用。还发现了好用的格式探测器python-magic库。

本题代码地址21_invader.ipynb