Module refinery.units.scripting.djs
Expand source code Browse git
from __future__ import annotations
from refinery.lib.scripts.js.analysis.environment import HostEnvironment
from refinery.lib.scripts.js.deobfuscation import deobfuscate
from refinery.lib.scripts.js.model import JsScript
from refinery.lib.scripts.js.options import ExecutionModel
from refinery.lib.scripts.js.parser import JsParser
from refinery.lib.scripts.js.synth import JsSynthesizer
from refinery.lib.types import Param
from refinery.units import Arg
from refinery.units.scripting import IterativeDeobfuscator
class djs(IterativeDeobfuscator):
"""
AST-based JavaScript deobfuscator and pretty-printer.
Parses the script into an abstract syntax tree, applies simplifying transformations, and
synthesizes clean output. This deobfuscator iterates until stable; running it twice does
not change the output. By default the input is assumed to run as a classic global script; pass
the module switch when it runs as an ES or CommonJS module instead, or the CommonJS switch when
it is known to run as the latter. Name any entrypoint a host calls into, or dead-code removal
will discard it as unreachable.
"""
def __init__(
self,
*entrypoints: Param[str, Arg.String(metavar='pattern', nargs='*', help=(
'A wildcard pattern naming top-level functions that a host invokes by name, such as the '
'run handler of a JXA script or a Windows Script Host event handler. Such a function has '
'no caller inside the file, so it is otherwise removed as unreachable along with '
'everything only it reached. Give a single asterisk to keep every top-level function.'))],
timeout=500,
module: Param[bool, Arg.Switch('-m', help=(
'Assume the input runs as a module, where a top-level declaration is scoped to the '
'module and does not attach to the global object, rather than as a classic global '
'script (a browser script tag, Windows Script Host). The module may be an ES module or '
'a CommonJS file; use -c when it is known to be the latter.'))] = False,
commonjs: Param[bool, Arg.Switch('-c', help=(
'Assume the input runs as a CommonJS module, as node file.js runs it when no package '
'says otherwise. This implies -m. Unlike an ES module, a CommonJS file is not strict '
'code unless it says so, so code the input runs from a string can be unpacked into '
'it.'))] = False,
environment: Param[str | HostEnvironment, Arg.Option('-e', metavar='E', choices=HostEnvironment, help=(
'Pin the host the input runs in, so that the global names that host defines are assumed '
'present and the reads that rely on them are resolved. The default is {default}, which '
'assumes only the globals every host shares, so a host-conditional read such as window '
'or global is kept. Options are: {choices}.'))] = HostEnvironment.universal,
loaded: Param[bool, Arg.Switch('-l', help=(
'Assume code may load the input and read what it exports: another file that requires it, '
'as with the main file of a package, or the file itself through the module registry. '
'Without this switch, a CommonJS file that never reads module back has the store that '
'replaces module.exports removed.'))] = False,
strict: Param[bool, Arg.Switch('-s', help=(
'Assume that unknown reflectively executed code (a direct eval, a Function construction, '
'a string timer) can change or read anything the rest of the script does. This cleans '
'less junk code but without the flag, the deobfuscation behavior is formally unsound.'))] = False,
):
super().__init__(
timeout=timeout,
module=module,
commonjs=commonjs,
entrypoints=entrypoints,
environment=Arg.AsOption(environment, HostEnvironment),
loaded=loaded,
strict=strict,
)
def parse(self, data: str) -> JsScript:
return JsParser(data).parse()
def transform(self, ast: JsScript) -> int:
if self.args.commonjs:
execution = ExecutionModel.commonjs
elif self.args.module:
execution = ExecutionModel.module
else:
execution = ExecutionModel.script
return deobfuscate(
ast,
execution=execution,
entrypoints=tuple(self.args.entrypoints),
environment=self.args.environment,
trust_eval=not self.args.strict,
loaded_by_other_files=self.args.loaded,
)
def synthesize(self, ast: JsScript) -> str:
return JsSynthesizer().convert(ast)
Classes
class djs (*entrypoints, timeout=500, module=False, commonjs=False, environment=HostEnvironment.universal, loaded=False, strict=False)-
AST-based JavaScript deobfuscator and pretty-printer.
Parses the script into an abstract syntax tree, applies simplifying transformations, and synthesizes clean output. This deobfuscator iterates until stable; running it twice does not change the output. By default the input is assumed to run as a classic global script; pass the module switch when it runs as an ES or CommonJS module instead, or the CommonJS switch when it is known to run as the latter. Name any entrypoint a host calls into, or dead-code removal will discard it as unreachable.
Expand source code Browse git
class djs(IterativeDeobfuscator): """ AST-based JavaScript deobfuscator and pretty-printer. Parses the script into an abstract syntax tree, applies simplifying transformations, and synthesizes clean output. This deobfuscator iterates until stable; running it twice does not change the output. By default the input is assumed to run as a classic global script; pass the module switch when it runs as an ES or CommonJS module instead, or the CommonJS switch when it is known to run as the latter. Name any entrypoint a host calls into, or dead-code removal will discard it as unreachable. """ def __init__( self, *entrypoints: Param[str, Arg.String(metavar='pattern', nargs='*', help=( 'A wildcard pattern naming top-level functions that a host invokes by name, such as the ' 'run handler of a JXA script or a Windows Script Host event handler. Such a function has ' 'no caller inside the file, so it is otherwise removed as unreachable along with ' 'everything only it reached. Give a single asterisk to keep every top-level function.'))], timeout=500, module: Param[bool, Arg.Switch('-m', help=( 'Assume the input runs as a module, where a top-level declaration is scoped to the ' 'module and does not attach to the global object, rather than as a classic global ' 'script (a browser script tag, Windows Script Host). The module may be an ES module or ' 'a CommonJS file; use -c when it is known to be the latter.'))] = False, commonjs: Param[bool, Arg.Switch('-c', help=( 'Assume the input runs as a CommonJS module, as node file.js runs it when no package ' 'says otherwise. This implies -m. Unlike an ES module, a CommonJS file is not strict ' 'code unless it says so, so code the input runs from a string can be unpacked into ' 'it.'))] = False, environment: Param[str | HostEnvironment, Arg.Option('-e', metavar='E', choices=HostEnvironment, help=( 'Pin the host the input runs in, so that the global names that host defines are assumed ' 'present and the reads that rely on them are resolved. The default is {default}, which ' 'assumes only the globals every host shares, so a host-conditional read such as window ' 'or global is kept. Options are: {choices}.'))] = HostEnvironment.universal, loaded: Param[bool, Arg.Switch('-l', help=( 'Assume code may load the input and read what it exports: another file that requires it, ' 'as with the main file of a package, or the file itself through the module registry. ' 'Without this switch, a CommonJS file that never reads module back has the store that ' 'replaces module.exports removed.'))] = False, strict: Param[bool, Arg.Switch('-s', help=( 'Assume that unknown reflectively executed code (a direct eval, a Function construction, ' 'a string timer) can change or read anything the rest of the script does. This cleans ' 'less junk code but without the flag, the deobfuscation behavior is formally unsound.'))] = False, ): super().__init__( timeout=timeout, module=module, commonjs=commonjs, entrypoints=entrypoints, environment=Arg.AsOption(environment, HostEnvironment), loaded=loaded, strict=strict, ) def parse(self, data: str) -> JsScript: return JsParser(data).parse() def transform(self, ast: JsScript) -> int: if self.args.commonjs: execution = ExecutionModel.commonjs elif self.args.module: execution = ExecutionModel.module else: execution = ExecutionModel.script return deobfuscate( ast, execution=execution, entrypoints=tuple(self.args.entrypoints), environment=self.args.environment, trust_eval=not self.args.strict, loaded_by_other_files=self.args.loaded, ) def synthesize(self, ast: JsScript) -> str: return JsSynthesizer().convert(ast)Ancestors
Subclasses
Class variables
var reverse-
The type of the None singleton.
Methods
def parse(self, data)-
Expand source code Browse git
def parse(self, data: str) -> JsScript: return JsParser(data).parse() def transform(self, ast)-
Expand source code Browse git
def transform(self, ast: JsScript) -> int: if self.args.commonjs: execution = ExecutionModel.commonjs elif self.args.module: execution = ExecutionModel.module else: execution = ExecutionModel.script return deobfuscate( ast, execution=execution, entrypoints=tuple(self.args.entrypoints), environment=self.args.environment, trust_eval=not self.args.strict, loaded_by_other_files=self.args.loaded, ) def synthesize(self, ast)-
Expand source code Browse git
def synthesize(self, ast: JsScript) -> str: return JsSynthesizer().convert(ast)
Inherited members
IterativeDeobfuscator:FilterEverythingRequiresactassemblecarvedclosecodecconsolefilterfinishhandlesis_quietis_reversibleisattylabelledleniencylog_alwayslog_debuglog_detachlog_faillog_infolog_levellog_warnloggernamenozzleoptional_dependenciesreadread1required_dependenciesresetrunsourcesuperinit
UnitBase: