覆盖C库文件函数?

6
我正在开发一个游戏,而我使用的声音资产根据许可协议的要求必须以使最终用户无法访问的方式进行分发。因此,我考虑将它们聚合到一个平面文件中并对其进行加密或类似操作。问题在于,我使用的声音库(Hekkus Sound System)只接受“char *”文件路径,并在内部处理文件读取。因此,如果我要继续使用它,我必须覆盖c stdio文件函数来处理加密或其他决定。这似乎是可行的,但令我担心的是,在我关注的平台(Win32、Android和iOS)上,我看到人们遇到了奇怪的令人沮丧的问题。
是否有跨平台库可以处理这个问题?您是否推荐更好的方法?

4
你能否将它们解码并将它们未解码的内容写入/tmp文件中,然后调用打开文件并在打开后立即删除它们?在打开后,Hekkus内部的文件描述符仍将保持有效。(编辑:下面的RAM磁盘想法似乎更好) - Charlie Burns
2
定义“无法访问”。如果您正在用户系统上播放声音,那听起来对我来说相当可访问。无论如何,关于Hekkus Sound System-作者的网站表示他向所有感兴趣的人提供源代码。因此,最简单的方法可能是获取源代码并打补丁。不过奇怪的是,声音库没有将获取数据的方式抽象化。 - n0rd
2
请勿在C语言中重新定义保留标识符,这将引发未定义的行为。C99草案标准指出(附录J,第J.2节):**以下情况下行为是未定义的: [...]程序试图声明一个库函数本身,而不是通过标准头文件,但该声明没有外部链接(7.1.2)。程序声明或定义保留标识符,除了允许的7.1.4之外(7.1.3)。** - Lorenzo Donati support Ukraine
你使用哪种工具链? - secmask
@charlie burns 这可能可行,但速度会慢一些,而且加载时间已经是一个问题了。文件描述符的引用计数行为是否是标准(可移植)的一部分? - Vigabrand
显示剩余5条评论
6个回答

7

您是否可以使用命名管道而不是普通文件?如果是,您可以将管道呈现给声音库作为要读取的文件,并且您可以解密数据并将其写入管道,没有问题。(有关命名管道的说明,请参见Beej's Guide。)


2
我不明白。您似乎在说,与其将声音数据传递给库,您必须向其传递文件的名称。如果是这种情况,命名管道,也称为FIFO,可能是解决方案。命名管道呈现为文件系统中的文件,因此无论谁打开该文件进行读取,都会发现自己位于管道的接收端,而不是读取磁盘上的文件。因此,您的程序可以创建命名管道,将“管道文件名”传递给声音库,并将解密后的音频数据写入管道的写入端。 - This isn't my real name
1
在Unix上,命名管道是一个可以像常规文件一样被打开(fopen)的文件,因此其名称是普通的“char *”。音频库不应该有问题从其中读取。但是,它必须使用mkfifo函数创建,例如在程序的另一个线程中,并写入数据,否则fopen将会阻塞(请参考https://dev59.com/1HRB5IYBdhLWcg3wl4EQ)。 - SirDarius
或者说,Windows有这个功能,但不幸的是它与fopen不兼容。 - Vigabrand
1
您已指定Android和iOS作为您关注的平台,而Google似乎表明这两个平台都支持POSIX。Windows并未被指定为感兴趣的平台,众所周知它不支持POSIX(如果有的话),因此在那里是行不通的。 - This isn't my real name
1
尽管如@Martin Schlott所说,Windows具有相同的功能(当然不是POSIX),并且与fopen兼容,因此这可能确实可行... - Vigabrand
显示剩余4条评论

5

覆盖stdio的方式,使你不知道其确切工作方式的库以开发者未曾考虑过的方式工作,这对我来说似乎不是正确的方法,因为它并不容易。实现一个ramdrive需要很多努力,我建议寻找另一个音频库。

我找到的Hekkus Sound System是由一个人构建的,并且最近更新于2012年。我不会信赖只有一个人在开发并且不分享源代码的库。

我的建议是,花时间寻找适当的声音库,而不是为了这个库寻找可疑的解决方案。


我明白你的意思。但如果真的发生这种情况,那将是不幸的,因为除了这个问题,Hekkus已经证明自己是一个非常高质量、功能完备且易于使用的库,尽管它只是一个人的工作,并且跨平台到我关心的平台。你为什么说覆盖stdio很难?似乎添加一个执行简单解密的薄层不应该太困难,只要我能让实际的函数覆盖工作正常即可。 - Vigabrand
可能是这样,当然完全由您决定。老实说,我不知道有没有一种以平台无关的方式覆盖stdio的方法。例如,Windows的解决方案是创建一个命名管道,您可以构建一个路径到命名管道,该路径可以被任何stdio文件函数打开。Linux也有类似的机制,但我不知道它是否适用于其他平台,如iPhone或Android。对于Windows,您可以使用Windows API的CreateFile来创建命名管道。据我所知,目前还没有可用的平台无关命名管道库。 - Martin Schlott
通过“覆盖stdio”,我的意思是通过在*nix上使用dlsym覆盖fopen/fread等,以及在Windows上的等效方法(嗯,有吗?)。 - Vigabrand
但是,你可能是正确的,需要一个不同的库。 - Vigabrand

2
一种可能的方法是使用加密回环文件系统(搜索其他资源请使用谷歌)。
这种方法的原理是将你的资产放在一个加密文件系统中,实际上它存在于一个简单的文件中。该文件系统被挂载到某个地方作为一个回环设备。密码需要在挂载时提供。一旦挂载,所有文件都可以作为常规文件供软件使用。但在其他情况下,这些文件是加密的且不可访问的。

这似乎是一个仅适用于Linux的概念? - Vigabrand
大多数*nix操作系统(包括MacOS)似乎都有它http://en.wikipedia.org/wiki/Loop_device。此外,由于Android是Linux的派生版本,因此它也应该具备此功能。 - Ziffusion
我也会在Windows上发布。 - Vigabrand
我相信你可以找到一些有用的东西。http://sourceforge.net/projects/freeotfe.mirror/ - Ziffusion

1

这是与编译器相关且不保证的功能,但许多编译器允许您将文件/资源直接嵌入到可执行文件中,并在代码中读取它们,就像从磁盘中读取一样。您可以通过这种方式嵌入声音文件。然而,这将显著增加您的可执行文件的大小。


这并不是透明的工作方式,因此该库将无法打开这些“文件”。 - Vigabrand
@Vigabrand为什么不呢?只需将它们加载到一个字节数组中即可。 - Neil Kirk
char* 在 Hekkus API 中指的是文件名。 - Vigabrand
@Vigabrand,我找不到Hekkus API文档,看看是否有其他替代方法。 - Neil Kirk

1

另一种基于UNIX的方法:

可以使用环境变量LD_PRELOAD来覆盖可执行文件已链接的任何共享库。在LD_PRELOAD中提到的库导出的所有符号都将解析为该库,包括对libc函数openreadclose的调用。使用libdl,还可以使封装库调用原始实现。

因此,你只需要在适当设置了LD_PRELOAD的环境中启动使用Hekkus音频系统的进程,就可以对其读取的文件进行任何操作。

但请注意,你无论如何都无法使数据对用户不可访问:他必须能听到它,这意味着他必须有访问权限。即使整个软件链都使用加密,并且你的用户不愿意黑客硬件,连接音频输出插孔和音频输入插孔也不会很困难,不是吗?而且你不能禁止用户使用耳机,对吧?当然,内核可以看到所有未加密的音频输出并将其发送到其他地方...


看起来是一个有趣的选择,不过我也得支持Windows。至于你提到的第二点,声音并不是单独播放的,有音乐和多个声音同时发生,所以这并不是很有用。 - Vigabrand
尽管我从未这样做过,但我可以想到反向工程原始声音的方法,它们并不是特别复杂... 但是,当然,如果您的音乐来源满意于加密原始文件,并且也满意于无论如何提取音乐的可能性,那么似乎就没有问题了。只要确保在音乐文件出现在互联网上时,他不能起诉你... - cmaster - reinstate monica

0
您的问题的解决方案将是使用随机存取内存(RAM)磁盘。 http://en.wikipedia.org/wiki/RAM_drive 将内存中的一段区域模拟成磁盘。 还有可用的软件可以实现此功能。在内存中缓存数据库越来越受欢迎。
这也使得文件不会被存储在磁盘上,从而使其易于访问。

在安卓上吗?在iPad上吗? - This isn't my real name
如果一个游戏或应用程序在运行时添加了新的驱动器,我会感到非常不满。此外,我不知道是否有便携式解决方案,而且可能需要 root /管理员权限。 - interjay
这个问题表明提问者在开发方面更偏向初学者。实现ramdisk似乎不是一个合适的建议。此外,我不知道有哪个ramdisk可以在各个平台上运行。 - Martin Schlott
@Martin Schlott 嗯,不一定哈哈 - Vigabrand
不想冒犯你。 - Martin Schlott

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接