版本控制可执行文件并在运行时修改它

时间:2011-05-24 21:36:38

标签: c++ c binary io versioning

我正在尝试做的是使用版本签名签署我编译的可执行文件的前32个字节,比如“1.2.0”,我需要在运行时中修改此签名,请记住的是:

  • 这将由可执行文件本身完成
  • 可执行文件驻留在客户端,这意味着无法重新编译
  • 使用外部文件来跟踪版本而不是在二进制文件中对其进行编码也不是一个选项
  • 解决方案必须与平台无关;我知道Windows / VC允许你使用.rc资源对可执行文件进行版本控制,但是我不知道Mac的等价物(可能是Info.plist?)和Linux

我头脑中的解决方案是在二进制文件的第一个或最后一个32个字节中写入版本签名(我还没弄明白 如何做)然后我会修改我需要的那些字节。可悲的是,这并不是那么简单,因为我正在尝试修改我正在执行的相同二进制文件。

如果您知道我如何能够做到这一点,或者知道这个问题的清洁/主流解决方案,我将非常感激。 FWIW,该应用程序是游戏的修补程序/启动程序;我选择在修补程序本身编码版本而不是游戏可执行文件,因为我希望它是自包含且与目标无关的。

更新:从您的有用答案和评论中,我发现弄乱二进制文件的页眉/页脚是不可取的。但是对于正在运行的用户的写入权限,游戏必须以这种或那种方式进行修补,并且需要修改游戏文件,没有办法规避:更新游戏,你需要管理员权限。

我会选择使用外部文件来保存签名,并在每次更新时修改它,但我看不出如何防止用户欺骗该文件:如果他们弄乱版本号,如何我可以检测到我正在运行的版本吗?

Update2 :感谢您的所有答案和评论,实际上有两种方法可以执行此操作:使用外部资源跟踪版本或将其嵌入主应用程序的二进制文件本身。我只能在SO上选择一个答案,所以我做了我要去的那个,虽然它不是唯一一个。 : - )

4 个答案:

答案 0 :(得分:3)

现代Windows版本不允许您更新已安装的程序文件,除非您以管理员权限运行。我相信所有版本的Windows都会阻止对正在运行的文件的修改;这就是您在更新后被迫重启的原因。我想你是在寻求不可能的事情。

答案 1 :(得分:2)

由于多种原因,这将是一个挑战。首先,写入二进制文件的前N个字节很可能踩到二进制文件的头信息,程序加载器使用它来确定代码和信息的位置。数据段等位于文件中。这在不同平台上会有所不同(请参阅ELF formatexecutable format comparison) - 有很多不同的二进制格式标准。

假设您可以克服这个问题,如果您在运行时开始修改程序代码,则可能会遇到安全/防病毒系统的问题。我不相信大多数当前的操作系统会允许您覆盖当前运行的可执行文件。至少,他们可能允许您通过提升权限这样做 - 在游戏时不太可能出现。

答案 2 :(得分:1)

我会就如何做到这一点提出一些想法。

我认为在没有副作用的情况下更改可执行文件中的某些任意字节是不可能的。为了克服这个问题,我会在你的源代码中创建一些字符串,例如:

char *Version = "Version: AA.BB.CC";

我不知道这是否是规则,但您可以在二进制代码中查找此字符串(在文本编辑器中打开它,您会看到)。因此,您在二进制文件中搜索并更改此字节的版本号。可能每次编译应用程序时它们的位置都会有所不同,所以只有当这个位置对你来说不是问题时才有可能。

因为正在使用该文件(它正在运行),所以您必须启动一个可执行此操作的外部程序。修改文件后,此外部程序可以重新启动原始应用程序。

版本将在某些部分存储在二进制代码中。这有用吗?你将如何检索版本号?

答案 3 :(得分:1)

如果您的应用程序是为了修补游戏,那么为什么不在你的应用程序中嵌入版本?您可以使用像@Juliano节目这样的字符串,并在游戏未运行时从修补程序中修改它 - 如果您当前正在进行修补,则应该是这种情况。 :P


编辑:如果您正在使用Visual Studio,根据this MSDN page,使用#pragma comment将此类字符串嵌入可执行文件中非常容易:

#pragma comment(user, "Version: 1.4.1")

由于第二个参数是一个简单的字符串文字,它可以连接起来,我的版本只有一个简单的#define

// somehwere
#define MY_EXE_VERSION "1.4.1"
// somewhere else
#pragma comment(user, "Version: " MY_EXE_VERSION)