quamvoluptatem
Version:
JavaScript Obfuscation Tool.
193 lines (170 loc) • 4.94 kB
text/typescript
import { ok } from "assert";
import { ObfuscateOrder } from "../order";
import { ComputeProbabilityMap } from "../probability";
import Template from "../templates/template";
import {
BinaryExpression,
CallExpression,
ForStatement,
FunctionExpression,
Identifier,
Literal,
ReturnStatement,
UpdateExpression,
VariableDeclaration,
VariableDeclarator,
} from "../util/gen";
import { clone, prepend } from "../util/insert";
import { getRandomInteger } from "../util/random";
import Transform from "./transform";
var Hash = function (s) {
var a = 1,
c = 0,
h,
o;
if (s) {
a = 0;
for (h = s.length - 1; h >= 0; h--) {
o = s.charCodeAt(h);
a = ((a << 6) & 268435455) + o + (o << 14);
c = a & 266338304;
a = c !== 0 ? a ^ (c >> 21) : a;
}
}
return ~~String(a).slice(0, 3);
};
var HashTemplate = Template(
`
var {name} = function(arr) {
var s = arr.map(x=>x+"").join(''), a = 1, c = 0, h, o;
if (s) {
a = 0;
for (h = s.length - 1; h >= 0; h--) {
o = s.charCodeAt(h);
a = (a<<6&268435455) + o + (o<<14);
c = a & 266338304;
a = c!==0?a^c>>21:a;
}
}
return ~~String(a).slice(0, 3);
};`
);
/**
* Shuffles arrays initial order of elements.
*
* "Un-shuffles" the array at runtime.
*/
export default class Shuffle extends Transform {
hashName: string;
constructor(o) {
super(o, ObfuscateOrder.Shuffle);
}
match(object, parents) {
return (
object.type == "ArrayExpression" &&
!parents.find((x) => x.$dispatcherSkip)
);
}
transform(object, parents) {
return () => {
if (object.elements.length < 3) {
// Min: 4 elements
return;
}
function isAllowed(e) {
return (
e.type == "Literal" &&
{ number: 1, boolean: 1, string: 1 }[typeof e.value]
);
}
// Only arrays with only literals
var illegal = object.elements.find((x) => !isAllowed(x));
if (illegal) {
return;
}
var mode = ComputeProbabilityMap(
this.options.shuffle,
(x) => x,
object.elements.map((x) => x.value)
);
if (mode) {
var shift = getRandomInteger(
1,
Math.min(100, object.elements.length * 6)
);
var expr = Literal(shift);
var name = this.getPlaceholder();
if (mode == "hash") {
var str = object.elements.map((x) => x.value + "").join("");
shift = Hash(str);
if (!this.hashName) {
prepend(
parents[parents.length - 1],
HashTemplate.single({
name: (this.hashName = this.getPlaceholder()),
})
);
}
for (var i = 0; i < shift; i++) {
object.elements.push(object.elements.shift());
}
var shiftedHash = Hash(
object.elements.map((x) => x.value + "").join("")
);
expr = BinaryExpression(
"-",
CallExpression(Identifier(this.hashName), [Identifier(name)]),
Literal(shiftedHash - shift)
);
} else {
for (var i = 0; i < shift; i++) {
object.elements.push(object.elements.shift());
}
}
var code = [];
var iName = this.getPlaceholder();
code.push(
ForStatement(
VariableDeclaration(VariableDeclarator(iName, expr)),
Identifier(iName),
UpdateExpression("--", Identifier(iName), false),
[Template(`${name}.unshift(${name}.pop())`).single()]
)
);
var inPlace = false;
var varDeclarator = parents[0];
if (varDeclarator.type == "VariableDeclarator") {
var varDec = parents[2];
if (varDec.type == "VariableDeclaration") {
var body = parents[3];
if (varDec.declarations.length == 1 && Array.isArray(body)) {
inPlace = true;
var i = body.indexOf(varDec);
ok(i != -1);
body.splice(
i + 1,
0,
VariableDeclaration(
VariableDeclarator(name, Identifier(varDeclarator.id.name))
),
...code
);
}
}
}
if (!inPlace) {
this.replace(
object,
CallExpression(
FunctionExpression(
[Identifier(name)],
[...code, ReturnStatement(Identifier(name))]
),
[clone(object)]
)
);
}
}
};
}
}