Avec les langages de machine virtuelle basés sur le bytecode comme Java, VB.NET, C #, ActionScript 3.0, etc., vous entendez parfois à quel point il est facile de télécharger un décompilateur sur Internet, d'exécuter le bytecode à travers lui un bon moment, et souvent, trouver quelque chose pas trop loin du code source d'origine en quelques secondes. Soi-disant ce type de langage est particulièrement vulnérable à cela.
J'ai récemment commencé à me demander pourquoi vous n'en entendez pas plus à ce sujet concernant le code binaire natif, alors que vous savez au moins dans quelle langue il a été écrit à l'origine (et donc, dans quelle langue essayer de décompiler). Pendant longtemps, j'ai pensé que c'était simplement parce que le langage machine natif était tellement plus fou et plus complexe que le bytecode typique.
Mais à quoi ressemble le bytecode? Cela ressemble à ceci:
1000: 2A 40 F0 14
1001: 2A 50 F1 27
1002: 4F 00 F0 F1
1003: C9 00 00 F2
Et à quoi ressemble le code machine natif (en hexadécimal)? Cela ressemble bien sûr à ceci:
1000: 2A 40 F0 14
1001: 2A 50 F1 27
1002: 4F 00 F0 F1
1003: C9 00 00 F2
Et les instructions viennent d'un état d'esprit quelque peu similaire:
1000: mov EAX, 20
1001: mov EBX, loc1
1002: mul EAX, EBX
1003: push ECX
Donc, étant donné le langage pour essayer de décompiler un binaire natif en, disons C ++, qu'est-ce qui est si difficile? Les deux seules idées qui me viennent immédiatement à l'esprit sont 1) c'est beaucoup plus complexe que le bytecode, ou 2) le fait que les systèmes d'exploitation ont tendance à paginer les programmes et à disperser leurs morceaux pose trop de problèmes. Si l'une de ces possibilités est correcte, veuillez expliquer. Mais de toute façon, pourquoi n'en entendez-vous jamais parler?
REMARQUE
Je suis sur le point d'accepter l'une des réponses, mais je veux d'abord mentionner quelque chose. Presque tout le monde fait référence au fait que différentes parties du code source original peuvent correspondre au même code machine; les noms des variables locales sont perdus, vous ne savez pas quel type de boucle a été utilisé à l'origine, etc.
Cependant, des exemples comme les deux qui viennent d'être mentionnés sont plutôt triviaux à mes yeux. Cependant, certaines des réponses tendent à dire que la différence entre le code machine et la source d'origine est considérablement plus que quelque chose d'aussi trivial.
Mais par exemple, lorsqu'il s'agit de choses comme les noms de variables locales et les types de boucles, le bytecode perd également ces informations (au moins pour ActionScript 3.0). J'ai déjà récupéré ces trucs dans un décompilateur auparavant, et je ne me souciais pas vraiment si une variable était appelée strMyLocalString:String
ou loc1
. Je pouvais toujours regarder dans cette petite portée locale et voir comment il était utilisé sans trop de problèmes. Et une for
boucle est à peu près la même chose exacte qu'unwhile
boucle, si vous y pensez. De plus, même lorsque j'exécutais la source via irrFuscator (qui, contrairement à secureSWF, ne fait pas beaucoup plus que simplement randomiser les noms de variables et de fonctions des membres), il semblait toujours que vous pouviez simplement commencer à isoler certaines variables et fonctions dans des classes plus petites, figure comment ils sont utilisés, attribuez-leur vos propres noms et travaillez à partir de là.
Pour que cela soit un gros problème, le code machine devrait perdre beaucoup plus d'informations que cela, et certaines des réponses vont dans ce sens.