一道ctf题,通过破解2048游戏获得flag
游戏的规则很简单,需要控制所有方块向同一个方向运动,两个相同数字方块撞在一起之后合并成为他们的和,每次操作之后会随机生成一个2或者4,最终得到一个“2048”的方块就算胜利了。
脚本内容如下
from __future__ import print_function import os import struct import marshal import zlib import sys import imp import types from uuid import uuid4 as uniquename class CTOCEntry: def __init__(self, position, cmprsdDataSize, uncmprsdDataSize, cmprsFlag, typeCmprsData, name): self.position = position self.cmprsdDataSize = cmprsdDataSize self.uncmprsdDataSize = uncmprsdDataSize self.cmprsFlag = cmprsFlag self.typeCmprsData = typeCmprsData self.name = name class PyInstArchive: PYINST20_COOKIE_SIZE = 24 # For pyinstaller 2.0 PYINST21_COOKIE_SIZE = 24 + 64 # For pyinstaller 2.1+ MAGIC = b'MEI\014\013\012\013\016' # Magic number which identifies pyinstaller def __init__(self, path): self.filePath = path def open(self): try: self.fPtr = open(self.filePath, 'rb') self.fileSize = os.stat(self.filePath).st_size except: print('[*] Error: Could not open {0}'.format(self.filePath)) return False return True def close(self): try: self.fPtr.close() except: pass def checkFile(self): print('[*] Processing {0}'.format(self.filePath)) # Check if it is a 2.0 archive self.fPtr.seek(self.fileSize - self.PYINST20_COOKIE_SIZE, os.SEEK_SET) magicFromFile = self.fPtr.read(len(self.MAGIC)) if magicFromFile == self.MAGIC: self.pyinstVer = 20 # pyinstaller 2.0 print('[*] Pyinstaller version: 2.0') return True # Check for pyinstaller 2.1+ before bailing out self.fPtr.seek(self.fileSize - self.PYINST21_COOKIE_SIZE, os.SEEK_SET) magicFromFile = self.fPtr.read(len(self.MAGIC)) if magicFromFile == self.MAGIC: print('[*] Pyinstaller version: 2.1+') self.pyinstVer = 21 # pyinstaller 2.1+ return True print('[*] Error : Unsupported pyinstaller version or not a pyinstaller archive') return False def getCArchiveInfo(self): try: if self.pyinstVer == 20: self.fPtr.seek(self.fileSize - self.PYINST20_COOKIE_SIZE, os.SEEK_SET) # Read CArchive cookie (magic, lengthofPackage, toc, tocLen, self.pyver) = \ struct.unpack('!8siiii', self.fPtr.read(self.PYINST20_COOKIE_SIZE)) elif self.pyinstVer == 21: self.fPtr.seek(self.fileSize - self.PYINST21_COOKIE_SIZE, os.SEEK_SET) # Read CArchive cookie (magic, lengthofPackage, toc, tocLen, self.pyver, pylibname) = \ struct.unpack('!8siiii64s', self.fPtr.read(self.PYINST21_COOKIE_SIZE)) except: print('[*] Error : The file is not a pyinstaller archive') return False print('[*] Python version: {0}'.format(self.pyver)) # Overlay is the data appended at the end of the PE self.overlaySize = lengthofPackage self.overlayPos = self.fileSize - self.overlaySize self.tableOfContentsPos = self.overlayPos + toc self.tableOfContentsSize = tocLen print('[*] Length of package: {0} bytes'.format(self.overlaySize)) return True def parseTOC(self): # Go to the table of contents self.fPtr.seek(self.tableOfContentsPos, os.SEEK_SET) self.tocList = [] parsedLen = 0 # Parse table of contents while parsedLen < self.tableOfContentsSize: (entrySize, ) = struct.unpack('!i', self.fPtr.read(4)) nameLen = struct.calcsize('!iiiiBc') (entryPos, cmprsdDataSize, uncmprsdDataSize, cmprsFlag, typeCmprsData, name) = \ struct.unpack( \ '!iiiBc{0}s'.format(entrySize - nameLen), \ self.fPtr.read(entrySize - 4)) name = name.decode('utf-8').rstrip('\0') if len(name) == 0: name = str(uniquename()) print('[!] Warning: Found an unamed file in CArchive. Using random name {0}'.format(name)) self.tocList.append( \ CTOCEntry( \ self.overlayPos + entryPos, \ cmprsdDataSize, \ uncmprsdDataSize, \ cmprsFlag, \ typeCmprsData, \ name \ )) parsedLen += entrySize print('[*] Found {0} files in CArchive'.format(len(self.tocList))) def extractFiles(self): print('[*] Beginning extraction...please standby') extractionDir = os.path.join(os.getcwd(), os.path.basename(self.filePath) + '_extracted') if not os.path.exists(extractionDir): os.mkdir(extractionDir) os.chdir(extractionDir) for entry in self.tocList: basePath = os.path.dirname(entry.name) if basePath != '': # Check if path exists, create if not if not os.path.exists(basePath): os.makedirs(basePath) self.fPtr.seek(entry.position, os.SEEK_SET) data = self.fPtr.read(entry.cmprsdDataSize) if entry.cmprsFlag == 1: data = zlib.decompress(data) # Malware may tamper with the uncompressed size # Comment out the assertion in such a case assert len(data) == entry.uncmprsdDataSize # Sanity Check with open(entry.name, 'wb') as f: f.write(data) if entry.typeCmprsData == b's': print('[+] Possible entry point: {0}'.format(entry.name)) elif entry.typeCmprsData == b'z' or entry.typeCmprsData == b'Z': self._extractPyz(entry.name) def _extractPyz(self, name): dirName = name + '_extracted' # Create a directory for the contents of the pyz if not os.path.exists(dirName): os.mkdir(dirName) with open(name, 'rb') as f: pyzMagic = f.read(4) assert pyzMagic == b'PYZ\0' # Sanity Check pycHeader = f.read(4) # Python magic value if imp.get_magic() != pycHeader: print('[!] Warning: The script is running in a different python version than the one used to build the executable') print(' Run this script in Python{0} to prevent extraction errors(if any) during unmarshalling'.format(self.pyver)) (tocPosition, ) = struct.unpack('!i', f.read(4)) f.seek(tocPosition, os.SEEK_SET) try: toc = marshal.load(f) except: print('[!] Unmarshalling FAILED. Cannot extract {0}. Extracting remaining files.'.format(name)) return print('[*] Found {0} files in PYZ archive'.format(len(toc))) # From pyinstaller 3.1+ toc is a list of tuples if type(toc) == list: toc = dict(toc) for key in toc.keys(): (ispkg, pos, length) = toc[key] f.seek(pos, os.SEEK_SET) fileName = key try: # for Python > 3.3 some keys are bytes object some are str object fileName = key.decode('utf-8') except: pass # Make sure destination directory exists, ensuring we keep inside dirName destName = os.path.join(dirName, fileName.replace("..", "__")) destDirName = os.path.dirname(destName) if not os.path.exists(destDirName): os.makedirs(destDirName) try: data = f.read(length) data = zlib.decompress(data) except: print('[!] Error: Failed to decompress {0}, probably encrypted. Extracting as is.'.format(fileName)) open(destName + '.pyc.encrypted', 'wb').write(data) continue with open(destName + '.pyc', 'wb') as pycFile: pycFile.write(pycHeader) # Write pyc magic pycFile.write(b'\0' * 4) # Write timestamp if self.pyver >= 33: pycFile.write(b'\0' * 4) # Size parameter added in Python 3.3 pycFile.write(data) def main(): if len(sys.argv) < 2: print('[*] Usage: pyinstxtractor.py <filename>') else: arch = PyInstArchive(sys.argv[1]) if arch.open(): if arch.checkFile(): if arch.getCArchiveInfo(): arch.parseTOC() arch.extractFiles() arch.close() print('[*] Successfully extracted pyinstaller archive: {0}'.format(sys.argv[1])) print('') print('You can now use a python decompiler on the pyc files within the extracted directory') return arch.close() if __name__ == '__main__': main()
压缩包已上传至博主资源,下载地址:https://blog.csdn.net/qq_50216270?type=download
将脚本和待编译的exe文件放在同一路径下后,在路径框中输入cmd打开终端
在终端中输入python后输入脚本名和待反编译exe文件名
编译成功后会在原路径生成如下文件夹
对应路径终端输入uncompyle6 puzzle.pyc > puzzle.py
https://tool.lu/pyc/
代码如下
#!/usr/bin/env python # visit http://tool.lu/pyc/ for more information import random from tkinter import Frame, Label, CENTER import logic import constants as c class GameGrid(Frame): def __init__(self): Frame.__init__(self) self.grid() self.master.title('C1CTF2019') self.master.bind('<Key>', self.key_down) self.commands = { c.KEY_J: logic.down, c.KEY_K: logic.up, c.KEY_L: logic.right, c.KEY_H: logic.left, c.KEY_RIGHT_ALT: logic.right, c.KEY_LEFT_ALT: logic.left, c.KEY_DOWN_ALT: logic.down, c.KEY_UP_ALT: logic.up, c.KEY_RIGHT: logic.right, c.KEY_LEFT: logic.left, c.KEY_DOWN: logic.down, c.KEY_UP: logic.up } self.grid_cells = [] self.init_grid() self.init_matrix() self.update_grid_cells() self.mainloop() def init_grid(self): background = Frame(self, c.BACKGROUND_COLOR_GAME, c.SIZE, c.SIZE, **('bg', 'width', 'height')) background.grid() for i in range(c.GRID_LEN): grid_row = [] for j in range(c.GRID_LEN): cell = Frame(background, c.BACKGROUND_COLOR_CELL_EMPTY, c.SIZE / c.GRID_LEN, c.SIZE / c.GRID_LEN, **('bg', 'width', 'height')) cell.grid(i, j, c.GRID_PADDING, c.GRID_PADDING, **('row', 'column', 'padx', 'pady')) t = Label(cell, '', c.BACKGROUND_COLOR_CELL_EMPTY, CENTER, c.FONT, 5, 2, **('master', 'text', 'bg', 'justify', 'font', 'width', 'height')) t.grid() grid_row.append(t) self.grid_cells.append(grid_row) def gen(self): return random.randint(0, c.GRID_LEN - 1) def init_matrix(self): self.matrix = logic.new_game(4) self.history_matrixs = list() self.matrix = logic.add_two(self.matrix) self.matrix = logic.add_two(self.matrix) def update_grid_cells(self): for i in range(c.GRID_LEN): for j in range(c.GRID_LEN): new_number = self.matrix[i][j] if new_number == 0: self.grid_cells[i][j].configure('', c.BACKGROUND_COLOR_CELL_EMPTY, **('text', 'bg')) continue self.grid_cells[i][j].configure(str(new_number), c.BACKGROUND_COLOR_DICT[new_number], c.CELL_COLOR_DICT[new_number], **('text', 'bg', 'fg')) self.update_idletasks() def key_down(self, event): key = repr(event.char) if key == c.KEY_BACK and len(self.history_matrixs) > 1: self.matrix = self.history_matrixs.pop() self.update_grid_cells() print('back on step total step:', len(self.history_matrixs)) elif key in self.commands: (self.matrix, done) = self.commands[repr(event.char)](self.matrix) if done: self.matrix = logic.add_two(self.matrix) self.history_matrixs.append(self.matrix) self.update_grid_cells() done = False if logic.game_state(self.matrix) == 'win': self.grid_cells[1][0].configure('C1CTF', c.BACKGROUND_COLOR_CELL_EMPTY, **('text', 'bg')) self.grid_cells[1][1].configure('{2048', c.BACKGROUND_COLOR_CELL_EMPTY, **('text', 'bg')) self.grid_cells[1][2].configure('_1s_', c.BACKGROUND_COLOR_CELL_EMPTY, **('text', 'bg')) self.grid_cells[1][3].configure('fun}', c.BACKGROUND_COLOR_CELL_EMPTY, **('text', 'bg')) if logic.game_state(self.matrix) == 'lose': self.grid_cells[1][1].configure('You', c.BACKGROUND_COLOR_CELL_EMPTY, **('text', 'bg')) self.grid_cells[1][2].configure('Lost!', c.BACKGROUND_COLOR_CELL_EMPTY, **('text', 'bg')) def generate_next(self): index = (self.gen(), self.gen()) while self.matrix[index[0]][index[1]] != 0: index = (self.gen(), self.gen()) self.matrix[index[0]][index[1]] = 2 gamegrid = GameGrid()
11.找到flag大公告成
到此这篇关于python反编译教程之2048小游戏实例的文章就介绍到这了,更多相关python反编译2048小游戏内容请搜索小牛知识库以前的文章或继续浏览下面的相关文章希望大家以后多多支持小牛知识库!
本文向大家介绍python实现2048小游戏,包括了python实现2048小游戏的使用技巧和注意事项,需要的朋友参考一下 2048的python实现。修改自某网友的代码,解决了原网友版本的两个小bug: 1. 原版游戏每次只消除一次,而不是递归消除。如 [2 ,2 ,2 ,2] 左移动的话应该是 [4, 4, 0, 0] , 而不是[8 , 0 , 0 ,0] 2. 对游戏结束的侦测有bug,已
本文向大家介绍Javascript编写2048小游戏,包括了Javascript编写2048小游戏的使用技巧和注意事项,需要的朋友参考一下 去年2048很火, 本来我也没玩过, 同事说如果用JS写2048 只要100多行代码; 今天试了一下, 逻辑也不复杂, 主要是数据构造函数上的数据的各种操作, 然后通过重新渲染DOM实现界面的更新, 整体不复杂, JS,css,和HTML合起来就300
本文向大家介绍一步步教你用Python实现2048小游戏,包括了一步步教你用Python实现2048小游戏的使用技巧和注意事项,需要的朋友参考一下 前言 2048游戏规则:简单的移动方向键让数字叠加,并且获得这些数字每次叠加后的得分,当出现2048这个数字时游戏胜利。同时每次移动方向键时,都会在这个4*4的方格矩阵的空白区域随机产生一个数字2或者4,如果方格被数字填满了,那么就GameOver了。
本文向大家介绍Python实现简单的2048小游戏,包括了Python实现简单的2048小游戏的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了Python实现简单的2048小游戏的具体代码,供大家参考,具体内容如下 运行效果: 1.项目结构 2.代码 configs.py main.py Game2048.py 注意这里需要导入两个包(numpy,pygame),然后运行main文件
这个游戏的引导界面是简单的2+2=4,4+4=8,似乎和消除类游戏一样。玩第一次的时候,总是想着这样的加法,可要是这样的话,这个游戏玩起了很困难,其实就是简单的上下左右滑动,相同的会叠加,不要去想加法,我觉得可以修改为仅仅靠重力感应来玩的游戏。
本文向大家介绍python pygame实现2048游戏,包括了python pygame实现2048游戏的使用技巧和注意事项,需要的朋友参考一下 实现2048相对来说比较简单,用4*4的二维数组保存地图,pygame.key.get_pressed()获取键盘操作,详见代码。 效果图 代码 后续可以考虑实现动画和AI。 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程