1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 | var esprima = require('esprima');
|
12 | var util = require('util');
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 | function encodeUnicode(str) {
|
20 | return String(str).replace(/[^\x09-\x7f\ufeff]/g, function (all) {
|
21 | return '\\u' + (0x10000 + all.charCodeAt()).toString(16).substring(1);
|
22 | });
|
23 | }
|
24 | var crossChars = [];
|
25 | for (var i = 0; i < 36; i++) {
|
26 | crossChars.push(String.fromCharCode(0x0620 + i) + String.fromCharCode(0x0300 + i));
|
27 | }
|
28 | function crossCode(index) {
|
29 | return index.toString(36).replace(/./g, function (all) {
|
30 | return crossChars[parseInt(all, 36)];
|
31 | });
|
32 | }
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 | function obfuscate(code, options) {
|
42 | if (!code) {
|
43 | return code;
|
44 | }
|
45 | options = options || {};
|
46 | code = String(code).replace(/\r\n?|[\n\u2028\u2029]/g, '\n')
|
47 | .replace(/^\uFEFF/, '');
|
48 | var syntax = esprima.parse(code, {
|
49 | range: true,
|
50 | loc: false
|
51 | });
|
52 | var memberExpressions = [];
|
53 | var propertys = {};
|
54 | var names = [];
|
55 | var expressions = [];
|
56 | var guid = 0;
|
57 | function scan(obj) {
|
58 | if (!obj) {
|
59 | return;
|
60 | }
|
61 | if (obj.type === 'MemberExpression') {
|
62 | if (obj.property.type === 'Literal' ||
|
63 | (obj.property.type === 'Identifier' && !obj.computed)) {
|
64 | memberExpressions.push(obj);
|
65 | var name = JSON.stringify(obj.property.type === 'Literal' ?
|
66 | obj.property.raw : obj.property.name);
|
67 | if (!propertys[name]) {
|
68 | propertys[name] = '$jfogs$' + (guid++);
|
69 | names.push(propertys[name]);
|
70 | expressions.push(name);
|
71 | }
|
72 | }
|
73 | }
|
74 | for (var key in obj) {
|
75 | if (typeof obj[key] === 'object') {
|
76 | scan(obj[key]);
|
77 | }
|
78 | }
|
79 | }
|
80 | scan(syntax);
|
81 | memberExpressions.sort(function (a, b) {
|
82 | return b.property.range[0] - a.property.range[1];
|
83 | });
|
84 | if (options.cross) {
|
85 | expressions.forEach(function (expression, index) {
|
86 | propertys[expression] = '$jfogs$prop.' + crossCode(index);
|
87 | });
|
88 | }
|
89 | memberExpressions.forEach(function (obj) {
|
90 | var name = JSON.stringify(obj.property.type === 'Literal' ?
|
91 | obj.property.raw : obj.property.name);
|
92 | if (obj.property.type === 'Literal') {
|
93 | code = code.slice(0, obj.property.range[0]) + propertys[name] +
|
94 | code.slice(obj.property.range[1]);
|
95 | }
|
96 | else {
|
97 | code = code.slice(0, obj.object.range[1]) +
|
98 | '[' + propertys[name] + ']' +
|
99 | code.slice(obj.property.range[1]);
|
100 | }
|
101 | });
|
102 | var decryption = '';
|
103 | switch (options.type) {
|
104 | case 'zero':
|
105 | expressions = expressions.map(function (item) {
|
106 | var t = parseInt('10000000', 2);
|
107 | return '"' + encodeUnicode(JSON.parse(item)).replace(/[^]/g, function (all) {
|
108 | return (t + all.charCodeAt()).toString(2).substring(1).replace(/[^]/g, function (n) {
|
109 | return {
|
110 | 0: '\u200c',
|
111 | 1: '\u200d'
|
112 | }[n];
|
113 | });
|
114 | }) + '"';
|
115 | });
|
116 | decryption = '' +
|
117 | 'var $jfogs$argv = arguments;\n' +
|
118 | 'for (var $jfogs$i = 0; $jfogs$i < $jfogs$argv.length; $jfogs$i++) {\n' +
|
119 | ' $jfogs$argv[$jfogs$i] = $jfogs$argv[$jfogs$i].replace(/./g,\n' +
|
120 | ' function (a) {\n' +
|
121 | ' return {\n' +
|
122 | ' "\u200c": 0,\n' +
|
123 | ' "\u200d": 1\n' +
|
124 | ' }[a]\n' +
|
125 | ' }\n' +
|
126 | ' ).replace(/.{7}/g, function (a) {\n' +
|
127 | ' return String.fromCharCode(parseInt(a, 2));\n' +
|
128 | ' });\n' +
|
129 | '}\n';
|
130 | break;
|
131 | case 'reverse':
|
132 | expressions = expressions.map(function (item) {
|
133 | return item.split('').reverse().join('');
|
134 | });
|
135 | decryption = '' +
|
136 | 'var $jfogs$argv = arguments;\n' +
|
137 | 'for (var $jfogs$i = 0; $jfogs$i < $jfogs$argv.length; $jfogs$i++) {\n' +
|
138 | ' $jfogs$argv[$jfogs$i] = $jfogs$argv[$jfogs$i].split("").reverse().join("");\n' +
|
139 | '}\n';
|
140 | break;
|
141 | }
|
142 | if (options.cross) {
|
143 | decryption += 'var $jfogs$prop = {};\n';
|
144 | expressions.forEach(function (expression, index) {
|
145 | decryption += util.format('$jfogs$prop.%s = %s;\n', crossCode(index), names[index]);
|
146 | });
|
147 | }
|
148 | return util.format('(function (%s) {\n%s\n%s\n})(%s);',
|
149 | names.join(', '),
|
150 | decryption,
|
151 | code,
|
152 | expressions.join(', ')
|
153 | );
|
154 | }
|
155 | exports.obfuscate = obfuscate; |
\ | No newline at end of file |