EVM approfondie - les risques derrière la question triviale de la classification des contrats

Dans le domaine des contrats intelligents, la "Ethereum Virtual Machine EVM" et ses algorithmes et structures de données sont des principes premiers.

Cet article commence par les raisons pour lesquelles les contrats doivent être classés, combine les types d'attaques malveillantes auxquelles chaque scénario peut être confronté et propose enfin un ensemble d'algorithmes d'analyse de classification des contrats relativement sûrs.

**Bien que le contenu technique soit élevé, il peut également être utilisé comme support de lecture pour des conférences diverses.**Regard sur la sombre forêt des jeux entre systèmes décentralisés.

1. Pourquoi les contrats doivent-ils être classifiés ?

Parce qu'il est si important, on peut dire qu'il est la pierre angulaire des Dapps tels que les échanges, les portefeuilles, les navigateurs blockchain, les plateformes d'analyse de données, etc. !

La raison pour laquelle une transaction est un transfert ERC20 est que son comportement est conforme à la norme ERC20, au moins :

  1. Le statut de la transaction est succès
  2. L'adresse de destination est un contrat conforme à la norme ERC20
  3. La fonction de transfert est appelée, et la caractéristique est que les 4 premiers chiffres du CallData de la transaction sont 0xa9059cbb
  4. Après exécution, un événement de transfert est envoyé sur l'adresse À

Si la classification est erronée, le comportement de la transaction sera mal jugé

Avec le comportement de la transaction comme pierre angulaire, la question de savoir si l'adresse To peut être classée avec précision conduira à une conclusion complètement différente dans le jugement de son CallData. Pour Dapp, la communication d'informations sur et hors de la chaîne dépend fortement de la surveillance des événements de transaction, et le même code d'événement ne peut être fiable que s'il est envoyé dans un contrat qui respecte les normes.

Si la classification est erronée, la transaction ira dans le trou noir par erreur

Si l'utilisateur transfère un Token dans un certain contrat, si le contrat n'a pas de méthode de fonction prédéfinie pour le transfert de Token, les fonds seront verrouillés de la même manière que Burn et ne pourront pas être contrôlés

Et maintenant qu'un grand nombre de projets ont commencé à ajouter un support de portefeuille intégré, il est inévitable de gérer les portefeuilles pour les utilisateurs. Il est nécessaire de classer les derniers contrats déployés de la chaîne en temps réel à tout moment, s'ils peuvent répondre les normes patrimoniales.

Au plus profond du risque derrière la question triviale de la classification des contrats EVM

2. Quels sont les risques du classement ?

**La chaîne est un endroit où il n'y a pas d'identité et pas d'état de droit. Vous ne pouvez pas arrêter une transaction normale, même si elle est malveillante. **

Il peut être un loup prétendant être une grand-mère, faisant la plupart des comportements que vous attendez d'une grand-mère, mais dans le but de pénétrer par effraction dans la maison et de voler.

Réclame la norme, mais peut ne pas répondre réellement

Une méthode de classification courante consiste à adopter directement la norme EIP-165 pour lire si l'adresse prend en charge ERC20, etc. Bien sûr, c'est une méthode efficace, mais après tout, le contrat est contrôlé par l'autre partie, donc une déclaration peut être forgé après tout.

La requête standard 165 n'est qu'une méthode pour empêcher les fonds d'être transférés dans des trous noirs avec le coût le plus bas parmi les codes d'opération limités de la chaîne.

C'est pourquoi, lorsque nous avons analysé NFT auparavant, nous avons spécifiquement mentionné qu'il y aura une méthode SafeTransferFrom dans la norme, où Safe fait référence à l'utilisation de la norme 165 pour déterminer que l'autre partie a la capacité de transférer NFT.

Ce n'est qu'en partant du bytecode du contrat, en effectuant une analyse statique au niveau du code source et en partant du comportement attendu du contrat qu'il peut être plus précis.

3. Conception du système de classification des contrats

Ensuite, nous analyserons systématiquement le plan global et notons que notre objectif ultime est les deux indicateurs de base de "précision" et "d'efficacité". **

Vous devez savoir que même si la direction est bonne, le chemin pour atteindre l'autre côté de la mer n'est pas clair. La première étape pour faire une analyse de bytecode est d'obtenir le code

3.1. Comment obtenir le code ?

Du point de vue d'aller à la chaîne, il y a getCode, une méthode RPC, qui permet d'obtenir le bytecode à partir de l'adresse indiquée sur la chaîne.C'est très rapide en terme de lecture, car le codeHash est placé dans la structure du compte de l'EVM tout en haut.

Au plus profond du risque derrière la question triviale de la classification des contrats EVM

Mais cette méthode revient à obtenir une certaine adresse seule.Vous voulez encore améliorer la précision et l'efficacité ?

S'il s'agit d'une transaction de déploiement de contrat, comment obtenir le code déployé juste après son exécution ou même lorsqu'il est encore dans le pool de mémoire ?

Si la transaction est en mode usine de contrat, y a-t-il un code source dans les données d'appel de la transaction ?

Au final, ma façon est de classer en mode passoire

  1. Pour les transactions déployées hors contrat, utilisez directement getCode pour obtenir les adresses impliquées pour la classification.
  2. Pour les dernières transactions de pool de mémoire, filtrez les transactions dont l'adresse est vide et dont CallData est le code source avec le constructeur
  3. Pour la transaction du mode contract factory, puisque le contrat déployé par le contrat peut être recyclé pour appeler d'autres contrats pour exécuter le déploiement, il va analyser récursivement les sous-transactions de la transaction, et enregistrer chaque appel dont le type est CREATE ou CRÉER2 .

Lorsque j'ai fait une implémentation de démonstration, j'ai trouvé que la version rpc est relativement élevée maintenant, car la partie la plus difficile de tout le processus est de trouver de manière récursive l'appel du type spécifié lors de l'exécution de 3. La méthode de niveau inférieur consiste à restaurer le contexte à travers l'opcode. J'ai été surpris !

Heureusement, il existe une méthode debug_traceTransaction dans la version actuelle de geth, qui peut aider à trier les informations de contexte de chaque appel via le code d'opération de l'opcode et à trier les champs principaux.

Au final, les bytecodes originaux des différents modes de déploiement (déploiement direct, déploiement unique en mode usine, déploiement par lots en mode usine) peuvent être obtenus.

3.2 Comment classer à partir du code ?

Le moyen le plus simple mais le moins sûr consiste à faire directement correspondre les chaînes avec le code. En prenant ERC20 comme exemple, la fonction qui répond à la norme a

Au plus profond du risque derrière la question triviale de la classification des contrats EVM

Après le nom de la fonction se trouve la signature de la fonction.Comme mentionné dans l'analyse précédente, la transaction dépend de la correspondance des 4 premiers chiffres de callData pour trouver la fonction cible.

Par conséquent, les signatures de ces 6 fonctions doivent être stockées dans le bytecode du contrat.

Bien sûr, cette méthode est très rapide et vous pouvez trouver les 6, mais le facteur dangereux est que si j'utilise le contrat de solidité et que je conçois une variable avec une valeur de stockage de 0x18160ddd, alors il pensera que j'ai cette fonction.

3.3. Amélioration du taux de précision 1- décompilation

La méthode la plus précise consiste à décompiler Opcode! La décompilation est le processus de conversion des bytecodes obtenus en opcodes, et une décompilation plus avancée consiste à les convertir en pseudocodes, ce qui est plus propice à la lecture humaine. Nous n'en avons pas besoin cette fois. La méthode de décompilation est répertoriée dans l'annexe à la fin de l'article.

solidity (langage de haut niveau) -> bytecode (bytecode) -> opcode (code d'opération)

Nous pouvons clairement trouver une fonctionnalité, la signature de fonction sera exécutée par l'opcode PUSH4, donc la méthode supplémentaire consiste à extraire le contenu après PUSH4 du texte intégral et à le faire correspondre à la norme de fonction.

Au plus profond des risques derrière la question triviale de la classification des contrats EVM

J'ai également fait une expérience de performance simple, et je dois dire que le langage Go est très efficace, et qu'il ne prend que 220 ms pour 10 000 décompilations.

La suite sera difficile

3.4. Amélioration du taux de précision Bloc de code 2-find

Le taux de précision ci-dessus a été amélioré mais pas assez, car il s'agit d'une recherche en texte intégral PUSH4, car nous pouvons toujours construire une variable, qui est de type byte4, qui déclenchera également la commande PUSH4.

Quand j'étais en détresse, j'ai pensé à la mise en place de certains projets open source. ETL est un outil de lecture de données sur la chaîne pour analyse. Il analysera le transfert de ERC20 et 721 dans des tables séparées, il doit donc avoir la capacité de classer contrats.

Au plus profond du risque derrière la question triviale de la classification des contrats EVM

Après analyse, on constate qu'il se base sur la classification des blocs de code et ne traite que les premiers blocs_de base [0] L'instruction push4 dans

** La question vient, comment juger avec précision le bloc de code **

Le concept de bloc de code vient des deux opcodes consécutifs de REVERT + JUMPDEST. Il doit y avoir deux opcodes consécutifs ici, car dans l'intervalle d'opcode de tout le sélecteur de fonction, s'il y a trop de fonctions, la logique de rotation de page apparaîtra Ensuite, la commande JUMPDEST apparaîtra également.

Au plus profond des risques derrière la question triviale de la classification des contrats EVM

3.5. Amélioration du taux de précision Sélecteur de fonction 3-Find

La fonction du sélecteur de fonction est de lire les 4 premiers octets des données d'appel de la transaction, et de les faire correspondre avec la signature de fonction de contrat prédéfinie dans le code, et d'aider l'instruction à sauter à l'emplacement de mémoire spécifié par la méthode de fonction

Essayons une simulation d'exécution minimale

Cette partie est le sélecteur store(uint 256) et retrieve() des deux fonctions, et la signature peut être calculée comme 2e64cec1, 6057361d

Au plus profond du risque derrière la question triviale de la classification des contrats EVM

Après la décompilation, vous obtiendrez la chaîne d'opcode suivante, qui peut être considérée comme divisée en deux parties

première partie:

Dans le compilateur, seule la partie sélecteur de fonction du contrat obtiendra le contenu de callData, ce qui signifie obtenir la signature d'appel de fonction de son CallData, comme indiqué dans la figure ci-dessous.

Au plus profond du risque derrière la question triviale de la classification des contrats EVM

Nous pouvons voir l'effet en simulant le changement du pool de mémoire d'EVM

Au plus profond du risque derrière la question triviale de la classification des contrats EVM

La seconde partie:

Le processus de jugement s'il correspond à la valeur du sélecteur

  1. Passez la signature de fonction 4 octets (0x2e64cec1) de retrieve() à la pile,

  2. L'opcode EQ extrait 2 variables de la zone de pile, à savoir 0x2e64cec1 et 0x6057361d, et vérifie si elles sont égales

  3. PUSH2 transfère 2 octets de données (ici 0x003b, 59 en décimal) dans la pile Il y a un compteur de programme dans la zone pile, qui précise la position de la prochaine commande à exécuter dans le bytecode. Ici, nous définissons 59 car c'est là que commence le bytecode retrieve()

  4. JUMPI signifie "Aller à si...", il extrait 2 valeurs de la pile en entrée, et si la condition est vraie, le compteur du programme sera mis à jour à 59.

C'est ainsi que l'EVM détermine l'emplacement du bytecode de fonction dont il a besoin pour s'exécuter en fonction de l'appel de fonction dans le contrat.

En réalité, il ne s'agit que d'un simple ensemble d'"instructions if" pour chaque fonction du contrat et où elles sautent.

Au plus profond du risque derrière la question triviale de la classification des contrats EVM

4. Résumé du régime

Le brief général est le suivant

  1. Chaque adresse de contrat peut obtenir le bytecode après le déploiement via rpcgetcode ou debug_traceTransaction, en utilisant les bibliothèques VM et ASM dans GO, et l'opcode peut être obtenu après décompilation
  2. Dans le principe de fonctionnement EVM, le contrat aura les caractéristiques suivantes
  • Utilisez REVERT+JUMPDEST comme distinction de bloc de code
  • Le contrat doit avoir la fonction d'un sélecteur de fonction, et cette fonction doit également être sur le premier bloc de code
  • Dans le sélecteur de fonction, ses méthodes de fonction utilisent toutes PUSH4 comme opcode,
  • Dans l'opcode contenu dans ce sélecteur, il y aura PUSH1 00 ; CALLDATALOAD ; PUSH1 e0 ; SHR ; DUP1. La fonction principale consiste à charger les données callDate et à effectuer des opérations de déplacement. À partir de la fonction contract, aucune autre syntaxe ne générera
  1. La signature de fonction correspondante est définie dans eip, et il existe des instructions claires obligatoires et facultatives

4.1. Preuve d'unicité

À ce stade, nous pouvons dire qu'une méthode d'analyse de contrat à haute efficacité et haute précision a été essentiellement réalisée. Bien sûr, puisqu'elle a été rigoureuse pendant si longtemps, nous pourrions tout aussi bien être plus rigoureux. Dans le schéma ci-dessus, nous utiliser REVER + JUMPDEST pour distinguer les blocs de code et combiner le chargement et le déplacement inévitables de CallDate pour porter un jugement unique Existe-t-il que je puisse utiliser un contrat de solidité pour implémenter une séquence d'opcode similaire?

J'ai fait une expérience de contrôle Bien qu'il existe des méthodes d'obtention de CallData telles que msg.sig à partir du niveau de grammaire solidité, les méthodes d'implémentation de l'opcode après compilation sont différentes.

Au plus profond du risque derrière la question triviale de la classification des contrats EVM

Voir l'original
Le contenu est fourni à titre de référence uniquement, il ne s'agit pas d'une sollicitation ou d'une offre. Aucun conseil en investissement, fiscalité ou juridique n'est fourni. Consultez l'Avertissement pour plus de détails sur les risques.
  • Récompense
  • Commentaire
  • Partager
Commentaire
0/400
Aucun commentaire
  • Épingler
Trader les cryptos partout et à tout moment
qrCode
Scan pour télécharger Gate.io app
Communauté
Français (Afrique)
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)