-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathindex.js
168 lines (151 loc) · 4.75 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#!/usr/bin/env node
/**
* @param n Integer number, such as: 1, 1942, -1942
* @returns A string represent the arguments' integer
*/
const fromNumber = (function () {
const num = {
'-': '([]+~+[])[+[]]',
0: '+[]',
1: '+!![]',
}
// Gnerate number map, 0-9
~(function genNum(n) {
if (n === 1) {
return num[1]
} else {
return num[n] = genNum(n - 1) + num[1]
}
}
)(9)
//
return function (n) {
if (num.hasOwnProperty(n)) {
return num[n]
} else {
return num[n] = `+([]+${('' + n)
.split('')
.map(i => {
if (!num.hasOwnProperty(i)) {
throw new Error(`fromNumber not support: '${i}'`)
}
return `(${num[i]})`
})
.join('+')})`
}
}
})()
const fromString = (function () {
// Generate base char map
const char = {};
[
'[]+{}', // '[object Object]'
'[]+![]', // 'false'
'[]+!![]', // 'true'
'[]+[][[]]', // 'undefined'
'[]+(+[]+[][[]])', // 'NaN'
].forEach(s =>
eval(s)
.split('')
.map((c, i) => {
const _ = `(${s})[${fromNumber(i)}]`
if (!char.hasOwnProperty(c)
|| char[c].length > _.length) {
char[c] = _
}
})
)
for (let i = 0; i < 10; i++) {
char[i] = `[]+(${fromNumber(i)})`
}
// Keep simple char
const simpleChar = {
...char,
}
// Transform char into magic string
function transform(code, map = char) {
return code
.split('')
.map(c => {
if (!char.hasOwnProperty(c)) {
throw new Error(`fromString not support: '${c}'`)
}
return `(${char[c]})`
})
.join('+')
}
// Get character for `toString`
// ''+''['constructor'] => 'function String() { [native code] }'
const _functionString = `[]+([]+[])[${transform('constructor')}]`
char.g = `(${_functionString})[${fromNumber(14)}]`
char.v = `(${_functionString})[${fromNumber(25)}]`
char.S = `(${_functionString})[${fromNumber(9)}]`
char['('] = `(${_functionString})[${fromNumber(15)}]`
char[')'] = `(${_functionString})[${fromNumber(16)}]`
// Fill all lowercase char using `(Number).toString`
for (let i = 10; i < 36; i++) {
const c = i.toString(36)
if (!char.hasOwnProperty(c)) {
// i['toString'](36)
char[c] = `(${fromNumber(i)})[${transform('toString')}](${fromNumber(36)})`
}
}
// Fill other with `unescape`
// There should be an other way because `unescape` is deprecated and will be remove in future
for (let i = 0; i < 256; i++) {
const hexStr = i.toString(16)
const c = unescape(`%${hexStr}`)
if (char.hasOwnProperty(c)) {
continue
}
// []['sort']['constructor']('return unescape')()
char[c] = `[][${transform('sort')}][${transform('constructor')}](${transform('return unescape')})()('%'+(${transform(hexStr)}))`
}
return function (str) {
if (!str) {
return ''
}
// Simple string
if (str.split('').every(c => simpleChar[c])) {
return transform(str, simpleChar)
}
// Complex string, use unescape
const hexCodes = str
.split('')
.map(c => c.charCodeAt(0).toString(16))
.map(hex => {
switch (hex.length) {
case 1:
return transform(`0${hex}`)
case 2:
return transform(`${hex}`)
default:
return transform(`u${hex}`)
}
})
.map(code => `('%'+${code})`)
.join('+')
return `[][${transform('sort')}][${transform('constructor')}](${transform('return unescape')})()(${hexCodes})`
}
})()
module.exports = {
fromNumber,
fromString,
}
/**
* @param
*/
const fs = require('fs')
const program = require('commander')
program
.version(require('./package.json').version)
.option('-r, --runtime', 'Transform to runable code')
.option('-f, --file <s>', 'Read from a file')
.parse(process.argv)
const args = program.args.join(' ')
let content = program.file ? fs.readFileSync(program.file, 'utf8') : args
if (program.runtime) {
console.log(`[][${fromString('sort')}][${fromString('constructor')}](${fromString(content)})()`)
} else if (content) {
console.log(fromString(content))
}