
Boîte à outils de désobfuscation statique pour le bytecode JavaScript V8 compilé, axée sur les charges utiles JSCeal. Fournit des filtres basés sur des motifs, le déplissement du flux de contrôle, la reconstruction de chaînes et un renommage de fonctions assisté par LLM en option pour l’analyse.
Cet outil est dédié à la désobfuscation statique du bytecode JavaScript V8 compilé qui a été protégé avec javascript-obfuscator.
Il opère sur le pseudocode produit par View8, plutôt que sur le code source JavaScript d'origine. Le projet a été développé et testé sur des charges utiles JSCeal.
Les filtres sont pilotés par des motifs et destinés principalement à servir de boîte à outils de recherche et d'implémentation de référence. L'outil n'est pas un désobfuscateur JavaScript à usage général, ne reconstruit pas le code source d'origine et ne produit pas de JavaScript exécutable. Sa sortie reste du pseudocode View8 destiné à l'inspection statique, la recherche, la comparaison et l'exportation d'arbres de fonctions.
pickle de Python. Charger un fichier .pkl malveillant ou non fiable peut exécuter du code. Ne chargez que des fichiers sérialisés que vous avez générés localement avec View8.requirements.txt ;brotli pour le flux de travail de dépaquetage par lots sous Linux ;Créez un environnement Python isolé :
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install --upgrade pip
python3 -m pip install -r requirements.txt
Le backend OpenAI dans deobf_ai.py nécessite en outre le package Python OpenAI :
python3 -m pip install openai
Le backend Anthropic utilise l'API HTTP via requests. Le backend Ollama attend un serveur Ollama accessible.
La charge utile JSCeal d'origine app.jsc est compressée en Brotli. Sous Linux, elle peut être décompressée avec l'utilitaire brotli :
brotli -d app.jsc -o app.decompressed.jsc
Le flux de travail par lots sous scripts/ effectue cette étape avec scripts/unpack_all.sh.
Sous Windows, ou lorsque l'utilitaire en ligne de commande brotli n'est pas disponible, l'assistant Node.js inclus peut être utilisé comme repli. Il décompresse uniquement l'entrée et ne l'exécute pas :
node Utils/decompress-jsc.js app.jsc
Il écrit :
app.jsc.decompressed.jsc
Le cache de code V8 est spécifique à une version. Utilisez un désassembleur construit pour la même version de V8 que la charge utile.
Les échantillons JSCeal utilisés pendant le développement étaient basés sur V8 10.2.154.26. Les désassembleurs par défaut d'une compilation V8 sans rapport ne fonctionneront pas correctement.
L'arborescence source contient le code source du désassembleur et les correctifs V8 requis sous :
Utils/disasm/v8dasm.cpp
Utils/disasm/patches/
Un binaire Linux précompilé est distribué avec la version du projet, tandis que l'arborescence source contient le code source et les correctifs nécessaires pour le recompiler. Une description détaillée est disponible sur le Wiki du projet. Après avoir obtenu ou compilé le v8dasm correspondant, exécutez :
/path/to/v8dasm app.decompressed.jsc > app.jsc.disasm.txt
Fournissez le fichier désassemblé à view8.py et produisez à la fois une sortie sérialisée pour un traitement ultérieur et un pseudocode lisible par l'humain :
mkdir -p decompiled
python3 View8/view8.py \
--input_format disassembled \
--inp app.jsc.disasm.txt \
--normalize \
--out decompiled/app.dec.txt \
--export_format decompiled serialized
Cela produit :
decompiled/app.dec.txt
decompiled/app.dec.pkl
L'option --normalize rend les identifiants de fonctions générés reproductibles entre les exécutions répétées de désassemblage et de décompilation.
Il existe des filtres séparés pour les différentes couches d'obfuscation. Ils peuvent être appliqués ensemble à la sortie sérialisée de View8 avec deobf_all.py :
mkdir -p deobfuscated
python3 deobf_all.py \
--inp decompiled/app.dec.pkl \
--out deobfuscated/app.deobf.txt \
--export_format decompiled serialized
Le filtre de chaînes par défaut est la variante 2, utilisée par la majorité des charges utiles JSCeal analysées. Pour sélectionner explicitement le schéma de chaînes plus simple, ajoutez :
--str_deobf 1
Les sorties typiques sont :
deobfuscated/app.deobf.txt
deobfuscated/app.deobf.pkl
deobfuscated/app.deobf.txt.strings.txt
decompiled/app.dec.resolved_funcs.csv
Le CSV des fonctions résolues est un cache spécifique à l'échantillon. Lorsqu'il est absent, la passe de chaînes récupère la configuration de décodeur requise, écrit le CSV et continue la désobfuscation des chaînes dans la même exécution. Les exécutions ultérieures réutilisent le cache et sont normalement plus rapides.
Ne réutilisez pas un CSV de fonctions résolues avec une charge utile décompilée différente.
Après l'application de tous les filtres de désobfuscation structurelle, deobf_ai.py peut proposer des noms qui décrivent le comportement des fonctions. Il prend en charge les backends Anthropic, OpenAI et Ollama.
Transmettez le modèle explicitement afin que les exécutions restent reproductibles.
export ANTHROPIC_API_KEY='...'
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--out deobfuscated/app.renamed.txt \
--llm_backend anthropic \
--model '<model-id>' \
--export_format decompiled serialized
export OPENAI_API_KEY='...'
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--out deobfuscated/app.renamed.txt \
--llm_backend openai \
--model '<model-id>' \
--export_format decompiled serialized
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--out deobfuscated/app.renamed.txt \
--llm_backend ollama \
--model '<local-model>' \
--ollama_url http://localhost:11434 \
--export_format decompiled serialized
En mode par défaut, le renommeur construit un arbre d'appels directs à partir de la fonction d'entrée et ne renomme que les fonctions atteintes par des appels. Ajoutez --greedy pour inclure toutes les références de fonctions visibles, y compris les callbacks et les gestionnaires assignés.
Le CSV à deux colonnes généré sert de cache et permet à une exécution interrompue de continuer. Sélectionnez un cache existant explicitement avec --csv :
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--out deobfuscated/app.renamed.txt \
--csv deobfuscated/app.deobf.renamed_funcs.greedy.example-model.csv \
--llm_backend anthropic \
--model '<model-id>' \
--greedy \
--export_format decompiled serialized