Techniques for obscuring sensitive strings in C++

后端 未结 14 839
孤街浪徒
孤街浪徒 2020-12-12 12:12

I need to store sensitive information (a symmetric encryption key that I want to keep private) in my C++ application. The simple approach is to do this:

std::         


        
相关标签:
14条回答
  • 2020-12-12 12:56

    One method I recently tried is:

    1. Take hash (SHA256) of the private data and populate it in code as part1
    2. Take XOR of private data and its hash and populate it in code as part2
    3. Populate data: Don't store it as char str[], but populate on runtime using assignment instructions (as shown in macro below)
    4. Now, generate the private data on run time by taking the XOR of part1 and part2
    5. Additional step: Calculate hash of generated data and compare it with part1. It will verify the integrity of private data.

    MACRO to populate data:

    Suppose, private data is of 4 bytes. We define a macro for it which saves the data with assignment instructions in some random order.

    #define POPULATE_DATA(str, i0, i1, i2, i3)\
    {\
        char *p = str;\
        p[3] = i3;\
        p[2] = i2;\
        p[0] = i0;\
        p[1] = i1;\
    }
    

    Now use this macro in code where you need to save part1 and part2, as follows:

    char part1[4] = {0};
    char part2[4] = {0};
    POPULATE_DATA(part1, 1, 2, 3, 4); 
    POPULATE_DATA(part2, 5, 6, 7, 8);
    
    0 讨论(0)
  • 2020-12-12 13:04

    There is a (very light) header-only project obfuscate made by adamyaxley that works perfectly. It is based on lambda functions and macros and it encrypts strings litteral with a XOR cipher at compile-time. If needed, we can change the seed for each string.

    The following code will not store the string "hello world" in the compiled binary.

    #include "obfuscate.h"
    
    int main()
    {
      std::cout << AY_OBFUSCATE("Hello World") << std::endl;
      return 0;
    }
    

    I have tested with c++17 and visual studio 2019, and check via IDA and I confirm the string is hidden. One precious advantage compared to ADVobfuscator is that it is convertible to a std::string (while being still hidden in the compiled binary) :

    std::string var = AY_OBFUSCATE("string");
    
    0 讨论(0)
  • 2020-12-12 13:06

    A strategy i've used in the past is to create an array of seemingly-random characters. You initially insert, and then locate your particular characters with a algebraic process where each step from 0 to N will yield a number < size of the array which contains the next char in your obfuscated string. (This answer is feeling obfuscated now!)

    Example:

    Given an array of chars (numbers and dashes are for reference only)

    0123456789
    ----------
    ALFHNFELKD
    LKFKFLEHGT
    FLKRKLFRFK
    FJFJJFJ!JL
    

    And an equation whose first six results are: 3, 6, 7, 10, 21, 47

    Would yield the word "HELLO!" from the array above.

    0 讨论(0)
  • 2020-12-12 13:06

    I've created a simple encryption tool for strings, it can automatically generate encrypted strings and has a few extra options to do that, a few examples:

    String as a global variable:

    // myKey = "mysupersupersecretpasswordthatyouwillneverguess";
    unsigned char myKey[48] = { 0xCF, 0x34, 0xF8, 0x5F, 0x5C, 0x3D, 0x22, 0x13, 0xB4, 0xF3, 0x63, 0x7E, 0x6B, 0x34, 0x01, 0xB7, 0xDB, 0x89, 0x9A, 0xB5, 0x1B, 0x22, 0xD4, 0x29, 0xE6, 0x7C, 0x43, 0x0B, 0x27, 0x00, 0x91, 0x5F, 0x14, 0x39, 0xED, 0x74, 0x7D, 0x4B, 0x22, 0x04, 0x48, 0x49, 0xF1, 0x88, 0xBE, 0x29, 0x1F, 0x27 };
    
    myKey[30] -= 0x18;
    myKey[39] -= 0x8E;
    myKey[3] += 0x16;
    myKey[1] += 0x45;
    myKey[0] ^= 0xA2;
    myKey[24] += 0x8C;
    myKey[44] ^= 0xDB;
    myKey[15] ^= 0xC5;
    myKey[7] += 0x60;
    myKey[27] ^= 0x63;
    myKey[37] += 0x23;
    myKey[2] ^= 0x8B;
    myKey[25] ^= 0x18;
    myKey[12] ^= 0x18;
    myKey[14] ^= 0x62;
    myKey[11] ^= 0x0C;
    myKey[13] += 0x31;
    myKey[6] -= 0xB0;
    myKey[22] ^= 0xA3;
    myKey[43] += 0xED;
    myKey[29] -= 0x8C;
    myKey[38] ^= 0x47;
    myKey[19] -= 0x54;
    myKey[33] -= 0xC2;
    myKey[40] += 0x1D;
    myKey[20] -= 0xA8;
    myKey[34] ^= 0x84;
    myKey[8] += 0xC1;
    myKey[28] -= 0xC6;
    myKey[18] -= 0x2A;
    myKey[17] -= 0x15;
    myKey[4] ^= 0x2C;
    myKey[9] -= 0x83;
    myKey[26] += 0x31;
    myKey[10] ^= 0x06;
    myKey[16] += 0x8A;
    myKey[42] += 0x76;
    myKey[5] ^= 0x58;
    myKey[23] ^= 0x46;
    myKey[32] += 0x61;
    myKey[41] ^= 0x3B;
    myKey[31] ^= 0x30;
    myKey[46] ^= 0x6C;
    myKey[35] -= 0x08;
    myKey[36] ^= 0x11;
    myKey[45] -= 0xB6;
    myKey[21] += 0x51;
    myKey[47] += 0xD9;
    

    As unicode string with decryption loop:

    // myKey = "mysupersupersecretpasswordthatyouwillneverguess";
    wchar_t myKey[48];
    
    myKey[21] = 0x00A6;
    myKey[10] = 0x00B0;
    myKey[29] = 0x00A1;
    myKey[22] = 0x00A2;
    myKey[19] = 0x00B4;
    myKey[33] = 0x00A2;
    myKey[0] = 0x00B8;
    myKey[32] = 0x00A0;
    myKey[16] = 0x00B0;
    myKey[40] = 0x00B0;
    myKey[4] = 0x00A5;
    myKey[26] = 0x00A1;
    myKey[18] = 0x00A5;
    myKey[17] = 0x00A1;
    myKey[8] = 0x00A0;
    myKey[36] = 0x00B9;
    myKey[34] = 0x00BC;
    myKey[44] = 0x00B0;
    myKey[30] = 0x00AC;
    myKey[23] = 0x00BA;
    myKey[35] = 0x00B9;
    myKey[25] = 0x00B1;
    myKey[6] = 0x00A7;
    myKey[27] = 0x00BD;
    myKey[45] = 0x00A6;
    myKey[3] = 0x00A0;
    myKey[28] = 0x00B4;
    myKey[14] = 0x00B6;
    myKey[7] = 0x00A6;
    myKey[11] = 0x00A7;
    myKey[13] = 0x00B0;
    myKey[39] = 0x00A3;
    myKey[9] = 0x00A5;
    myKey[2] = 0x00A6;
    myKey[24] = 0x00A7;
    myKey[46] = 0x00A6;
    myKey[43] = 0x00A0;
    myKey[37] = 0x00BB;
    myKey[41] = 0x00A7;
    myKey[15] = 0x00A7;
    myKey[31] = 0x00BA;
    myKey[1] = 0x00AC;
    myKey[47] = 0x00D5;
    myKey[20] = 0x00A6;
    myKey[5] = 0x00B0;
    myKey[38] = 0x00B0;
    myKey[42] = 0x00B2;
    myKey[12] = 0x00A6;
    
    for (unsigned int fngdouk = 0; fngdouk < 48; fngdouk++) myKey[fngdouk] ^= 0x00D5;
    

    String as a global variable:

    // myKey = "mysupersupersecretpasswordthatyouwillneverguess";
    unsigned char myKey[48] = { 0xAF, 0xBB, 0xB5, 0xB7, 0xB2, 0xA7, 0xB4, 0xB5, 0xB7, 0xB2, 0xA7, 0xB4, 0xB5, 0xA7, 0xA5, 0xB4, 0xA7, 0xB6, 0xB2, 0xA3, 0xB5, 0xB5, 0xB9, 0xB1, 0xB4, 0xA6, 0xB6, 0xAA, 0xA3, 0xB6, 0xBB, 0xB1, 0xB7, 0xB9, 0xAB, 0xAE, 0xAE, 0xB0, 0xA7, 0xB8, 0xA7, 0xB4, 0xA9, 0xB7, 0xA7, 0xB5, 0xB5, 0x42 };
    
    for (unsigned int dzxykdo = 0; dzxykdo < 48; dzxykdo++) myKey[dzxykdo] -= 0x42;
    
    0 讨论(0)
  • 2020-12-12 13:07

    I agree with @Checkers, your executable can be reverse-engineered.

    A bit better way is to create it dynamically, for example:

    std::string myKey = part1() + part2() + ... + partN();
    
    0 讨论(0)
  • 2020-12-12 13:12

    First of all, realise that there is nothing you can do that will stop a sufficiently determined hacker, and there are plenty of those around. The protection on every game and console around is cracked eventually, so this is only a temporary fix.

    There are 4 things you can do that will increase you chances of staying hidden for a while.

    1) Hide the elements of the string in some way -- something obvious like xoring ( the ^ operator) the string with another string will be good enough to make the string impossible to search for.

    2) Split the string into pieces -- split up your string and pop bits of it into strangely named methods in strange modules. Don't make it easy to search through and find the method with the string in it. Of course some method will have to call all these bits, but it still makes it a little harder.

    3) Don't ever build the string in memory -- most hackers use tools that let them see the string in memory after you have encoded it. If possible, avoid this. If for example you are sending the key off to a server, send it character by character, so the whole string is never around. Of course, if you are using it from something like RSA encoding, then this is trickier.

    4) Do an ad-hoc algorithm -- on top of all this, add a unique twist or two. Maybe just add 1 to everything you produce, or do any encryption twice, or add a sugar. This just makes it a little harder for the hacker who already knows what to look for when someone is using, for example, vanilla md5 hashing or RSA encryption.

    Above all, make sure it isn't too important when (and it will be when if you application becomes popular enough) your key is discovered!

    0 讨论(0)
提交回复
热议问题