我发现可以从二进制文件中提取硬编码字符串 例如,Process Explorer的属性视图显示超过3个字符的所有字符串。
这是我编写的简单可执行文件的代码,只是为了测试它:
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif
#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
int _tmain(int argc, _TCHAR* argv[])
{
_TCHAR* hiddenString1 =_T("4537774B-CC80-4eda-B3E4-7A9EE77991F5");
_TCHAR* hiddenString2 =_T("hidden_password_or_whatever");
for (int i= 0; i<argc; i++) {
if (0 == _tcscmp(argv[i],hiddenString1)) {
_tprintf (_T("The guid argument is correct.\n")); }
else if (0 == _tcscmp(argv[i],hiddenString2)) {
_tprintf (_T("Do something here.\n")); }
}
_tprintf (_T("This is a visible string.\n"));
//Keep Running
Sleep(60000);
return 0;
}
可以从相应的可执行文件中清楚地提取字符串:
我认为找到字符串有点太容易了。
我的问题是:
答案 0 :(得分:29)
欢迎来到更广阔的防御性节目世界。
有两种选择,但我相信所有选项都依赖于某种形式的混淆;虽然不完美,但至少是一些东西。
您可以将文本存储为其他二进制格式(十六进制?),而不是直字符串值。
您可以加密存储在应用中的字符串,然后在运行时解密它们。
您可以在代码中的各个点上拆分它们,然后重新构建。
或其某些组合。
请记住,有些攻击比查看实际的二进制文件更进一步。有时他们会在程序运行时调查程序的内存地址空间。 MS想出了一个名为SecureString in .Net 2.0的东西。目的是在应用程序运行时保持字符串加密。
第四个想法是不将字符串存储在应用程序本身中,而是依赖于将验证代码提交给您控制的服务器。在服务器上,您可以验证它是否是合法的“作弊代码”。
答案 1 :(得分:18)
在可执行文件中隐藏数据的方法有很多种。这里的其他人发布了很好的解决方案 - 有些比其他更强我不会添加到该列表中。
请注意:这只是一场猫捉老鼠的游戏:不可能 保证没有人会发现你的“秘密”。
无论您使用多少加密或其他技巧;无论你付出多少努力或金钱。无论有多少“NASA / MIT / CIA / NSA”类型都隐藏它。
这一切都归结为简单的物理学:
如果任何用户无法从可执行文件中提取您的秘密并“取消隐藏”它,那么计算机也无法取消隐藏它,并且您的程序将无法使用它。任何有足够激励的中等技术型开发人员都会找到取消隐藏秘密的方法。
您将可执行文件交给用户的那一刻,他们拥有了查找秘密所需的一切。
你能想到的最好的事情就是让它如此努力来揭开你知道这个秘密变得不值得麻烦所带来的任何好处的秘密。
因此,如果数据仅仅是“不好”而不是公开的,或者如果它变为公共的后果只是“不方便”,那么试图模糊数据是可以的。但是,甚至不要想在程序中隐藏“主客户端数据库的密码”,私钥或其他一些关键秘密。你不能。
如果你有一个真正关键的秘密信息,你的程序将以某种方式需要但不应该成为公共信息(如私钥),那么你需要让你的程序与你控制下的远程服务器对话,应用适当的身份验证和授权控制(,即确保只有经过批准的人员或计算机能够向服务器发出请求),并让该服务器保守秘密并使用它。
答案 2 :(得分:9)
最简单的方法是使用像xor或rot-13这样简单的东西加密它们,然后在使用时动态解密它们。这将消除对它们的随意观察,但它不会阻止任何有逆转经验的人。
答案 3 :(得分:6)
除了Chris提到的那些方法,您还可以使用散列算法。如果您只想检查是否指定了正确的ID,则实际上并不需要将整个ID存储在您的程序中。
这样,实际文本永远不会存储在您的程序中,并且他们无法对您的程序进行反向工程以找出原始文本的内容,因为哈希算法只是单向的。
答案 4 :(得分:5)
我还想隐藏http请求的网址。
如果您的应用正在发出请求,则无法隐藏此信息。运行像fiddler,http分析器或许多其他免费且随时可用的方法之一的应用程序将显示您的应用正在创建的所有流量。
答案 5 :(得分:2)
如果有一个特定的字符串,你不希望人们能够看到,那么加密它并在运行时解密。
如果您不希望人们看到您的GUID,那么从字节构造它,而不是从字符串构造:
const GUID SecretGuid =
{ 0x4537774B, 0xCC80, 0x4eda, { 0x7A, 0x9E, 0xE7, 0x79, 0x91, 0xF5 } };
答案 6 :(得分:2)
您的所有密码都是GUID还是仅仅是一个例子?
也许将你的秘密存储为二进制guid:
const GUID SecretGuid =
{ 0x4537774B, 0xCC80, 0x4eda, { 0x7A, 0x9E, 0xE7, 0x79, 0x91, 0xF5 } };
然后将提供的guid从字符串转换为二进制格式,并比较两个二进制guid。
答案 7 :(得分:1)
您可以做的最好的事情是将您要隐藏的密码或其他字符串编码为char数组。例如:
std::string s1 = "Hello"; // This will show up in exe in hex editor
char* s2 = "World"; // this will show up in exe in hex editor
char s3[] = {'G', 'O', 'D'}; // this will not show up in exe in hex editor.
答案 8 :(得分:1)
这是我用于此目的的方法。首先,我使用Strings的Sysinternals工具在EXE或DLL中显示字符串。 然后,我使用following small tool(请参阅article)将这些字符串替换为以算术表达式形式存储的加扰字符数组:例如:而不是字符串: “这是一个测试” 我将放置以下代码:(由this tool自动生成)
WCHAR T1[28];
T1[22] = 69;
T1[15] = 121 - 17;
T1[9] = L':' + -26;
T1[12] = L't' - 1;
T1[6] = 116 - 1;
T1[17] = 117 - 12;
T1[3] = 116 - 1;
T1[14] = L'' - 3;
T1[13] = L'w' - 3;
T1[23] = 69;
T1[26] = L'Y' + 3;
T1[19] = 111 + 0;
T1[21] = L'k' - 34;
T1[27] = L'\\' - 8;
T1[20] = L'B' + 32;
T1[4] = 42 + -10;
T1[25] = L'm' - 17;
T1[16] = L'H' + 18;
T1[18] = L'A' + 56;
T1[24] = 68;
T1[1] = 105 - 1;
T1[11] = L'k' - 6;
T1[10] = 66 + 50;
T1[2] = 105;
T1[0] = 117 - 1;
T1[5] = L'k' - 2;
T1[8] = 89 + 8;
T1[7] = 32;
有许多解决此问题的方法,但是没有一个(包括我的)完美的解决方案,但是有一些方法可以加扰,伪装和隐藏敏感字符串。您当然可以在运行时对它们进行加密和解密(请参阅本文),但是我发现使这些字符串在可执行文件的位和字节之间消失更重要,并且它可以正常工作。运行我的工具后,您将在可执行文件中找不到“这是一个测试”。