7 Stimmen

Brauchen Sie Hilfe bei der Erklärung eines verschleierten C++-Codes?

Dieser Codeschnipsel hat mich verrückt gemacht, kann mir jemand helfen, das zu erklären?

#include <stdio.h>
char*_="XxTIHRCXCxTIHRXRCxTIHXHRCxTIXIHRCxTXTIHRCxXxTIHRCX";
int main(int l){for(l+=7;l!=putchar(010);++l);if(*(++_))main
    (*_!=88?(putchar(*_^073)|putchar(33))&1:0xffff2a8b);}

Danke,
Chan Nguyen

7voto

peoro Punkte 24751

Um zu verstehen, wie dieser Code funktioniert, schreiben Sie ihn in einer lesbaren Form um:

#include <stdio.h>

char*_="XxTIHRCXCxTIHRXRCxTIHXHRCxTIXIHRCxTXTIHRCxXxTIHRCX";

int main(int l)
{
    for( l += 7; l != putchar(010); ++l ) {
    }

    if( *(++_) ) {
        main( ( *_ != 88 ) ? ( putchar(*_^073) | putchar(33) )&1 : 0xffff2a8b );
    }

    return 0;
}

Jetzt wollen wir es verstehen:

  • sein Parameter l (der 1 ist, wenn Sie das Programm ohne Parameter ausführen) wird um 7 erhöht (es wird 8)

  • wird die Schleife Folgendes ausgeben 010 (oktal für 8: ascii backspace) bis l==8 (daher wird es nichts bewirken, wenn Sie das Programm ausführen

  • wenn das nächste Zeichen, das durch _ (es ist x jetzt) anders als 0 ist (dies bedeutet wahrscheinlich "bis wir das Ende von _ "), main aufgerufen wird, aber sehen wir uns an, was passiert, während wir seine Parameter auswerten:

    • das Zeichen, auf das aktuell durch _ von 88 verschieden ist (88 ist x in ascii), der Parameter für main ist also das Ergebnis des Ausdrucks ( putchar(*_^073) | putchar(33) )&1 :

      bei der Auswertung von main Parameter werden zwei Zeichen gedruckt

      • Die erste ist: *_^073 , das war's, 120^59 (seit x ist 120 in ascii und 073 in oktal ist 59 in dezimal), das ist 67 : 120( 0b1000011 ) XOR 59( 0b111011 ) = 67 0b1000011

      • die zweite ist 33 ( ! )

      main Parameter ist dann das Ergebnis von (67|33)&1 was 1 ist

Wenn Sie wirklich verstehen wollen, was im Detail passiert, müssen Sie mit dieser Arbeit fortfahren, aber Sie können sehen, was passiert, wenn Sie das Programm ausführen (vielleicht eine usleep(10000) irgendwo, so dass Sie die Ausgabe sehen können). Es wird eine auswendig gelernte Zeichenkette " Corsix! ".

Ein solches Programm zu schreiben, ist ziemlich einfach: Sobald Sie sich entschieden haben, wie Ihr Algorithmus funktioniert, ist es einfach, eine Zeichenkette zu erzeugen, wie _ Dadurch erzeugt der Algorithmus das Gewünschte, aber es ist sehr viel schwieriger, ihn zurückzuentwickeln.

4voto

Ze Blob Punkte 2767

Dieses Stück Code ist zwar nicht standardkonform, aber gcc kompiliert es und die Ausgabe stimmt mit meiner Analyse des Codes überein. Leider kann ich die Ausgabe ohne etwas mehr Kontext nicht wirklich interpretieren. Wenn ich die Backspaces ignoriere, sieht die Ausgabe ungefähr so aus:

C!o!r!s!i!...

Um den Code zu analysieren, müssen wir ihn zunächst ein wenig formatieren:

#include <stdio.h>

char* _ ="XxTIHRCXCxTIHRXRCxTIHXHRCxTIXIHRCxTXTIHRCxXxTIHRCX";

int main(int l){
    for(l+=7; l != putchar(010); ++l); // 010 = 8 -> backspace char
    if(*(++_))
        main(
            *_ != 88 ? // *_ != 'X'
                ( putchar(*_ ^ 073) | putchar(33) ) & 1 : // 33 = '!'
                0xffff2a8b);
}

Bevor wir weitermachen, sollten wir noch ein paar Dinge erwähnen:

  1. Si putchar erfolgreich ist, gibt es das übergebene Zeichen zurück.
  2. In C sind Zahlen, die mit 0 beginnen, eigentlich Oktale und nicht Dezimalzahlen. 010 ist also eigentlich die Dezimalzahl 8.

Beachten Sie nun, dass der Zeiger _ bei jeder Ausgabe mit dem Oktalwert 073 XOR-verknüpft wird. Wenn wir dies auf die gesamte Zeichenfolge anwenden, erhalten wir:

cCorsixcxCorsicixCorscsixCorcrsixCocorsixCcCorsixc

Dies ähnelt allmählich der Ausgabe, die wir zuvor gesehen haben. Fahren wir fort, indem wir einige der interessanteren Zeilen analysieren:

for(l+=7; l != putchar(010); ++l); // 010 = 8 -> backspace char

Der Sinn dieser Zeile ist es, eine Reihe von Leerzeichen auszugeben. Wenn l gleich 1 ist, wird nur ein Backspace ausgegeben. Wenn es aber gleich etwas anderem ist, wird es durchdrehen und eine ganze Ladung von Zeichen ausgeben. Das Verhalten hängt davon ab, wie main aufgerufen wird. Beim Start scheint es immer mit dem Wert 1 aufgerufen zu werden (ich weiß nicht, warum).

Schauen wir uns nun die Komponenten des rekursiven Hauptaufrufs an.

( putchar(*_ ^ 073) | putchar(33) ) & 1 : // 33 = '!'

Dies ist die erste mögliche Verzweigung. Zuerst wird eines der XOR-verknüpften Zeichen und dann ein '!'-Zeichen ausgegeben. Wenn Sie sich das Bitmuster von 33 ansehen, werden Sie feststellen, dass (x | 33) & 1 immer zu 1 ausgewertet wird. In diesem Fall geben wir also nur ein einziges Backspace-Zeichen in der for-Schleife aus.

Die zweite Verzweigung hingegen ist ein wenig kniffliger, weil der an main übergebene Wert nicht 1 ist. Wenn Sie sich die Ausgabe des Programms genau ansehen, werden Sie feststellen, dass es an einer bestimmten Stelle in der Zeichenkette eine ganze Reihe von Leerzeichen ausgibt. Ohne Kontext kann ich nicht wirklich sagen, was das Ziel ist.

Nun, da wir alle Teile haben, können wir den Code neu schreiben:

#include <stdio.h>

#define BIG_CONSTANT 42 // Not the actual value.

int main () {
    char* str = "cCorsixcxCorsicixCorscsixCorcrsixCocorsixCcCorsixc";

    putchar(8);

    char* c = str;
    while (*c != '\0') {

        if (*c != 'c') { // 'X' ^ 073 = 'c'
            putchar(*c);
            putchar('!');
            putchar(8);
        }
        else {
            for (int i = 0; i < BIG_CONSTANT; ++i)
                putchar(8);
        }
        c++;
    }
}

Mein C ist ein wenig eingerostet, so dass dies möglicherweise nicht kompilieren/ausführen. Es sollte immer noch geben Sie eine gute Vorstellung davon, was los ist.

EDIT: Nun, ich war ein wenig spät dran, meine Antwort zu posten, und ich habe gerade festgestellt, dass meine Konsole die Leerzeichen ein wenig zu wörtlich ausgibt, anstatt einfach nur Zeichen zu entfernen. Das ist der Grund, warum ich die Ausgabe etwas falsch interpretiert habe. Also wie die akzeptierte Antwort sagt, wenn Sie tatsächlich die Backspaces richtig verarbeiten, druckt es Corsix!.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X