How to hide a string in binary code?

2019-01-02 20:11发布

Sometimes, it is useful to hide a string from a binary (executable) file. For example, it makes sense to hide encryption keys from binaries.

When I say “hide”, I mean making strings harder to find in the compiled binary.

For example, this code:

const char* encryptionKey = "My strong encryption key";
// Using the key

after compilation produces an executable file with the following in its data section:

4D 79 20 73 74 72 6F 6E-67 20 65 6E 63 72 79 70   |My strong encryp|
74 69 6F 6E 20 6B 65 79                           |tion key        |

You can see that our secret string can be easily found and/or modified.

I could hide the string…

char encryptionKey[30];
int n = 0;
encryptionKey[n++] = 'M';
encryptionKey[n++] = 'y';
encryptionKey[n++] = ' ';
encryptionKey[n++] = 's';
encryptionKey[n++] = 't';
encryptionKey[n++] = 'r';
encryptionKey[n++] = 'o';
encryptionKey[n++] = 'n';
encryptionKey[n++] = 'g';
encryptionKey[n++] = ' ';
encryptionKey[n++] = 'e';
encryptionKey[n++] = 'n';
encryptionKey[n++] = 'c';
encryptionKey[n++] = 'r';
encryptionKey[n++] = 'y';
encryptionKey[n++] = 'p';
encryptionKey[n++] = 't';
encryptionKey[n++] = 'i';
encryptionKey[n++] = 'o';
encryptionKey[n++] = 'n';
encryptionKey[n++] = ' ';
encryptionKey[n++] = 'k';
encryptionKey[n++] = 'e';
encryptionKey[n++] = 'y';

…but it's not a nice method. Any better ideas?

PS: I know that merely hiding secrets doesn't work against a determined attacker, but it's much better than nothing…

Also, I know about assymetric encryption, but it's not acceptable in this case. I am refactoring an existing appication which uses Blowfish encryption and passes encrypted data to the server (the server decrypts the data with the same key).

I can't change the encryption algorithm because I need to provide backward compatibility. I can't even change the encryption key.

20条回答
伤终究还是伤i
2楼-- · 2019-01-02 20:31

Here's a perl script to generate obfuscated c-code to hide a plaintext password from "strings" program.

  obfuscate_password("myPassword123");

  sub obfuscate_password($) {

  my $string = shift;
  my @c = split(//, $string);
  push(@c, "skip"); # Skip Null Terminator
                    # using memset to clear this byte
  # Add Decoy Characters
  for($i=0; $i < 100; $i++) {
    $ch = rand(255);
    next if ($ch == 0);
    push(@c, chr($ch));
  }                     
  my $count1 = @c;
  print "  int x1, x2, x3, x4;\n";
  print "  char password[$count1];\n";
  print "  memset(password, 0, $count1);\n";
  my $count2 = 0;
  my %dict  = ();
  while(1) {
    my $x = int(rand($count1));
    $y = obfuscate_expr($count1, $x);
    next if (defined($dict{$x}));
    $dict{$x} = 1;
    last if ($count2+1 == $count1);
    if ($c[$x] ne "skip") {
      #print "  $y\n";
      print "  $y password[x4] = (char)" . ord($c[$x]) . ";\n";
    }
    $count2++;
  }
  }

  sub obfuscate_expr($$) {
    my $count  = shift;
    my $target = shift;
    #return $target;

    while(1) {

       my $a = int(rand($count*2));
       my $b = int(rand($count*2));
       my $c = int(rand($count*2));
       next if (($a == 0) || ($b == 0) || ($c == 0));
       my $y = $a - $b;
       #print "$target: $y : $a - $b\n";
       if ($y == $target) {
          #return "$a - $b + $c";
          return "x1=$a; x2=$b; x3=$c; x4=x1-x2+x3; x5= +=x4;";
       }
    } 
  }
查看更多
像晚风撩人
3楼-- · 2019-01-02 20:32

For C check this out: https://github.com/mafonya/c_hide_strings

For C++ this:

class Alpha : public std::string
{
public:
    Alpha(string str)
    {
        std::string phrase(str.c_str(), str.length());
        this->assign(phrase);
    }
    Alpha c(char c) {
        std::string phrase(this->c_str(), this->length());
        phrase += c;
        this->assign(phrase);

        return *this;
    }
};

In order to use this, just include Alpha and:

Alpha str("");
string myStr = str.c('T').c('e').c('s').c('t');

So mystr is "Test" now and the string is hidden from strings table in binary.

查看更多
萌妹纸的霸气范
4楼-- · 2019-01-02 20:32

I think you want to make it look like instructions, your example of

x[y++]='M'; x[y++]='y'; ...

Would do just that, the long sequence of repeated instructions with a little variation may stand out and that would be bad, the byte in question may get encoded in the instruction as is and that would be bad, so perhaps the xor method, and perhaps some other tricks to make that long section of code not stand out, some dummy function calls perhaps. Depends on your processor as well, ARM for example it is real easy to look at binary data and pick out the instructions from the data and from there (if you are looking for a default key) to possibly pick out what might be the key because it is data but is not ascii and attack that. Likewise a block of similar instructions with the immediate field varying, even if you have the compiler xor the data with a constant.

查看更多
明月照影归
5楼-- · 2019-01-02 20:35

I was once in a similarly awkward position. I had data that needed to be in the binary but not in plain text. My solution was to encrypt the data using a very simple scheme that made it look like the rest of the program. I encrypted it by writing a program that took a string, converted all the characters to the ASCII code (padded with zeros as necessary to get a three digit number) and then added a random digit to the beginning and the end of the 3 digit code. Thus each character of the string was represented by 5 characters (all numbers) in the encrypted string. I pasted that string into the application as a constant and then when I needed to use the string, I decrypted and stored the result in a variable just long enough to do what I needed to.

So to use your example, "My strong encryption key" becomes "207719121310329211541116181145111157110071030703283101101109309926114151216611289116161056811109110470321510787101511213". Then when you need your encryption key, decode it but undoing the process.

It's certainly not bulletproof but I wasn't aiming for that.

查看更多
弹指情弦暗扣
6楼-- · 2019-01-02 20:37

Hiding passwords in your code is security by obscurity. This is harmful because makes you think you have some level of protection, when in fact you have very little. If something is worth securing, it is worth securing properly.

PS: I know that it doesn't work against real hacker, but it's much better than nothing...

Actually, in a lot of situations nothing is better than weak security. At least you know exactly where you stand. You don't need to be a "real hacker" to circumvent an embedded password ...

EDIT: Responding to this comment:

I know about pairs of keys, but it not acceptable in this case. I refactoring existing appication which uses Blowfish encryption. Encrypted data passed to server and server decrypt data. I can't change ecryption algorithm because I should provide backward compatibility.

If you care about security at all, maintaining backwards compatibility is a REALLY BAD reason to leave yourself vulnerable with embedded passwords. It is a GOOD THING to break backwards compatibility with an insecure security scheme.

It is like when the street kids discover that you leave your front door key under the mat, but you keep doing it because grandpa expects to find it there.

查看更多
骚的不知所云
7楼-- · 2019-01-02 20:37

The technology of encryption is strong enough to secure important data without hiding it in a binary file.

Or is your idea to use a binary file to disguise the fact that something is hidden?

That would be called steganography.

查看更多
登录 后发表回答