Как запустить неуправляемый исполняемый файл из памяти, а не с диска - PullRequest
8 голосов
/ 03 августа 2009

Я хочу встроить утилиту командной строки в мое приложение на C #, чтобы я мог захватывать его байты в виде массива и запускать исполняемый файл, даже не сохраняя его на диск как отдельный файл (избегает хранения исполняемого файла как отдельного файла и избегает нужна возможность записи временных файлов в любом месте).

Я не могу найти метод для запуска исполняемого файла только из его байтового потока. Windows требует, чтобы это было на диске, или есть способ запустить это из памяти? Если Windows требует, чтобы он был на диске, есть ли простой способ в .NET Framework создать виртуальный диск / файл какого-либо вида и сопоставить файл с потоком памяти исполняемого файла?

Ответы [ 4 ]

11 голосов
/ 16 ноября 2009

Вы запрашиваете очень низкоуровневую, специфичную для платформы функцию, которая будет реализована в управляемой среде высокого уровня. Все возможно ... но никто не сказал, что будет легко ...

(Кстати, я не знаю, почему вы считаете, что управление временными файлами является обременительным. BCL делает это за вас: http://msdn.microsoft.com/en-us/library/system.io.path.gettempfilename.aspx)


  1. Выделите достаточно памяти для хранения исполняемого файла. Конечно, он не может находиться в управляемой куче, поэтому, как и почти все в этом упражнении, вам понадобится PInvoke. (На самом деле я рекомендую C ++ / CLI, чтобы не сводить себя с ума слишком сумасшедший). Обратите особое внимание на биты атрибутов, которые вы применяете к выделенным страницам памяти: сделайте их неправильно, и вы либо откроете зияющую дыру в безопасности, либо ваш процесс будет остановлен DEP (то есть вы потерпите крах). Смотри http://msdn.microsoft.com/en-us/library/aa366553(VS.85).aspx

  2. Найдите исполняемый файл в библиотеке ресурсов вашей сборки и получите закрепленный дескриптор к нему.

  3. Memcpy () код из закрепленной области управляемой кучи в собственный блок.

  4. Освободите GCHandle.

  5. Вызовите VirtualProtect , чтобы предотвратить дальнейшую запись в исполняемый блок памяти.

  6. Рассчитать адрес функции Main исполняемого файла в виртуальном адресном пространстве вашего процесса на основе дескриптора, полученного из VirtualAlloc, и смещения в файле, как показано DUMPBIN или аналогичными инструментами.

  7. Поместите нужные аргументы командной строки в стек. ( Соглашение Windows Stdcall ). Конечно, любые указатели должны указывать на родные или закрепленные регионы.

  8. Перейти к вычисленному адресу. Возможно, проще всего использовать _call (встроенный язык ассемблера).

  9. Молитесь Богу, чтобы в исполняемом образе не было абсолютных скачков, которые можно было бы исправить, вызвав LoadLibrary обычным способом. (Если, конечно, вы не захотите повторно реализовать мозг LoadLibrary во время шага № 3).

  10. Получить возвращаемое значение из регистра @eax.

  11. Позвоните в VirtualFree.

Шаги № 5 и № 11 должны выполняться в блоке finally и / или использовать шаблон IDisposable.


Другой основной вариант - создать RAM-диск, записать в него исполняемый файл, запустить его и очистить. Это может быть немного безопаснее, поскольку вы не пытаетесь писать самоизменяющийся код (что сложно в любом случае, но особенно в тех случаях, когда код даже не ваш). Но я вполне уверен, что для этого потребуется еще больше вызовов API платформы, чем для динамического внедрения кода - все они, естественно, требуют C ++ или PInvoke.

2 голосов
/ 03 августа 2009

Взгляните на раздел «В памяти» этой статьи. Поймите, что это с точки зрения удаленного внедрения DLL, но концепция должна быть такой же.

Удаленный впрыск библиотеки

1 голос
/ 03 августа 2009

Создание RAM-диска или выгрузка кода в память и последующее его выполнение являются возможными, но чрезвычайно сложными решениями (возможно, в большей степени в управляемом коде).

Это должен быть исполняемый файл? Если вы упаковали его как сборку, вы можете использовать Assembly.Load () из потока памяти - пару тривиальных строк кода.

Или, если это действительно исполняемый файл, что на самом деле не так с записью временного файла? Потребуется несколько строк кода, чтобы выгрузить его во временный файл, выполнить его, подождать, пока он выйдет, а затем удалить временный файл - он может даже не выйти из дискового кэша, пока вы его не удалили! Иногда простое, очевидное решение - лучшее решение.

0 голосов
/ 11 мая 2010

Это явно запрещено в Vista +. Вы можете использовать недокументированные вызовы Win32 API в XP, чтобы сделать это, но в Vista + это было сломано, потому что это была огромная дыра в безопасности, и единственными, кто использовал ее, были авторы вредоносных программ.

...