Igor Machado Coelho

50 papers B 3C 3Misc 2Journal 26Unranked 12
YearRankTypeTitle / Venue / Authors
2025 conf
GECCO Companion
Tatiana Machado Brito dos Santos, Milena Faria Pinto, Matheus B. Jenevain, Laís Rios Berno, Igor Machado Coelho
2025 conf
ICVNS
Filipe P. Sousa, Augusto M. P. de Mendonça, Igor Machado Coelho
2024 J jnl
Eur. J. Oper. Res.
Daniel Porumbel, Igor Machado Coelho, El-Ghazali Talbi
2023 J jnl
Optim. Lett.
Elias L. Marques, Vitor Nazário Coelho, Igor Machado Coelho, Luiz Satoru Ochi, Nelson Maculan, Nenad Mladenovic, Bruno N. Coelho
2023 Misc conf
PAAMS
Nilson Mori Lazarin, Igor Machado Coelho, Carlos Eduardo Pantoja, José Viterbo
2022 J jnl
Optim. Lett.
Janio Carlos Nascimento Silva, Igor Machado Coelho, Uéverton S. Souza, Luiz Satoru Ochi, Vitor Nazário Coelho
2022 J jnl
RAIRO Oper. Res.
Elias L. Marques, Vitor Nazário Coelho, Igor Machado Coelho, Yuri Abitbol de Menezes Frota, Roozbeh Haghnazar Koochaksaraei, Luiz Satoru Ochi, Bruno N. Coelho
2020 J jnl
Future Internet
Vitor Nazário Coelho, Rodolfo Pereira Araujo, Haroldo Gambini Santos, Wang Yong Qiang, Igor Machado Coelho
2020 J jnl
Parallel Comput.
Rodolfo Pereira Araujo, Igor Machado Coelho, Leandro Augusto Justen Marzulo
2020 J jnl
Future Internet
Igor Machado Coelho, Vitor Nazário Coelho, Rodolfo P. Araujo, Wang Yong Qiang, Brett D. Rhodes
2020 J jnl
Future Internet
Thays A. Oliveira, Yuri B. Gabrich, Helena Ramalhinho, Miquel Oliver, Miri Weiss-Cohen, Luiz S. Ochi, Serigne Gueye, Fábio Protti, Alysson A. Pinto, Diógenes V. M. Ferreira, Igor Machado Coelho, Vitor Nazário Coelho
2019 C conf
SBAC-PAD
Vanessa Fernandes da Silva, Mateus Nazário Coelho, Bruno Nazário Coelho, Vitor Nazário Coelho, Igor Machado Coelho
2019 conf
ICVNS
Elias L. Marques, Vitor Nazário Coelho, Igor Machado Coelho, Bruno N. Coelho, Luiz S. Ochi
2019 J jnl
Int. J. Grid Util. Comput.
Bruno Marques, Igor Machado Coelho, Alexandre da Costa Sena, Maria Clicia Stelling de Castro
2019 ch.
Smart and Digital Cities
Leonardo Pio Vasconcelos, José Viterbo, Igor Machado Coelho, João Marcos Meirelles da Silva
2019 J jnl
Concurr. Comput. Pract. Exp.
Leandro A. J. Marzulo, Alexandre da Costa Sena, Alexandre Solon Nery, Cristiana Bentes, Igor Machado Coelho, Maria Clicia Stelling de Castro, Saulo T. Oliveira, Tiago A. O. Alves, Felipe M. G. França
2019 ch.
Smart and Digital Cities
Vitor Nazário Coelho, Igor Machado Coelho, Thays A. Oliveira, Luiz S. Ochi
2019 conf
SBES
João Victor Esteves, Daniel Coutinho, Marcelo Schots, Igor Machado Coelho
2019 C conf
SBAC-PAD
Rodolfo Pereira Araujo, Igor Machado Coelho, Luiz Satoru Ochi, Vitor Nazário Coelho
2019 book
Smart and Digital Cities
Vitor Nazário Coelho, Igor Machado Coelho, Thays A. Oliveira, Luiz Satoru Ochi
2019 ch.
Smart and Digital Cities
Vitor Nazário Coelho, Yuri B. Gabrich, Thays A. Oliveira, Luiz S. Ochi, Alexandre C. Barbosa, Igor Machado Coelho
2018 J jnl
Electron. Notes Discret. Math.
Vitor Nazário Coelho, Haroldo Gambini Santos, Igor Machado Coelho, Puca Huachi Vaz Penna, Thays A. Oliveira, Marcone Jamilson Freitas Souza, Angelo Sifaleras
2018 conf
IPDPS Workshops
Rodolfo Pereira Araujo, Igor Machado Coelho, Leandro A. J. Marzulo
2018 J jnl
Electron. Notes Discret. Math.
Rodolfo P. Araujo, Eyder Rios, Igor Machado Coelho, Leandro A. J. Marzulo, Maria Clicia Stelling de Castro
2018 J jnl
Electron. Notes Discret. Math.
Anderson Zudio, Daniel Henrique da Silva Costa, Bruno Porto Masquio, Igor Machado Coelho, Paulo Eustáquio Duarte Pinto
2018 J jnl
J. Parallel Distributed Comput.
Eyder Rios, Luiz Satoru Ochi, Cristina Boeres, Vitor Nazário Coelho, Igor Machado Coelho, Ricardo C. Farias
2018 J jnl
Electron. Notes Discret. Math.
Mateus N. Coelho, Vitor Nazário Coelho, Igor Machado Coelho, Bruno N. Coelho, Marcone J. F. Souza
2018 conf
ICVNS
Vitor Nazário Coelho, Igor Machado Coelho, Nenad Mladenovic, Helena Ramalhinho, Luiz Satoru Ochi, Frederico G. Guimarães, Marcone J. F. Souza
2018 B conf
IJCNN
Edcarllos Santos, Puca Huachi Vaz Penna, Igor Machado Coelho, Heder Dorneles Soares, Luiz Satoru Ochi, Luidi Simonetti
2017 conf
SBAC-PAD (Workshops)
Bruno Marques, Igor Machado Coelho, Alexandre da Costa Sena, Maria Clicia Stelling de Castro
2017 conf
ICCSA (1)
Danilo S. Souza, Haroldo G. Santos, Igor Machado Coelho, Janniele A. S. Araujo
2017 Misc conf
ICCS
Danilo S. Souza, Haroldo G. Santos, Igor Machado Coelho
2017 J jnl
Electron. Notes Discret. Math.
Thays A. Oliveira, Vitor Nazário Coelho, Helena R. Lourenço, Marcone J. F. Souza, Bruno N. Coelho, Daniel C. Rezende, Igor Machado Coelho
2017 J jnl
Comput. Oper. Res.
Bruno N. Coelho, Vitor Nazário Coelho, Igor Machado Coelho, Luiz S. Ochi, Roozbeh Haghnazar Koochaksaraei, Demetrius Zuidema, Milton S. F. Lima, Adilson Rodrigues da Costa
2017 J jnl
Electron. Notes Discret. Math.
Eyder Rios, Luiz Satoru Ochi, Cristina Boeres, Igor Machado Coelho, Vitor Nazário Coelho, Nenad Mladenovic
2017 J jnl
Electron. Notes Discret. Math.
Vitor Nazário Coelho, Igor Machado Coelho, Bruno N. Coelho, Marcone J. F. Souza, Frederico G. Guimarães, Eduardo José da S. Luz, Alexandre C. Barbosa, Mateus N. Coelho, Guilherme G. Netto, R. C. Costa, Alysson A. Pinto, A. de P. Figueiredo, M. E. V. Elias, D. C. O. G. Filho, Thays A. Oliveira
2017 J jnl
Comput. Oper. Res.
Vitor Nazário Coelho, Thays A. Oliveira, Igor Machado Coelho, Bruno N. Coelho, Peter J. Fleming, Frederico G. Guimarães, Helena Ramalhinho Dias Lourenço, Marcone J. F. Souza, El-Ghazali Talbi, Thibaut Lust
2016 conf
SBAC-PAD (Workshops)
Eyder Rios, Igor Machado Coelho, Luiz Satoru Ochi, Cristina Boeres, Ricardo C. Farias
2016 J jnl
Eur. J. Oper. Res.
Vitor Nazário Coelho, Alex Grasas, Helena Ramalhinho Dias Lourenço, Igor Machado Coelho, Marcone J. F. Souza, R. C. Cruz
2016 B conf
IJCNN
Vitor Nazário Coelho, Igor Machado Coelho, Ivan Reinaldo Meneghini, Marcone J. F. Souza, Frederico G. Guimarães
2016 J jnl
Evol. Comput.
Vitor Nazário Coelho, Igor Machado Coelho, Marcone J. F. Souza, Thays A. Oliveira, Luciano Perdigão Cota, Matheus Nohra Haddad, Nenad Mladenovic, Rodrigo C. P. Silva, Frederico G. Guimarães
2015 conf
EMO (1)
Sophie Jacquin, Lucien Mousin, Igor Machado Coelho, El-Ghazali Talbi, Laetitia Jourdan
2015 J jnl
Electron. Notes Discret. Math.
Thays A. Oliveira, Vitor Nazário Coelho, Marcone J. F. Souza, D. L. T. Boava, F. Boava, Igor Machado Coelho, Bruno N. Coelho
2015 C conf
CLEI
Marques Moreira de Sousa, Luiz Satoru Ochi, Igor Machado Coelho, Luciana Brugiolo Gonçalves
2014 B conf
FUZZ-IEEE
Vitor Nazário Coelho, Frederico G. Guimarães, Agnaldo J. Rocha Reis, Igor Machado Coelho, Bruno N. Coelho, Marcone J. F. Souza
2012 J jnl
Electron. Notes Discret. Math.
Igor Machado Coelho, Pablo Luiz Araújo Munhoz, Matheus Nohra Haddad, Marcone Jamilson Freitas Souza, Luiz Satoru Ochi
2012 conf
SCCC
Matheus Nohra Haddad, Igor Machado Coelho, Marcone Jamilson Freitas Souza, Luiz Satoru Ochi, Haroldo Gambini Santos, Alexandre Xavier Martins
2012 J jnl
Electron. Notes Discret. Math.
Vitor Nazário Coelho, Marcone J. F. Souza, Igor Machado Coelho, Frederico G. Guimarães, Thibaut Lust, R. C. Cruz
2012 conf
HPCC-ICESS
Igor Machado Coelho, Luiz Satoru Ochi, Pablo Luiz Araújo Munhoz, Marcone Jamilson Freitas Souza, Ricardo C. Farias, Cristiana Bentes
2010 J jnl
Eur. J. Oper. Res.
Marcone J. F. Souza, Igor Machado Coelho, Sabir Ribas, Haroldo G. Santos, Luiz Henrique de Campos Merschmann
redb/extractors/js_extractors/js_strings.py
← Index redb/extractors/js_extractors/js_strings.py python
import base64
import bisect
import inspect
import re
from datetime import datetime, timezone
from typing import Any

from redb.extractors.enum import Tag
from redb.extractors.js_extractor import JSExtractor
from redb.extractors.js_extractors.js_patterns import STRING_PATTERNS, line_offsets

# Local aliases for the compiled patterns this extractor uses. Defined and
# compiled exactly once in js_patterns.STRING_PATTERNS.
_HEX_STRING_RE = STRING_PATTERNS["hex_escape_seq"]
_UNICODE_STRING_RE = STRING_PATTERNS["unicode_escape_seq"]
_CHARCODE_RE = STRING_PATTERNS["charcode_call"]
_BASE64_STRING_RE = STRING_PATTERNS["base64_quoted"]
_CONCAT_STRING_RE = STRING_PATTERNS["concat_chain"]

# Tokeniser used inside _reconstruct_concat to pull each quoted part out of a
# matched concat chain. Compiled once at module load (was recompiled on every
# concat match before).
_CONCAT_TOKEN_RE = re.compile(r'["\']([^"\']*)["\']')


class JSStringsExtractor(JSExtractor):

    def __init__(
        self, filepath, log, exporters=None, index_prefix=None,
        known_benign=False, known_malicious=False, source=None, context=None,
    ):
        super().__init__(
            filepath, log, exporters, index_prefix,
            known_benign, known_malicious, source, context=context,
        )
        self.string_findings = None
        self.log.debug(inspect.currentframe().f_code.co_name)

    def tag(self):
        return Tag.JS_STRINGS.value

    def _decode_hex_string(self, hex_str):
        """Decode \\x41\\x42 style hex strings."""
        try:
            # Remove \\x prefix and decode
            clean = hex_str.replace('\\x', '')
            return bytes.fromhex(clean).decode('utf-8', errors='replace')
        except Exception:
            return None

    def _decode_unicode_string(self, uni_str):
        """Decode \\u0041\\u0042 style unicode strings."""
        try:
            return uni_str.encode('utf-8').decode('unicode_escape')
        except Exception:
            return None

    def _decode_charcode(self, charcode_str):
        """Decode String.fromCharCode(72, 101, 108, ...) sequences."""
        try:
            codes = [int(c.strip()) for c in charcode_str.split(',') if c.strip().isdigit()]
            return ''.join(chr(c) for c in codes if 0 <= c <= 0x10FFFF)
        except Exception:
            return None

    def _decode_base64(self, b64_str):
        """Attempt to decode base64 string."""
        try:
            decoded = base64.b64decode(b64_str)
            # Check if result is printable text
            text = decoded.decode('utf-8', errors='strict')
            # Only return if it looks like text (>80% printable)
            printable = sum(1 for c in text if c.isprintable() or c in '\n\r\t')
            if printable / len(text) > 0.8:
                return text
        except Exception:
            pass
        return None

    def _reconstruct_concat(self, concat_match):
        """Reconstruct concatenated string parts."""
        try:
            parts = _CONCAT_TOKEN_RE.findall(concat_match)
            return ''.join(parts)
        except Exception:
            return None

    def _find_line_number(self, match_start):
        """1-indexed line number for `match_start`, looked up in O(log L) via
        bisect over `self._line_offsets` (built once per extract() call).

        Replaces the historical `self.js_source[:match_start].count('\\n') + 1`
        which was O(N) per call and quadratic across all matches in a sample.
        """
        return bisect.bisect_right(self._line_offsets, match_start)

    def _scan_text(self, text):
        """Run every encoded-string pattern over `text` and return a list of
        finding dicts. Stateless apart from the per-call `_line_offsets` cache,
        which `_find_line_number` reads — callers must reset it before invoking
        this so line numbers reference the text being scanned, not the previous
        one.
        """
        findings = []

        # Hex-encoded strings
        for m in _HEX_STRING_RE.finditer(text):
            raw = m.group()
            decoded = self._decode_hex_string(raw)
            if decoded and len(decoded) >= 4:
                findings.append({
                    'string': decoded[:4000],
                    'string_raw': raw[:4000],
                    'string_encoding': 'hex',
                    'string_offset': self._find_line_number(m.start()),
                    'string_length': len(decoded),
                    'string_raw_length': len(raw),
                    'string_entropy': self._calculate_text_entropy(decoded),
                })

        # Unicode-encoded strings
        for m in _UNICODE_STRING_RE.finditer(text):
            raw = m.group()
            decoded = self._decode_unicode_string(raw)
            if decoded and len(decoded) >= 3:
                findings.append({
                    'string': decoded[:4000],
                    'string_raw': raw[:4000],
                    'string_encoding': 'unicode',
                    'string_offset': self._find_line_number(m.start()),
                    'string_length': len(decoded),
                    'string_raw_length': len(raw),
                    'string_entropy': self._calculate_text_entropy(decoded),
                })

        # String.fromCharCode sequences
        for m in _CHARCODE_RE.finditer(text):
            raw = m.group()
            decoded = self._decode_charcode(m.group(1))
            if decoded and len(decoded) >= 4:
                findings.append({
                    'string': decoded[:4000],
                    'string_raw': raw[:4000],
                    'string_encoding': 'charcode',
                    'string_offset': self._find_line_number(m.start()),
                    'string_length': len(decoded),
                    'string_raw_length': len(raw),
                    'string_entropy': self._calculate_text_entropy(decoded),
                })

        # Base64-encoded strings
        for m in _BASE64_STRING_RE.finditer(text):
            raw = m.group(0)
            b64_val = m.group(1)
            decoded = self._decode_base64(b64_val)
            if decoded and len(decoded) >= 10:
                findings.append({
                    'string': decoded[:4000],
                    'string_raw': raw[:4000],
                    'string_encoding': 'base64',
                    'string_offset': self._find_line_number(m.start()),
                    'string_length': len(decoded),
                    'string_raw_length': len(raw),
                    'string_entropy': self._calculate_text_entropy(decoded),
                })

        # Concatenated strings (reassembled)
        for m in _CONCAT_STRING_RE.finditer(text):
            raw = m.group()
            reconstructed = self._reconstruct_concat(raw)
            if reconstructed and len(reconstructed) >= 20:
                findings.append({
                    'string': reconstructed[:4000],
                    'string_raw': raw[:4000],
                    'string_encoding': 'concat',
                    'string_offset': self._find_line_number(m.start()),
                    'string_length': len(reconstructed),
                    'string_raw_length': len(raw),
                    'string_entropy': self._calculate_text_entropy(reconstructed),
                })

        return findings

    def extract(self):
        src = self.js_source
        if not src:
            return None

        # Pass 1: raw source. _line_offsets is keyed off whichever text is
        # currently being scanned so _find_line_number resolves to that text.
        self._line_offsets = line_offsets(src)
        findings = self._scan_text(src)

        # Pass 2: deobfuscated text, when the deobfuscator produced something
        # meaningfully different. Same patterns, but a different surface — for
        # samples where the encoded payload is hidden behind an outer wrapper
        # (e.g. array.join() + eval in Vjw0rm/WSH-RAT) only this pass yields
        # any rows at all.
        deobf_text, _ = self._context.deobfuscated
        if deobf_text and deobf_text != src:
            self._line_offsets = line_offsets(deobf_text)
            findings.extend(self._scan_text(deobf_text))

        if not findings:
            return None

        # Deduplicate by decoded string value (raw pass wins on collision: it
        # comes first in `findings`). A string that surfaces only in the
        # deobfuscated text still gets persisted, which is the whole point of
        # the second pass.
        seen_values = set()
        deduped = []
        for f in findings:
            val_key = f['string'][:100]
            if val_key not in seen_values:
                seen_values.add(val_key)
                deduped.append(f)

        self.string_findings = deduped[:500]  # Limit per file
        # Publish to the shared context so post-loop consumers (notably the IOC
        # plumbing in workers.py) can scrape the decoded strings without
        # holding a reference to this extractor instance.
        self._context.decoded_strings = self.string_findings
        return self.string_findings

    def prepare_export_data(self, exporter_type: str) -> Any:
        if exporter_type == "ClickHouseExporter":
            if not self.string_findings:
                return None

            data = []
            for f in self.string_findings:
                data.append([
                    self.sha256,
                    f['string'],
                    f['string_raw'],
                    f['string_encoding'],
                    f['string_offset'],
                    f['string_length'],
                    f['string_raw_length'],
                    f['string_entropy'],
                ])

            column_names = [
                "sha256",
                "string",
                "string_raw",
                "string_encoding",
                "string_offset",
                "string_length",
                "string_raw_length",
                "string_entropy",
            ]

            column_type_names = [
                "FixedString(64)",
                "String",
                "String",
                "LowCardinality(String)",
                "UInt64",
                "UInt32",
                "UInt32",
                "Float32",
            ]

            return (data, column_names, column_type_names)

    def get_clickhouse_table(self) -> str:
        return "code_binja_strings_raw"