8
votes

Comment exécuter une exécutable non gérée de la mémoire plutôt que du disque

Je veux intégrer une utilitaire de ligne de commande dans mon application C #, de sorte que je puisse saisir ses octets comme une matrice et exécuter l'exécutable sans jamais l'enregistrer sur le disque sous forme de fichier séparé (évite de stocker exécutable comme fichier séparé et évite besoin de capacité à écrire des fichiers temporaires n'importe où).

Je ne trouve pas de méthode pour exécuter un exécutable à partir de son flux d'octets. Windows requiert-il qu'il soit sur un disque ou existe-t-il un moyen de l'exécuter de la mémoire? Si Windows exige qu'il soit sur disque, existe-t-il un moyen facile dans la framework .NET pour créer un lecteur / fichier virtuel d'une sorte et cartographier le fichier dans le flux de la mémoire de l'exécutable?


1 commentaires

vous pouvez utiliser un utilitaire comme imDisk


4 Réponses :


1
votes

Création d'un ramdisk ou de jeter le code dans la mémoire puis de l'exécuter est à la fois possible, mais des solutions extrêmement compliquées (éventuellement plus dans le code géré).

Cela doit-il être exécutable? Si vous l'emballez comme un assemblage, vous pouvez utiliser Assemblage.load () à partir d'un flux de mémoire - quelques lignes de code triviales.

ou s'il doit être exécutable, qu'est-ce qui ne va pas en réalité avec rédaction d'un fichier temporaire? Il faudra quelques lignes de code pour le jeter dans un fichier Temp, l'exécuter, attendez qu'il quitte, puis supprimez le fichier temporaire - il ne peut même pas sortir du cache de disque avant de l'avoir supprimé! Parfois, la solution simple et évidente est la meilleure solution.


6 commentaires

Un exécutable est juste un groupe d'octets, et je ne vois aucune raison pour laquelle un système d'exploitation devrait se soucier de savoir si les octets proviennent de disque ou de mémoire, tant que les deux types d'emplacements peuvent être verrouillés (et ils peuvent). Le système d'exploitation semble-t-il dépendre d'un exécutable étant situé dans un système de fichiers, pourquoi? Si nous pouvons les fichiers de carte mémoire, pourquoi ne pas facilement faire l'inverse en enregistrant un chemin UNC unique sur un fichier virtuel uniquement par une région de mémoire verrouillée? Windows 7 ne peut toujours pas monter une image ISO sur un lecteur virtuel de manière native sans logiciel tiers, même si toutes les propres choses de Microsoft sont distribuées en tant qu'images ISO.


Je ne pense pas pouvoir emballer une tierce partie une utilitaire de ligne de commande non géographique compilée en C ++ comme montage pouvant être utilisé avec Assemblage.LoLoad. La seule chose qui ne va pas avec l'écriture de fichiers temporaires, c'est que je ne pense pas que cela devrait être nécessaire, et cela me demande de trouver un répertoire temporaire et d'assurer un accès en écriture, ce qui est également inutile. Il n'y a que toutes ces étapes inutiles qui pourraient causer des problèmes que j'essaye d'éviter, mais le système d'exploitation et le .NET .NET le rend difficile de le faire.


Je suis d'accord avec toi. Je pense simplement que vous aurez du mal à trouver quoi que ce soit de manière facile à mettre en œuvre et à tester en tant que rédaction d'un fichier temporaire.


Je suis d'accord il n'y a rien de plus facile, c'est exactement ce que j'essaie d'éviter parce que je ne veux pas écrire sur le disque pour une raison quelconque.


Pas même "parce que tu aurais pu le faire il y a 2 mois et je suis passé à un autre problème"? Ou "Parce que c'est l'approche standard et travaillerait simplement pour tout exécutable (géré ou non géré, etc.), car il est spécifiquement pris en charge par .NET"?


Non, car cela implique d'écrire sur un disque, ce qui est exactement ce que j'évite. Dans un système sans disques inscriptibles, un disque RAM est la seule option et, en appelant cela extrêmement compliqué, vous venez de renforcer mon affirmation qui obligeant le code exécutable à origine sur un disque est une exigence lourd et inutile, mais malheureusement c'est tout Le système d'exploitation et ses anciennes DLL sous-jacentes ont été écrites pour gérer.



2
votes

Regardez la section "en mémoire" de ce document. Réalisez que c'est à partir d'une perspective d'injection DLL distante, mais le concept devrait être identique.

injection de bibliothèque à distance


10 commentaires

Intéressant, mais je cherche un moyen d'utiliser quelque chose comme processus.Start, en passant un tableau d'octets plutôt qu'un nom de fichier. Je n'aime pas leur justification de ne pas lancer de processus de mémoire, car "le scanner Virus ne peut pas analyser les programmes qui n'existent jamais sur le disque" ... Quel est un flic. S'ils construisent le système d'exploitation pour exécuter des programmes de manière sécurisée de commencer, la règle «Dû origine sur le disque» serait inutile.


Que veux-tu dire? Il n'y a pas de telle règle. C'est juste un fait de la vie que les scanners de virus (qui ne sont pas écrits par MS) soient suspects à tout moment, un processus commence soudainement à exécuter du code auto-modificateur. Cela ressemble à un comportement approprié pour moi, quel que soit le système d'exploitation du scanner. Si vous ne voulez pas compter sur des scanners virus pour ce type de protection, c'est pourquoi Windows a eu des DPE intégrées depuis de nombreuses années.


Le framework .NET applique une règle implicite selon laquelle "le code exécutable doit provenir de disque" en fournissant des surcharges de processus.Start qui n'accepteront qu'aucun nom de fichier en tant que signaleur de code exécutable. Il n'acceptera ni un tableau d'octet géré ni un pointeur d'octets non gérés contenant du code exécutable.


Une bonne API accepterait principalement les octets et soutenez les noms de fichiers comme un épargnant de temps, pas l'inverse. Le code finalement finit en mémoire, mais l'API existante oblige-t-on à copier des octets de code de la mémoire, au disque et à la mémoire de la mémoire, fonctionnant avec un fichier temporaire entre les deux. C'est un travail inutile et le cadre ne le fait que parce qu'il enveloppe une API de plate-forme sous-jacente (LoadLibrary, etc.) qui est bloquée sur l'idée que le code exécutable provient toujours d'un disque. Le code est des octets. Le fait que le système d'exploitation nécessite un fichier est vraiment quelque chose que le cadre devrait abstraiter. Pensez-y.


Le système d'exploitation est insécurisé par conception, car son système d'autorisations est en arrière. Un système d'exploitation vraiment sécurisé affecterait des autorisations aux instances virtuelles du code exécutable, plutôt que des comptes d'utilisateur, car les utilisateurs ne fournissent que des entrées, tandis que le code exécutable fait tout le reste. C'est pourquoi, lorsque vous téléchargez un exécutable dans Windows, vous devez trembler sur la terreur, il peut accéder à tous les fichiers que votre compte est autorisé à accéder, et la seule différence de Vista est quand vous tremblez (après avoir cliqué sur OK au Invite, lol).


Le code exécutable doit accéder uniquement aux dossiers qu'il a explicitement accordé l'accès à l'administrateur et les utilisateurs doivent pouvoir exécuter et fournir une entrée uniquement sur les instances virtuelles appropriées attribuées par l'administrateur. Par exemple, l'utilisateur "Littlejohn" peut exécuter l'instance "Xbox One", qui ne peut accéder que le dossier ou le groupe "Childrens 'Games", ainsi que l'utilisateur "BigJohn" peut exécuter "Xbox Two", qui peut accéder à ce dossier en plus de la Groupe "Jeux pour adultes". Les deux instances partagent le même fichier exécutable, mais la clé est que les instances virtuelles sont attribuées des autorisations uniques.


Vous pouvez mettre toutes les données que vous aimez en mémoire et aussi longtemps que vous appelez l'adresse de point d'entrée correcte à l'intérieur, vous pouvez l'exécuter. Mais c'est une chose très non gérée à vouloir faire, donc c # n'est probablement pas la langue de le faire - elle devrait être plus facile à réaliser par p / invoquant au code non géré (C ++, C, assembleur). Bien sûr, comme indiqué ci-dessus, vous devrez peut-être fonctionner avec des autorisations élevées et gérer le gant de vérificateurs de virus.


Tous les autres systèmes d'exploitation importants fondent également son modèle de sécurité sur les comptes d'utilisateurs. Et il y a de très bonnes raisons de le faire. Pas assez de place dans les commentaires pour énumérer toutes les raisons pour lesquelles vous vous trompez, je vais donc laisser Raymond parler: blogs.msdn.com/oldnewthing/archive/2006/08/18/705957.aspx


Et c'est pourquoi chaque système d'exploitation majeur est en proie aux virus et aux avertissements de sécurité. J'ai lu ce blog et ça ne réfute pas mon point. En fait, l'un des commentaires indique la même chose que j'ai dit: «Le problème est que les modèles de sécurité Windows et UNIX sont à l'envers. Les systèmes d'exploitation vont de grandes longueurs pour se protéger de moi, mais ne font rien pour protéger mon Données des programmes I Exécute. Ré-architecture Windows avec un modèle de sécurité de capacités serait irréalisable, mais .NET est une excellente étape dans la bonne direction. "


Et par exemple: "Ce n'est pas correct - la plupart des unix Unix ont l'utilisateur comme centre du système de sécurité, mais SELINUX et APPARMOR Changez cela complètement. Ils vous permettent d'attribuer des privilèges à grains fins aux applications et pas les utilisateurs. Les fichiers binaires sont étiquetés avec des attributs étendus identifiant quel contexte de sécurité ils doivent l'exécuter (ou à l'APPARMOR, ils sont identifiés par des chemins de fichiers). "



11
votes

Vous demandez une fonctionnalité spécifique à une très basse plate-forme à mettre en œuvre dans un environnement géré de haut niveau. Tout est possible ... mais personne n'a dit que ce serait facile ...

(BTW, je ne sais pas pourquoi vous pensez que la gestion des fichiers TEMP est onéreuse. Le BCL le fait pour vous: http://msdn.microsoft.com/en-us/library/system.io.path.gettempfilename.aspx )


  1. allouer suffisamment de mémoire pour maintenir l'exécutable. Il ne peut pas résider sur le tas géré, bien sûr, comme presque tout dans cet exercice, vous aurez besoin de Pinvoke. (Je recommande C ++ / CLI, en fait, afin de ne pas vous rendre trop fou). Portez une attention particulière aux bits d'attribut Vous appliquez aux pages de mémoire allouées: faites-les mal et que vous ouvrez un trou de sécurité béant ou que votre processus soit fermé par DEP (c'est-à-dire que vous vous plez). Voir http://msdn.microsoft.com/en-us /Library/aa366553(vs.85).aspx

  2. localiser l'exécutable dans la bibliothèque de ressources de votre montage et acquis un poignée épinglée à elle.

  3. memcpy () le code de la région épinglée du tas de geste géré au bloc natif.

  4. GRATUIT LE GLANDLE.

  5. appelez VirtualProtect pour empêcher écrit en outre au bloc de mémoire exécutable.

  6. Calculez l'adresse de la fonction principale de l'exécutable dans l'espace d'adresses virtuel de votre processus, en fonction de la poignée que vous avez obtenue de Virtualalloc et du décalage dans le fichier, comme indiqué par Dumbin ou des outils similaires.

  7. Placez les arguments de la ligne de commande souhaités sur la pile. ( Convention Windows StdCall ). Tous les pointeurs doivent indiquer sur des régions natales ou épinglées, bien sûr.

  8. Allez à l'adresse calculée. Probablement plus facile à utiliser _Call (langue d'assemblage en ligne).

  9. prie à Dieu que l'image exécutable n'a pas de sauts absolus qui aurait été fixée en appelant la voie normale. (À moins que, bien sûr, vous avez envie de rééchaler le cerveau de LoadLibrary lors de l'étape 3).

  10. récupérez la valeur de retour dans le registre @easx.

  11. appelez virtualfree.

    Les étapes n ° 5 et n ° 11 doivent être faites dans un bloc enfin et / ou utilisez le motif iDisposable.


    L'autre option principale serait de créer une ramdive, écrivez l'exécutable là-bas, exécuté et nettoyer. Cela pourrait être un peu plus sûr puisque vous n'essayez pas d'écrire un code auto-modificateur (ce qui est difficile dans tous les cas, mais surtout lorsque le code n'est même pas le vôtre). Mais je suis assez certain que cela nécessitera encore plus d'appels d'API de plate-forme que l'option d'injection de code dynamique - toutes nécessitant C ++ ou Pinvoke, naturellement.


6 commentaires

En regardant à tous ces marches et prières, j'espère que c'est évident pourquoi le "code doit être sur le disque" est si onéreuse. Étant donné que le code exécutable est finalement chargé en mémoire, je devrais pouvoir l'exécuter directement à partir de la mémoire ou le charger du disque à la mémoire, puis de l'exécuter. L'API actuel .NET souhaiterait que je prenne du code en mémoire, écrivez-le sur le disque, fonctionnant avec un système de gestion de fichier temporaire, uniquement pour la lire immédiatement dans la mémoire, où il était déjà en premier lieu! Cela ne fait que démontrer ce qui se passe lorsque vous enveloppez une ancienne technologie dans de nouveaux vêtements et donnez-lui un nouveau nom.


De plus, cette fonctionnalité "de bas niveau" spécifique à la plate-forme est déjà dans le cadre géré de haut niveau en tant que "process.start". Le problème est que le seul type de pointeur accepte d'exécuter les octets de code est un nom de fichier, ce qui implique qu'un disque est le seul code de lieu devrait être originaire.


Je ne pense tout simplement pas que les autorisations de fichiers devraient jamais avoir besoin d'entrer dans le mélange du tout et malheureusement avec des fichiers temporaires qu'ils font. Voir le commentaire sur MSDN pour PATH.GETTTEMPFILEName: Dans les environnements de Droits faibles E.G. Dans certaines configurations ASP.NET, cette fonction échouera avec une exception de sécurité ... car elle doit trouver le répertoire temporaire et la lecture de "environnement" ... elle nécessite une maintenance de l'environnement pour un accès sans restriction aux variables d'environnement. Enumération associée: PermissionState.Unrestrillée


N ° Calling Process.Start est très très différent de simplement définir CS: IP à un décalage aléatoire dans une région de mémoire exécutable et en sautant. Surtout du code géré. Même dans les applications natives Win32, il y a beaucoup, beaucoup plus impliqué dans le chargement de modules arbitraires .exe / .dll que vous ne le pensez. Ce que vous voyez dans ma réponse ci-dessus n'est pas destiné à être lourd; C'est en fait une simplicité spectaculaire. Voici un article qui [commence à] gratter la surface de toutes les poignées de LoadLibrary pour vous: msdn.microsoft.com/en-us/magazine/cc33727.aspx


Lorsque j'ai dit que la fonctionnalité est déjà dans la framework .NET, je voulais dire que le processus est disponible. J'ai reconnu que cela dépend des méthodes indigènes (avec une fonctionnalité complexe) lorsque j'ai dit qu'il est "enveloppant une ancienne technologie dans de nouveaux vêtements", le point étant que la nouvelle technologie est limitée par l'ancienne technologie. Dans ce cas, tout ce que je veux faire, c'est ignorer la partie où elle charge les données d'un disque. Je viens de dire, il est ridicule que les API natives existantes qui procédent.Start dépendent de l'enroulement de la nécessité d'un point de départ / nom de fichier plutôt que d'une adresse mémoire.


Je comprends ce qui est impliqué dans le chargement d'un EXE, tout mon point était qu'il est ridicule qu'il n'y a pas de fonction comme CreateProcesswithlogonw qui accepte une adresse mémoire en tant que pointeur au lieu d'un nom de fichier et le prend à partir de là. Vous seriez toujours en train de spécifier un répertoire de travail et d'autres paramètres, mais pourquoi est-ce tellement enfermé en dépendant de l'avoir soutenu par un disque, quand il va simplement la rendre dans la mémoire de toute façon?



-1
votes

Ceci est explicitement non autorisé dans Vista +. Vous pouvez utiliser des appels de API Win32 sans papiers en XP pour le faire, mais il a été cassé à Vista + parce qu'il s'agissait d'un trou de sécurité énorme et que les seuls gens qui utilisent étaient des écrivains malveillants.


6 commentaires

Eh bien c'est ridicule. Un flux d'octets est un flux d'octets, peu importe la façon dont vous le regardez ou d'où cela vient. Forcer ces octets à venir du fichier plutôt que de la mémoire à l'exécution ne sert aucun but. Malware? Sérieusement? Donnez-moi une pause ... Donc, ils doivent simplement l'écrire à un fichier d'abord à l'exécuter. Êtes-vous en train de dire qu'il y avait un trou de sécurité dans l'API (OK, je suppose), ou vous dites-vous qu'il y a un trou de sécurité dans l'idée d'exécution d'un code de mémoire d'octets plutôt que d'un flux de fichiers d'octets (définitivement non).


Cela compte, et ce n'est pas ridicule. Par exemple; Comment validez-vous correctement et sécurisé la signature d'une image exécutable si le fichier n'est pas sur le disque? Comment filtrer les pilotes fonctionnent maintenant que vous exécutez à partir d'une image mémoire? Comment supporterez-vous que les images fonctionnent maintenant que vous vous nourrissez d'un flux de mémoire plutôt que d'un nom de fichier? Ce ne sont là que quelques-uns, mais vous avez encore un million de cas d'angle, comme traiter des options d'exécution des fichiers image, des incohérences avec le débogage, etc. Il est vraiment trivial pour écrire le fichier, cela traite avec les courages d'un très compliqué OS.


Validez la signature en lisant les octets à partir du bloc de mémoire au lieu des blocs de disque! Il ne devrait pas y avoir de différence; C'est une mauvaise conception. Les pilotes de filtrage ne sont pas pertinents, car nous parlons de code qui exécute déjà, demandant à ce que certains autres codes spécifiques commencent à courir et qu'aucun filtre ne doit interférer avec ce code. Si vous avez vraiment besoin de filtres, le système d'exploitation pourrait fournir des crochets de bas niveau pour permettre aux filtres de numériser la mémoire juste avant qu'elle ne soit protégée et que l'exécution commence. Encore une fois, il n'y a rien de spécial sur les données sur un disque, c'est une architecture pauvre.


IFEOS sont une exploitement en attente de se produire et rien de plus qu'une commodité paresseuse pour commencer les processus avec une configuration particulière. C'est un design bâclé. Je vois que le registre a des entrées telles que "HKLM \ Software \ Microsoft \ Windows NT \ CurrentVersion \ Options d'exécution du fichier \ Searchindexer.exe". Alors maintenant, si j'exécute un fichier qui se trouve être nommé Searchindexer.exe, il y aura ce comportement spécial caché, instigué à un système, à l'instar de l'utilisateur? C'est un exploit en attente d'arriver, imo. Débogage, encore une fois, est dans un bateau similaire.


Si vous suivez ma logique, je ne suis même pas surpris qu'une recherche de "Exploice Ifeo" présente une simple exploitement qui permet à une personne de se donner un accès à une invite de commande élevée de l'écran de connexion en activant les touches collantes en appuyant sur Shift 5 Times ( RedmondPie.com / ... ). Tout ce dont j'avais besoin, c'est 10 secondes sur l'ordinateur d'un ami pour ajouter une clé de registre avec un fichier .reg pour faire ce travail. Design pathétique et évidemment médiocre.


Reg Ajouter "HKLM \ Software \ Microsoft \ Windows NT \ Courroversion \ Options d'exécution du fichier image \ Sethc.exe" / V Debugger / TG_SZ / D "C: \ Windows \ System32 \ cmd.exe" Les dégâts que l'on pourrait faire avec ceci (J'aime effacer un système de fichiers), compte tenu de la fréquence à laquelle les gens activent accidentellement des touches collantes, lol.