JS混淆助手类

先看效果:

string js = @"var a=1
              alert(a);//注释1
              alert(a);/*注释2*/";
string result = PackBus.PackJavascript(js).Replace("
", "
");

result:
eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fr.............

助手类:

using System;
using System.Collections;
using System.Collections.Specialized;
using System.Text;
using System.Text.RegularExpressions;

/*
    packer, version 2.0 (beta) (2005/02/01)
    Copyright 2004-2005, Dean Edwards
    Web: http://dean.edwards.name/

    This software is licensed under the CC-GNU LGPL
    Web: http://creativecommons.org/licenses/LGPL/2.1/
    
    Ported to C# by Jesse Hansen, twindagger2k@msn.com

    http://dean.edwards.name/packer/
*/

namespace MeShop.Web.Pack
{
    /// <summary>
    /// Packs a javascript file into a smaller area, removing unnecessary characters from the output.
    /// </summary>
    public class ECMAScriptPacker
    {
        /// <summary>
        /// The encoding level to use. See http://dean.edwards.name/packer/usage/ for more info.
        /// </summary>
        public enum PackerEncoding { None = 0, Numeric = 10, Mid = 36, Normal = 62, HighAscii = 95 };

        private PackerEncoding encoding = PackerEncoding.Normal;
        private bool fastDecode = true;
        private bool specialChars = false;
        private bool enabled = true;

        string IGNORE = "$1";

        /// <summary>
        /// The encoding level for this instance
        /// </summary>
        public PackerEncoding Encoding
        {
            get { return encoding; }
            set { encoding = value; }
        }

        /// <summary>
        /// Adds a subroutine to the output to speed up decoding
        /// </summary>
        public bool FastDecode
        {
            get { return fastDecode; }
            set { fastDecode = value; }
        }

        /// <summary>
        /// Replaces special characters
        /// </summary>
        public bool SpecialChars
        {
            get { return specialChars; }
            set { specialChars = value; }
        }

        /// <summary>
        /// Packer enabled
        /// </summary>
        public bool Enabled
        {
            get { return enabled; }
            set { enabled = value; }
        }

        public ECMAScriptPacker()
        {
            Encoding = PackerEncoding.Normal;
            FastDecode = true;
            SpecialChars = false;
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="encoding">The encoding level for this instance</param>
        /// <param name="fastDecode">Adds a subroutine to the output to speed up decoding</param>
        /// <param name="specialChars">Replaces special characters</param>
        public ECMAScriptPacker(PackerEncoding encoding, bool fastDecode, bool specialChars)
        {
            Encoding = encoding;
            FastDecode = fastDecode;
            SpecialChars = specialChars;
        }

        /// <summary>
        /// Packs the script
        /// </summary>
        /// <param name="script">the script to pack</param>
        /// <returns>the packed script</returns>
        public string Pack(string script)
        {
            if (enabled)
            {
                script += "
";
                script = basicCompression(script);
                if (SpecialChars)
                    script = encodeSpecialChars(script);
                if (Encoding != PackerEncoding.None)
                    script = encodeKeywords(script);
            }
            return script;
        }

        //zero encoding - just removal of whitespace and comments
        private string basicCompression(string script)
        {
            ParseMaster parser = new ParseMaster();
            // make safe
            parser.EscapeChar = '\';
            // protect strings
            parser.Add("'[^'\n\r]*'", IGNORE);
            parser.Add(""[^"\n\r]*"", IGNORE);
            // remove comments
            parser.Add("\/\/[^\n\r]*[\n\r]");
            parser.Add("\/\*[^*]*\*+([^\/][^*]*\*+)*\/");
            // protect regular expressions
            parser.Add("\s+(\/[^\/\n\r\*][^\/\n\r]*\/g?i?)", "$2");
            parser.Add("[^\w\$\/'"*)\?:]\/[^\/\n\r\*][^\/\n\r]*\/g?i?", IGNORE);
            // remove: ;;; doSomething();
            if (specialChars)
                parser.Add(";;[^\n\r]+[\n\r]");
            // remove redundant semi-colons
            parser.Add(";+\s*([};])", "$2");
            // remove white-space
            parser.Add("(\b|\$)\s+(\b|\$)", "$2 $3");
            parser.Add("([+\-])\s+([+\-])", "$2 $3");
            parser.Add("\s+");
            // done
            return parser.Exec(script);
        }

        WordList encodingLookup;
        private string encodeSpecialChars(string script)
        {
            ParseMaster parser = new ParseMaster();
            // replace: $name -> n, $$name -> na
            parser.Add("((\$+)([a-zA-Z\$_]+))(\d*)",
                new ParseMaster.MatchGroupEvaluator(encodeLocalVars));

            // replace: _name -> _0, double-underscore (__name) is ignored
            Regex regex = new Regex("\b_[A-Za-z\d]\w*", RegexOptions.None, TimeSpan.FromSeconds(2));

            // build the word list
            encodingLookup = analyze(script, regex, new EncodeMethod(encodePrivate));

            parser.Add("\b_[A-Za-z\d]\w*", new ParseMaster.MatchGroupEvaluator(encodeWithLookup));

            script = parser.Exec(script);
            return script;
        }

        private string encodeKeywords(string script)
        {
            // escape high-ascii values already in the script (i.e. in strings)
            if (Encoding == PackerEncoding.HighAscii) script = escape95(script);
            // create the parser
            ParseMaster parser = new ParseMaster();
            EncodeMethod encode = getEncoder(Encoding);

            // for high-ascii, don't encode single character low-ascii
            Regex regex = new Regex(
                    (Encoding == PackerEncoding.HighAscii) ? "\w\w+" : "\w+", RegexOptions.None, TimeSpan.FromSeconds(2)
                );
            // build the word list
            encodingLookup = analyze(script, regex, encode);

            // encode
            parser.Add((Encoding == PackerEncoding.HighAscii) ? "\w\w+" : "\w+",
                new ParseMaster.MatchGroupEvaluator(encodeWithLookup));

            // if encoded, wrap the script in a decoding function
            return (script == string.Empty) ? "" : bootStrap(parser.Exec(script), encodingLookup);
        }

        private string bootStrap(string packed, WordList keywords)
        {
            // packed: the packed script
            packed = "'" + escape(packed) + "'";

            // ascii: base for encoding
            int ascii = Math.Min(keywords.Sorted.Count, (int)Encoding);
            if (ascii == 0)
                ascii = 1;

            // count: number of words contained in the script
            int count = keywords.Sorted.Count;

            // keywords: list of words contained in the script
            foreach (object key in keywords.Protected.Keys)
            {
                keywords.Sorted[(int)key] = "";
            }
            // convert from a string to an array
            StringBuilder sbKeywords = new StringBuilder("'");
            foreach (string word in keywords.Sorted)
                sbKeywords.Append(word + "|");
            sbKeywords.Remove(sbKeywords.Length - 1, 1);
            string keywordsout = sbKeywords.ToString() + "'.split('|')";

            string encode;
            string inline = "c";

            switch (Encoding)
            {
                case PackerEncoding.Mid:
                    encode = "function(c){return c.toString(36)}";
                    inline += ".toString(a)";
                    break;
                case PackerEncoding.Normal:
                    encode = "function(c){return(c<a?"":e(parseInt(c/a)))+" +
                        "((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))}";
                    inline += ".toString(a)";
                    break;
                case PackerEncoding.HighAscii:
                    encode = "function(c){return(c<a?"":e(c/a))+" +
                        "String.fromCharCode(c%a+161)}";
                    inline += ".toString(a)";
                    break;
                default:
                    encode = "function(c){return c}";
                    break;
            }

            // decode: code snippet to speed up decoding
            string decode = "";
            if (fastDecode)
            {
                decode = "if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1;}";
                if (Encoding == PackerEncoding.HighAscii)
                    decode = decode.Replace("\\w", "[\xa1-\xff]");
                else if (Encoding == PackerEncoding.Numeric)
                    decode = decode.Replace("e(c)", inline);
                if (count == 0)
                    decode = decode.Replace("c=1", "c=0");
            }

            // boot function
            string unpack = "function(p,a,c,k,e,d){while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p;}";
            Regex r;
            if (fastDecode)
            {
                //insert the decoder
                r = new Regex("\{", RegexOptions.None, TimeSpan.FromSeconds(2));
                unpack = r.Replace(unpack, "{" + decode + ";", 1);
            }

            if (Encoding == PackerEncoding.HighAscii)
            {
                // get rid of the word-boundries for regexp matches
                r = new Regex("'\\\\b'\s*\+|\+\s*'\\\\b'", RegexOptions.None, TimeSpan.FromSeconds(2));
                unpack = r.Replace(unpack, "");
            }
            if (Encoding == PackerEncoding.HighAscii || ascii > (int)PackerEncoding.Normal || fastDecode)
            {
                // insert the encode function
                r = new Regex("\{", RegexOptions.None, TimeSpan.FromSeconds(2));
                unpack = r.Replace(unpack, "{e=" + encode + ";", 1);
            }
            else
            {
                r = new Regex("e\(c\)", RegexOptions.None, TimeSpan.FromSeconds(2));
                unpack = r.Replace(unpack, inline);
            }
            // no need to pack the boot function since i've already done it
            string _params = "" + packed + "," + ascii + "," + count + "," + keywordsout;
            if (fastDecode)
            {
                //insert placeholders for the decoder
                _params += ",0,{}";
            }
            // the whole thing
            return "eval(" + unpack + "(" + _params + "))
";
        }

        private string escape(string input)
        {
            Regex r = new Regex("([\\'])", RegexOptions.None, TimeSpan.FromSeconds(2));
            return r.Replace(input, "\$1");
        }

        private EncodeMethod getEncoder(PackerEncoding encoding)
        {
            switch (encoding)
            {
                case PackerEncoding.Mid:
                    return new EncodeMethod(encode36);
                case PackerEncoding.Normal:
                    return new EncodeMethod(encode62);
                case PackerEncoding.HighAscii:
                    return new EncodeMethod(encode95);
                default:
                    return new EncodeMethod(encode10);
            }
        }

        private string encode10(int code)
        {
            return code.ToString();
        }

        //lookups seemed like the easiest way to do this since 
        // I don't know of an equivalent to .toString(36)
        private static string lookup36 = "0123456789abcdefghijklmnopqrstuvwxyz";

        private string encode36(int code)
        {
            string encoded = "";
            int i = 0;
            do
            {
                int digit = (code / (int)Math.Pow(36, i)) % 36;
                encoded = lookup36[digit] + encoded;
                code -= digit * (int)Math.Pow(36, i++);
            } while (code > 0);
            return encoded;
        }

        private static string lookup62 = lookup36 + "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

        private string encode62(int code)
        {
            string encoded = "";
            int i = 0;
            do
            {
                int digit = (code / (int)Math.Pow(62, i)) % 62;
                encoded = lookup62[digit] + encoded;
                code -= digit * (int)Math.Pow(62, i++);
            } while (code > 0);
            return encoded;
        }

        private static string lookup95 = "、¥ウЖ┆���辈炒刀犯购患骄坷谅媚牌侨墒颂臀闲岩釉罩棕仝圮蒉哙徕沅彐玷殛腱眍镳耱篝貊鼬���";

        private string encode95(int code)
        {
            string encoded = "";
            int i = 0;
            do
            {
                int digit = (code / (int)Math.Pow(95, i)) % 95;
                encoded = lookup95[digit] + encoded;
                code -= digit * (int)Math.Pow(95, i++);
            } while (code > 0);
            return encoded;
        }

        private string escape95(string input)
        {
            Regex r = new Regex("[xa1-xff]", RegexOptions.None, TimeSpan.FromSeconds(2));
            return r.Replace(input, new MatchEvaluator(escape95Eval));
        }

        private string escape95Eval(Match match)
        {
            return "\x" + ((int)match.Value[0]).ToString("x"); //return hexadecimal value
        }

        private string encodeLocalVars(Match match, int offset)
        {
            int length = match.Groups[offset + 2].Length;
            int start = length - Math.Max(length - match.Groups[offset + 3].Length, 0);
            return match.Groups[offset + 1].Value.Substring(start, length) +
                match.Groups[offset + 4].Value;
        }

        private string encodeWithLookup(Match match, int offset)
        {
            return (string)encodingLookup.Encoded[match.Groups[offset].Value];
        }

        private delegate string EncodeMethod(int code);

        private string encodePrivate(int code)
        {
            return "_" + code;
        }

        private WordList analyze(string input, Regex regex, EncodeMethod encodeMethod)
        {
            // analyse
            // retreive all words in the script
            MatchCollection all = regex.Matches(input);
            WordList rtrn;
            rtrn.Sorted = new StringCollection(); // list of words sorted by frequency
            rtrn.Protected = new HybridDictionary(); // dictionary of word->encoding
            rtrn.Encoded = new HybridDictionary(); // instances of "protected" words
            if (all.Count > 0)
            {
                StringCollection unsorted = new StringCollection(); // same list, not sorted
                HybridDictionary Protected = new HybridDictionary(); // "protected" words (dictionary of word->"word")
                HybridDictionary values = new HybridDictionary(); // dictionary of charCode->encoding (eg. 256->ff)
                HybridDictionary count = new HybridDictionary(); // word->count
                int i = all.Count, j = 0;
                string word;
                // count the occurrences - used for sorting later
                do
                {
                    word = "$" + all[--i].Value;
                    if (count[word] == null)
                    {
                        count[word] = 0;
                        unsorted.Add(word);
                        // make a dictionary of all of the protected words in this script
                        //  these are words that might be mistaken for encoding
                        Protected["$" + (values[j] = encodeMethod(j))] = j++;
                    }
                    // increment the word counter
                    count[word] = (int)count[word] + 1;
                } while (i > 0);
                /* prepare to sort the word list, first we must protect
                    words that are also used as codes. we assign them a code
                    equivalent to the word itself.
                   e.g. if "do" falls within our encoding range
                        then we store keywords["do"] = "do";
                   this avoids problems when decoding */
                i = unsorted.Count;
                string[] sortedarr = new string[unsorted.Count];
                do
                {
                    word = unsorted[--i];
                    if (Protected[word] != null)
                    {
                        sortedarr[(int)Protected[word]] = word.Substring(1);
                        rtrn.Protected[(int)Protected[word]] = true;
                        count[word] = 0;
                    }
                } while (i > 0);
                string[] unsortedarr = new string[unsorted.Count];
                unsorted.CopyTo(unsortedarr, 0);
                // sort the words by frequency
                Array.Sort(unsortedarr, (IComparer)new CountComparer(count));
                j = 0;
                /*because there are "protected" words in the list
                  we must add the sorted words around them */
                do
                {
                    if (sortedarr[i] == null)
                        sortedarr[i] = unsortedarr[j++].Substring(1);
                    rtrn.Encoded[sortedarr[i]] = values[i];
                } while (++i < unsortedarr.Length);
                rtrn.Sorted.AddRange(sortedarr);
            }
            return rtrn;
        }

        private struct WordList
        {
            public StringCollection Sorted;
            public HybridDictionary Encoded;
            public HybridDictionary Protected;
        }

        private class CountComparer : IComparer
        {
            HybridDictionary count;

            public CountComparer(HybridDictionary count)
            {
                this.count = count;
            }

            #region IComparer Members

            public int Compare(object x, object y)
            {
                return (int)count[y] - (int)count[x];
            }

            #endregion
        }
    }
}
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Text;
using System.Text.RegularExpressions;

/*
    ParseMaster, version 1.0 (pre-release) (2005/02/01) x4
    Copyright 2005, Dean Edwards
    Web: http://dean.edwards.name/

    This software is licensed under the CC-GNU LGPL
    Web: http://creativecommons.org/licenses/LGPL/2.1/

    Ported to C# by Jesse Hansen, twindagger2k@msn.com
*/

namespace MeShop.Web.Pack
{
    /// <summary>
    /// a multi-pattern parser
    /// </summary>
    public class ParseMaster
    {
        // used to determine nesting levels
        Regex GROUPS = new Regex("\(", RegexOptions.None, TimeSpan.FromSeconds(2)),
            SUB_REPLACE = new Regex("\$", RegexOptions.None, TimeSpan.FromSeconds(2)),
            INDEXED = new Regex("^\$\d+$", RegexOptions.None, TimeSpan.FromSeconds(2)),
            ESCAPE = new Regex("\\.", RegexOptions.None, TimeSpan.FromSeconds(2)),
            QUOTE = new Regex("'", RegexOptions.None, TimeSpan.FromSeconds(2)),
            DELETED = new Regex("\x01[^\x01]*\x01", RegexOptions.None, TimeSpan.FromSeconds(2));

        /// <summary>
        /// Delegate to call when a regular expression is found.
        /// Use match.Groups[offset + &lt;group number&gt;].Value to get
        /// the correct subexpression
        /// </summary>
        public delegate string MatchGroupEvaluator(Match match, int offset);

        private string DELETE(Match match, int offset)
        {
            return "x01" + match.Groups[offset].Value + "x01";
        }

        private bool ignoreCase = false;
        private char escapeChar = '';

        /// <summary>
        /// Ignore Case?
        /// </summary>
        public bool IgnoreCase
        {
            get { return ignoreCase; }
            set { ignoreCase = value; }
        }

        /// <summary>
        /// Escape Character to use
        /// </summary>
        public char EscapeChar
        {
            get { return escapeChar; }
            set { escapeChar = value; }
        }

        /// <summary>
        /// Add an expression to be deleted
        /// </summary>
        /// <param name="expression">Regular Expression String</param>
        public void Add(string expression)
        {
            Add(expression, string.Empty);
        }

        /// <summary>
        /// Add an expression to be replaced with the replacement string
        /// </summary>
        /// <param name="expression">Regular Expression String</param>
        /// <param name="replacement">Replacement String. Use $1, $2, etc. for groups</param>
        public void Add(string expression, string replacement)
        {
            if (replacement == string.Empty)
                add(expression, new MatchGroupEvaluator(DELETE));

            add(expression, replacement);
        }

        /// <summary>
        /// Add an expression to be replaced using a callback function
        /// </summary>
        /// <param name="expression">Regular expression string</param>
        /// <param name="replacement">Callback function</param>
        public void Add(string expression, MatchGroupEvaluator replacement)
        {
            add(expression, replacement);
        }

        /// <summary>
        /// Executes the parser
        /// </summary>
        /// <param name="input">input string</param>
        /// <returns>parsed string</returns>
        public string Exec(string input)
        {
            return DELETED.Replace(unescape(getPatterns().Replace(escape(input), new MatchEvaluator(replacement))), string.Empty);
            //long way for debugging
            /*input = escape(input);
            Regex patterns = getPatterns();
            input = patterns.Replace(input, new MatchEvaluator(replacement));
            input = DELETED.Replace(input, string.Empty);
            return input;*/
        }

        ArrayList patterns = new ArrayList();
        private void add(string expression, object replacement)
        {
            Pattern pattern = new Pattern();
            pattern.expression = expression;
            pattern.replacement = replacement;
            //count the number of sub-expressions
            // - add 1 because each group is itself a sub-expression
            pattern.length = GROUPS.Matches(internalEscape(expression)).Count + 1;

            //does the pattern deal with sup-expressions?
            if (replacement is string && SUB_REPLACE.IsMatch((string)replacement))
            {
                string sreplacement = (string)replacement;
                // a simple lookup (e.g. $2)
                if (INDEXED.IsMatch(sreplacement))
                {
                    pattern.replacement = int.Parse(sreplacement.Substring(1)) - 1;
                }
            }

            patterns.Add(pattern);
        }

        /// <summary>
        /// builds the patterns into a single regular expression
        /// </summary>
        /// <returns></returns>
        private Regex getPatterns()
        {
            StringBuilder rtrn = new StringBuilder(string.Empty);
            foreach (object pattern in patterns)
            {
                rtrn.Append(((Pattern)pattern).ToString() + "|");
            }
            rtrn.Remove(rtrn.Length - 1, 1);
            return new Regex(rtrn.ToString(), ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None, TimeSpan.FromSeconds(2));
        }

        /// <summary>
        /// Global replacement function. Called once for each match found
        /// </summary>
        /// <param name="match">Match found</param>
        private string replacement(Match match)
        {
            int i = 1, j = 0;
            Pattern pattern;
            //loop through the patterns
            while (!((pattern = (Pattern)patterns[j++]) == null))
            {
                //do we have a result?
                if (match.Groups[i].Value != string.Empty)
                {
                    object replacement = pattern.replacement;
                    if (replacement is MatchGroupEvaluator)
                    {
                        return ((MatchGroupEvaluator)replacement)(match, i);
                    }
                    else if (replacement is int)
                    {
                        return match.Groups[(int)replacement + i].Value;
                    }
                    else
                    {
                        //string, send to interpreter
                        return replacementString(match, i, (string)replacement, pattern.length);
                    }
                }
                else //skip over references to sub-expressions
                    i += pattern.length;
            }
            return match.Value; //should never be hit, but you never know
        }

        /// <summary>
        /// Replacement function for complicated lookups (e.g. Hello $3 $2)
        /// </summary>
        private string replacementString(Match match, int offset, string replacement, int length)
        {
            while (length > 0)
            {
                replacement = replacement.Replace("$" + length--, match.Groups[offset + length].Value);
            }
            return replacement;
        }

        private StringCollection escaped = new StringCollection();

        //encode escaped characters
        private string escape(string str)
        {
            if (escapeChar == '')
                return str;
            Regex escaping = new Regex("\\(.)", RegexOptions.None, TimeSpan.FromSeconds(2));
            return escaping.Replace(str, new MatchEvaluator(escapeMatch));
        }

        private string escapeMatch(Match match)
        {
            escaped.Add(match.Groups[1].Value);
            return "\";
        }

        //decode escaped characters
        private int unescapeIndex = 0;
        private string unescape(string str)
        {
            if (escapeChar == '')
                return str;
            Regex unescaping = new Regex("\" + escapeChar, RegexOptions.None, TimeSpan.FromSeconds(2));
            return unescaping.Replace(str, new MatchEvaluator(unescapeMatch));
        }

        private string unescapeMatch(Match match)
        {
            return "\" + escaped[unescapeIndex++];
        }

        private string internalEscape(string str)
        {
            return ESCAPE.Replace(str, "");
        }

        //subclass for each pattern
        private class Pattern
        {
            public string expression;
            public object replacement;
            public int length;

            public override string ToString()
            {
                return "(" + expression + ")";
            }
        }
    }
}
原文地址:https://www.cnblogs.com/fanfan-90/p/13914294.html