def createMpegAudioMagic(): # ID3v1 magic magics = [("TAG", 0)] # ID3v2 magics for ver_major in ID3v2.VALID_MAJOR_VERSIONS: magic = "ID3%c\x00" % ver_major magics.append((magic, 0)) # MPEG frame magic # TODO: Use longer magic: 32 bits instead of 16 bits SYNC_BITS = 2047 for version in Frame.VERSION_NAME.iterkeys(): for layer in Frame.LAYER_NAME.iterkeys(): for crc16 in (0, 1): magic = (SYNC_BITS << 5) | (version << 3) | (layer << 1) | crc16 magic = long2raw(magic, BIG_ENDIAN, 2) magics.append((magic, 0)) return magics
def writeInteger(self, value, signed, size_byte, endian): if signed: value += 1 << (size_byte * 8 - 1) raw = long2raw(value, endian, size_byte) self.writeBytes(raw)
class PythonCompiledFile(Parser): PARSER_TAGS = { "id": "python", "category": "program", "file_ext": ("pyc", "pyo"), "min_size": 9 * 8, "description": "Compiled Python script (.pyc/.pyo files)" } endian = LITTLE_ENDIAN # Dictionnary which associate the pyc signature (32-bit integer) # to a Python version string (eg. "m\xf2\r\n" => "Python 2.4b1"). # This list comes from CPython source code, see MAGIC_NUMBER # in file Lib/importlib/_bootstrap_external.py MAGIC = { # Python 1.x 20121: ("1.5", 0x1050000), 50428: ("1.6", 0x1060000), # Python 2.x 50823: ("2.0", 0x2000000), 60202: ("2.1", 0x2010000), 60717: ("2.2", 0x2020000), 62011: ("2.3a0", 0x2030000), 62021: ("2.3a0", 0x2030000), 62041: ("2.4a0", 0x2040000), 62051: ("2.4a3", 0x2040000), 62061: ("2.4b1", 0x2040000), 62071: ("2.5a0", 0x2050000), 62081: ("2.5a0 (ast-branch)", 0x2050000), 62091: ("2.5a0 (with)", 0x2050000), 62092: ("2.5a0 (WITH_CLEANUP opcode)", 0x2050000), 62101: ("2.5b3", 0x2050000), 62111: ("2.5b3", 0x2050000), 62121: ("2.5c1", 0x2050000), 62131: ("2.5c2", 0x2050000), 62151: ("2.6a0", 0x2070000), 62161: ("2.6a1", 0x2070000), 62171: ("2.7a0", 0x2070000), 62181: ("2.7a0", 0x2070000), 62191: ("2.7a0", 0x2070000), 62201: ("2.7a0", 0x2070000), 62211: ("2.7a0", 0x2070000), # Python 3.x 3000: ("3.0 (3000)", 0x3000000), 3010: ("3.0 (3010)", 0x3000000), 3020: ("3.0 (3020)", 0x3000000), 3030: ("3.0 (3030)", 0x3000000), 3040: ("3.0 (3040)", 0x3000000), 3050: ("3.0 (3050)", 0x3000000), 3060: ("3.0 (3060)", 0x3000000), 3061: ("3.0 (3061)", 0x3000000), 3071: ("3.0 (3071)", 0x3000000), 3081: ("3.0 (3081)", 0x3000000), 3091: ("3.0 (3091)", 0x3000000), 3101: ("3.0 (3101)", 0x3000000), 3103: ("3.0 (3103)", 0x3000000), 3111: ("3.0a4", 0x3000000), 3131: ("3.0a5", 0x3000000), 3141: ("3.1a0", 0x3010000), 3151: ("3.1a0", 0x3010000), 3160: ("3.2a0", 0x3020000), 3170: ("3.2a1", 0x3020000), 3180: ("3.2a2", 0x3020000), 3190: ("Python 3.3a0", 0x3030000), 3200: ("Python 3.3a0 ", 0x3030000), 3210: ("Python 3.3a0 ", 0x3030000), 3220: ("Python 3.3a1 ", 0x3030000), 3230: ("Python 3.3a4 ", 0x3030000), 3250: ("Python 3.4a1 ", 0x3040000), 3260: ("Python 3.4a1 ", 0x3040000), 3270: ("Python 3.4a1 ", 0x3040000), 3280: ("Python 3.4a1 ", 0x3040000), 3290: ("Python 3.4a4 ", 0x3040000), 3300: ("Python 3.4a4 ", 0x3040000), 3310: ("Python 3.4rc2", 0x3040000), 3320: ("Python 3.5a0 ", 0x3050000), 3330: ("Python 3.5b1 ", 0x3050000), 3340: ("Python 3.5b2 ", 0x3050000), 3350: ("Python 3.5b2 ", 0x3050000), 3351: ("Python 3.5.2 ", 0x3050000), 3360: ("Python 3.6a0 ", 0x3060000), 3361: ("Python 3.6a0 ", 0x3060000), 3370: ("Python 3.6a1 ", 0x3060000), 3371: ("Python 3.6a1 ", 0x3060000), 3372: ("Python 3.6a1 ", 0x3060000), 3373: ("Python 3.6b1 ", 0x3060000), 3375: ("Python 3.6b1 ", 0x3060000), 3376: ("Python 3.6b1 ", 0x3060000), 3377: ("Python 3.6b1 ", 0x3060000), 3378: ("Python 3.6b2 ", 0x3060000), 3379: ("Python 3.6rc1", 0x3060000), 3390: ("Python 3.7a0 ", 0x3070000), } # Dictionnary which associate the pyc signature (4-byte long string) # to a Python version string (eg. "m\xf2\r\n" => "2.4b1") STR_MAGIC = dict((long2raw(magic | (ord('\r') << 16) | (ord('\n') << 24), LITTLE_ENDIAN), value[0]) for magic, value in MAGIC.items()) def validate(self): magic_number = self["magic_number"].value if magic_number not in self.MAGIC: return "Unknown magic number (%s)" % magic_number if self["magic_string"].value != "\r\n": return r"Wrong magic string (\r\n)" version = self.getVersion() if version >= 0x3030000 and self['magic_number'].value >= 3200: offset = 12 else: offset = 8 value = self.stream.readBits(offset * 8, 7, self.endian) if value != ord(b'c'): return "First object bytecode is not code" return True def getVersion(self): if not hasattr(self, "version"): signature = self.stream.readBits(0, 16, self.endian) self.version = self.MAGIC[signature][1] return self.version def createFields(self): yield UInt16(self, "magic_number", "Magic number") yield String(self, "magic_string", 2, r"Magic string \r\n", charset="ASCII") yield TimestampUnix32(self, "timestamp", "Timestamp") version = self.getVersion() if version >= 0x3030000 and self['magic_number'].value >= 3200: yield UInt32(self, "filesize", "Size of the Python source file (.py) modulo 2**32") yield Object(self, "content")