如何隐藏exe或dll中的字符串?

Posted

技术标签:

【中文标题】如何隐藏exe或dll中的字符串?【英文标题】:How to hide strings in a exe or a dll? 【发布时间】:2009-05-29 14:10:17 【问题描述】:

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

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

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

我的问题是:

    如何简单地隐藏 hiddenString1hiddenString2 可执行吗? 有没有更安全的 使用“作弊码”的方法比使用 一些晦涩的隐藏输入?

【问题讨论】:

这个问题是关于 GUID 还是关于一般字符串? GUID 只是一个例子:我也想隐藏一些 http 请求的 URL。 隐藏 http 请求的 URL 是行不通的。任何拥有嗅探器的人都可以准确地看到您的应用在做什么,而且这样做比检查您的进程的内存要容易得多。 How to hide a string in binary code? 你可以参考this - 它解释了什么是函数加密和全同态加密。 【参考方案1】:

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

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

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

    您可以加密存储在应用程序中的字符串,然后在运行时对其进行解密。

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

或它们的某种组合。

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

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

【讨论】:

不错的选择。由于提问者特别关心隐藏 Windows GUID 字符串(它只是一个十六进制数字),因此数据也可以存储为几个整数。 我想在你的好答案中添加加盐密码的可能性。 @Cyber​​Spock:我不确定加盐的目的是什么。字符串(盐渍与否)存储在二进制文件中,因此可能会被发现。这意味着只有两种解决方案:混淆以至少使其更难一点,或者根本不将其存储在应用程序中。 如果密码被加盐,可能会更难发现密码,因为这是一种将密码相互比较的算法,但无论如何这都是徒劳的。 我刚刚尝试将我的数组字符串 (char str[] = 'H', 'i', '\0') 转换为十六进制字节序列,它们很容易被发现同样的方式【参考方案2】:

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

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

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

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

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

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

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

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

【讨论】:

说得好。而真正的饼干是相当强大的,你将无法用一个小技巧来阻止它们。他们会注意到你玩字符串的热点,并耐心地让应用程序解密它以看到真实的东西。【参考方案3】:

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

【讨论】:

没有什么能真正阻止任何在倒车方面有丰富经验的人 ;) 既然他们必须在内存中拥有解密密钥才能运行程序,那么 AES 也不会阻止他们。【参考方案4】:

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

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

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

【讨论】:

小心,现在可以相对容易地发现某些哈希(例如 md5)的冲突.. 我不确定这是否有问题。 你可以走得更远,只做公钥加密交易的公钥部分。这将处理碰撞问题。它也是一种更安全的方法 - 与您使用的加密算法一样安全,即使在通过十六进制编辑器挖掘出来之后也是如此。【参考方案5】:

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

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

【讨论】:

这真的很糟糕。 :( @ZeeshanMahmood 什么部分? 意思是,我们不能在代码中隐藏 URL,因为通过其他方式,这些 URL 会被泄露。 您可以隐藏它们,但只要您访问它,它就会显示出来【参考方案6】:

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

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

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

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

【讨论】:

GUID 只是一个示例。我也想隐藏一些 http 请求的 URL。 每个知道在可执行文件中查找字符串的人都可以启动嗅探器并监视来自您的应用程序的 HTTP 请求。事实上,在寻找字符串之前,我会先尝试嗅探器。【参考方案7】:

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

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

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

【讨论】:

【参考方案8】:

您可以做的最好的事情是将您的密码或其他您想要隐藏的字符串编码为 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.

【讨论】:

在这个简单的 C char s3[] = 'G', 'O', 'D'; int n = sizeof(s3)/sizeof(s3[0]); printf("%d\n", n); 程序中,我在构建可执行文件中使用十六进制编辑器 -> .D$.G.D$.O.D$.D.D$. 找到了文本。 我看到如果数据在堆中,则可执行文件中的字符串是普通的,如果在堆栈中,则字符串消失。我知道这非常依赖于编译器/平台(我在 win 10 上)【参考方案9】:

这是我用于此目的的方法。首先,我使用Sysinternals 的Strings 工具来显示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;

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

【讨论】:

以上是关于如何隐藏exe或dll中的字符串?的主要内容,如果未能解决你的问题,请参考以下文章

编译时如何在 DLL 文件中隐藏字符串?

.Net·使用ILSpy反编译exe或dll文件保存为项目结构

E语言中如何释放DLL

如何查看exe或dll的依赖库dll

WiX:如何打包 exe 或 dll 以仅在安装期间使用

我用VB调用dll函数,该函数的输出参数为byte* buffer,如何把缓冲数据读出来,急啊!谢谢了