On Friday, 1 July 2016 at 22:56:48 UTC, Basile B. wrote:
On Friday, 1 July 2016 at 22:23:23 UTC, Hiemlick Hiemlicker
wrote:
I know this is probably a lot to ask for an many won't see the
point, but a secure program should not expose readable
strings, it makes it far too easy for the attacker to see what
is going on.
Is it possible to encrypt every static string in D and decrypt
before it is output in an automatic fashion?
Even something like
e{This is an encrypted string}
which encrypts the string using a user defined function(which
is ctfe'able) is better than nothing.
Even a simple xor type of cypher is better than nothing.
Obviously optional.
The problem is that there is no way to encrypt strings in the
binary through code because one must pass express the string
non-encrypted to the encryption function.
encrypt("This string will still end up in the binary");
even though the string is only used once, at the encryption
call site. It seems D won't replace
encrypt("This string will still end up in the binary");
with "skadf2903jskdlfaos;e;fo;aisjdfja;soejfjjfjfjfjfjfeij" or
whatever the ctfe value of encrypt actually is.
This also seems like a bug in D because manifest constants
used as sole arguments to ctfe'able functions should be
replaced by the function result.
e.g.,
factorial(3) should be replaced by 6 and the function should
never be called at run time. This is the whole point of ctfe,
is it not?
I'm not actually sure if the functions are ctfe'ed and the
un-encrypted string is just stored in the binary or what but
it's there
import std.stdio;
string e(string s)
{
string q;
foreach(c; s)
q ~= c + 1;
return q;
}
void main()
{
writeln(e("What is this string doing in the binary?"));
}
You must make a template that follows this pattern:
template KrypticString(string s)
{
string processor()
{
return /*do some stuff here on 's'*/ "";
}
enum KrypticString = processor();
}
It's already used in phobos for example for octal() and
hexString(). Also seen i dont remember where, for a float
format.
ok. For some reason I thought CTFE's applied to normal functions
but I realize that doesn't make a lot of sense. (would be nice
but most functions are not CTFE'able and the compiler would have
trouble figuring that out)
But another important thing is that you must absolutely not
release with -debug.
Strings are a thing but every one who has made the thug with
IDA knows that the most usefull informations are the "Names"
and not the "strings". The calls to the OS API can't be easily
hidden, they are always in the "Names" but D functions names
can.
Yes, of course. Do D names change depending on -debug vs -release?
For example it's even not worth crypting the strings if the
attacker can see
_D4main7decryptFAyaZAya
in the "Names", because in this case he "just" has to put a
breakpoint on the C3 of the matching function, look for the
decrypted string in memory, and bookmark the static addresses
of the parameters passed to this function during the execution.
Also, if you take a minute to think a bit you'll find that
cryptic strings will hit the eyes of the attacker quite
quickly: "mmmh why is the content crypted ?!, let's see
that...".
I'm not too concerned about the attacker seeing them because they
will have to watch every decryption to get the string(or possibly
write a utility to automate the decryption).
If everything is encrypted it will give the attacker grief far
more than being decrypted.
If pretty much every string is encrypted then it will make his
life a little more difficult I would think. After all, it is
impossible to completely stop an attacker given enough time and
energy. The goal is to make it not worth it.
Also, Is there a simple way to make this work for "direct" output:
writeln(de_encrypt!("This is my string"));
it encrypts it at compile time but decrypts it at run time.(hence
no binary)
Alternatively, treat every string as a call to an anonymous
function that decrypts it at runtime(possibly using different
cypher).
e.g.,
enstring s = "This is really an encrypted string function";
enstring could wrap opCall which decrypts it when used. This
might be a drop in replacement for string?
s() calls the decryption function, which is uniquely generated
for each string. We can drop the ()...
This would definitely add an order of magnitude to the complexity
of decoding the strings.