diff -r 000000000000 -r ca70ae20a155 src/tools/py2sis/ensymble/decodesisx.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/tools/py2sis/ensymble/decodesisx.py Tue Feb 16 10:07:05 2010 +0530 @@ -0,0 +1,463 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +############################################################################## +# decodesisx.py - Decodes a Symbian OS v9.x SISX file +# Copyright 2006, 2007 Jussi Ylänen +# +# This program is based on a whitepaper by Symbian's Security team: +# Symbian OS v9.X SIS File Format Specification, Version 1.1, June 2006 +# http://developer.symbian.com/main/downloads/papers/SymbianOSv91/softwareinstallsis.pdf +# +# This program is part of Ensymble developer utilities for Symbian OS(TM). +# +# Ensymble is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Ensymble is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ensymble; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# +# +# Version history +# --------------- +# +# v0.09 2006-09-22 +# Replaced every possible range(...) with xrange(...) for efficiency +# +# v0.08 2006-09-12 +# Implemented a SISController dump option (-c, for use with -d and/or -f) +# +# v0.07 2006-09-05 +# Implemented a header hex dump option (-e) +# +# v0.06 2006-08-29 +# Fixed errors in uncompressed SISCompressed field handling +# +# v0.05 2006-08-10 +# Option --dumptofile (-f) now uses a directory for dumped files +# A temporary directory is generated if none given by the user +# Other small corrections and polishing +# +# v0.04 2006-08-09 +# Added command line options using getopt +# Added support for reading the SISX file from stdin +# Made it possible to extract files from SISX +# Improved hexdump ASCII support +# +# v0.03 2006-08-07 +# Added some crude debug features: dumping to files, decompressed data dumping +# +# v0.02 2006-08-06 +# Changed field type flags to callbacks for flexibility +# Added an UID checking and printing +# +# v0.01 2006-08-04 +# Initial version +# +# v0.00 2006-08-03 +# Work started +############################################################################## + +VERSION = "v0.09 2006-09-22" + +import sys +import os +import zlib +import struct +import getopt +import random +import tempfile + +# Parameters +MAXSISFILESIZE = 8 * 1024 * 1024 # Arbitrary maximum size of SISX file + +sisfilename = None +tempdir = None +dumpcounter = 0 +norecursecompressed = False + +class options: + '''Command line options''' + + hexdump = False + headerdump = False + dumpcontroller = False + dumptofile = False + +def mkdtemp(template): + ''' + Create a unique temporary directory. + + tempfile.mkdtemp() was introduced in Python v2.3. This is for + backward compatibility. + ''' + + # Cross-platform way to determine a suitable location for temporary files. + systemp = tempfile.gettempdir() + + if not template.endswith("XXXXXX"): + raise ValueError("invalid template for mkdtemp(): %s" % template) + + for n in xrange(10000): + randchars = [] + for m in xrange(6): + randchars.append(random.choice("abcdefghijklmnopqrstuvwxyz")) + + tempdir = os.path.join(systemp, template[: -6]) + "".join(randchars) + + try: + os.mkdir(tempdir, 0700) + return tempdir + except OSError: + pass + +def hexdump(data, datalen = None): + '''Print binary data as a human readable hex dump.''' + + if datalen == None or datalen > len(data): + datalen = len(data) + + offset = 0 + while offset < datalen: + line = [] + line.append("%06x:" % offset) + for n in xrange(16): + if n & 3 == 0: + line.append(" ") + if (offset + n) < datalen: + c = data[offset + n] + line.append("%02x " % ord(c)) + else: + line.append(" ") + line.append(' "') + for n in xrange(16): + if (offset + n) < datalen: + c = data[offset + n] + if ord(c) >= 32 and ord(c) < 127: + line.append(c) + else: + line.append(".") + else: + break + line.append('"') + + print "".join(line) + offset += 16 + +def handlearray(data, datalen, reclevel): + '''Handle SISArray.''' + + arraytype = data[:4] + data = data[4:] + + arraypos = 0 + arraylen = datalen - 4 + while arraypos < arraylen: + # Construct virtual SISFields for each array element. + arraydata = arraytype + data[arraypos:] + arraypos += parsesisfield(arraydata, + arraylen - arraypos + 4, reclevel + 1) - 4 + + if arraypos != arraylen: + raise ValueError("SISArray data length mismatch") + +def handlecompressed(data, datalen, reclevel): + '''Handle SISCompressed.''' + + if datalen < 12: + raise ValueError("SISCompressed contents too short") + + compalgo = struct.unpack(" datalen: + raise ValueError("SISField contents too short") + + print "%s%s: %d bytes" % (" " * reclevel, fieldname, fieldlen) + + if options.headerdump: + hexdump(data[:headerlen]) + print + + # Call field callback. + sisfieldtypes[fieldtype][1](data[headerlen:], fieldlen, reclevel) + + return headerlen + fieldlen + padlen + +def parsebuffer(data, datalen, reclevel): + '''Parse all successive SISFields.''' + + datapos = 0 + while datapos < datalen: + fieldlen = parsesisfield(data[datapos:], datalen - datapos, reclevel) + datapos += fieldlen + + return datapos + +def main(): + global sisfilename, tempdir, dumpcounter, options + + pgmname = os.path.basename(sys.argv[0]) + pgmversion = VERSION + + try: + try: + gopt = getopt.gnu_getopt + except: + # Python 1 or "--help" in opts.keys() or "-h" in opts.keys(): + # Help requested. + print ( +''' +DecodeSISX - Symbian OS v9.x SISX file decoder %(pgmversion)s + +usage: %(pgmname)s [--dumptofile] [--hexdump] [--dumpdir=DIR] [sisfile] + + -d, --hexdump - Show interesting SISFields as hex dumps + -e, --headerdump - Show SISField headers as hex dumps + -c, --dumpcontroller - Dump each SISController SISField separately + -f, --dumptofile - Save interesting SISFields to files + -t, --dumpdir - Directory to use for dumped files (automatic) + sisfile - SIS file to decode (stdin if not given or -) + +''' % locals()) + return 0 + + if "--hexdump" in opts.keys() or "-d" in opts.keys(): + options.hexdump = True + + if "--headerdump" in opts.keys() or "-e" in opts.keys(): + options.headerdump = True + + if "--dumpcontroller" in opts.keys() or "-c" in opts.keys(): + options.dumpcontroller = True + + if "--dumptofile" in opts.keys() or "-f" in opts.keys(): + options.dumptofile = True + + # A temporary directory is generated by default. + tempdir = opts.get("--dumpdir", opts.get("-t", None)) + + if len(pargs) == 0 or pargs[0] == '-': + sisfilename = "stdin" + sisfile = sys.stdin + else: + sisfilename = pargs[0] + sisfile = file(sisfilename, "rb") + + try: + # Load the whole SIS file as a string. + sisdata = sisfile.read(MAXSISFILESIZE) + if len(sisdata) == MAXSISFILESIZE: + raise IOError("%s: file too large" % sisfilename) + finally: + if sisfile != sys.stdin: + sisfile.close() + + if len(sisdata) < 16: + raise ValueError("%s: file too short" % sisfilename) + + # Check UIDs. + uid1, uid2, uid3, uidcrc = struct.unpack("