在C++中模糊敏感字符串的技术

Tho*_*omi 85 c++ security obfuscation defensive-programming

我需要在我的C++应用程序中存储敏感信息(我想保密的对称加密密钥).简单的方法是这样做:

std::string myKey = "mysupersupersecretpasswordthatyouwillneverguess";

但是,通过该strings过程(或从二进制应用程序中提取字符串的任何其他应用程序)运行应用程序将显示上述字符串.

应使用哪些技术来掩盖这些敏感数据?

编辑:

好的,所以你们所有人都说"你的可执行文件可以进行逆向工程" - 当然!这是我的一个宠儿,所以我要在这里咆哮:

为什么99%(好吧,或许我夸大一点)这个网站上所有与安全相关的问题都会被"没有可能的方法来创建一个完全安全的程序"所回答 - 这不是一个有用的回答!安全性是完美可用性与一端无安全性之间的滑动尺度,完美的安全性,但另一方面没有可用性.

关键在于,您可以根据您要执行的操作以及运行软件的环境来选择滑动比例.我不是在为军事装置编写应用程序,我正在为家用PC编写应用程序.我需要使用预先知道的加密密钥在不受信任的网络上加密数据.在这些情况下,"通过默默无闻的安全"可能已经足够了!当然,有足够时间,精力和技能的人可以对二进制文件进行逆向工程并找到密码,但猜猜是什么?我不在乎:

实施顶级安全系统所花费的时间比破解版本的销售损失更为昂贵(不是说我实际上是卖这个,但你明白了我的意思).在新程序员的编程中,这个蓝天"让我们尽可能做到绝对最好的方式"的趋势至少可以说是愚蠢的.

感谢您抽出宝贵时间回答这个问题 - 他们最有帮助.不幸的是,我只能接受一个答案,但我已经投了所有有用的答案.

csl*_*csl 41

基本上,任何人都可以访问您的程序和调试器可以发现在应用的关键,如果他们想.

但是,如果您只想确保在strings二进制文件上运行时没有显示密钥,则可以确保密钥不在可打印范围内.

用XOR模糊键

例如,您可以使用XOR将密钥拆分为两个字节数组:

key = key1 XOR key2
Run Code Online (Sandbox Code Playgroud)

如果创建具有相同字节长度的key1,则key可以使用(完全)随机字节值,然后计算key2:

key1[n] = crypto_grade_random_number(0..255)
key2[n] = key[n] XOR key1[n]
Run Code Online (Sandbox Code Playgroud)

您可以在构建环境做到这一点,然后只存储key1key2应用程序中.

保护你的二进制文件

另一种方法是使用工具来保护您的二进制文件.例如,有几种安全工具可以确保您的二进制文件被混淆并启动它运行的虚拟机.这使得调试变得困难,并且也是许多商业级安全应用程序(也包括恶意软件)受到保护的常规方式.

最重要的工具之一是Themida,它可以很好地保护你的二进制文件.它通常被众所周知的程序(如Spotify)用于防止逆向工程.它具有防止在OllyDbg和Ida Pro等程序中进行调试的功能.

还有一个更大的列表,可能有点过时,保护您的二进制文件工具.
其中一些是免费的.

密码匹配

这里有人讨论过哈希密码+盐.

如果你需要存储密钥以匹配某种用户提交的密码,你应该使用单向散列函数,最好是结合用户名,密码和盐.但问题是,您的应用程序必须知道salt能够单向执行并比较生成的哈希值.因此,您仍然需要将盐存储在应用程序的某个位置.但是,正如@Edward在下面的评论中指出的那样,这将有效地防止使用例如彩虹表的字典攻击.

最后,您可以结合使用上述所有技术.

  • 了解盐值通常不会给对手带来优势 - 盐的目的是避免"字典攻击",即攻击者预先计算了许多可能输入的哈希值.使用盐迫使他们使用基于盐的新词典预先计算他们的词典.如果每种盐仅使用一次,则字典攻击变得完全无用. (4认同)
  • 我发现在查看反汇编程序时,通常没有很多XOR,所以如果你希望使用XOR来模糊某些东西,请记住它们会引起对自己的注意. (2认同)
  • @kb - 这是一个有趣的观点.我猜你会看到按位和超过xor发生的事情.a ^ b ==(a&~b)|| (~a&b) (2认同)

Mal*_*ick 13

有一个由 adamyaxley 制作的(非常轻的)仅包含标头的项目混淆,可以完美地工作。它基于 lambda 函数和宏,并在编译时使用 XOR 密码对字符串进行加密。如果需要,我们可以更改每个字符串的种子。

以下代码不会在编译的二进制文件中存储字符串“hello world”。

#include "obfuscate.h"

int main()
{
  std::cout << AY_OBFUSCATE("Hello World") << std::endl;
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我已经使用 c++17 和 Visual Studio 2019 进行了测试,并通过 IDA 检查,确认该字符串已隐藏。与ADVobfuscator相比,一个宝贵的优势是它可以转换为 std::string (同时仍然隐藏在编译的二进制文件中):

std::string var = AY_OBFUSCATE("string");
Run Code Online (Sandbox Code Playgroud)


Chr*_*son 7

首先,要意识到没有什么可以阻止一个足够坚定的黑客,并且周围有很多人.每个游戏和控制台周围的保护最终都会被破解,所以这只是一个临时修复.

你可以做4件事,这会增加你隐藏一段时间的机会.

1)以某种方式隐藏字符串的元素 - 像xoring(^运算符)这样的字符串与另一个字符串的字符串将足以使字符串无法搜索.

2)将字符串拆分成碎片 - 将您的字符串拆分并将其弹出到奇怪模块中奇怪命名的方法中.不要轻易搜索并找到包含字符串的方法.当然有些方法必须调用所有这些位,但它仍然会让它变得更难.

3)不要在内存中构建字符串 - 大多数黑客使用的工具可以让你在编码后看到内存中的字符串.如果可能,请避免这种情况 例如,如果您将密钥发送到服务器,请逐个字符地发送它,因此整个字符串永远不会出现.当然,如果你从RSA编码之类的东西使用它,那么这是更棘手的.

4)做一个特殊的算法 - 除此之外,添加一个或两个独特的扭曲.也许只需在您生产的所有产品中添加1,或者进行两次加密,或添加糖.这对于已经知道在有人使用时寻找什么的黑客来说有点难度,例如,vanilla md5哈希或RSA加密.

最重要的是,确保它不是太重要的时候(并且如果你的应用程序变得足够流行的时候)你的钥匙被发现了!


Nic*_*kis 5

我同意@Checkers,你的可执行文件可以进行逆向工程。

更好的方法是动态创建它,例如:

std::string myKey = part1() + part2() + ... + partN();
Run Code Online (Sandbox Code Playgroud)


Pau*_*sik 5

我过去使用的策略是创建一组看似随机的字符.您最初插入,然后使用代数过程定位您的特定字符,其中从0到N的每个步骤将产生一个数字<数组的大小,其中包含混淆字符串中的下一个字符.(这个答案现在感觉很混乱!)

例:

给定一组字符(数字和短划线仅供参考)

0123456789
----------
ALFHNFELKD
LKFKFLEHGT
FLKRKLFRFK
FJFJJFJ!JL
Run Code Online (Sandbox Code Playgroud)

一个方程式的前六个结果是:3,6,7,10,21,47

会产生"你好!"这个词.从上面的数组.