J'ai fait cela plusieurs fois et je continue de le faire. Dans ce cas où votre objectif principal est de lire et non d'écrire l'assembleur, je pense que cela s'applique.
Écrivez votre propre désassembleur. Pas dans le but de fabriquer le prochain plus grand désassembleur, celui-ci est strictement pour vous. Le but est d'apprendre le jeu d'instructions. Si j'apprends l'assembleur sur une nouvelle plateforme, je me souviens d'assembleur pour une plateforme que je connaissais autrefois. Commencez avec seulement quelques lignes de code, en ajoutant des registres par exemple, et en faisant un ping-pong entre le démontage de la sortie binaire et l'ajout d'instructions de plus en plus compliquées côté entrée:
1) apprendre le jeu d'instructions pour le processeur spécifique
2) Apprenez les nuances sur la façon d'écrire du code dans l'assemblage pour ledit processeur de sorte que vous puissiez agiter chaque bit d'opcode dans chaque instruction
3) vous apprenez mieux le jeu d'instructions que la plupart des ingénieurs qui utilisent ce jeu d'instructions pour gagner leur vie
Dans votre cas, il y a quelques problèmes, je recommande normalement le jeu d'instructions ARM pour commencer, il y a plus de produits basés sur ARM expédiés aujourd'hui que tout autre (ordinateurs x86 inclus). Mais la probabilité que vous utilisiez ARM maintenant et que vous ne connaissiez pas suffisamment l'assembleur pour qu'il puisse écrire du code de démarrage ou d'autres routines sachant ARM peut ou non aider ce que vous essayez de faire. La deuxième et la plus importante raison pour ARM d'abord est que les longueurs d'instructions sont de taille fixe et alignées. Démonter des instructions de longueur variable comme x86 peut être un cauchemar comme votre premier projet, et le but ici est d'apprendre le jeu d'instructions pour ne pas créer un projet de recherche. Third ARM est un jeu d'instructions bien fait, les registres sont créés égaux et n'ont pas de nuances particulières individuelles.
Vous devrez donc déterminer avec quel processeur vous souhaitez démarrer. Je suggère d'abord le msp430 ou ARM, puis le premier ou le second ARM, puis le chaos de x86. Quelle que soit la plate-forme, toute plate-forme qui vaut la peine d'être utilisée dispose de fiches techniques ou de manuels de référence pour les programmeurs gratuits du fournisseur qui incluent le jeu d'instructions ainsi que le codage des opcodes (les bits et les octets du langage machine). Dans le but d'apprendre ce que fait le compilateur et comment écrire du code avec lequel le compilateur n'a pas à lutter, il est bon de connaître quelques jeux d'instructions et de voir comment le même code de haut niveau est implémenté sur chaque jeu d'instructions avec chaque compilateur avec chaque optimisation réglage. Vous ne voulez pas vous lancer dans l'optimisation de votre code uniquement pour constater que vous l'avez amélioré pour un compilateur / plateforme mais bien pire pour tous les autres.
Oh pour désassembler les jeux d'instructions de longueur variable, au lieu de simplement commencer par le début et de désassembler tous les quatre octets linéairement à travers la mémoire comme vous le feriez avec l'ARM ou tous les deux octets comme le msp430 (Le msp430 a des instructions de longueur variable mais vous pouvez toujours vous en tirer aller linéairement dans la mémoire si vous commencez aux points d'entrée de la table des vecteurs d'interruption). Pour une longueur variable, vous voulez trouver un point d'entrée basé sur une table vectorielle ou des connaissances sur le démarrage du processeur et suivre le code dans l'ordre d'exécution. Vous devez décoder complètement chaque instruction pour savoir combien d'octets sont utilisés, alors si l'instruction n'est pas une branche inconditionnelle, supposez que l'octet suivant après cette instruction est une autre instruction. Vous devez également stocker toutes les adresses de succursales possibles et supposer que ce sont les adresses d'octet de départ pour plus d'instructions. La seule fois où j'ai réussi, j'ai fait plusieurs passages dans le binaire. En commençant au point d'entrée, j'ai marqué cet octet comme le début d'une instruction, puis décodé linéairement à travers la mémoire jusqu'à ce qu'il atteigne une branche inconditionnelle. Toutes les cibles de branche ont été marquées comme adresses de départ d'une instruction. J'ai fait plusieurs passages dans le binaire jusqu'à ce que je n'ai trouvé aucune nouvelle cible de branche. Si à tout moment vous trouvez, disons, une instruction de 3 octets mais que pour une raison quelconque vous avez marqué le deuxième octet comme le début d'une instruction, vous avez un problème. Si le code a été généré par un compilateur de haut niveau, cela ne devrait pas arriver à moins que le compilateur fasse quelque chose de mal, si le code a un assembleur écrit à la main (comme disons un vieux jeu d'arcade), il est tout à fait possible qu'il y ait des branches conditionnelles qui ne peuvent jamais arriver comme r0 = 0 suivi d'un saut sinon zéro. Vous devrez peut-être les modifier à la main hors du binaire pour continuer. Pour vos objectifs immédiats qui, je suppose, seront sur x86, je ne pense pas que vous aurez un problème.
Je recommande les outils gcc, mingw32 est un moyen simple d'utiliser les outils gcc sous Windows si x86 est votre cible. Sinon mingw32 plus msys est une excellente plate-forme pour générer un compilateur croisé à partir de sources binutils et gcc (généralement assez facile). mingw32 a quelques avantages par rapport à cygwin, comme des programmes nettement plus rapides et vous évitez l'enfer des dll cygwin. gcc et binutils vous permettront d'écrire en C ou en assembleur et de désassembler votre code et il y a plus de pages Web que vous ne pouvez en lire pour vous montrer comment faire l'un ou l'autre des trois. Si vous prévoyez de faire cela avec un jeu d'instructions de longueur variable, je vous recommande vivement d'utiliser un jeu d'outils qui comprend un désassembleur. Un désassembleur tiers pour x86 par exemple va être un défi à utiliser car vous ne savez jamais vraiment s'il s'est démonté correctement. Une partie de cela dépend également du système d'exploitation, l'objectif est de compiler les modules dans un format binaire contenant des instructions de marquage d'informations à partir de données afin que le désassembleur puisse faire un travail plus précis. Votre autre choix pour cet objectif principal est d'avoir un outil qui peut compiler directement vers l'assembleur pour votre inspection, puis espérez que lorsqu'il se compile dans un format binaire, il crée les mêmes instructions.
La réponse courte (d'accord un peu plus courte) à votre question. Écrivez un désassembleur pour apprendre un jeu d'instructions. Je commencerais par quelque chose de risqué et facile à apprendre comme ARM. Une fois que vous connaissez un jeu d'instructions, d'autres deviennent beaucoup plus faciles à saisir, souvent en quelques heures, par le troisième jeu d'instructions, vous pouvez commencer à écrire du code presque immédiatement en utilisant la fiche technique / manuel de référence pour la syntaxe. Tous les processeurs à utiliser ont une fiche technique ou un manuel de référence qui décrit les instructions jusqu'aux bits et octets des opcodes. Apprenez un processeur RISC comme ARM et un CISC comme x86 suffisamment pour avoir une idée des différences, des choses comme devoir passer par des registres pour tout ou être capable d'effectuer des opérations directement sur la mémoire avec moins ou pas de registres. Trois instructions d'opérande contre deux, etc. Lorsque vous réglez votre code de haut niveau, compilez pour plus d'un processeur et comparez la sortie. La chose la plus importante que vous apprendrez est que, quelle que soit la qualité de l'écriture du code de haut niveau, la qualité du compilateur et les choix d'optimisation effectués font une énorme différence dans les instructions réelles. Je recommande llvm et gcc (avec binutils), ni produireexcellent code, mais ils sont multi-plateformes et multi-cibles et tous deux ont des optimiseurs. Et les deux sont gratuits et vous pouvez facilement créer des compilateurs croisés à partir de sources pour divers processeurs cibles.