Как создать виртуальный файл?

Я хотел бы смоделировать файл без записи на диск. У меня есть файл в конце моего исполняемого файла, и я хотел бы указать его путь к DLL. Конечно, поскольку у него нет реального пути, я должен притворяться.

Сначала я попытался использовать именованные каналы под Windows, чтобы сделать это. Это позволило бы использовать путь типа \\.\ Pipe\mymemoryfile, но я не могу заставить его работать, и я не уверен, что dll будет поддерживать такой путь.

Во-вторых, я нашел CreateFileMapping и GetMappedFileName. Могут ли они быть использованы для имитации файла в фрагменте другого? Я не уверен, что это то, что делает этот API.

То, что я пытаюсь сделать, похоже на boxedapp. Есть идеи о том, как они это делают? Я предполагаю, что это что-то вроде перехвата API (например, Detour), но это было бы много работы. Есть ли другой способ сделать это?

Зачем? Я заинтересован в этом конкретном решении, потому что хотел бы скрыть данные и распространять только один файл, а также по гениальным причинам заставить его работать таким образом;) Я согласен, что копирование данных во временный файл будет работать и будет гораздо более простым решением.

12 ответов

Решение

Вы можете хранить данные в потоке NTFS. Таким образом, вы можете получить реальный путь, указывающий на ваши данные, которые вы можете дать своей DLL в виде

x:\myfile.exe:mystreamname

Это работает точно так же, как обычный файл, однако это работает, только если файловая система NTFS. Это стандартно для Windows в настоящее время, но, конечно, это не вариант, если вы хотите поддерживать более старые системы или хотели бы иметь возможность запускать это с USB-флешки или подобного. Обратите внимание, что любые потоки, присутствующие в файле, будут потеряны, если файл будет отправлен как вложение в почту или просто скопирован из раздела NTFS в раздел FAT32.

Я бы сказал, что наиболее совместимым способом было бы записать ваши данные в реальный файл, но вы, конечно, можете сделать это одним способом в системах NTFS и другим способом в системах FAT. Я рекомендую против этого из-за дополнительной сложности. Конечно, правильным способом было бы распространять ваши файлы отдельно, но, поскольку вы указали, что вам это не нужно, вы должны в этом случае записать его во временный файл и указать dll путь к этому файлу. Убедитесь, что вы записали временный файл во временный каталог пользователя (вы можете найти путь, используя GetTempPath в C/C++).

Другой вариант - написать драйвер фильтра файловой системы, но я настоятельно рекомендую эту дорогу. Такого рода поражение цели использования одного файла также...

Кроме того, если вам нужен только один файл для распространения, как насчет использования zip-файла или установщика?

Используйте BoxedApp и не волнуйтесь.

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

Если вы придерживаетесь поведения, похожего на файл, лучше всего всегда использовать файл. Под Windows вы можете пройти FILE_ATTRIBUTE_TEMPORARY в CreateFileкак подсказка системе, чтобы избежать сброса данных на диск при наличии достаточного объема памяти.

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

Если вы пытаетесь избежать записи на диск по какой-либо другой причине, вы можете объяснить, почему? В общем, довольно сложно остановить попадание данных на диск - например, пользователь всегда может перевести компьютер в спящий режим.

Поскольку у вас нет контроля над DLL, вы должны предположить, что DLL ожидает фактический файл. Это, вероятно, в какой-то момент делает такое предположение, поэтому именованные каналы не работают на вас.

Самое простое решение - создать временный файл во временном каталоге, записать данные из вашего EXE-файла во временный файл и затем удалить временный файл.

Есть ли причина, по которой вы встраиваете этот "псевдофайл" в конец вашего EXE-файла, а не просто распространяете его с нашим приложением? Вы, очевидно, уже распространяете эту стороннюю DLL-библиотеку вместе с вашим приложением, так что, похоже, еще один файл не навредит вам?

Другой вопрос, будут ли эти данные меняться? То есть вы рассчитываете записать данные этого "псевдо-файла" в ваш EXE-файл? Я не думаю, что это будет хорошо работать. Обычные пользователи могут не иметь права на запись в EXE, и это, вероятно, приведет к появлению антивирусных программ.

И никакие CreateFileMapping и GetMappedFileName определенно не будут работать, так как они не дают вам имя файла, которое может быть передано в CreateFile. Если бы вы могли как-то заставить эту DLL принять РУЧКУ, тогда это сработало бы.

И я бы даже не стал перехватывать API. Просто передайте DLL путь к точному файлу.

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

Если вы действительно должны предоставить "виртуальный файл", то самое чистое решение - это драйвер фильтра файловой системы. "чистый" не означает "хороший" - фильтр является полностью документированным и поддерживаемым решением, поэтому он чище, чем перехват API, внедрение и т. д. Однако фильтры файловой системы не легки.

OSR Online - лучшее место для поиска информации о файловой системе Windows. Список рассылки NTFSD - это то место, где тусуются разработчики файловой системы.

Чтение вашего вопроса заставило меня задуматься: если вы можете притвориться, что область памяти является файлом и имеет своего рода "виртуальный путь" к нему, то это позволит загрузить DLL непосредственно из памяти, что LoadLibrary Запрещено по замыслу, спрашивая имя пути. И именно поэтому люди пишут собственный PE-загрузчик, когда хотят этого достичь.

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

Использование Detours подразумевает, что вам придется копировать все, что делает перехваченная функция DLL, кроме получения данных из реального файла; следовательно, это не универсально. Или, что еще сложнее, давайте представим, что DLL использует fopen; тогда вы предоставляете свой собственный fopen который обнаруживает особый паттерн в пути, и вы имитируете внутреннюю среду C времени... Хм, действительно ли это стоит всей боли?:D

Что ж, если вам нужно выделить виртуальный файл в вашем exe-файле, вам нужно будет создать массив векторов, потоков или символов, достаточно большой, чтобы вместить все виртуальные данные, которые вы хотите записать.

это единственное решение, которое я могу придумать, не выполняя ввод-вывод на диск (даже если вы не записываете в файл).

Если вам нужно сохранить файл, похожий на синтаксис пути, просто напишите класс, имитирующий это поведение, и вместо записи в файл запишите в буфер памяти. Это так просто, как только может. Помни ПОЦЕЛУЙ.

ура

Откройте файл с именем "NUL:" для записи. Это доступно для записи, но данные молча отбрасываются. Вроде как /dev/null из *nix fame.

Вы не можете отобразить это в памяти. Отображение памяти подразумевает доступ для чтения / записи, а NUL только для записи.

Вы пытались использовать префикс \?\ При использовании именованных каналов? Многие API поддерживают использование \?\ Для прямой передачи оставшейся части пути без разбора / изменения.

http://msdn.microsoft.com/en-us/library/aa365247(VS.85,lightweight).aspx

Как насчет использования своего рода RamDisk и записи файла на этот диск? Я сам попробовал несколько рамдисков, хотя ни разу не нашел хорошего, скажите мне, если вы успешны.

Почему бы просто не добавить его в качестве ресурса - http://msdn.microsoft.com/en-us/library/7k989cfy(VS.80).aspx - так же, как вы добавили бы значок.

Я предполагаю, что эта DLL не может принять поток? Почти просто спросить НО, если это возможно, вы могли бы просто использовать это.

Другие вопросы по тегам