We got a file called PPC300 and told to get 10000 points.
File is a "Snake" video game written in Python and packet to exe using py2exe.
Ofcourse you can play a game for fun and get a flag(or, oops - you can't, read ahead),
but that's a good case for imporoving your Python bytecode reversing skills.
First, we extract bytecode from exe using py2exe extract.
Then try to disassemble it using dis, not so readable, but we can see the constants:
I decided to decompile bytecode to a human readable form, tried Uncompyle, then Decompyle with my patch, both didn't work, but decompilation errors were in different places.
I fixed the decompyle using some parser code pieces from Uncompyle and my patch (decompyle.patch) and got a readable source code (snake.p_).
As we can see - flag is generated from "fps" value, not from points. But the original source code has a mistake and you can't get a flag even if you get enough points: "f" is called with 1 parameter, but requires 2:
First, we extract bytecode from exe using py2exe extract.
Then try to disassemble it using dis, not so readable, but we can see the constants:
'Snake Score:%s' #caption template 100 #points, incremented per eaten food 2000 #speed tick incrementFirst idea was to patch a points incrementor constant and get a flag, it didn't work.
I decided to decompile bytecode to a human readable form, tried Uncompyle, then Decompyle with my patch, both didn't work, but decompilation errors were in different places.
I fixed the decompyle using some parser code pieces from Uncompyle and my patch (decompyle.patch) and got a readable source code (snake.p_).
As we can see - flag is generated from "fps" value, not from points. But the original source code has a mistake and you can't get a flag even if you get enough points: "f" is called with 1 parameter, but requires 2:
def f(fps, control):
x = ((dumps(color) + dumps(control)) + dumps(fontsize))
t = ''
for i in x:
t += hex((ord(i) ^ fps))[2:]
return t
...
while mainloop:
...
tickFPS = Clock.tick(fps)
if (fps >= 101):
pygame.display.set_caption(f(fps))
screen.fill((0, 0, 0))
tickFPS = Clock.tick(2000)
I made a script for flag generation and reported the mistake to authors.
from cPickle import dumps
color = (32, 32, 32)
fontsize = 35
fps = 1
control = 251
def f(fps, control):
x = ((dumps(color) + dumps(control)) + dumps(fontsize))
t = ''
for i in x:
t += hex((ord(i) ^ fps))[2:]
return t
if __name__ == '__main__':
while True:
fps += 1
control -= 1
if (fps >= 101):
print f(fps, control)
break
Flag: 4d2c56576f2c56576f2c56576f1115546f4b2c5450546f4b2c56506f4b
Well done :)
Although it looks outdated, www.depython.net successfully (and strangely) decompiles pyc file.
For me it was fun ;) For me Uncompyle is better than online services like depython.net
yea, certainly more fun, but I was wondering why an old (~5years) service handles that shit better than Uncompyle *_*