有多种方法可以实现您所说的。通常,更强大的技术在提供更高级别的保护的同时,也会给创建软件的程序员带来更多负担。因此,按照难度大致递增的顺序,这里有一些想法:
非连续地存储数据
最简单的方法是简单地不连续存储数据。也就是说,将数据存储在不同的部分,并在运行时在您需要它之前重新组合它。与所有其他技术一样,通常建议将值保留在内存中的时间尽可能短。
混淆存储的数据
有很多方法可以混淆数据。一种简单的方法是简单地与一些固定常数进行异或。一种更复杂的方法是加密数据,但除非您有某种安全的方法来存储加密密钥,否则这实际上可能无法提供更高的安全性。一种可能性是使用整个程序(减去受保护数据)的加密散列作为加密密钥。这将在很大程度上防止更改二进制文件并提供一种非显而易见的方式来存储密钥。
在运行时重新计算数据
如果您可以完全避免存储数据,我们就消除了能够从静态分析中导出数据的问题。如果出于性能原因预先计算某些数据的哈希值,请考虑在程序启动时而不是在编译时进行。或者,如果数据是固定的,请考虑编写一个可以在编译时包含的多态生成器。也就是说,编写一个采用固定常量并生成代码的程序,该代码在运行时会生成该值,而无需明确包含该值。然后将生成的代码与您的程序链接。由于多态生成器将成为构建过程的一部分而不是运行时的一部分,因此触发 A/V 警告的可能性要小得多。
这个想法的概念证明
我用 C++ 编写了一个小程序来更全面地演示这种技术。这是程序:
线性.cpp
#include <iostream>
#include <cstdlib>
#include <random>
int main(int argc, char *argv[])
{
std::random_device rd;
std::uniform_int_distribution<> r{-32768,32767};
for (int i=1; i < argc; ++i) {
int y = std::atoi(argv[i]);
int x;
for (x=r(rd); x==0; x= r(rd)); // make sure x!=0
int m = r(rd);
int b = y-m*x;
std::cout << "int generate" << i << "(int x) { return x * " << m << " + " << b << "; }\n";
std::cout << "\tassert(" << y << " == generate" << i << "(" << x << "));\n";
}
}
怎么运行的
这是一个非常简单的程序,它将一系列整数作为输入,并为每个整数创建一个线性函数。例如,使用此命令行:
./linear 39181 3802830 938833 -41418699
该程序生成了以下输出:
int generate1(int x) { return x * -5646 + 182450149; }
assert(39181 == generate1(32308));
int generate2(int x) { return x * -14922 + 10696794; }
assert(3802830 == generate2(462));
int generate3(int x) { return x * -15424 + -320805807; }
assert(938833 == generate3(-20860));
int generate4(int x) { return x * -8144 + -127093579; }
assert(-41418699 == generate4(-10520));
该assert
s为只是那里的文档和测试。在实际使用中,如果要39181
在代码中重新创建常量,可以使用generate1(32308)
. 如果我们将这些行重新排列成一个完整的程序,我们会得到:
tryme.cpp
int generate1(int x) { return x * -5646 + 182450149; }
int generate2(int x) { return x * -14922 + 10696794; }
int generate3(int x) { return x * -15424 + -320805807; }
int generate4(int x) { return x * -8144 + -127093579; }
#include <cassert>
int main() {
assert(39181 == generate1(32308));
assert(3802830 == generate2(462));
assert(938833 == generate3(-20860));
assert(-41418699 == generate4(-10520));
}
显然,如果您需要更长的数字或字符串,您可以将它们相乘或连接,并且我选择的具有随机数值范围的线性函数完全是任意的。随意替换和试验。
远程获取数据
根据环境,可以远程存储数据,然后在需要时通过 HTTPS 之类的方式安全地获取数据。请注意,这样做也可能意味着即使是普通的网络中断或错误配置的防火墙也会导致您的软件无法运行,但您可以决定这是否符合您的目的。