StevenPZChan
StevenPZChan
27 min read

Categories

Tags

继续挑战,又是很抽象


第18题地址balloons.html

  • balloons.jpg
  • 网页标题是can you tell the difference?,题目内容为空,源码中有一行隐藏信息:

    <!– it is more obvious that what you might think –>

图片是由大致相同的一明一暗两张图组成的。
标题说你能找出不同么?,还提示说比你想的还要明显,这该不会是来找茬吧?
想到这两张图是有明暗差别的,估计还是图像处理:

from io import BytesIO
from itertools import product
import requests
from PIL import Image

with requests.Session() as sess:
    sess.auth = ('huge', 'file')
    response = sess.get('http://www.pythonchallenge.com/pc/return/balloons.jpg').content
    img = Image.open(BytesIO(response))

width, height = img.size
img_diff = Image.new(img.mode, (width // 2, height))
img_diff_data = img_diff.load()
img_data = img.load()

for x, y in product(range(width // 2), range(height)):
    left = img_data[x, y]
    right = img_data[x + width // 2, y]
    img_diff_data[x, y] = tuple(l - r for l, r in zip(left, right))

img_diff

png

还是那张图啊!
该不会还有更明显的结论吧?
试试亮度brightness.html,居然打开了另外一个一模一样的页面,但是源码里面隐藏信息不一样:

<!– maybe consider deltas.gz –>

好了,不多说,这个deltas.gz才是这个题目的重头戏。
我们下载下来看看:

import gzip
from io import BytesIO
import requests

with requests.Session() as sess:
    sess.auth = ('huge', 'file')
    response = sess.get('http://www.pythonchallenge.com/pc/return/deltas.gz').content
    with gzip.open(BytesIO(response)) as f:
        deltas = f.read().decode()

for i, line in enumerate(deltas.splitlines()):
    if i % 100 == 0:
        print(line)
89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00   89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00
9c bf da 23 d4 30 b9 ca 4b 1a a4 94 02 68 b8 59 f2 7c   02 07 0f d7 bf ae 09 a5 2d b7 1e ce e1 c3 c3 b3 82 1a
e4 d3 5a 28 63 48 43 a9 15 1d 83 b5 02 94 42 4e 19 ca   37 5c 37 dc 1c fb 67 57 e1 f2 4d 1c 75 40 58 f3 6a 11
0d 57 88 ab 1d 1d f3 6f 79 ea 6d a6 0d ec 62 02 dd 3a   9a 22 33 b0 1a 26 41 22 b4 8a b8 91 38 b8 15 3e a3 12
dc 08 c4 83 19 9f 59 30 19 c3 f3 1b 91 50 56 a9 61 4e   d5 3f 8d 1d 5a 80 3c fb 8b 6f 34 63 bb b9 2a 50 d6 9c
e9 ce 71 f5 b9 97 18 65 1f e8 48 bb 1e 30 be b8 c4 f6   d3 13 3c 7f b5 14 4e 28 91 d8 3c 50 c3 84 52 b3 a9 c8
50 09 a5 13 b5 fb c0 7c 7f a0 8f 72 2a 1c 9c 14 cd 2d   4b fe 8c f2 48 0d 3d 50 a3 df 99 3f fe de fe f3 8e da
25 4f fb f0 f1 6a 8b f1 eb 8b 3b 1b a2 e9 c6 52 eb e5   f6 70 50 63 bd c6 52 16 93 3b 74 5f ef 04 c1 4b 38 e7
eb 0b 84 8b cd 9d 0e 6e 94 56 d0 3d 1b 59 5b ea 3f df   72 dd bb 1a 69 e8 a9 de 1b a9 c9 81 3e 22 90 21 23 3e
3c 22 3b c7 87 8b 35 55 45 5a ed 09 36 67 5e 3b d4 c0   af c3 d5 df ba 3f 3f 75 8f 6e 21 36 f7 2f b9 de b2 b5
32 d1 ef ba 7e 15 13 ec fe 91 fe a5 c4 a0 40 59 d2 c0   3a 61 44 a5 3d fc 6b 43 04 d6 c2 06 0a 15 0f 3f 80 b4
f9 88 8d 14 09 a5 87 fa 68 aa f6 2c 12 43 9b 4f b4 39   a6 56 87 b4 0c c1 d4 6c 22 ad 52 3a 95 e8 05 22 67 4a
b0 cb cb 39 d3 35 0c d4 f6 48 83 27 27 fa cd 28 d1 ca   a5 c4 52 a2 61 0c 69 03 9b 50 da 72 d3 52 3d 55 7b 03
d2 05 e6 b7 ef 17 7d 12 09 18 52 c9 94 1e a4 41 28 b3   73 cc 12 2c ee fe 63 c9 91 cd 31 2d 51 48 75 b7 55 5f
be af d9 df 0f 4d eb ae d0 ba ea 61 e3 76 ac 3d e2 fa   c0 74 a2 07 ce dd c5 be aa 75 16 bb ac 7f ca ba 12 bd
83 95 c9 a3 a7 5f 7d 16 d9 ce 36 57 6e 16 23 97 62 e0   4c cb ce e4 66 17 7b 52 a7 ee 78 8e 0e a0 14 bd 3b 12
14 33 9e 88 36 6a 89 32 e1 85 58 74 c8 4d 75 86 e3 37   3d e2 d0 d0 f2 70 2d 45 66 0f 1e 33 4b f6 2c 69 ae 24
26 7c b9 c0 ec e1 6b ac 15 ca 98 e7 20 ac aa 83 49 69   71 3c ed 2c 81 f0 c4 08 f4 d7 18 71 c8 f7 21 11 41 ab
80 d0 27 df a7 40 1e 67 44 64 b9 ae b9 b2 b0 0b 9e 3e   51 70 3e 75 93 c7 9e e9 b8 17 39 d2 23 7e ff 0a af 43
d1 97 a7 41 07 9e cc 99 37 aa ef 0c 20 5d 6b 65 4b dc   b3 47 cf b7 b0 2b 3f b7 10 91 e8 bb 89 82 ac 0c de a3
e7 d5 37 3f c3 e4 1d ff 10 51 c7 72 3d a2 0d 91 c6 94   fc 9b 8a cd 52 02 91 82 ad 08 bc 5b d4 dc f8 32 49 35
18 90 07 8a 03 29 5e a3 54 09 8f fb a9 bd e0 41 43 71   3b 8f 79 f1 71 ee 2e a7 87 12 45 8e cc 63 1f c4 15 aa
51 14 45 51 14 45 51 14 45 51 14 45 51 14 45 51 14 45   ed 51 fd 7e e2 2e 0b ce ff be 9e dd df fc f1 bc f6 48

我们可以看到,这个delta数据分为左右两部分,有很大一部分是一样的,也有一部分是不一样的。
结合这题的标题,应该是要用文本比较工具找出它们的不同之处:

from difflib import Differ

split_lines = deltas.splitlines()
left, right = [line[:53] for line in split_lines], [line[56:] for line in split_lines]
diff = Differ().compare(left, right)
for i, d in enumerate(diff):
    if i % 100 == 0:
        print(d)
  89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00
  9c bf da 23 d4 30 b9 ca 4b 1a a4 94 02 68 b8 59 f2 7c
  6c df d5 e8 b8 53 a4 6a 5f 47 2a ec ce c2 90 dd 51 7b
- 11 66 da 22 0d 1e 9b df 7f 75 27 95 9e 6e e9 3e e8 ce
  48 ac f2 2c d9 8c 8a 18 a1 ef 5a e9 6c 6e f8 bb 75 dc
+ 02 01 83 11 e8 95 11 e8 ae 32 12 09 ce 61 a2 6c 29 49
- 19 30 7e 7d 01 a5 15 99 92 f4 bc 87 0e 20 f9 88 b4 19
+ 9d f7 2f 4d 67 aa 0a f7 ea 1a f7 9b 06 b7 e8 af 10 54
  fe 77 e6 c7 23 fd 5d a5 06 e2 82 5b f3 3a e5 66 15 16
+ 76 58 55 d8 65 c3 b2 e1 3d a2 cb 0d 45 22 2b 92 a7 90
- 7a e8 39 65 9e e7 0e ec 2a 94 49 c6 14 23 c0 c7 d1 9c
+ a6 07 20 d3 49 77 ab 0a b1 14 ec 79 8f 5b 75 3d d7 2e
- 2a ed 4a 19 30 f4 66 a0 1b 4a 22 0d e7 6b 7a 13 ba 8f
+ 25 86 10 50 f3 41 d9 0f 01 5f b5 2d 9e c6 88 15 bb cc
  6c 3a b5 bc e1 96 6b ac 3a b4 0b 9e 37 af cb 3f 2c 92
  2e 8e f1 74 80 51 df fe 94 cc c6 22 91 91 a7 82 aa 11
+ 55 04 f4 5f 77 1d fe f3 ee 2e ee d0 53 40 3b d6 6f de
  6c 35 ea 56 3a ed e9 bf 4a 29 3b 37 67 91 ba 6a 46 38
- 32 44 e0 fd f1 f7 ed c8 6e 26 0d dc d9 02 93 4f cf d0
- cc 43 b8 0a 8d 9b 11 e3 8b 4b ac fe e7 7f 42 3b 83 fe
  7b 03 6f 6c 36 46 66 1c d2 72 b4 a4 55 b7 b7 b0 32 96
- 23 76 7f 78 01 a4 5c 75 ae 48 19 aa b5 48 83 af 7e a1
  ad 01 34 03 74 52 fc ef a0 db a5 be cf fe ed e7 95 5d
  72 ff a4 88 6f 2f bd 14 9c d7 54 4b ca cb cb 8a 3d 5a
  84 1c b5 09 7a 89 e2 f6 a7 e4 10 e3 17 f8 6e 35 36 ff
+ a7 6d e2 94 3f eb 32 45 54 df 2b 24 71 9c 12 3a 3a f7
  68 cf dc 4d cf ed c9 95 bb a8 f8 7e 43 34 cb 94 85 ef
  c8 71 c8 ef 40 78 c1 3f 97 25 c1 52 96 e4 8b 2c 7d fd
  ed 51 fd 7e e2 2e 0b ce ff be 9e dd df fc f1 bc f6 48
  51 14 45 51 14 45 51 14 45 51 14 45 51 14 45 51 14 45

我们把相同( )、左边有右边没有(-)、左边没有右边有(+)的分别收集起来并且将其转换成bytes形式:

def hex2bytes(data: str) -> bytes:
    return bytes(int(s, 16) for s in data.split())

diff = Differ().compare(left, right)
same = bytearray()
plus = bytearray()
minus = bytearray()
for d in diff:
    code = d[0]
    data = d[2:]
    if code == ' ':
        same.extend(hex2bytes(data))
    elif code == '-':
        minus.extend(hex2bytes(data))
    elif code == '+':
        plus.extend(hex2bytes(data))
        
print(same[:20])
print(plus[:20])
print(minus[:20])
bytearray(b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x02\x8a')
bytearray(b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x01P')
bytearray(b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x01P')

很惊奇地发现,这三部分都是PNG图片的文件头。让我们来看看是什么东东:

from PIL import Image
from matplotlib import pyplot as plt
%matplotlib inline

for i, b in zip(range(3), (same, plus, minus)):
    img = Image.open(BytesIO(b))
    plt.subplot(1, 3, i + 1)
    plt.imshow(img)
    plt.axis('off')

png

分别是../hex/bin.htmlbutterfly
网址打开之后要求输入密码,提示是pluses and minuses,尝试用户名butter和密码fly便来到了下一题!

总结:这一题也不简单,第一步就卡住了,不过后面文本比较还算顺利的。学习了gzip格式和库的使用,和difflib库里面文本比较的相关操作。

本题代码地址18_balloons.ipynb