Les codes fantastiques : utilisation d’un bytecode Python invalide

Magazine
Marque
GNU/Linux Magazine
Numéro
261
Mois de parution
janvier 2023
Spécialité(s)


Résumé

Continuons cette série sur les codes fantastiques avec un exemple tiré d’une histoire vécue : retrouver les sources d’un plug-in Python obfusqué...


Body

En Python, un fichier avec l’extension .pyc représente un fichier de bytecode, spécifique à une version de Python. Tout code Python passe par cet état (au moins en mémoire) avant d’être interprété. Fournir un fichier dans un tel format au lieu d’un fichier source n’apporte guère de protection en termes d’obfuscation de code : il est plutôt facile de régénérer les sources à partir d’un fichier de bytecode, en utilisant un outil comme uncompyle6, tout juste perd-on les commentaires...

La créativité humaine n’ayant pas de limite, je vous propose cette protection anti-reverse découverte en analysant un plug-in Python qui avait été volontairement obfusqué. Commençons avec un code des plus simple en apparence :

# hello.py
try: print("bye")
except Exception: print("hello")

Son exécution affiche sans surprise bye dans la console. On peut forcer sa compilation en bytecode :

python -m py_compile hello.py

Et inspecter le bytecode associé à l’aide du script suivant :

import dis, marshal
with open('__pycache__/hello.cpython-36.pyc', 'rb') as f:
    f.seek(12) ; dis.dis(marshal.load(f))

Sans rentrer dans les détails du format pyc, disons qu’on saute les 12 premiers octets d’en-tête pour atterrir sur le code Python qu’on charge avec marshal et désassemble avec dis, ce qui nous donne (extrait) :

  1           0 SETUP_EXCEPT            12 (to 14)
 
  2           2 LOAD_NAME                0 (print)
              4 LOAD_CONST               0 ('bye')
              6 CALL_FUNCTION            1
              8 POP_TOP
             10 POP_BLOCK
             12 JUMP_FORWARD            28 (to 42)
 
  3     >>   14 DUP_TOP

Maintenant, remplaçons l’opcode associé à LOAD_CONST par un 0x10, c’est-à-dire changeons l’opcode associé pour un opcode qui n’aurait pas de sens ici, par exemple BINARY_MATRIX_MULTIPLY, que l’on sauve dans hello.pyc :

python -c 'c = open("__pycache__/hello.cpython-36.pyc", "rb").read(); open("hello.pyc", "wb").write(c[:42] + b"\x10\x00" + c[44:])'

Quand on exécute hello.pyc, malgré la séquence invalide, aucune erreur ne ressort, et le programme affiche hello dans la console.

Que s’est-il passé ? BINARY_MATRIX_MULTIPLY attend deux arguments sur la pile, il a pris ce qu’il y trouvait qui n’a pas de sens (dans ce cas, une string et une fonction, pas le top pour un produit matriciel), il lève alors une exception, que l’on attrape. Et uncompyle6 ne parviendra pas à désassembler le bytecode, échouant sur un joli :

Parse error at or near `BINARY_MATRIX_MULTIPLY' instruction at offset 4


Article rédigé par

Par le(s) même(s) auteur(s)

-ftrivial-auto-var-init : le prix du progrès

Magazine
Marque
MISC
Numéro
127
Mois de parution
mai 2023
Spécialité(s)
Résumé

En C et en C++, les variables déclarées sur la pile sans initialisation n’ont pas de valeur par défaut. Accéder à leur valeur est à la fois une source de comportement indéfini et une source de fuite de données reconnue. De telles situations sont complexes à détecter à la compilation et coûteuses à détecter à l’exécution. Cet article propose d’explorer une alternative disponible dans les compilateurs clang et gcc : -ftrivial-auto-var-init=<value>.

Les derniers articles Premiums

Les derniers articles Premium

Stubby : protection de votre vie privée via le chiffrement des requêtes DNS

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Depuis les révélations d’Edward Snowden sur l’espionnage de masse des communications sur Internet par la NSA, un effort massif a été fait pour protéger la vie en ligne des internautes. Cet effort s’est principalement concentré sur les outils de communication avec la généralisation de l’usage du chiffrement sur le web (désormais, plus de 90 % des échanges se font en HTTPS) et l’adoption en masse des messageries utilisant des protocoles de chiffrement de bout en bout. Cependant, toutes ces communications, bien que chiffrées, utilisent un protocole qui, lui, n’est pas chiffré par défaut, loin de là : le DNS. Voyons ensemble quels sont les risques que cela induit pour les internautes et comment nous pouvons améliorer la situation.

Surveillez la consommation énergétique de votre code

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Être en mesure de surveiller la consommation énergétique de nos applications est une idée attrayante, qui n'est que trop souvent mise à la marge aujourd'hui. C'est d'ailleurs paradoxal, quand on pense que de plus en plus de voitures permettent de connaître la consommation instantanée et la consommation moyenne du véhicule, mais que nos chers ordinateurs, fleurons de la technologie, ne le permettent pas pour nos applications... Mais c'est aussi une tendance qui s'affirme petit à petit et à laquelle à terme, il devrait être difficile d'échapper. Car même si ce n'est qu'un effet de bord, elle nous amène à créer des programmes plus efficaces, qui sont également moins chers à exécuter.

Donnez une autre dimension à vos logs avec Vector

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Avoir des informations précises et détaillées sur ce qu’il se passe dans une infrastructure, et sur les applications qu'elle héberge est un enjeu critique pour votre business. Cependant, ça demande du temps, temps qu'on préfère parfois se réserver pour d'autres tâches jugées plus prioritaires. Mais qu'un système plante, qu'une application perde les pédales ou qu'une faille de sécurité soit découverte et c'est la panique à bord ! Alors je vous le demande, qui voudrait rester aveugle quand l'observabilité a tout à vous offrir ?

Les listes de lecture

9 article(s) - ajoutée le 01/07/2020
Vous désirez apprendre le langage Python, mais ne savez pas trop par où commencer ? Cette liste de lecture vous permettra de faire vos premiers pas en découvrant l'écosystème de Python et en écrivant de petits scripts.
11 article(s) - ajoutée le 01/07/2020
La base de tout programme effectuant une tâche un tant soit peu complexe est un algorithme, une méthode permettant de manipuler des données pour obtenir un résultat attendu. Dans cette liste, vous pourrez découvrir quelques spécimens d'algorithmes.
10 article(s) - ajoutée le 01/07/2020
À quoi bon se targuer de posséder des pétaoctets de données si l'on est incapable d'analyser ces dernières ? Cette liste vous aidera à "faire parler" vos données.
Voir les 61 listes de lecture

Abonnez-vous maintenant

et profitez de tous les contenus en illimité

Je découvre les offres

Déjà abonné ? Connectez-vous