Skip to content

Latest commit

 

History

History
333 lines (212 loc) · 9.88 KB

File metadata and controls

333 lines (212 loc) · 9.88 KB

Level 21

zlib doesn't have a file extension unlike gzip or bzip, so you won't need to change the filename.

First let's try checking what's inside the file.

Here's the first 30 bytes of package.pack.

import zlib

with open("package.pack", "rb") as f:
    content = f.read()
    print(content[:30])
    print()

# b'x\x9c\x00\n@\xf5\xbfx\x9c\x00\x07@\xf8\xbfx\x9c\x00\x06@\xf9\xbfx\x9c\x00\xff?\x00\xc0x\x9c'

It gave me a whole bunch of byte strings so I checked the first 30 bytes to see if there if I could recognize a file header.

Nothing really special. After searching online for a bit, zlib's default compressions file headers are 0x78, 0x9c. I can't find the 0x78 but we can spot the \x9c in package.pack.

Let's try checking the 2 starting bytes of the byte-string.

When indexing byte-strings, Python will return the integer value of that specific byte.

start=b'x\x9c'
hex(start[0]) # 0x78 
hex(start[1]) # 0x9c 

You still might have a confusion on how b'x\x9c' returns 0x78 and 0x9c when using hex.

b'x\x9c' is made up of two bytes. b'x' and b'\x9c'.

b'x'.hex() # 0x78 
b'\x9c'.hex() # 0x9c 

The '\x' used in the byte-string are used for representing hexadecimal characters. Python uses '\x' to enable escape sequences.

It looks like it matches the zlib file header explained here.

Now we can finally ascertain that package.pack is a default compressed zlib file.

Then I tried decompressing package.pack which also gave me binary data that started with b\x\x9c. Python has a built-in zilb module. For decompressing zlib files I used zlib.decompress.

output = zlib.decompress(content)
print(output[:30]) 
# b'x\x9c\x00\x07@\xf8\xbfx\x9c\x00\x06@\xf9\xbfx\x9c\x00\xff?\x00\xc0x\x9c\x00\xff?\x00\xc0x\x9c'

I'm not even sure that we're dealing with proper zlib files but maybe I should decompress until the byte-string doesn't start with b'x\x9c'.

Here's the following code.

import zlib
import bz2

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

while True:
    try:
        data = zlib.decompress(content)
        content = data
        print(data[:30])
    except zlib.error:
        break

# b'x\x9c\x00\x07@\xf8\xbfx\x9c\x00\x06@\xf9\xbfx\x9c\x00\xff?\x00\xc0x\x9c\x00\xff?\x00\xc0x\x9c'
# b'x\x9c\x00\x06@\xf9\xbfx\x9c\x00\xff?\x00\xc0x\x9c\x00\xff?\x00\xc0x\x9c\x84vuT\x14N\xd4'
# b'x\x9c\x00\xff?\x00\xc0x\x9c\x00\xff?\x00\xc0x\x9c\x84vuT\x14N\xd46\xddH#\xad\x80\x84'
# b'x\x9c\x00\xff?\x00\xc0x\x9c\x84vuT\x14N\xd46\xddH#\xad\x80\x84tH\x97\x80\x94\x80 '
# b'x\x9c\x84vuT\x14N\xd46\xddH#\xad\x80\x84tH\x97\x80\x94\x80 -)\xd2\xdd \xb1H'
# b'BZh91AY&SY\x91\xe8/+\x00v\xa9\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'

Decompressing until it's not a zlib file will give you a bzip file. You can tell that it's a zlib file with the file header BZh91AY as we've experienced before back in level8.

import zlib
import bz2

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

while True:
    try:
        data = zlib.decompress(content)
        content = data
        print(data[:30])
    except zlib.error:
        try:
            data=bz2.decompress(content)
            content=data 
        except OSError:
            break

I used OSError because when bz2 can't decompress a bzip file using bz2.decompress it returns an OSError like below OSError: Invalid data stream During handling of the above exception, another exception occurred:

Now let's check which kind of file package.pack is after decompressing it zlib and bzip.

I checked the first 30 bytes of what was leftover after zlip decompressing and bzip decompressing.

data[:30]
b'\x80\x8d\x96\xcb\xb5r\xa7\x00\x06Xz\xdafO\x19\xee\x84k\xa4dAB\xe1\x14\xc9]\xfc\xffT!'

Now I'm stuck again. what should I do lol...

Then I remembered that the readme.txt file said this When I had no idea what to do, I looked backwards.

Let's try inspecting the bytes backwards.

I reversed the string and selected the first 30 bytes. Here's what we get.

print(data[::-1][:30]) # b'x\x9c\x00\x0c@\xf3\xbfx\x9c\x00\x05@\xfa\xbfx\x9c\x00\x05@\xfa\xbfx\x9c\x84\xb7UT\x1c\xbe\x17'

Hey it looks like a zlib file again!. The zlib file header we saw before b'x\x9c is at the start of the reversed byte-string.

So we can probably deflate it if it's a zlib file or a bzip file or reverse the bytes if it's neither of them.

Here's the code that I wrote.

import zlib
import bz2


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

while True:
    try:
        data = zlib.decompress(content)
        content = data
    except zlib.error:
        try:
            data = bz2.decompress(content)
            content = data
        except OSError:
            try:
                data = zlib.decompress(content[::-1])
                content = data
            except zlib.error:
                try:
                    data = bz2.decompress(content[::-1])
                    content = data
                except OSError:
                    break

print(data) # b'sgol ruoy ta kool'

b'sgol ruoy ta kool' is the result. I can't read it lol, we should probably reverse it as well.

b'sgol ruoy ta kool'[::-1] 
# b'look at your logs'

When reversing the string it says to look at my logs. What am I supposed to do now.

Let's try printing characters when package.pack is a zlib file, a bzip file or neither(reversed).

import zlib
import bz2


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


while True:
    try:
        data = zlib.decompress(content)
        content = data
        print("z",end=" ")
    except zlib.error:
        try:
            data = bz2.decompress(content)
            content = data
            print("b",end=" ")
        except OSError:
            try:
                data = zlib.decompress(content[::-1])
                content = data
                print("r")
            except zlib.error:
                try:
                    data = bz2.decompress(content[::-1])
                    content = data
                except OSError:
                    break

Here's the output.

z z z z z z b b b z z z z z z z z z z b b b z z z z z z b b b b b b b b z z z z b b b b b b b b z z z z b b b b b b b b b b z z b b b b b b b b r
z z z b b b b b b b z z z z z z b b b b b b b z z z z b b b b b b b b b z z z b b b b b b b b b z z z b b b b b b b b b z z z b b b b b b b b b r
z z b b z z z z z b b z z z z b b z z z z z b b z z z b b z z z z z z b b z z b b z z z z z z b b z z b b z z z z z z z z z z b b z z z z z z b b r
z b b z z z z z z z z z z z b b z z z z z z z b b z z b b z z z z z z b b z z b b z z z z z z b b z z b b z z z z z z z z z z b b z z z z z z b b r
z b b z z z z z z z z z z z b b z z z z z z z b b z z b b b b b b b b b z z z b b b b b b b b b z z z b b b b b b b b z z z z b b b b b b b b b r
z b b z z z z z z z z z z z b b z z z z z z z b b z z b b b b b b b b z z z z b b b b b b b b z z z z b b b b b b b b z z z z b b b b b b b b z r
z b b z z z z z z z z z z z b b z z z z z z z b b z z b b z z z z z z z z z z b b z z z z z z z z z z b b z z z z z z z z z z b b z z z b b z r
z z b b z z z z z b b z z z z b b z z z z z b b z z z b b z z z z z z z z z z b b z z z z z z z z z z b b z z z z z z z z z z b b z z z z b b z r
z z z b b b b b b b z z z z z z b b b b b b b z z z z b b z z z z z z z z z z b b z z z z z z z z z z b b b b b b b b b z z z b b z z z z z b b z r
z z z z z b b b z z z z z z z z z z b b b z z z z z z b b z z z z z z z z z z b b z z z z z z z z z z b b b b b b b b b b z z b b z z z z z z b b 

It looks like crap, but if you zoom out on the output the result looks like the word copper.

Now that we know the result is copper.

Let's try cleaning the code so it only prints the word copper.

I modified the code so we don't have to zoom out to see the word copper.

Here's the final code.

import zlib
import bz2


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

copper=""
while True:
    try:
        data = zlib.decompress(content)
        content = data
        copper+=" "
    except zlib.error:
        try:
            data = bz2.decompress(content)
            content = data
            copper+="#"
        except OSError:
            try:
                data = zlib.decompress(content[::-1])
                content = data
                copper+="\n"
            except zlib.error:
                try:
                    data = bz2.decompress(content[::-1])
                    content = data
                except OSError:
                    break

print(copper)

The cleaned up copper looks like this. BTW concatenating strings in Python isn't a good practice I used it because that was the only way I could print copper neatly, if anyone has a better method please tell me.

   #######      #######    #########   #########   #########   #########
  ##     ##    ##     ##   ##      ##  ##      ##  ##          ##      ##
 ##           ##       ##  ##      ##  ##      ##  ##          ##      ##
 ##           ##       ##  #########   #########   ########    #########
 ##           ##       ##  ########    ########    ########    ######## 
 ##           ##       ##  ##          ##          ##          ##   ## 
  ##     ##    ##     ##   ##          ##          ##          ##    ## 
   #######      #######    ##          ##          #########   ##     ## 
     ###          ###      ##          ##          ##########  ##      ##

Now that we've taken care of everything let's change the url to http://www.butter:fly@pythonchallenge.com/pc/hex/copper.html.

We're on level22. Man that was a lot ...