H. Ted Goranson

17 papers C 2Journal 1Unranked 14
YearRankTypeTitle / Venue / Authors
2017 conf
AAAI Spring Symposia
Beth Cardier, Larry D. Sanford, H. Ted Goranson, Patric S. Lundberg, Richard P. Ciavarra, Keith Devlin, Niccolo Cassas, Alessio Erioli
2016 J jnl
Comput. Ind.
Peter Bernus, H. Ted Goranson, John Gøtze, Anders Jensen-Waud, Hadi Kandjani, Arturo Molina, Ovidiu Noran, Ricardo J. Rabelo, David Romero, Pallab Saha, Patrick Turner
2009 conf
OTM Workshops
Hervé Panetto, Peter Bernus, Ricardo Jardim-Gonçalves, H. Ted Goranson
2003 C conf
PRO-VE
H. Ted Goranson
2002 conf
ICEIMT
H. Ted Goranson, Michael N. Huhns, James G. Nell, Hervé Panetto, Guillermina Tormo Carbó, Michael Wunram
2002 conf
ICEIMT
James G. Nell, H. Ted Goranson
2002 conf
ICEIMT
H. Ted Goranson, Guillermina Tormo Carbó, Yoshiro Fukuda, Lee Eng Wah, James G. Nell, Martin Zelm
2002 conf
ICEIMT
H. Ted Goranson
2002 conf
ICEIMT
H. Ted Goranson, Roland Jochem, James G. Nell, Hervé Panetto, Christopher Partridge, Francesca Sempere Ripoll, David N. Shorter, Peter Webb, Martin Zelm
2002 conf
ICEIMT
H. Ted Goranson, Bei-Tseng Chu, Michael Grüninger, Nenad Ivezic, Boonserm Kulvatunyou, Yannis Labrou, Ryusuke Masuoka, Yun Peng, Amit P. Sheth, David N. Shorter
2000 conf
E-Business and Virtual Enterprises
H. Ted Goranson
1997 conf
ICEIMT
Brian W. Hollocks, H. Ted Goranson, David N. Shorter, François B. Vernadat
1997 conf
ICEIMT
Peter Bernus, Bernard Espinasse, Mark Fox, H. Ted Goranson
1997 conf
ICEIMT
H. Ted Goranson
1997 conf
ICEIMT
H. Ted Goranson, R. Borowsky, Gary J. Colquhoun, Arturo Molina, Gérard Morel, James G. Nell, C. Reyneri, H. Synterä, François B. Vernadat, M. Walz, M. Winkler
1997 conf
ICEIMT
Andrew Kusiak, H. Ted Goranson, James G. Nell, François B. Vernadat
1993 C conf
ICIS
August-Wilhelm Scheer, H. Ted Goranson, Kurt Kosanke, Helmut Krcmar
redb/extractors/js_extractors/js_deobfuscator.py
← Index redb/extractors/js_extractors/js_deobfuscator.py python
"""Subprocess-driven JavaScript deobfuscator with jsbeautifier fallback.

Owns the heavy lifting that was previously embedded inside
`JSDeobfuscationExtractor` (`_run_deobfuscator` + `_try_jsbeautifier`). Exposed
as a single module-level entry point `deobfuscate(source, log)` so it can be
called from `JSContext.deobfuscated` (cached per sample) without dragging
extractor state through the call.

Configuration (env vars):
    JS_DEOBFUSCATOR_PATH    Path or name of the external tool (default: webcrack).
    JS_DEOBFUSCATE_TIMEOUT  Seconds before the external tool is killed
                            (process-group SIGTERM, then SIGKILL). Default: 60.

If the external tool produces non-empty output and exits 0, that wins. Otherwise
the source is run through jsbeautifier (which only normalises formatting, but
already exposes strings hidden by minification). If neither path produces
output, returns (None, None).

`FileNotFoundError` for the external tool is treated as routine — the analysis
server is either provisioned with the tool or it isn't — and demoted to a
debug-level log.
"""

import os
import signal
import subprocess
import tempfile
from typing import Optional, Tuple

DEFAULT_DEOBFUSCATOR = "webcrack"
DEFAULT_TIMEOUT_SECS = 60


def _run_external(
    source: str, deobfuscator_path: str, timeout: int, log
) -> Tuple[Optional[str], int]:
    """Run the configured external deobfuscator over `source` and capture stdout.

    Returns (text, returncode). `text` is `None` and `returncode` is `-1` when
    the binary is missing, the run timed out, or any other unexpected failure
    occurred. Missing-binary is logged at debug; timeouts and unexpected errors
    surface at warning/error.
    """
    try:
        with tempfile.NamedTemporaryFile(
            suffix=".js", mode="w", delete=False, encoding="utf-8"
        ) as tmp:
            tmp.write(source)
            tmp_path = tmp.name

        try:
            process = subprocess.Popen(
                [deobfuscator_path, tmp_path],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                preexec_fn=os.setsid,
            )

            try:
                stdout, _ = process.communicate(timeout=timeout)
                return stdout.decode("utf-8", errors="replace"), process.returncode
            except subprocess.TimeoutExpired:
                # Kill the entire process group so spawned helpers (e.g. node
                # subprocesses webcrack itself launches) get cleaned up too.
                try:
                    os.killpg(os.getpgid(process.pid), signal.SIGTERM)
                    process.wait(timeout=5)
                except Exception:
                    try:
                        os.killpg(os.getpgid(process.pid), signal.SIGKILL)
                    except Exception:
                        pass
                log.warning(f"Deobfuscation timed out after {timeout}s")
                return None, -1
        finally:
            try:
                os.unlink(tmp_path)
            except Exception:
                pass
    except FileNotFoundError:
        log.debug(f"Deobfuscator binary not found at {deobfuscator_path}")
        return None, -1
    except Exception as e:
        log.error(f"Error running deobfuscator: {e}")
        return None, -1


def _try_jsbeautifier(source: str, log) -> Tuple[Optional[str], Optional[str]]:
    """Fallback path: format the source with jsbeautifier. Returns
    `(text, "jsbeautifier")` or `(None, None)` if jsbeautifier isn't installed
    or the call raised."""
    try:
        import jsbeautifier
        opts = jsbeautifier.default_options()
        opts.indent_size = 2
        return jsbeautifier.beautify(source, opts), "jsbeautifier"
    except ImportError:
        log.debug("jsbeautifier not available")
        return None, None
    except Exception as e:
        log.warning(f"jsbeautifier failed: {e}")
        return None, None


def deobfuscate(source: str, log) -> Tuple[Optional[str], Optional[str]]:
    """Run the configured external deobfuscator, falling back to jsbeautifier.

    Returns `(text, normalizer_used)` on success, or `(None, None)` when neither
    path produced non-empty output. `normalizer_used` is the basename of the
    external tool (e.g. `"webcrack"`) or the literal `"jsbeautifier"`.
    """
    if not source:
        return None, None

    deobfuscator_path = os.getenv("JS_DEOBFUSCATOR_PATH", DEFAULT_DEOBFUSCATOR)
    timeout = int(os.getenv("JS_DEOBFUSCATE_TIMEOUT", str(DEFAULT_TIMEOUT_SECS)))

    text, returncode = _run_external(source, deobfuscator_path, timeout, log)
    if text and returncode == 0 and text.strip():
        return text, os.path.basename(deobfuscator_path)

    return _try_jsbeautifier(source, log)