【问题标题】:How to embed strings inside code of executable?如何在可执行文件的代码中嵌入字符串?
【发布时间】:2011-10-02 04:36:16
【问题描述】:

我有一个字符串文字,它在我的可执行文件周围的许多不同地方使用。

让我们这样说:

const char *formatString = "Something I don't want to make obvious: %d";

int format1(char *buf) { sprintf(buf, formatString, 1); }
int format2(char *buf) { sprintf(buf, formatString, 2); }

//...

现在,这个字符串文字在可执行代码中变得非常很明显,因为它是按字面嵌入的。

有什么方法可以避免这种情况,例如强制编译器生成汇编指令(例如mov [ptr + 4], 0x65)指令来创建字符串,而不是按字面嵌入字符串?

我不想做任何形式的混淆——我只是想避免在可执行文件中制作字符串 obvious。 (我也不想在使用字符串的每个地方都修改我的代码。)

这可能吗?

【问题讨论】:

  • 我这样做的方法是在运行时从加密版本开始构建字符串。但这和混淆是一样的......
  • 同意神秘主义。这正是混淆的定义。如果您的程序是安全的,您就不必担心人们知道格式字符串。
  • @Downvoters:嗯,愿意发表评论吗?
  • 当我读到这样的问题时,我不禁想:你真正想要达到什么目标?似乎您担心(恶意?)用户足够聪明,可以在您的可执行文件中观看,但不愿意非常努力地尝试。我没有投反对票,但会在投赞成票之前了解一些背景知识......
  • @Francesco:它不是商业程序或任何东西,所以它只是为了我的学习,控制编译器的二进制输出。

标签: c visual-c++ executable portable-executable string-literals


【解决方案1】:

为避免手动将加密字符串粘贴到代码中,您可以创建一个宏来标记需要混淆的字符串和一个解密它们的函数:

#define OB(s) dec("START_MARK_GUID" s "\0" "END_MARK_GUID")
const char* dec(const char* s) { ... }
...
const char* s = OB("not easily readable"); // on all strings needed
const char* s = OB("either");

函数必须做两件事:

  1. 如果参数以 START_MARK_GUID 开头,则只需返回原始字符串(不带 guid)。这也将允许您使用未混淆的可执行文件,例如调试时。

  2. 如果它以 ENCRYPTED_MARK_GUID 开头,请先去混淆,然后返回一个新字符串。在 C 中,您必须在这里关心内存寿命;在 C++ 中,您可以简单地返回 std::string()。

最后,创建一个混淆器程序,在已编译的二进制文件中查找 GUID 并加密它们之间的数据。它只是 Python 或类似语言的几行代码。我还建议修复 EXE 的 CRC,尽管我的程序即使没有它也能正常工作。

您可以更改具有较少唯一标识符的 guid 以节省一些空间。您还可以改进这一点,使解密只发生一次(例如,使用 ENCRYPTED_MARK_GUID 在其中写入字符串 ID,并通过该 ID 将解密的字符串保存在字典中)。

【讨论】:

    【解决方案2】:

    混淆可能是您最好的选择。在运行任何需要字符串的代码之前,使用简单的混淆(例如 XOR),并在程序开头将其解混淆为另一个变量。

    【讨论】:

    • 嗯...所以我的理解是不可能强制编译器通过指令或其他方式在本地创建字符串?他们必须以某种方式在全球(和字面上)共享?
    • 如果你修改编译器或通过宏来实现,可能的,但我还没有遇到默认情况下这样做的。
    • 修改编译器显然是行不通的,但是宏怎么工作呢?我必须手动生成所有内容并将其放入源代码中,对吗? (即没有外部工具和东西就没有办法自动化它?)
    • 可以,但您只需执行一次(每个混淆机制)。
    【解决方案3】:

    使用 C++11 很快你就可以使用用户定义的文字了。

    constexpr const char*
    operator"" _decrypto(const char*, size_t len)
    {
      //  decrypt input string.
    }
    
    const char* formatString = "encrypted gibberish"_decrypto;
    
    int format1(char* buf) { sprintf(buf, formatString, 1); }
    int format2(char* buf) { sprintf(buf, formatString, 2); }
    
    int
    main()
    {
    }
    

    gcc is working on this furiously 我认为 IBM 已经有了。不确定 Visual Studio 的状态。这是在修补的 gcc 上编译的。

    【讨论】:

    • 我认为你对被问到的内容有点搞砸了。 OP 希望它不会在目标代码中显示为明文。 constexpr 运算符在编译时对字符串进行解密并将其存储为常量。所以你基本上做了相反的事情。 constexpr 应该对其进行加密(它将被混淆存储在可执行文件中),并且应该在使用前在运行时解密。
    • @Tim 是的,你是对的。我想我出于某种原因开始从混淆的角度考虑它。我会重新考虑一下。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-08
    • 2012-07-26
    • 2014-11-21
    • 1970-01-01
    • 1970-01-01
    • 2011-11-13
    • 1970-01-01
    相关资源
    最近更新 更多