Skip to content

Commit

Permalink
Add deobfuscator method
Browse files Browse the repository at this point in the history
  • Loading branch information
yotamN committed Apr 14, 2023
1 parent d5402e2 commit 3af5edf
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 0 deletions.
5 changes: 5 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const Env = require('./lib/env');
const Types = require('./lib/types');
const VM = require('./lib/vm');
const { checkJniResult } = require('./lib/result');
const Deobfuscator = require('./lib/deobfuscator');

const jsizeSize = 4;
const pointerSize = Process.pointerSize;
Expand Down Expand Up @@ -566,6 +567,10 @@ class Runtime {

return result;
}

deobfuscator(mapping) {
return new Deobfuscator(mapping);
}
}

function initFactoryFromApplication (factory, app) {
Expand Down
102 changes: 102 additions & 0 deletions lib/deobfuscator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
class Deobfuscator {
#mapping;
#reverseMapping;

constructor (mapping) {
if (mapping instanceof Map) {
this.#mapping = mapping;
} else {
const o = Object.entries(mapping).map(e => [e[0], {
realSpecifier: e[1].realSpecifier,
properties: new Map(Object.entries(e[1].properties))
}]);
this.#mapping = new Map(o);
}

this.#reverseMapping = new Map();
for (const [key, value] of this.#mapping.entries()) {
this.#reverseMapping.set(value.realSpecifier, key);
}
}

#getRealSpecifier (deobfuscatedSpecifier) {
const specifierMapping = this.#mapping.get(deobfuscatedSpecifier);
return specifierMapping?.realSpecifier;
}

use (deobfuscatedSpecifier) {
const realSpecifier = this.#getRealSpecifier(deobfuscatedSpecifier) || deobfuscatedSpecifier;
let realUse;
Java.performNow(() => {
realUse = Java.use(realSpecifier);
});
return this.wrap(realUse);
}

choose (deobfuscatedSpecifier, callbacks) {
const realSpecifier = this.#getRealSpecifier(deobfuscatedSpecifier) || deobfuscatedSpecifier;
Java.perform(() => {
Java.choose(realSpecifier, {
onMatch: instance => callbacks.onMatch(this.wrap(instance)),
onComplete: () => callbacks.onComplete()
});
});
}

wrap (wrapper) {
const realSpecifier = wrapper.$className;
const deobfuscatedSpecifier = this.#reverseMapping.get(realSpecifier) || realSpecifier;
const propertiesMapping = this.#mapping.get(deobfuscatedSpecifier)?.properties || new Map();

return new Proxy(wrapper, {
get: (target, prop, receiver) => {
const realProp = propertiesMapping.get(prop) || prop;
const result = Reflect.get(target, realProp, receiver);

if (result) {
if (result.value && result.value.$className) {
return this.#wrapField(result);
}

if (result instanceof Function) {
return this.#wrapMethod(target, result);
}
}

return result;
}
});
}

#wrapField (field) {
return new Proxy(field, {
get: (target, prop, receiver) => {
if (prop === 'value') {
return this.wrap(target.value);
}
return Reflect.get(target, prop, receiver);
}
});
}

#wrapMethod (wrapper, method) {
return new Proxy(method, {
apply: (_, thisArg, argumentsList) => {
const result = method.apply(thisArg, argumentsList);
if (result && result.$className) {
return this.wrap(result);
}
return result;
},
set: (target, prop, newValue, receiver) => {
if (prop === 'implementation') {
return Reflect.set(target, prop, newValue.bind(wrapper), receiver);
}

return Reflect.set(target, prop, newValue, receiver);
}
});
}
}

module.exports = Deobfuscator;

0 comments on commit 3af5edf

Please sign in to comment.