
Cet article est une version texte de mon
discours au 35e Chaos Computer Congress fin 2018.
Et donc je dois admettre que MS-DOS me fait un peu scandale, malgré le fait que les logiciels malveillants MS-DOS m'ont toujours fasciné dans une certaine mesure, mais nous devons d'abord demander: "Qu'est-ce que DOS?"
- DOS est une version de CP / M, un autre très ancien système d'exploitation.
- La famille DOS couvre un large éventail de fournisseurs, tout simplement parce que c'est DOS ne signifie pas qu'il fonctionnera sur un processeur 8086 ou mieux
- Certains de ces fournisseurs DOS ont une compatibilité API, ce qui signifie que certains d'entre eux utilisent des logiciels malveillants!
Vidéo de performance:
Le poste a été écrit avec le soutien d'EDISON Software, qui développe une application pour un opérateur mobile virtuel et est engagé dans le développement et la maintenance de sites en Python .

Mais en fait, la plupart de nos souvenirs de l'ère DOS sont l'esthétique de l'apparence des ordinateurs de l'époque:

C'est l'ère du «calcul beige» et du clavier Model M, qui peuvent être célèbres ou tristement célèbres selon que vous aimez ou non le clavier bruyant.

Certains d'entre nous peuvent avoir des souvenirs de l'utilisation de DOS, et certains peuvent toujours utiliser DOS!

Par exemple, selon la rumeur, George R. Martin, qui a écrit The Game of Thrones, aurait utilisé Wordstar sous DOS pour écrire un livre!

Nous ne pouvons pas non plus manquer QBASIC, pour beaucoup ce serait leur première connaissance de la programmation!

Mais parfois, la vie avec DOS n'était pas si bonne, parfois vous utilisiez DOS, et des choses comme ça se produisaient soudainement. Dans cet exemple, une petite mélodie est jouée pendant l'impression, ce qui peut être une situation très délicate dans un environnement de bureau.

Certains d'entre eux sont plus «mignons», dans ce cas, par exemple, une ambulance dessinée par des symboles ascii passe, puis le programme que vous souhaitez ouvrir démarre, dans le pire des cas, avec de légers inconvénients.
Grâce à un tas d'archivistes de malwares fonctionnant sous le nom de VX Heavens, nous avons une bonne archive historique de malwares DOS, ou du moins jusqu'à ce que la police ukrainienne fasse une descente sur le site:
Vendredi 23 mars, le serveur a été saisi par la police dans le cadre d'une enquête criminelle (article 361-1 du Code pénal d'Ukraine - création de logiciels malveillants dans le but de le vendre ou de le distribuer) sur la base d'une incitation de quelqu'un. sur «la mise en libre accès de logiciels malveillants conçus pour le piratage non autorisé d'ordinateurs, de systèmes automatisés, de réseaux informatiques».
Heureusement, les sites torrent populaires ont toujours des copies de la base de données du site qui peuvent nous fournir un excellent ensemble de données:
$ tar -tvf viruses-20070914.tar | wc -l 66714 $ ls -alh viruses-20070914.tar 6.6G viruses-20070914.tar
Cependant, pour commencer à étudier ces échantillons, nous devons d'abord comprendre le flux de distribution typique de ces échantillons, étant donné que ces programmes fonctionnaient à l'ère pré-Internet:

Après avoir reçu le fichier infecté sur votre système et l'exécuter, le programme malveillant recherchera ou installera activement des intercepteurs d'appels système pour les programmes que vous exécutez. Il le fait souvent de manière subtile et invisible pour éviter d'être détecté. L'importance de la subtilité est importante car pour distribuer ce programme malveillant, vous devez soit le transférer sur un autre système à l'aide d'un support (disquette), soit le télécharger sur un autre point de distribution, tel que BBS.

À l'exécution, le logiciel malveillant a deux options; il peut soit rester caché et infecter de nouveaux fichiers, soit afficher une charge utile.
Certaines charges utiles sont plutôt jolies! L'exemple ci-dessous utilise des fonctions inhabituelles, telles que 256 couleurs:

Ou celui-ci qui joue avec votre tampon d'écran:


Cependant, dans la plupart des cas, le logiciel malveillant restera silencieux et tentera de trouver des fichiers à infecter. L'infection de la plupart des fichiers est très simple, par exemple, si vous affichez le fichier COM comme une longue bande de code machine:

Ensuite, «tout ce que vous avez à faire» consiste à insérer JMP au début du programme et à ajouter des données à la fin du programme. Cela ressemblera à ceci:

Certains codes étaient plus intelligents et trouvaient de «l'espace vide» dans le fichier binaire et s'y écrivaient, ce qui empêchait le fichier binaire d'augmenter de taille, ce qui signifiait peut-être que l'antivirus pouvait utiliser le drapeau rouge.

Cependant, plus tôt, j'ai également mentionné l'interception des appels système. Malgré le fait que le runtime MS-DOS est très simple et pratiquement non protégé (vous pouvez trivialement charger Linux à partir d'un fichier COM). Il contient toujours l'API complète afin que les applications n'aient pas besoin d'avoir leur propre implémentation de système de fichiers. Voici quelques fonctionnalités de syscalls:

Ils fonctionnent en provoquant une interruption logicielle, dans laquelle le programme demande au processeur de se déplacer vers une autre section de la mémoire système pour traiter quelque chose:

Cependant, MS-DOS offre également la possibilité d'ajouter / modifier ces appels (en utilisant un autre appel), vous permettant d'étendre le système afin que les nouveaux pilotes puissent se charger au moment de l'exécution. Cependant, c'est également un endroit idéal pour ajouter des interceptions de logiciels malveillants:

C'était une astuce bien utilisée, car vous pouviez intercepter l'appel «Open File» et ensuite l'utiliser pour détecter de nouveaux fichiers exécutables dans le système ... et les infecter.
Comme exemple rapide de leur utilisation, regardons un simple programme Hello World:

Comme nous pouvons le voir, il existe deux appels de type
int
. Nous utilisons
21h
(h = hex) comme numéro d'appel système principal, et nous pouvons spécifier quelle action nous voulons que MS-DOS effectue en fonction de la valeur de
Ah

Dans ce cas, le programme effectue un appel pour imprimer la ligne, puis se termine avec le code retour 0 (non défini).
Comme mentionné précédemment. Lorsque vous appelez int 21h, le processeur central cherchera dans la table IVT où aller, à l'intérieur de ce gestionnaire, il y a souvent un segment tel qu'un routeur qui achemine divers appels principaux, dans le cas d'Int 21h, il dirige vers diverses fonctions en fonction de la valeur ah. Dès que nous arrivons à l'endroit, le gestionnaire d'appel réel s'occupera de la tâche, puis il exécutera iret pour revenir au programme principal, laissant souvent des registres des résultats de l'appel:

Alors Si nous voulons voir tous les appels système que le programme a démarrés, nous pouvons définir un point d'arrêt au début du gestionnaire d'interruption et vérifier ce qu'est ah:

Nous le faisons parce que le gestionnaire d'interruption est toujours à un emplacement fixe dans MS-DOS (c'est beaucoup plus tôt que l'ère ASLR et ASLR du noyau), et l'emplacement du programme ne l'est pas.

Une fois que nous l'avons lancé, nous pouvons voir les défis posés par ce modèle. Alors que nous pouvons voir à l'écran qu'il vient d'imprimer une notification sur le fichier Goat (Goat est un fichier conçu pour infecter, comme une chèvre sacrificielle). Nous voyons également que ce programme fait plus que simplement imprimer une ligne. Il vérifie la version DOS (probablement pour vérifier la compatibilité) puis ouvre, lit et écrit des données!

C'est intéressant! Mais nous aimerions en savoir plus sur ce que le système appelle surligné en rouge, car ils doivent avoir une entrée pour des choses comme les noms de fichiers et les données à écrire dans les fichiers / sortie à l'écran.
Pour ce faire, nous devons examiner d'autres registres lors de l'appel système:

En utilisant "Print String" comme exemple simple, nous pouvons voir à quoi ressemble l'utilisation:

Qu'est-ce que DS: DX? Pourquoi y a-t-il deux registres ici, et comment pouvons-nous obtenir des données d'eux?
Pour ce faire, nous devons comprendre un peu plus le processeur 8086.

Le processeur 8086 est un processeur 16 bits, mais avec un adressage mémoire 20 bits. Cela signifie que le processeur ne peut stocker que des valeurs qui indiquent 64 Ko, c'est un problème lorsque la capacité de mémoire est jusqu'à 1 Mo.
Pour contourner cela, nous devons comprendre les registres de segmentation:

Le processeur 8086 dispose de 4 registres de segmentation dont nous devons prendre soin:
- CS - segment de code
- DS - segment de données
- SS - segment de pile
- ES - un segment supplémentaire (au cas où vous en auriez besoin d'un de plus pour contourner différentes situations)
Il existe un certain nombre d'autres registres à usage général qui vous évitent une utilisation excessive de la mémoire et vous permettent de passer des paramètres à d'autres fonctions.
La segmentation enregistre le travail en changeant le bloc en RAM:

Cela permet au CPU 16 bits de voir les 20 bits de RAM, garantissant que pour chaque valeur DS, le bloc est décalé de 16 octets.

Dans ce cas, l'appel DS est utilisé comme pointeur à l'intérieur de la fenêtre 16 bits concernant l'emplacement du début de la ligne. Ensuite, l'imprimante de ligne va numériser jusqu'à ce qu'elle trouve le caractère $, puis elle s'arrête. Ceci est similaire à d'autres systèmes qui utilisent des octets nuls au lieu de $.

Avec l'ère d'ISA x86, peu de choses ont changé, au lieu du fait que la taille des bits du processeur a augmenté, les mêmes registres sont devenus plus larges.
Ainsi, avec cette connaissance, nous pouvons créer une liste de «tâches» pour suivre ces programmes:

Avec ce paramètre, nous pouvons jeter plusieurs gros ordinateurs sur le problème pendant plusieurs heures et collecter les résultats!

Et nous obtenons ...

Rien de tel.
C'est décevant.
Nous avons brûlé au moins une valeur de puissance de hamsters et obtenu presque aucune activation cool!
(Xs comment traduire cela)
Si nous regardons quelques échantillons, nous verrons un pistolet fumant ici. Un échantillon décent vérifie la date ou l'heure.
Si nous regardons la documentation de ces appels, nous verrons que l'appel système renvoie des valeurs sous forme de registres pour le programme:

Nous pouvons donc les forcer brutalement! Tout ce que nous devons faire est quelque chose comme ceci:

Mais il y a un problème avec cette méthode.

L'étape de test de l'exemple prend environ 15 secondes, car il utilise le processus d'émulation qemu complet, et cela peut prendre jusqu'à 15 secondes pour exécuter complètement le programme dans la machine virtuelle. Étant donné que DOS n'a pas de fonctionnalités d'économie d'énergie, cela signifie que lorsque DOS est en mode veille, il est dans un
cycle occupéNous pourrions donc examiner ce problème différemment en examinant le code qui sera exécuté après la demande de date / heure.
Puisque notre traceur est dans le gestionnaire d'interruption, nous ne savons pas dans la boîte où se trouve le programme:

Pour ce faire, nous devons regarder la pile où les registres CS et IP nous attendent!

Dès que nous prenons ces deux registres de la pile, nous pouvons les utiliser pour obtenir le code retour afin que notre liste de contrôle ressemble à ceci:

Après avoir fait cela et répété les tests de l'ensemble de données, nous verrons à quoi ressemble le code de retour!

En voici un exemple. Ici, nous voyons qu'une comparaison est faite pour DL et 0x1e.

Si nous regardons notre documentation, nous verrons que DL est le jour du mois, c'est-à-dire que nous pouvons analyser les trois principaux codes d'opération comme suit:

Nous pourrions aller chercher manuellement tout cela, mais il y a beaucoup de ces échantillons qui vérifient l'heure, environ 4700:

Nous devons donc plutôt faire autre chose. Nous devons écrire quelque chose ... Nous devons écrire ...

Le pire émulateur x86 au monde, appelé BenX86, est un émulateur conçu spécifiquement pour nos besoins, et rien de plus:

Mais il a quelques avantages dans sa vitesse.


Nous avons ajouté 10 000 tests d'exécution différents en fonction des chemins que nous avons trouvés en utilisant la force brute à l'aide de BenX86. Donc, je terminerai avec certaines de mes découvertes préférées qui sont activées par le temps:

Ce modèle s'active le jour de l'an et raccroche votre système après l'affichage d'un message d'accueil. Cela peut être bon si vous êtes coincé au bureau pour la nouvelle année, ou cela peut être mauvais si vous avez vraiment besoin de faire quelque chose le jour de l'an.

Cet exemple m'a beaucoup surpris. Il est activé au début de 1995 et informe l'utilisateur de tous les fichiers infectés qu'il a infectés, puis supprime le virus (supprimant la transition au début) et ne fait rien d'autre. Bien que, pour une raison quelconque, il soit recommandé d'acheter McAfee, ce message n'est évidemment pas obsolète.

Franchement, cela m'embrouille vraiment, le 8 novembre de n'importe quelle année, cela transformera tous les 0 du système en minuscules glyphes de «haine». Cela me dérange vraiment si vous savez pourquoi vous en avez besoin, faites le moi savoir ...

C'est probablement mon cauchemar quand, après avoir démarré un programme, il affiche un message indiquant qu'elle n'a pas pu manger votre lecteur principal. Ce serait incroyablement dérangeant de voir à l'improviste.

En conclusion, nous avons ce qui est la version Navy Seal Copypasta du malware DOS. Je ne suis pas sûr que cet auteur n'aime pas Aladdin, mais quoi que vous fassiez, vous êtes une personne.
Si vous êtes intéressé par le code qui a fonctionné dans cet article, j'ai
publié ma boîte à outils sur github , sans aucune garantie. Si vous souhaitez créer ce code vous-même, vous devrez vous assurer qu'il fonctionne avec votre installation MS-DOS (correction d'un point d'arrêt de gestionnaire)
Cependant, si vous regardez juste pour voir ce que j'ai vu en regardant ce projet, j'ai archivé l'interface web ici:
dosv.benjojo.co.ukA très bientôt!