| Abstract: | Modern decompilers have significantly lowered the barrier to reverse engineering, producing
readable pseudo-code that enables rapid analysis of compiled binaries. While numerous obfuscation
techniques exist to impede comprehension, they typically introduce distinctive patterns
that make protected code trivially detectable, undermining their practical utility.
This thesis presents four composable anti-decompilation primitives for the x86 architecture
that exploit implicit assumptions in decompiler algorithms to hide code from analysis tools
while minimizing observable artifacts. The primitives include: state corruption through calleesaved
register manipulation to induce dead branch elimination; x86-64 mode switching to
exploit instruction encoding differences between 32-bit and 64-bit modes; overlapping instruction
encoding to conceal function calls within legitimate instruction operands; and function
boundary confusion to prevent function discovery in disassembler listings.
Unlike traditional potency-focused obfuscation that makes code difficult to understand, these
primitives achieve concealment-focused protection that renders target code invisible to decompilers.
Each primitive has a well-defined artifact profile enabling strategic composition, where
multiple primitives can be layered to achieve complete artifact elimination.
A source-to-source transformation tool implementing these primitives is presented, allowing
selective application through simple code annotations. Evaluation across IDA Pro, Ghidra, and
Binary Ninja demonstrates that all primitives successfully hide target code while maintaining
high concealment across local, global, and strategic dimensions.***
Les décompilateurs modernes ont considérablement réduit la barrière à la rétro-ingénierie,
produisant un pseudo-code lisible qui permet une analyse rapide des binaires compilés. Bien que
de nombreuses techniques d’obfuscation existent pour entraver la compréhension, elles introduisent
généralement des motifs distinctifs qui rendent le code protégé trivialement détectable,
compromettant ainsi leur utilité pratique.
Cette thèse présente quatre éléments de base anti-décompilation composables pour
l’architecture x86 qui exploitent les hypothèses implicites des algorithmes de décompilateurs
pour cacher le code aux outils d’analyse tout en minimisant les artefacts observables. Ces
éléments comprennent : la corruption d’état par manipulation des registres sauvegardés par
l’appelé pour induire l’élimination de branches mortes ; le changement de mode x86-64 pour
exploiter les différences d’encodage des instructions entre les modes 32 bits et 64 bits ; l’encodage
d’instructions chevauchantes pour dissimuler les appels de fonctions dans les opérandes
d’instructions légitimes ; et la confusion des limites de fonctions pour empêcher la découverte
de fonctions dans les listings du désassembleur.
Contrairement à l’obfuscation traditionnelle axée sur la puissance qui rend le code difficile à
comprendre, ces éléments de base réalisent une protection axée sur la dissimulation qui rend
le code cible invisible aux décompilateurs. Chaque élément possède un profil d’artefacts bien
défini permettant une composition stratégique, où plusieurs éléments peuvent être superposés
pour atteindre une élimination complète des artefacts.
Un outil de transformation source-à-source implémentant ces éléments est présenté, permettant
une application sélective via de simples annotations de code. L’évaluation sur IDA Pro, Ghidra
et Binary Ninja démontre que tous les éléments cachent avec succès le code cible tout en
maintenant une haute dissimulation à travers les dimensions locale, globale et stratégique. |