一般情况下,如果不重新编译,您将无法更改任何内容。
在实践中,在非常有限的情况下,您可能会修补您的二进制文件。这主要是特定于处理器(以及特定于可执行格式和特定于 ABI)的,并且较少依赖于您的特定操作系统版本(例如,如果它适用于 Windows 9,它也适用于 Windows 10)。
(但是,我不知道也从未使用过 Windows;我只使用 Linux;您应该根据您的操作系统调整我的答案)
所以在某些情况你可能会对你的二进制可执行文件进行逆向工程。如果你有 C 源代码,你可以让你的编译器发出汇编代码(例如,用gcc -O -fverbose-asm -S 和GCC 编译)。然后您可以反汇编您的可执行文件,并使用二进制或十六进制编辑器更改包含该常量的机器代码。
这并不总是有效,因为机器指令(及其大小)可能取决于常量的大小(位大小)。
举个简单的例子,在 C 语言中,对于 GCC 7,在 Linux/x86-64 上,考虑以下 C 文件:
/// A, B, C are preprocessor symbols defined as integers
int f(int x) {
if (x > 0)
return A*x + B;
return C;
}
如果我用 gcc -fverbose-asm -S -O -DA=12751 -DB=32 -DC=11 e.c 编译它,我会得到:
.type f, @function
f:
.LFB0:
.cfi_startproc
# e.c:3: if (x > 0)
testl %edi, %edi # x
jle .L3 #,
# e.c:4: return A * x + B;
imull $12751, %edi, %edi #, x, tmp90
leal 32(%rdi), %eax #, <retval>
ret
.L3:
# e.c:5: return C;
movl $11, %eax #, <retval>
# e.c:6: }
ret
.cfi_endproc
.LFE0:
.size f, .-f
但如果我这样做 gcc -S -O -fverbose-asm -DA=12753 -DB=32 -DC=10 e.c 我会得到
.type f, @function
f:
.LFB0:
.cfi_startproc
# e.c:3: if (x > 0)
testl %edi, %edi # x
jle .L3 #,
# e.c:4: return A * x + B;
imull $12753, %edi, %edi #, x, tmp90
leal 32(%rdi), %eax #, <retval>
ret
.L3:
# e.c:5: return C;
movl $10, %eax #, <retval>
# e.c:6: }
ret
确实,在上述情况下,我可以修补二进制文件(我需要在机器代码中找到 12751 和 11 常量;在这种情况下可行但很乏味)。
现在,让我们试试 A 是 2 的小幂,比如 16,C 是 0,所以
gcc -S -O -fverbose-asm -DA=16 -DB=32 -DC=0 e.c:
f:
.LFB0:
.cfi_startproc
# e.c:4: return A * x + B;
leal 2(%rdi), %eax #, tmp90
sall $4, %eax #, tmp93
testl %edi, %edi # x
movl $0, %edx #, tmp92
cmovle %edx, %eax # tmp93,, tmp92, <retval>
# e.c:6: }
ret
由于编译器优化,代码发生了显着变化。打补丁不容易。
重要提示
只要付出足够的努力、金钱和时间(想想类似 NSA 的能力),很多事情都是可能的。
如果您的目标是混淆二进制文件中的某些数据(例如某些密码),您可能会对其进行加密以使黑客的生活更加困难(但不要天真,NSA 将能够得到它)。记住座右铭:有No Silver Bullet;看起来这就是你的目标,但不要太天真(顺便说一句,围绕你的软件的法律保护,例如许可证,更重要;所以你需要一个律师来写一个好的 EULA)。
如果您的目标是调整一些性能关键的代码,您可以使用metaprogramming 和partial evaluation 技术。我喜欢做的一个做法是在运行时生成一些临时 C(或 C++)代码(更适合您的特定情况和数据),将临时 C 或 C++ 代码编译为一些 plugin,然后 @ 987654326@ 那个临时插件(在 Linux 上使用 dlopen 和 dlsym;在 Windows 上你需要 LoadLibrary 但我让你了解细节和后果)。您可以使用 JIT compiling 库,例如 libgccjit,而不是在运行时生成 C 或 C++ 代码。如果您喜欢这种技术,如果您的管理层允许,请考虑使用更好的编程语言(例如带有 SBCL 的 Common Lisp)。
但我不想为 1000 个客户编译我的程序 1000 次
这让我很惊讶。编译一个只包含常量的简单(短)C 文件很快,链接时间也很快。我会考虑为每个客户重新编译。
顺便说一句,我觉得 你太天真了。最重要的保护不是二进制文件中的技术,而是法律保护(您需要一份好的合同,所以要找一个好的律师并支付费用)。
相反,您是否考虑过让您的产品成为免费软件?许多公司都在这样做(并通过许可的其他方式赚钱,例如支持)。
注意。有很多现有的license managers。你考虑过购买和使用吗?另请注意,公司有很大的动机来避免作弊,而那些愿意窃取您的软件的人无论如何都可以这样做。您将通过致力于软件质量来销售更多产品,而不是花精力在使客户烦恼的徒劳的“保护”措施上,增加您的logistics 和分发和维护成本,并加强对客户发现的错误的调试。