c - 试图用一些散列来篡改我的可执行文件,但遇到一些意外和未知的编译器行为
问题描述
为了用一些散列来篡改我的可执行文件,我遇到了一些意外和未知的编译器行为。
我有这样的想法,即通过简单地将二进制文件中的所有字节相加并将总数除以 256 的余数作为哈希值来计算我的程序的简单哈希值。
我想如果在我的程序中我有一个字符串文字“0000”,并且我使用上述算法计算的哈希给出了例如 163,那么我可以通过将“0”之一替换为“1”来得到 164 . 然而我得到的结果远非如此。通过用单个值替换单个字符,我得到了完全不同的哈希结果。对于这个例子,163 可能变成 84,这让我很困惑。
我计算哈希的函数非常简单,但无论如何都是这样。
int calcHash(const char *filename) {
int hash = 0;
int c;
FILE *fh = fopen(filename, "r");
if (!fh)
return -1;
while((c = fgetc(fh)) != EOF)
hash = (hash + c) % 256;
fclose(fh);
return hash;
}
我用这个语句从 main() 调用它。
int hash = calcHash(argv[0]);
编译过程中究竟发生了什么?无论如何,我可以获得更多可预测的哈希值?
也许并非所有编译器都会发生这种情况。我对这种意想不到的行为感到完全困惑。
我在 Ubuntu 上使用 gcc。
解决方案
这是一个比看起来更难的问题,也是一个比看起来更糟糕的想法 - 我不能不推荐这个。
我在一个客户系统上工作过,他们这样做了,这和建议的一样让人头疼,所以我最终对它进行了逆向工程以编写我自己的重新密封实用程序,这样我就可以编辑该死的文件和应用新的哈希。而且这些更改总是有利于软件供应商及其客户,绝不会窃取它或任何东西。
但无论如何,据我所知,它通过在代码中包含一些数据区域来工作:
char tamper_marker_1[] = "SOME MAGIC STRING";
int fileSize;
unsigned checksum;
char endmarker[] = "OTHER MAGIC STRING";
外部的 apply-seal 程序会打开.exe
并找到通向上述数据区域的魔术字符串,并将除了seal-info 区域之外的所有数据填充到fileSize
和。checksum
可执行文件将通过将自身作为文件打开并执行相同的检查来测试篡改。
在 Windows 下,您可以使用GetModuleFilename()
来查找可执行文件的完整路径,在 Linux 上,您可以打开/proc/12345/exe
(其中 12345 是您的进程 ID),它是程序的符号链接等等。
我不知道通过描述这一点是否有助于使世界变得更糟,但 SO 是用于问答,也许有合理的需要。请不要这样做,除非你真的,真的必须这样做。
编辑:您可能会指出,很少有人会像我做的逆向工程那样麻烦,但我会指出,您只需要一个人来创建重新密封工具并发布它,您所有的聪明工作就是无济于事。
EDIT2:当我想到这一点时,如果它只是一个程序,你就不必实际对算法进行逆向工程——你只需要能够反汇编它就可以取消测试。
推荐阅读
- javascript - React-TypeScript - 类型'(调度:调度)上不存在属性'then'
) => 承诺 ' - graphql - 如何监控 GraphQL 请求,例如使用 Charles 监控 Rest API
- java - 在 Hibernate/JPA 中保存一个带有子对象的对象 - @OneToMany
- flutter - Flutter/Dart:参数类型“bool Function(MyStateNotifier)”不能分配给参数类型“dynamic Function(dynamic)”
- android - msalclientexception 重定向 URI 不匹配
- python - TensorFlow 中图像分类模型的均方误差
- spring-boot - Swagger UI 结合 Maven OpenAPI Codegen 忽略注释
- java - 从 Java 调用 SQL 函数并设置参数
- spring-boot - 基于标志的日志记录以禁用/启用在 JPA 中选择 SQL 查询日志
- php - 如何在 php jquery 中将 ajax 响应转换为 pdf 文档?