34

我发现可以从二进制文件中提取硬编码字符串。
例如,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;
}

可以清楚地从相应的可执行文件中提取字符串:
替代文字

我认为找到字符串有点太容易了。

我的问题是:

  1. 如何在可执行文件中简单地隐藏hiddenString1hiddenString2
  2. 有没有比使用一些晦涩的隐藏输入更安全的方法来使用“作弊码”?
4

9 回答 9

32

欢迎来到更广阔的防御性编程世界。

有几种选择,但我相信它们都依赖于某种形式的混淆;这虽然不完美,但至少是一些东西。

  1. 您可以将文本存储为其他二进制形式(十六进制?),而不是直接的字符串值。

  2. 您可以加密存储在应用程序中的字符串,然后在运行时解密它们。

  3. 您可以将它们拆分到代码中的各个点,然后再重新组合。

或者它们的某种组合。

请记住,有些攻击比查看实际二进制文件更进一步。有时他们会在程序运行时调查程序的内存地址空间。MS 在 .Net 2.0 中提出了一种称为SecureString 的东西。目的是在应用程序运行时保持字符串加密。

第四个想法是不要将字符串存储在应用程序本身中,而是依赖于将验证代码提交到您控制的服务器。在服务器上,您可以验证它是否是合法的“作弊码”。

于 2009-05-29T14:14:12.390 回答
20

有很多方法可以隐藏可执行文件中的数据。这里的其他人已经发布了很好的解决方案——一些比其他的更强大。我不会添加到该列表中。

请注意:这完全是一场猫捉老鼠的游戏:不可能保证没有人会发现你的“秘密”。

无论您使用多少加密或其他技巧;无论你投入多少精力或金钱。无论隐藏它涉及多少“NASA / MIT / CIA / NSA”类型。

这一切都归结为简单的物理原理:
如果任何用户都无法从可执行文件中提取您的秘密并“取消隐藏”它,那么计算机也无法取消隐藏它,您的程序也无法取消隐藏它。用它。任何有足够动力的中等技能开发人员都会找到揭开秘密的方法。

在您将可执行文件交给用户的那一刻,他们就拥有了找出秘密所需的一切。

您所能期望的最好的结果就是让揭开秘密变得如此困难,以至于您从知道秘密中获得的任何好处都变得不值得麻烦。

因此,如果数据公开只是“不好”,或者公开的后果只是“不方便”,则可以尝试隐藏数据。但千万不要想在你的程序中隐藏“主客户端数据库的密码”、私钥或其他一些关键机密。你就是不能。

如果你有真正的机密信息,你的程序会以某种方式需要但绝不应该成为公共信息(如私钥),那么你需要让你的程序与你控制的远程服务器通信,应用适当的身份验证和授权控制(也就是说,确保只有经过批准的人员或计算机才能向服务器发出请求),并让该服务器保密并使用它。

于 2009-05-29T21:04:22.933 回答
10

最简单的方法是用 xor 或 rot-13 之类的微不足道的东西加密它们,然后在使用它们时即时解密它们。这将消除对它们的随意观看,但不会阻止任何有丰富经验的人倒车。

于 2009-05-29T14:19:47.120 回答
6

除了克里斯提到的那些方法之外,您还可以使用散列算法。如果您只想检查是否指定了正确的 ID,您实际上不需要将整个 ID 存储在程序中。

  • 创建您要比较的字符串/密码/id 的哈希(MD5、SHA 等),可能会向其添加“盐”值。将其存储在您的程序中
  • 程序运行时,对输入的字符串/密码/id做同样的算法,比较两个哈希值是否匹配。

这样,实际文本永远不会存储在您的程序中,并且他们无法对您的程序进行逆向工程以找出原始文本是什么,因为哈希算法只是单向的。

于 2009-05-29T14:18:30.010 回答
5

我也想隐藏一些 http 请求的 URL。

如果您的应用程序正在发出请求,那么隐藏它是没有意义的。运行像 fiddler、http 分析器或其他数十种免费且现成的方法中的一种应用程序将显示您的应用程序正在创建的所有流量。

于 2010-01-19T15:32:58.547 回答
2

如果存在您不希望人们看到的特定字符串,则在运行时对其进行加密和解密。

如果您不希望人们看到您的 GUID,请从字节构造它,而不是从字符串构造:

const GUID SecretGuid = 
      { 0x4537774B, 0xCC80, 0x4eda, { 0x7A, 0x9E, 0xE7, 0x79, 0x91, 0xF5 } };
于 2009-05-29T14:23:39.203 回答
2

你所有的密码都是 GUID 还是只是一个例子?

也许将您的秘密存储为二进制 guid:

const GUID SecretGuid =
    { 0x4537774B, 0xCC80, 0x4eda, { 0x7A, 0x9E, 0xE7, 0x79, 0x91, 0xF5 } };

然后将您提供的 guid 从字符串转换为二进制格式并比较两个二进制 guid。

于 2009-05-29T15:24:14.247 回答
2

您可以做的最好的事情是将您的密码或其他要隐藏的字符串编码为 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.
于 2009-06-12T13:14:23.913 回答
2

这是我为此目的使用的方法。首先,我使用Sysinternals的字符串工具来显示 EXE 或 DLL 中的字符串。然后,我使用以下小工具(请参阅文章)将这些字符串替换为存储为算术表达式的加扰字符数组:例如:而不是字符串: “这是一个测试” 我将放置以下代码:(由该工具自动生成)

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;

这个问题有很多解决方案,但没有一个(包括我的)是完美的,但是有一些方法可以打乱、伪装和隐藏敏感字符串。您当然可以在运行时对其进行加密和解密(请参阅本文),但我发现更重要的是让这些字符串在可执行文件的位和字节中消失并且它可以工作。运行我的工具后,您不会在可执行文件中找到“这是一个测试”。

于 2018-08-07T12:42:12.477 回答