jsfuck.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /*! JSFuck 0.5.0 - http://jsfuck.com */
  2. (function(self){
  3. const MIN = 32, MAX = 126;
  4. const SIMPLE = {
  5. 'false': '![]',
  6. 'true': '!![]',
  7. 'undefined': '[][[]]',
  8. 'NaN': '+[![]]',
  9. 'Infinity': '+(+!+[]+(!+[]+[])[!+[]+!+[]+!+[]]+[+!+[]]+[+[]]+[+[]]+[+[]])' // +"1e1000"
  10. };
  11. const CONSTRUCTORS = {
  12. 'Array': '[]',
  13. 'Number': '(+[])',
  14. 'String': '([]+[])',
  15. 'Boolean': '(![])',
  16. 'Function': '[]["flat"]',
  17. 'RegExp': 'Function("return/"+false+"/")()',
  18. 'Object': '[]["entries"]()'
  19. };
  20. const MAPPING = {
  21. 'a': '(false+"")[1]',
  22. 'b': '([]["entries"]()+"")[2]',
  23. 'c': '([]["flat"]+"")[3]',
  24. 'd': '(undefined+"")[2]',
  25. 'e': '(true+"")[3]',
  26. 'f': '(false+"")[0]',
  27. 'g': '(false+[0]+String)[20]',
  28. 'h': '(+(101))["to"+String["name"]](21)[1]',
  29. 'i': '([false]+undefined)[10]',
  30. 'j': '([]["entries"]()+"")[3]',
  31. 'k': '(+(20))["to"+String["name"]](21)',
  32. 'l': '(false+"")[2]',
  33. 'm': '(Number+"")[11]',
  34. 'n': '(undefined+"")[1]',
  35. 'o': '(true+[]["flat"])[10]',
  36. 'p': '(+(211))["to"+String["name"]](31)[1]',
  37. 'q': '("")["fontcolor"]([0]+false+")[20]',
  38. 'r': '(true+"")[1]',
  39. 's': '(false+"")[3]',
  40. 't': '(true+"")[0]',
  41. 'u': '(undefined+"")[0]',
  42. 'v': '(+(31))["to"+String["name"]](32)',
  43. 'w': '(+(32))["to"+String["name"]](33)',
  44. 'x': '(+(101))["to"+String["name"]](34)[1]',
  45. 'y': '(NaN+[Infinity])[10]',
  46. 'z': '(+(35))["to"+String["name"]](36)',
  47. 'A': '(+[]+Array)[10]',
  48. 'B': '(+[]+Boolean)[10]',
  49. 'C': 'Function("return escape")()(("")["italics"]())[2]',
  50. 'D': 'Function("return escape")()([]["flat"])["slice"]("-1")',
  51. 'E': '(RegExp+"")[12]',
  52. 'F': '(+[]+Function)[10]',
  53. 'G': '(false+Function("return Date")()())[30]',
  54. 'H': null,
  55. 'I': '(Infinity+"")[0]',
  56. 'J': null,
  57. 'K': null,
  58. 'L': null,
  59. 'M': '(true+Function("return Date")()())[30]',
  60. 'N': '(NaN+"")[0]',
  61. 'O': '(+[]+Object)[10]',
  62. 'P': null,
  63. 'Q': null,
  64. 'R': '(+[]+RegExp)[10]',
  65. 'S': '(+[]+String)[10]',
  66. 'T': '(NaN+Function("return Date")()())[30]',
  67. 'U': '(NaN+Object()["to"+String["name"]]["call"]())[11]',
  68. 'V': null,
  69. 'W': null,
  70. 'X': null,
  71. 'Y': null,
  72. 'Z': null,
  73. ' ': '(NaN+[]["flat"])[11]',
  74. '!': null,
  75. '"': '("")["fontcolor"]()[12]',
  76. '#': null,
  77. '$': null,
  78. '%': 'Function("return escape")()([]["flat"])[21]',
  79. '&': '("")["fontcolor"](")[13]',
  80. '\'': null,
  81. '(': '([]["flat"]+"")[13]',
  82. ')': '([0]+false+[]["flat"])[20]',
  83. '*': null,
  84. '+': '(+(+!+[]+(!+[]+[])[!+[]+!+[]+!+[]]+[+!+[]]+[+[]]+[+[]])+[])[2]',
  85. ',': '[[]]["concat"]([[]])+""',
  86. '-': '(+(.+[0000001])+"")[2]',
  87. '.': '(+(+!+[]+[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+[!+[]+!+[]]+[+[]])+[])[+!+[]]',
  88. '/': '(false+[0])["italics"]()[10]',
  89. ':': '(RegExp()+"")[3]',
  90. ';': '("")["fontcolor"](NaN+")[21]',
  91. '<': '("")["italics"]()[0]',
  92. '=': '("")["fontcolor"]()[11]',
  93. '>': '("")["italics"]()[2]',
  94. '?': '(RegExp()+"")[2]',
  95. '@': null,
  96. '[': '([]["entries"]()+"")[0]',
  97. '\\': '(RegExp("/")+"")[1]',
  98. ']': '([]["entries"]()+"")[22]',
  99. '^': null,
  100. '_': null,
  101. '`': null,
  102. '{': '(true+[]["flat"])[20]',
  103. '|': null,
  104. '}': '([]["flat"]+"")["slice"]("-1")',
  105. '~': null
  106. };
  107. const GLOBAL = 'Function("return this")()';
  108. function fillMissingDigits(){
  109. var output, number, i;
  110. for (number = 0; number < 10; number++){
  111. output = "+[]";
  112. if (number > 0){ output = "+!" + output; }
  113. for (i = 1; i < number; i++){ output = "+!+[]" + output; }
  114. if (number > 1){ output = output.substr(1); }
  115. MAPPING[number] = "[" + output + "]";
  116. }
  117. }
  118. function replaceMap(){
  119. var character = "", value, i, key;
  120. function replace(pattern, replacement){
  121. value = value.replace(
  122. new RegExp(pattern, "gi"),
  123. replacement
  124. );
  125. }
  126. function digitReplacer(_,x) { return MAPPING[x]; }
  127. function numberReplacer(_,y) {
  128. var values = y.split("");
  129. var head = +(values.shift());
  130. var output = "+[]";
  131. if (head > 0){ output = "+!" + output; }
  132. for (i = 1; i < head; i++){ output = "+!+[]" + output; }
  133. if (head > 1){ output = output.substr(1); }
  134. return [output].concat(values).join("+").replace(/(\d)/g, digitReplacer);
  135. }
  136. for (i = MIN; i <= MAX; i++){
  137. character = String.fromCharCode(i);
  138. value = MAPPING[character];
  139. if(!value) {continue;}
  140. for (key in CONSTRUCTORS){
  141. replace("\\b" + key, CONSTRUCTORS[key] + '["constructor"]');
  142. }
  143. for (key in SIMPLE){
  144. replace(key, SIMPLE[key]);
  145. }
  146. replace('(\\d\\d+)', numberReplacer);
  147. replace('\\((\\d)\\)', digitReplacer);
  148. replace('\\[(\\d)\\]', digitReplacer);
  149. replace("GLOBAL", GLOBAL);
  150. replace('\\+""', "+[]");
  151. replace('""', "[]+[]");
  152. MAPPING[character] = value;
  153. }
  154. }
  155. function replaceStrings(){
  156. var regEx = /[^\[\]\(\)\!\+]{1}/g,
  157. all, value, missing,
  158. count = MAX - MIN;
  159. function findMissing(){
  160. var all, value, done = false;
  161. missing = {};
  162. for (all in MAPPING){
  163. value = MAPPING[all];
  164. if (value && value.match(regEx)){
  165. missing[all] = value;
  166. done = true;
  167. }
  168. }
  169. return done;
  170. }
  171. function mappingReplacer(a, b) {
  172. return b.split("").join("+");
  173. }
  174. function valueReplacer(c) {
  175. return missing[c] ? c : MAPPING[c];
  176. }
  177. for (all in MAPPING){
  178. if (MAPPING[all]){
  179. MAPPING[all] = MAPPING[all].replace(/\"([^\"]+)\"/gi, mappingReplacer);
  180. }
  181. }
  182. while (findMissing()){
  183. for (all in missing){
  184. value = MAPPING[all];
  185. value = value.replace(regEx, valueReplacer);
  186. MAPPING[all] = value;
  187. missing[all] = value;
  188. }
  189. if (count-- === 0){
  190. console.error("Could not compile the following chars:", missing);
  191. }
  192. }
  193. }
  194. function escapeSequence(c) {
  195. var cc = c.charCodeAt(0);
  196. if (cc < 256) {
  197. return '\\' + cc.toString(8);
  198. } else {
  199. var cc16 = cc.toString(16);
  200. return '\\u' + ('0000' + cc16).substring(cc16.length);
  201. }
  202. }
  203. function escapeSequenceForReplace(c) {
  204. return escapeSequence(c).replace('\\', 't');
  205. }
  206. function encode(input, wrapWithEval, runInParentScope){
  207. var output = [];
  208. if (!input){
  209. return "";
  210. }
  211. var unmappped = ''
  212. for(var k in MAPPING) {
  213. if (MAPPING[k]){
  214. unmappped += k;
  215. }
  216. }
  217. unmappped = unmappped.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  218. unmappped = new RegExp('[^' + unmappped + ']','g');
  219. var unmappedCharactersCount = (input.match(unmappped) || []).length;
  220. if (unmappedCharactersCount > 1) {
  221. // Without this optimization one unmapped caracter has encoded length
  222. // of about 3600 characters. Every additional unmapped character adds
  223. // 2000 to the total length. For example, the lenght of `~` is 3605,
  224. // `~~` is 5600, and `~~~` is 7595.
  225. //
  226. // The loader with replace has encoded length of about 5300 characters
  227. // and every additional character adds 100 to the total length.
  228. // In the same example the length of `~~` becomes 5371 and `~~~` -- 5463.
  229. //
  230. // So, when we have more than one unmapped character we want to encode whole input
  231. // except select characters (that have encoded length less than about 70)
  232. // into an escape sequence.
  233. //
  234. // NOTE: `t` should be escaped!
  235. input = input.replace(/[^0123456789.adefilnrsuN]/g, escapeSequenceForReplace);
  236. } else if (unmappedCharactersCount > 0) {
  237. //Because we will wrap the input into a string we need to escape Backslash
  238. // and Double quote characters (we do not need to worry about other characters
  239. // because they are not mapped explicitly).
  240. // The JSFuck-encoded representation of `\` is 2121 symbols,
  241. // so esacped `\` is 4243 symbols and escaped `"` is 2261 symbols
  242. // however the escape sequence of that characters are
  243. // 2168 and 2155 symbols respectively, so it's more practical to
  244. // rewrite them as escape sequences.
  245. input = input.replace(/["\\]/g, escapeSequence);
  246. //Convert all unmapped characters to escape sequence
  247. input = input.replace(unmappped, escapeSequence);
  248. }
  249. var r = "";
  250. for (var i in SIMPLE) {
  251. r += i + "|";
  252. }
  253. r+= ".";
  254. input.replace(new RegExp(r, 'g'), function(c) {
  255. var replacement = SIMPLE[c];
  256. if (replacement) {
  257. output.push("(" + replacement + "+[])");
  258. } else {
  259. replacement = MAPPING[c];
  260. if (replacement){
  261. output.push(replacement);
  262. } else {
  263. throw new Error('Found unmapped character: ' + c);
  264. }
  265. }
  266. });
  267. output = output.join("+");
  268. if (/^\d$/.test(input)){
  269. output += "+[]";
  270. }
  271. if (unmappedCharactersCount > 1) {
  272. // replace `t` with `\\`
  273. output = "(" + output + ")[" + encode("split") + "](" + encode ("t") + ")[" + encode("join") +"](" + encode("\\") + ")";
  274. }
  275. if (unmappedCharactersCount > 0) {
  276. output = "[][" + encode("flat") + "]"+
  277. "[" + encode("constructor") + "]" +
  278. "(" + encode("return\"") + "+" + output + "+" + encode("\"") + ")()";
  279. }
  280. if (wrapWithEval){
  281. if (runInParentScope){
  282. output = "[][" + encode("flat") + "]" +
  283. "[" + encode("constructor") + "]" +
  284. "(" + encode("return eval") + ")()" +
  285. "(" + output + ")";
  286. } else {
  287. output = "[][" + encode("flat") + "]" +
  288. "[" + encode("constructor") + "]" +
  289. "(" + output + ")()";
  290. }
  291. }
  292. return output;
  293. }
  294. fillMissingDigits();
  295. replaceMap();
  296. replaceStrings();
  297. self.JSFuck = {
  298. encode: encode
  299. };
  300. })(typeof(exports) === "undefined" ? window : exports);