corrade-nucleus-nucleons – Blame information for rev 4

Subversion Repositories:
Rev:
Rev Author Line No. Line
2 office 1 #
2 # Unpacker for Dean Edward's p.a.c.k.e.r, a part of javascript beautifier
3 # by Einar Lielmanis <einar@jsbeautifier.org>
4 #
5 # written by Stefano Sanfilippo <a.little.coder@gmail.com>
6 #
7 # usage:
8 #
9 # if detect(some_string):
10 # unpacked = unpack(some_string)
11 #
12  
13 """Unpacker for Dean Edward's p.a.c.k.e.r"""
14  
15 import re
16 import string
17 from jsbeautifier.unpackers import UnpackingError
18  
19 PRIORITY = 1
20  
21 def detect(source):
22 """Detects whether `source` is P.A.C.K.E.R. coded."""
23 return source.replace(' ', '').startswith('eval(function(p,a,c,k,e,')
24  
25 def unpack(source):
26 """Unpacks P.A.C.K.E.R. packed js code."""
27 payload, symtab, radix, count = _filterargs(source)
28  
29 if count != len(symtab):
30 raise UnpackingError('Malformed p.a.c.k.e.r. symtab.')
31  
32 try:
33 unbase = Unbaser(radix)
34 except TypeError:
35 raise UnpackingError('Unknown p.a.c.k.e.r. encoding.')
36  
37 def lookup(match):
38 """Look up symbols in the synthetic symtab."""
39 word = match.group(0)
40 return symtab[unbase(word)] or word
41  
42 source = re.sub(r'\b\w+\b', lookup, payload)
43 return _replacestrings(source)
44  
45 def _filterargs(source):
46 """Juice from a source file the four args needed by decoder."""
47 juicers = [ (r"}\('(.*)', *(\d+), *(\d+), *'(.*)'\.split\('\|'\), *(\d+), *(.*)\)\)"),
48 (r"}\('(.*)', *(\d+), *(\d+), *'(.*)'\.split\('\|'\)"),
49 ]
50 for juicer in juicers:
51 args = re.search(juicer, source, re.DOTALL)
52 if args:
53 a = args.groups()
54 try:
55 return a[0], a[3].split('|'), int(a[1]), int(a[2])
56 except ValueError:
57 raise UnpackingError('Corrupted p.a.c.k.e.r. data.')
58  
59 # could not find a satisfying regex
60 raise UnpackingError('Could not make sense of p.a.c.k.e.r data (unexpected code structure)')
61  
62  
63  
64 def _replacestrings(source):
65 """Strip string lookup table (list) and replace values in source."""
66 match = re.search(r'var *(_\w+)\=\["(.*?)"\];', source, re.DOTALL)
67  
68 if match:
69 varname, strings = match.groups()
70 startpoint = len(match.group(0))
71 lookup = strings.split('","')
72 variable = '%s[%%d]' % varname
73 for index, value in enumerate(lookup):
74 source = source.replace(variable % index, '"%s"' % value)
75 return source[startpoint:]
76 return source
77  
78  
79 class Unbaser(object):
80 """Functor for a given base. Will efficiently convert
81 strings to natural numbers."""
82 ALPHABET = {
83 53 : '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQ',
84 59 : '0123456789abcdefghijklmnopqrstuvwABCDEFGHIJKLMNOPQRSTUVWXYZ',
85 62 : '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
86 95 : (' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ'
87 '[\]^_`abcdefghijklmnopqrstuvwxyz{|}~')
88 }
89  
90 def __init__(self, base):
91 self.base = base
92  
93 # If base can be handled by int() builtin, let it do it for us
94 if 2 <= base <= 36:
95 self.unbase = lambda string: int(string, base)
96 else:
97 # Build conversion dictionary cache
98 try:
99 self.dictionary = dict((cipher, index) for
100 index, cipher in enumerate(self.ALPHABET[base]))
101 except KeyError:
102 raise TypeError('Unsupported base encoding.')
103  
104 self.unbase = self._dictunbaser
105  
106 def __call__(self, string):
107 return self.unbase(string)
108  
109 def _dictunbaser(self, string):
110 """Decodes a value to an integer."""
111 ret = 0
112 for index, cipher in enumerate(string[::-1]):
113 ret += (self.base ** index) * self.dictionary[cipher]
114 return ret