diff options
Diffstat (limited to 'venv/lib/python3.11/site-packages/jsbeautifier/unpackers/packer.py')
-rw-r--r-- | venv/lib/python3.11/site-packages/jsbeautifier/unpackers/packer.py | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/venv/lib/python3.11/site-packages/jsbeautifier/unpackers/packer.py b/venv/lib/python3.11/site-packages/jsbeautifier/unpackers/packer.py new file mode 100644 index 0000000..117ff58 --- /dev/null +++ b/venv/lib/python3.11/site-packages/jsbeautifier/unpackers/packer.py @@ -0,0 +1,161 @@ +# +# Unpacker for Dean Edward's p.a.c.k.e.r, a part of javascript beautifier +# by Einar Lielmanis <einar@beautifier.io> +# +# written by Stefano Sanfilippo <a.little.coder@gmail.com> +# +# usage: +# +# if detect(some_string): +# unpacked = unpack(some_string) +# + +"""Unpacker for Dean Edward's p.a.c.k.e.r""" + +import re +import string +import sys +from jsbeautifier.unpackers import UnpackingError + +PRIORITY = 1 + + +def detect(source): + global beginstr + global endstr + beginstr = "" + endstr = "" + begin_offset = -1 + """Detects whether `source` is P.A.C.K.E.R. coded.""" + mystr = re.search( + r"eval[ ]*\([ ]*function[ ]*\([ ]*p[ ]*,[ ]*a[ ]*,[ ]*c[" + " ]*,[ ]*k[ ]*,[ ]*e[ ]*,[ ]*", + source, + ) + if mystr: + begin_offset = mystr.start() + beginstr = source[:begin_offset] + if begin_offset != -1: + """Find endstr""" + source_end = source[begin_offset:] + if source_end.split("')))", 1)[0] == source_end: + try: + endstr = source_end.split("}))", 1)[1] + except IndexError: + endstr = "" + else: + endstr = source_end.split("')))", 1)[1] + return mystr is not None + + +def unpack(source): + """Unpacks P.A.C.K.E.R. packed js code.""" + payload, symtab, radix, count = _filterargs(source) + + if count != len(symtab): + raise UnpackingError("Malformed p.a.c.k.e.r. symtab.") + + try: + unbase = Unbaser(radix) + except TypeError: + raise UnpackingError("Unknown p.a.c.k.e.r. encoding.") + + def lookup(match): + """Look up symbols in the synthetic symtab.""" + word = match.group(0) + return symtab[unbase(word)] or word + + payload = payload.replace("\\\\", "\\").replace("\\'", "'") + if sys.version_info.major == 2: + source = re.sub(r"\b\w+\b", lookup, payload) + else: + source = re.sub(r"\b\w+\b", lookup, payload, flags=re.ASCII) + return _replacestrings(source) + + +def _filterargs(source): + """Juice from a source file the four args needed by decoder.""" + juicers = [ + (r"}\('(.*)', *(\d+|\[\]), *(\d+), *'(.*)'\.split\('\|'\), *(\d+), *(.*)\)\)"), + (r"}\('(.*)', *(\d+|\[\]), *(\d+), *'(.*)'\.split\('\|'\)"), + ] + for juicer in juicers: + args = re.search(juicer, source, re.DOTALL) + if args: + a = args.groups() + if a[1] == "[]": + a = list(a) + a[1] = 62 + a = tuple(a) + try: + return a[0], a[3].split("|"), int(a[1]), int(a[2]) + except ValueError: + raise UnpackingError("Corrupted p.a.c.k.e.r. data.") + + # could not find a satisfying regex + raise UnpackingError( + "Could not make sense of p.a.c.k.e.r data (unexpected code structure)" + ) + + +def _replacestrings(source): + global beginstr + global endstr + """Strip string lookup table (list) and replace values in source.""" + match = re.search(r'var *(_\w+)\=\["(.*?)"\];', source, re.DOTALL) + + if match: + varname, strings = match.groups() + startpoint = len(match.group(0)) + lookup = strings.split('","') + variable = "%s[%%d]" % varname + for index, value in enumerate(lookup): + source = source.replace(variable % index, '"%s"' % value) + return source[startpoint:] + return beginstr + source + endstr + + +class Unbaser(object): + """Functor for a given base. Will efficiently convert + strings to natural numbers.""" + + ALPHABET = { + 62: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + 95: ( + " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" + ), + } + + def __init__(self, base): + self.base = base + + # fill elements 37...61, if necessary + if 36 < base < 62: + if not hasattr(self.ALPHABET, self.ALPHABET[62][:base]): + self.ALPHABET[base] = self.ALPHABET[62][:base] + # attrs = self.ALPHABET + # print ', '.join("%s: %s" % item for item in attrs.items()) + # If base can be handled by int() builtin, let it do it for us + if 2 <= base <= 36: + self.unbase = lambda string: int(string, base) + else: + # Build conversion dictionary cache + try: + self.dictionary = dict( + (cipher, index) for index, cipher in enumerate(self.ALPHABET[base]) + ) + except KeyError: + raise TypeError("Unsupported base encoding.") + + self.unbase = self._dictunbaser + + def __call__(self, string): + return self.unbase(string) + + def _dictunbaser(self, string): + """Decodes a value to an integer.""" + ret = 0 + for index, cipher in enumerate(string[::-1]): + ret += (self.base**index) * self.dictionary[cipher] + return ret |