Compile-Time string obfuscation mit langen strings



  • Hallo,

    in meinem Programm möchte ich bestimmte strings zur Compile-Zeit verschlüsseln, so dass diese nicht in der erzeugten exe als Klartext lesbar sind.

    Dafür würde ich gerne ein Macro/constexpr verwenden, welche die Verschlüsselung automatisch erledigt.
    Bis jetzt habe ich diese Lösung, die ich per Google gefunden habe, verwendet. Das hat soweit auch geklappt.

    Problem ist allerdings, dass diese Methode anscheinend Probleme hat, sobald man etwas längere strings verwenden will. Der folgende Code führt bei mir zu einem Fehler:

    #include <iostream>
    #include <string>
    #include "xor_string.h"
    
    int main()
    {
    	auto str = XorString("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
    	std::cout << str << "\n";
    }
    

    nämlich: " fatal error C1202: Der Kontext für einen rekursiven Typ oder eine Funktionsabhängigkeit ist zu komplex".

    Dabei hat die Zeichenkette lediglich 269 Zeichen...

    Bereits ab 49 Zeichen gibt Intellisense eine Fehlermeldung aus: "Ein unvollständiger Typ ist nicht zulässig". Kompilieren lässt sich der Code allerdings trotzdem.

    Bei kürzeren strings funktioniert alles, allerdings erhalte ich die drei Warnungen:

    xor_string.h(60): warning C4307: "*": Überlauf einer ganzzahligen Konstanten
    xor_string.h(60): warning C4307: "+": Überlauf einer ganzzahligen Konstanten
    xor_string.h(60): warning C4309: "static_cast": Verkürzung eines konstanten Wertes
    

    bei der Zeile

    const char XORKEY = static_cast<char>(RandomNumber(0, 0xFF));
    

    des oben verlinkten Codes.

    Ich vermute also, dass das auch der/ein Grund ist warum das nicht geht, allerdings verstehe ich leider nicht wie der Code genau funktioniert.

    Daher die Fragen:

    • Kann man den oben verlinkten Code fixen, so dass das gewünschte Verhalten erreicht wird?
    • Oder gibt es andere/bessere Methoden die das selbe machen ohne so schnell in Probleme zu geraten wenn die strings zu lange werden?

    Kompiliert wurde übrigens mit Visual Studio 2017 im Release Modus.


  • Mod

    Hab ich nicht schon einmal irgendwo einen compile-time rot13 encrypter gepostet, für genau das? IIRC in irgendeinem Thread mit camper.



  • Arcoth schrieb:

    Hab ich nicht schon einmal irgendwo einen compile-time rot13 encrypter gepostet, für genau das? IIRC in irgendeinem Thread mit camper.

    Du meinst das hier?

    Wenn ich den von dir dort verlinkten Code testen will, bekomme ich folgende Fehlermeldung vom Compiler:

    error C3686: "operator ""_rot13": Literaloperator-Vorlage muss exakt einen Vorlagenparameter aufweisen, bei dem es sich um ein Parameterpaket handelt
    error C3687: "operator ""_rot13": Literaloperator-Vorlage muss einen Nicht-Typvorlagenparameter des Typs "char" aufweisen
    error C3688: ungültiges Literalsuffix "_rot13"; Literaloperator oder Literaloperator-Vorlage "operator ""_rot13" nicht gefunden
    note: Literaloperator muss eine Parameterliste des Typs "const char *, std::size_t" aufweisen
    


  • Dieser Moment, wenn man über seinen eigenen Witz lacht und 2 Minuten später dies erst bemerkt.

    P.S.: 'a' bzw 'A' + 26 ist doch 1 über das 'z'/'Z' hinaus, oder?

    if (ch >= base && ch <= base+26)
    

  • Mod

    happystudent schrieb:

    Arcoth schrieb:

    Hab ich nicht schon einmal irgendwo einen compile-time rot13 encrypter gepostet, für genau das? IIRC in irgendeinem Thread mit camper.

    Du meinst das hier?

    Wenn ich den von dir dort verlinkten Code testen will, bekomme ich folgende Fehlermeldung vom Compiler:

    error C3686: "operator ""_rot13": Literaloperator-Vorlage muss exakt einen Vorlagenparameter aufweisen, bei dem es sich um ein Parameterpaket handelt
    error C3687: "operator ""_rot13": Literaloperator-Vorlage muss einen Nicht-Typvorlagenparameter des Typs "char" aufweisen
    error C3688: ungültiges Literalsuffix "_rot13"; Literaloperator oder Literaloperator-Vorlage "operator ""_rot13" nicht gefunden
    note: Literaloperator muss eine Parameterliste des Typs "const char *, std::size_t" aufweisen
    

    VC++ unterstützt keine string literal operator templates.

    HarteWare schrieb:

    Dieser Moment, wenn man über seinen eigenen Witz lacht und 2 Minuten später dies erst bemerkt.

    P.S.: 'a' bzw 'A' + 26 ist doch 1 über das 'z'/'Z' hinaus, oder?

    if (ch >= base && ch <= base+26)
    

    Richtig.



  • HarteWare schrieb:

    Dieser Moment, wenn man über seinen eigenen Witz lacht und 2 Minuten später dies erst bemerkt.

    Welcher Witz 😕

    Arcoth schrieb:

    VC++ unterstützt keine string literal operator templates.

    EDIT: ach so, hab das string übersehen... Trotzdem eine Frage:

    Auf cppreference steht (unter literal operators) allerdings auch folgendes:

    If the literal operator is a template, it must have an empty parameter list and can have only one template parameter, which must be a non-type template parameter pack with element type char

    Dein Code verletzt diese Regel so wie ich das sehe?

    In dem Link ist auch bereits von C++17 die Rede, also sollte diese aktuell sein, oder?


  • Mod

    happystudent schrieb:

    HarteWare schrieb:

    Dieser Moment, wenn man über seinen eigenen Witz lacht und 2 Minuten später dies erst bemerkt.

    Welcher Witz 😕

    Er hat einen Beitrag in dem von dir verlinkten Thread gelesen, darüber gelacht, aber erst später bemerkt, dass es seiner war.

    happystudent schrieb:

    Arcoth schrieb:

    VC++ unterstützt keine string literal operator templates.

    EDIT: ach so, hab das string übersehen... Trotzdem eine Frage:

    Auf cppreference steht (unter literal operators) allerdings auch folgendes:

    If the literal operator is a template, it must have an empty parameter list and can have only one template parameter, which must be a non-type template parameter pack with element type char

    Dein Code verletzt diese Regel so wie ich das sehe?

    In dem Link ist auch bereits von C++17 die Rede, also sollte diese aktuell sein, oder?

    Dass string literal operator templates (noch) kein Teil der Sprache sind, ist schlicht und einfach ein Designfehler. Clang und GCC unterstützen sie aus dem Grund (noch?). Man sollte dieses Problem aber auch ohne lösen können.



  • Hey, mal was freudiges:

    happystudent - Beiträge: 777
    Arcoth - Beiträge: 3333
    

    Und das direkt untereinander, das muss gefeiert werden! Schade nur, dass happystudent noch nicht 7777 Beiträge hat.

    Und wehe, einer von euch schreibt noch einen Beitrag 😃 !



  • wob schrieb:

    Hey, mal was freudiges:

    happystudent - Beiträge: 777
    Arcoth - Beiträge: 3333
    

    Und das direkt untereinander, das muss gefeiert werden! Schade nur, dass happystudent noch nicht 7777 Beiträge hat.

    Und wehe, einer von euch schreibt noch einen Beitrag 😃 !

    Harte Ware ist mit derzeit 399 auch nur knapp von 444 entfernt. Also Schreibverbot für Happystudent und Arcoth, bis Harte Ware die 444 erreicht hat.

    Edit:
    Die beiden können ja als Unregs weiterschreiben...



  • wob schrieb:

    Hey, mal was freudiges:

    happystudent - Beiträge: 777
    Arcoth - Beiträge: 3333
    

    Und das direkt untereinander, das muss gefeiert werden! Schade nur, dass happystudent noch nicht 7777 Beiträge hat.

    Stimmt, ist mir gar nicht aufgefallen, Danke 🙂

    DocShoe schrieb:

    Harte Ware ist mit derzeit 399 auch nur knapp von 444 entfernt. Also Schreibverbot für Happystudent und Arcoth, bis Harte Ware die 444 erreicht hat.

    Edit:
    Die beiden können ja als Unregs weiterschreiben...

    Alles klar, mal sehen wie lange wir das durchhalten 😃

    Arcoth schrieb:

    Er hat einen Beitrag in dem von dir verlinkten Thread gelesen, darüber gelacht, aber erst später bemerkt, dass es seiner war.

    Ach so^^

    Habe aber noch eine Frage zu der Implementierung. Habe mich nämlich mal an einem rot13 encoder versucht (ohne string literal operator templates) und komme fast ans Ziel damit, aber eben nur fast. Folgender Code:

    #include <iostream>
    #include <string>
    
    struct meta_string
    {
    	const char *m_str;
    	size_t m_size;
    
    	template <size_t N>
    	constexpr meta_string(const char (&str)[N]) : m_str(str), m_size(N) {}
    	constexpr size_t size() const { return m_size; }
    	constexpr const char &operator[](size_t index) const { return m_str[index]; }
    };
    
    template <typename Char, std::size_t N>
    struct meta_encoder 
    {
    	Char arr[N];
    	constexpr meta_encoder(meta_string str)
    		: arr()
    	{
    		for (size_t i = 0; i < str.size() - 1; ++i)
    		{
    			if (str[i] >= 'a' && str[i] <= 'm') { arr[i] = str[i] + 13; }
    			else if (str[i] >= 'A' && str[i] <= 'M') { arr[i] = str[i] + 13; }
    			else if (str[i] >= 'n' && str[i] <= 'z') { arr[i] = str[i] - 13; }
    			else if (str[i] >= 'N' && str[i] <= 'Z') { arr[i] = str[i] - 13; }
    			else arr[i] = str[i];
    		}
    	}
    	constexpr size_t size() const { return N; }
    };
    
    template <size_t N>
    constexpr auto create_encoder_from_string(meta_string str) { return meta_encoder<char, N>(str); }
    
    template <typename Char, std::size_t N>
    constexpr auto encode(const Char(&str)[N]) { return create_encoder_from_string<N>(meta_string(str)); }
    
    int main() 
    {
    	constexpr auto str = encode("Hello World"); std::cout << str.arr << "\n"; // "Hello World" ist nicht sichtbar in der exe
    	std::cout << encode("Hello World").arr << "\n"; // "Hello World" ist sichtbar....
    }
    

    Wenn ich also meinen string in einer constexpr Hilfsvariable zwischenspeicher, dann funktioniert alles wie gewünscht und das String Literal ist in der exe nicht auffindbar.

    Will ich das selbe aber inlinen (zweite Zeile in main), dann ist das Literal sichtbar.

    Da die Auswertung ja prinzipiell zur Compile-Zeit möglich ist (erste Zeile in main) müsste ich den Compiler nur noch dazu "zwingen" dies auch für Variante 2 zu tun...

    Wie kann ich das machen?



  • Habs hinbekommen:

    #define ENCODE(Str) ( []() { constexpr auto tmp = encode(Str); return tmp; }().arr )
    

Anmelden zum Antworten