-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdeobfuscator.js
152 lines (120 loc) · 4.13 KB
/
deobfuscator.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
const fs = require("fs");
const path = require("path");
const { deobf_rules } = require("./deobf_rules.js");
/* Throws a bunch of console.logs to help diagnose deep issues */
const debug = false;
/*
true: If a deobfuscation rule applies to more than 1 file, an exception is thrown, halting operations
false: If a deobfuscation rule applies to more than 1 file, warnings are shown, but modules are still processed so that it's easier to diagnose.
*/
let duplicatesAreErrors = false;
class Deobfuscator {
/*
Object that keeps track of which deobf rules were used, and where they were used.
This lets the deobfuscator flag down any duplicate rules.
*/
static doneOnes = {};
static duplicateAware = {};
static deobfCount = 0;
static totalCount = 0;
static warnings = [];
constructor() {
return this;
}
static initializeRules() {
for (var i in deobf_rules) {
let rule = deobf_rules[i];
if (typeof rule !== "object") {
continue;
}
if ("duplicates" in rule) {
if (!("rule" in rule)){
throw "Uh oh, duplicate-aware rule is missing the rule part of the rule: " + rule;
}
Deobfuscator.duplicateAware[i] = {
total: rule.duplicates,
found: []
};
deobf_rules[i] = rule.rule;
}
}
}
/*
If any rules go unused, we'll let you know.
This is useful,
1. To diagnose malformed rules (it happens!)
2. We'll know if TweetDeck removes any modules/features
*/
static checkIfAllWereReplaced() {
for (var i in deobf_rules) {
if (typeof Deobfuscator.duplicateAware[i] !== "undefined") {
var entry = Deobfuscator.duplicateAware[i];
var count = entry.found.length;
if (count !== entry.total) {
Deobfuscator.warnings.push("Duplicate-aware rule " + i + " applied an incorrect amount of times, expected " + entry.total + ", got " + count + ": [ " + entry.found.join(", ") + " ]");
}
} else if (typeof Deobfuscator.doneOnes[i] === "undefined") {
Deobfuscator.warnings.push("Rule " + i + " did not apply to any modules.");
}
}
}
static printStatus() {
if (Deobfuscator.warnings.length === 0) {
console.log("\n Deobfuscation finished with no warnings!");
} else {
console.log("\n Deobfuscation finished with " + Deobfuscator.warnings.length + " warning(s):");
for (var warn of Deobfuscator.warnings.sort()) {
console.log(" > " + warn);
}
}
console.log("\n " + Deobfuscator.deobfCount + " modules were deobfuscated out of " + Deobfuscator.totalCount + " modules.");
}
static run(source, thisMod) {
let returnMe = null;
Deobfuscator.totalCount++;
for (var i in deobf_rules) {
let rule = deobf_rules[i];
let matches = false;
if (typeof rule === "string") {
matches = source.includes(rule);
} else if (rule instanceof RegExp) {
if (rule.global) {
throw "Uh oh, RegExp rule must not be global: " + rule; // global modifies RegExp lastIndex after each match
}
matches = rule.test(source);
} else if (typeof rule === "function") {
matches = rule(source, thisMod);
} else {
throw "Uh oh, could not determine rule type, expected string/RegExp/function, got: " + rule;
}
if (debug) {
console.log("Rule: " + rule);
console.log("Matches: " + matches);
}
if (matches) {
if (typeof Deobfuscator.duplicateAware[i] !== "undefined") {
var found = Deobfuscator.duplicateAware[i].found;
found.push(thisMod);
if (i.includes(".js")) {
returnMe = i.replace(".js", "." + found.length + ".js");
} else {
throw "Uh oh, rule " + i + " is missing the .js extension";
}
} else if (typeof Deobfuscator.doneOnes[i] !== "undefined") {
if (!duplicatesAreErrors) {
Deobfuscator.warnings.push("Rule " + i + " was duplicated in " + thisMod + ", originally found in " + Deobfuscator.doneOnes[i] + ".");
return null;
}
throw "Uh oh, seems we have a duplicate on " + i + " (duplicated in " + thisMod + ", originally seen in " + Deobfuscator.doneOnes[i] + ")";
} else {
Deobfuscator.doneOnes[i] = thisMod;
returnMe = i;
}
Deobfuscator.deobfCount++;
}
}
return returnMe;
}
}
Deobfuscator.initializeRules();
exports.Deobfuscator = Deobfuscator;