如何创建虚拟文件?
我想模拟一个文件而不将其写入磁盘。我的可执行文件末尾有一个文件,我想给出它的 dll 路径。当然,由于它没有真正的路径,所以我必须伪造它。
我首先尝试在Windows下使用命名管道来做到这一点。这将允许像 \\.\pipe\mymemoryfile 这样的路径,但我无法使其工作,并且我不确定 dll 是否支持这样的路径。
其次,我找到了 CreateFileMapping 和 GetMappedFileName。它们可以用来模拟另一个文件片段中的文件吗?我不确定这个 API 是做什么的。
我想做的事情似乎与 boxedapp 类似。关于他们如何做到这一点有什么想法吗?我认为这类似于 API 拦截(如 Detour ),但这需要大量工作。还有其他方法吗?
为什么 ?我对这个特定的解决方案很感兴趣,因为我想隐藏数据,并且为了只分发一个文件,但也出于令人讨厌的原因使其以这种方式工作;) 我同意将数据复制到临时文件会起作用并且是一个更容易的解决方案。
I'd like to simulate a file without writing it on disk. I have a file at the end of my executable and I would like to give its path to a dll. Of course since it doesn't have a real path, I have to fake it.
I first tried using named pipes under Windows to do it. That would allow for a path like \\.\pipe\mymemoryfile but I can't make it works, and I'm not sure the dll would support a path like this.
Second, I found CreateFileMapping and GetMappedFileName. Can they be used to simulate a file in a fragment of another ? I'm not sure this is what this API does.
What I'm trying to do seems similar to boxedapp. Any ideas about how they do it ? I suppose it's something like API interception (Like Detour ), but that would be a lot of work. Is there another way to do it ?
Why ? I'm interested in this specific solution because I'd like to hide the data and for the benefit of distributing only one file but also for geeky reasons of making it works that way ;)
I agree that copying data to a temporary file would work and be a much easier solution.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
使用 BoxedApp 不用担心。
Use BoxedApp and do not worry.
您可以将数据存储在 NTFS 流中。这样,您可以获得指向数据的真实路径,您可以将其以以下形式提供给 dll。
这与普通文件完全一样,但仅在使用的文件系统是 NTFS 时才有效。这是当今 Windows 下的标准配置,但如果您想支持较旧的系统或希望能够从 USB 记忆棒或类似设备运行它,这当然不是一个选择。请注意,如果文件作为邮件附件发送或只是从 NTFS 分区复制到 FAT32 分区,则文件中存在的任何流都将丢失。
我想说最兼容的方法是将数据写入实际文件,但您当然可以在 NTFS 系统上采用一种方法,在 FAT 系统上采用另一种方法。我确实建议不要这样做,因为会增加复杂性。当然,适当的方法是单独分发文件,但由于您已经表明您不希望这样做,因此在这种情况下您应该将其写入临时文件并为 dll 提供该文件的路径。确保将临时文件写入用户的临时目录(您可以使用 GetTempPath(C/C++ 中))。
您的另一个选择是编写一个文件系统过滤器驱动程序,但我强烈建议不要这样做。这也违背了使用单个文件的目的...
此外,如果您只想分发单个文件,那么使用 zip 文件或安装程序怎么样?
You can store the data in an NTFS stream. That way you can get a real path pointing to your data that you can give to your dll in the form of
This works precisely like a normal file, however it only works if the file system used is NTFS. This is standard under Windows nowadays, but is of course not an option if you want to support older systems or would like to be able to run this from a usb-stick or similar. Note that any streams present in a file will be lost if the file is sent as an attachment in mail or simply copied from a NTFS partition to a FAT32 partition.
I'd say that the most compatible way would be to write your data to an actual file, but you can of course do it one way on NTFS systems and another on FAT systems. I do recommend against it because of the added complexity. The appropriate way would be to distribute your files separately of course, but since you've indicated that you don't want this, you should in that case write it to a temporary file and give the dll the path to that file. Make sure you write the temporary file to the users' temp directory (you can find the path using GetTempPath in C/C++).
Your other option would be to write a filesystem filter driver, but that is a road that I strongly advise against. That sort of defeats the purpose of using a single file as well...
Also, in case you want only a single file for distribution, how about using a zip file or an installer?
管道用于同时运行的进程之间的通信。它们不存储数据以供以后访问,并且它们没有与文件相同的语义(例如,您无法查找或倒带管道)。
如果您追求类似文件的行为,那么最好的选择始终是使用文件。在 Windows 下,您可以将
FILE_ATTRIBUTE_TEMPORARY
传递给CreateFile
作为系统的提示,以避免在内存足够的情况下将数据刷新到磁盘。如果您担心写入磁盘对性能造成的影响,上述内容应该足以避免大多数情况下的性能影响。 (如果系统内存不足,无法将文件数据强制写入磁盘,那么无论如何,它也可能会进行大量交换——您已经遇到了性能问题。)
如果您出于其他原因试图避免写入磁盘,你能解释一下为什么吗?一般来说,阻止数据访问磁盘是相当困难的——例如,用户总是可以使机器休眠。
Pipes are for communication between processes running concurrently. They don't store data for later access, and they don't have the same semantics as files (you can't seek or rewind a pipe, for instance).
If you're after file-like behaviour, your best bet will always be to use a file. Under Windows, you can pass
FILE_ATTRIBUTE_TEMPORARY
toCreateFile
as a hint to the system to avoid flushing data to disk if there's sufficient memory.If you're worried about the performance hit of writing to disk, the above should be sufficient to avoid the performance impact in most cases. (If the system is low enough on memory to force the file data out to disk, it's probably also swapping heavily anyway -- you've already got a performance problem.)
If you're trying to avoid writing to disk for some other reason, can you explain why? In general, it's quite hard to stop data from ever hitting the disk -- the user can always hibernate the machine, for instance.
由于您无法控制 DLL,因此您必须假设 DLL 需要一个实际的文件。它可能在某个时候做出了这样的假设,这就是命名管道对你失败的原因。
最简单的解决方案是在临时目录中创建一个临时文件,将 EXE 中的数据写入临时文件,然后删除临时文件。
您在 EXE 末尾嵌入这个“伪文件”而不是仅仅将其与我们的应用程序一起分发是否有原因?显然,您已经将这个第三方 DLL 与您的应用程序一起分发,因此再添加一个文件似乎不会对您造成伤害?
还有一个问题,这个数据会改变吗?也就是说,您是否希望在 EXE 中写回这个“伪文件”的数据?我认为这不会很好地发挥作用。标准用户可能没有对 EXE 的写访问权限,这可能会导致防病毒软件疯狂。
而且 CreateFileMapping 和 GetMappedFileName 肯定不会工作,因为它们不会为您提供可以传递给 CreateFile 的文件名。如果你能以某种方式让这个 DLL 接受一个 HANDLE 那么那就可以了。
我什至不会去关心 API 拦截。只需将 DLL 传递给实际文件的路径即可。
Since you don't have control over the DLL you have to assume that the DLL expects an actual file. It probably at some point makes that assumption which is why named pipes are failing on you.
The simplest solution is to create a temporary file in the temp directory, write the data from your EXE to the temp file and then delete the temporary file.
Is there a reason you are embedding this "pseudo-file" at the end of your EXE instead of just distributing it with our application? You are obviously already distributing this third party DLL with your application so one more file doesn't seem like it is going to hurt you?
Another question, will this data be changing? That is are you expecting to write back data this "pseudo-file" in your EXE? I don't think that will work well. Standard users may not have write access to the EXE and that would probably drive anti-virus nuts.
And no CreateFileMapping and GetMappedFileName definitely won't work since they don't give you a file name that can be passed to CreateFile. If you could somehow get this DLL to accept a HANDLE then that would work.
And I wouldn't even bother with API interception. Just hand the DLL a path to an acutal file.
阅读你的问题让我想到:如果你可以假装内存区域是一个文件并且有某种“虚拟路径”,那么这将允许直接从内存加载DLL,这就是
LoadLibrary
通过询问路径名来设计禁止。这就是为什么人们在想要实现这一目标时编写自己的 PE 加载器。我想说你无法通过文件映射实现你想要的:文件映射的目的是将文件的一部分视为物理内存,而你想要倒数。
使用 Detours 意味着您必须复制拦截的 DLL 函数所做的一切,除了从真实文件获取数据之外;因此它不是通用的。或者,更复杂的是,让我们假设 DLL 使用
fopen
;然后你提供自己的fopen
来检测路径中的特殊模式,并模仿 C 运行时内部结构...嗯,这真的值得所有的痛苦吗? :DReading your question made me think: if you can pretend an area of memory is a file and have kind of "virtual path" to it, then this would allow loading a DLL directly from memory which is what
LoadLibrary
forbids by design by asking for a path name. And this is why people write their own PE loader when they want to achieve that.I would say you can't achieve what you want with file mapping: the purpose of file mapping is to treat a portion of a file as if it was physical memory, and you're wanting the reciprocal.
Using Detours implies that you would have to replicate everything the intercepted DLL function does except from obtaining data from a real file; hence it's not generic. Or, even more intricate, let's pretend the DLL uses
fopen
; then you provide your ownfopen
that detects a special pattern in the path and you mimmic the C runtime internals... Hmm is it really worth all the pain? :D请解释为什么您无法从 EXE 中提取数据并将其写入临时文件。许多应用程序都这样做——这是这个问题的经典解决方案。
如果您确实必须提供“虚拟文件”,最干净的解决方案可能是文件系统过滤器驱动程序。 “干净”并不意味着“好”——过滤器是一个完整记录和支持的解决方案,因此它比 API 挂钩、注入等更干净。但是,文件系统过滤器并不容易。
OSR Online 是查找 Windows 文件系统信息的最佳场所。 NTFSD 邮件列表是文件系统开发人员常去的地方。
Please explain why you can't extract the data from your EXE and write it to a temporary file. Many applications do this -- it's the classic solution to this problem.
If you really must provide a "virtual file", the cleanest solution is probably a filesystem filter driver. "clean" doesn't mean "good" -- a filter is a fully documented and supported solution, so it's cleaner than API hooking, injection, etc. However, filesystem filters are not easy.
OSR Online is the best place to find Windows filesystem information. The NTFSD mailing list is where filesystem developers hang out.
使用某种 RamDisk 并将文件写入该磁盘怎么样?我自己尝试了一些虚拟磁盘,但从未找到好的虚拟磁盘,请告诉我你是否成功。
How about using a some sort of RamDisk and writing the file to this disk? I have tried some ramdisks myself, though never found a good one, tell me if you are successful.
那么,如果您需要在 exe 中分配虚拟文件,则需要创建一个足够大的向量、流或字符数组来容纳您想要写入的所有虚拟数据。
这是我能想到的唯一解决方案,无需对磁盘执行任何 I/O(即使您不写入文件)。
如果您需要保留类似路径语法的文件,只需编写一个模仿该行为的类,而不是写入文件写入内存缓冲区。就这么简单。记住吻。
干杯
Well, if you need to have the virtual file allocated in your exe, you will need to create a vector, stream or char array big enough to hold all of the virtual data you want to write.
that is the only solution I can think of without doing any I/O to disk (even if you don't write to file).
If you need to keep a file like path syntax, just write a class that mimics that behaviour and instead of writing to a file write to your memory buffer. It's as simple as it gets. Remember KISS.
Cheers
打开名为“NUL:”的文件进行写入。它是可写的,但数据会被默默丢弃。有点像 *nix 名声中的 /dev/null 。
但您无法对其进行内存映射。内存映射意味着读/写访问,而 NUL 是只写的。
Open the file called "NUL:" for writing. It's writable, but the data are silently discarded. Kinda like /dev/null of *nix fame.
You cannot memory-map it though. Memory-mapping implies read/write access, and NUL is write-only.
我猜这个 dll 不能接受流?询问起来几乎很简单,但如果可以的话,您可以使用它。
I'm guessing that this dll cant take a stream? Its almost to simple to ask BUT if it can you could just use that.
您是否尝试过在使用命名管道时使用 \?\ 前缀?许多 API 支持使用 \?\ 直接传递路径的其余部分,无需任何解析/修改。
http://msdn.microsoft.com/en -us/library/aa365247(VS.85,轻量级).aspx
Have you tried using the \?\ prefix when using named pipes? Many APIs support using \?\ to pass the remainder of the path directly through without any parsing/modification.
http://msdn.microsoft.com/en-us/library/aa365247(VS.85,lightweight).aspx
为什么不将其添加为资源 - http:// msdn.microsoft.com/en-us/library/7k989cfy(VS.80).aspx - 与添加图标的方式相同。
Why not just add it as a resource - http://msdn.microsoft.com/en-us/library/7k989cfy(VS.80).aspx - the same way you would add an icon.