How to express characters and numbers by JS obfuscation
SHINOVI (opens new window) converts data into complex code for Javascript, and it takes many ways to obfuscate data.
# Variables with signature
First, you can express some variables just with signatures. Here are some examples:
console.log(![]) // false
console.log(!![]) // true
console.log(+[{}]) // NaN
console.log([]/[]) // NaN
console.log(!![]/[]) // Infinity
console.log(-!![]/[]) // -Infinity
console.log([][[]]) // undefined
console.log(~~[]) // 0
console.log(+![]) // 0
console.log(-~[]) // 1
console.log(-~-~[]) // 2
console.log(-~-~-~[]) // 3
2
3
4
5
6
7
8
9
10
11
12
13
Actually many obfuscation tools use this way of expressions.
# Alphabet characters included in a string
In Javascript, any variables can be easily changed into alphanumeric characters like this:
console.log("" + false) // "false"
console.log("" + true) // "true"
console.log("" + undefined) // "undefined"
2
3
Then you can use this with signature expression together like this:
console.log(""+![]) // "false"
console.log(""+!![]) // "true"
2
In Javascript, you can extract a single character from a string as you can extract some characters like this:
console.log((""+![])[0]) // f
console.log((""+![])[1]) // a
console.log((""+![])[2]) // l
console.log((""+![])[3]) // s
console.log((""+![])[4]) // e
console.log((""+[][[]])[0]) // u
console.log((""+[][[]])[1]) // n
console.log((""+[][[]])[2]) // d
console.log((""+[][[]])[3]) // e
console.log((""+[][[]])[4]) // f
console.log((""+[][[]])[5]) // i
console.log((""+[][[]])[6]) // n
console.log((""+[][[]])[7]) // e
console.log((""+[][[]])[8]) // d
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Express numbers with smaller numbers
Numbers can be expressed with smaller numbers.
# Addition
console.log(1 + 2 + 3) // 6
# Multiplication
console.log(2 * 2 * 2 * 3) // 24
Also 2 to the nth power can be expressed with bitwise operators.
2 * 2 * 2 * 3
, 3 * (2 ** 3)
, and 3 << 3
are all the same.
console.log(3 * (2 ** 3)) // 24
console.log(3 << 3) // 24
2
# Bitwise operation
As above, 2 to the nth power can be expressed with bitwise operator <<
.
console.log(1 << 0) // 1
console.log(1 << 1) // 1 * 2 = 2
console.log(1 << 2) // 1 * 2 * 2 = 4
console.log(1 << 3) // 1 * 2 * 2 * 2 = 8
2
3
4
Bitwise AND (&)
or OR (|)
are also useful.
// 14 -> 1110
// 7 -> 111
// 6 -> 110
console.log(14 & 7) // 6
// 15 -> 1111
console.log(14 | 7) // 15
2
3
4
5
6
7
8
# Combination of these expressions
These various operations can be combined like this:
console.log(((1|2|4)+1)<<2 ) // 32
# Expression with signatures
Then replace some numbers with signature expressions.
console.log(((-~[]|-~-~[]|(-~-~[]<<-~[]))+-~[])<<(-~-~[])) // 32
# Convert dicimal numbers to 36-ary and vice versa
In Javascript, it is easy to convert dicimal to 36-ary.
console.log((35).toString(36)) // "z"
console.log(parseInt("z" , 36)) // 35
2
Actually you can extract all alphabet characters, a-z, with this way.
console.log((62009168814).toString(36)) // "shinovi"
console.log(parseInt("shinovi" , 36)) // 62009168814
2
But when you use 36-ary in this way, you should be careful of overflowing digits. MDN (opens new window) says The JavaScript Number type is a double-precision 64-bit binary format IEEE 754 value
but Number.MAX_SAFE_INTEGER
, which can be referred to as the maximum safe integer in JS, is actually (2^53 - 1)
. To handle numbers safely, SHINOVI (opens new window) is designed to handle numbers of just less than 32-bit signed integers.
# Express more than 2-byte characters
Now various numbers can be expressed in various ways, then you can more than 2-byte characters such as Japanese 漢字 (kanji) characters using String.fromCodePoint
, which returns a string from code points like this:
String.fromCodePoint(23665,26412) // 山本
// The `apply` method is usable for an array of strings.
String.fromCodePoint.apply(null, [23665,26412]) // 山本
2
3
4