Wie funktioniert dieses C-Programm?
main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1:10);}
Es wird so kompiliert, wie es ist (getestet am gcc 4.6.3
). Es druckt die Zeit beim Kompilieren. Auf meinem System:
!! !!!!!! !! !!!!!! !! !!!!!!
!! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !!
!! !!!!!! !! !! !! !! !! !!!!!!
!! !! !! !! !! !! !!
!! !! !! !! !! !! !!
!! !!!!!! !! !! !! !!!!!!
Quelle: sykes2 - Eine Uhr in einer Zeile , Hinweise des Sykes2-Autors
Einige Hinweise: Standardmäßig keine Kompilierungswarnungen. Zusammen mit -Wall
werden die folgenden Warnungen ausgegeben:
sykes2.c:1:1: warning: return type defaults to ‘int’ [-Wreturn-type]
sykes2.c: In function ‘main’:
sykes2.c:1:14: warning: value computed is not used [-Wunused-value]
sykes2.c:1:1: warning: implicit declaration of function ‘putchar’ [-Wimplicit-function-declaration]
sykes2.c:1:1: warning: suggest parentheses around arithmetic in operand of ‘|’ [-Wparentheses]
sykes2.c:1:1: warning: suggest parentheses around arithmetic in operand of ‘|’ [-Wparentheses]
sykes2.c:1:1: warning: control reaches end of non-void function [-Wreturn-type]
c
obfuscation
deobfuscation
kitschig
quelle
quelle
printf("%d", _);
zum Anfang dermain
Drucke: pastebin.com/HHhXAYdJint
./a.out $(seq 0 447)
Antworten:
Lassen Sie es uns verschleiern.
Einrücken:
Einführung von Variablen, um dieses Durcheinander zu entwirren:
Beachten Sie, dass
-~i == i+1
wegen Zweierkomplement. Deshalb haben wirBeachten Sie nun, dass dies
a[b]
dasselbe ist wieb[a]
, und wenden Sie die-~ == 1+
Änderung erneut an:Konvertieren Sie die Rekursion in eine Schleife und schleichen Sie sich etwas vereinfachter:
Dies gibt ein Zeichen pro Iteration aus. Jedes 64. Zeichen gibt eine neue Zeile aus. Andernfalls werden zwei Datentabellen verwendet, um herauszufinden, was ausgegeben werden soll, und entweder das Zeichen 32 (ein Leerzeichen) oder das Zeichen 33 (a
!
) eingefügt. Die erste Tabelle (">'txiZ^(~z?"
) besteht aus 10 Bitmaps, die das Erscheinungsbild jedes Zeichens beschreiben, und die zweite Tabelle (";;;====~$::199"
) wählt das entsprechende Bit aus der Bitmap aus.Der zweite Tisch
Beginnen wir mit der Untersuchung der zweiten Tabelle
int shift = ";;;====~$::199"[(i*2&8) | (i/64)];
.i/64
ist die Zeilennummer (6 bis 0) undi*2&8
ist 8, wenni
4, 5, 6 oder 7 mod 8 ist.if((i & 2) == 0) shift /= 8; shift = shift % 8
wählt entweder die hohe Oktalstelle (füri%8
= 0,1,4,5) oder die niedrige Oktalstelle (füri%8
= 2,3,6,7) des Tabellenwerts aus. Der Schichttisch sieht am Ende so aus:oder in tabellarischer Form
Beachten Sie, dass der Autor den Null-Terminator für die ersten beiden Tabelleneinträge verwendet hat (hinterhältig!).
Dies ist nach einer Sieben-Segment-Anzeige mit
7
s als Leerzeichen ausgelegt. Die Einträge in der ersten Tabelle müssen also die Segmente definieren, die beleuchtet werden.Der erste Tisch
__TIME__
ist ein spezielles Makro, das vom Präprozessor definiert wird. Es wird in der Form zu einer Zeichenfolgenkonstante erweitert, die den Zeitpunkt enthält, zu dem der Präprozessor ausgeführt wurde"HH:MM:SS"
. Beachten Sie, dass es genau 8 Zeichen enthält. Beachten Sie, dass 0-9 die ASCII-Werte 48 bis 57 und:
den ASCII-Wert 58 haben. Die Ausgabe beträgt 64 Zeichen pro Zeile, sodass 8 Zeichen pro Zeichen von übrig bleiben__TIME__
.7 - i/8%8
ist also der Index, der__TIME__
gerade ausgegeben wird (der7-
wird benötigt, weil wir nachi
unten iterieren ). Sot
ist der Charakter der__TIME__
Ausgabe.a
Abhängig von der Eingabe entspricht dies in Binärform dem Folgendent
:Jede Zahl ist eine Bitmap , die die Segmente beschreibt, die in unserer Sieben-Segment-Anzeige leuchten. Da die Zeichen alle 7-Bit-ASCII sind, wird das High-Bit immer gelöscht. Daher wird
7
in der Segmenttabelle immer als Leerzeichen gedruckt. Die zweite Tabelle sieht so aus, mit dem7
s als Leerzeichen:So zum Beispiel
4
ist01101010
(Bits 1, 3, 5 und 6 gesetzt), die als DruckUm zu zeigen, dass wir den Code wirklich verstehen, passen wir die Ausgabe mit dieser Tabelle ein wenig an:
Dies ist codiert als
"?;;?==? '::799\x07"
. Für künstlerische Zwecke fügen wir einigen Zeichen 64 hinzu (da nur die niedrigen 6 Bits verwendet werden, wirkt sich dies nicht auf die Ausgabe aus). Dies gibt"?{{?}}?gg::799G"
(beachten Sie, dass das 8. Zeichen nicht verwendet wird, so dass wir es tatsächlich machen können, was wir wollen). Fügen Sie unsere neue Tabelle in den Originalcode ein:wir bekommen
genau wie wir erwartet hatten. Es sieht nicht so solide aus wie das Original, was erklärt, warum der Autor die Tabelle verwendet hat, die er gemacht hat.
quelle
*
(Dereferenzierung) als auch eine+
: PFormatieren wir dies zum leichteren Lesen:
Wenn Sie es also ohne Argumente ausführen, ist _ (konventionell argc)
1
.main()
ruft sich rekursiv auf und übergibt das Ergebnis von-(~_)
(negativ bitweise NICHT von_
), so dass es wirklich 448 Rekursionen gibt (nur Bedingung wo_^448 == 0
).Wenn Sie das nehmen, werden 7 64 Zeichen breite Linien gedruckt (die äußere ternäre Bedingung und
448/64 == 7
). Schreiben wir es also etwas sauberer um:Jetzt
32
ist dezimal für den ASCII-Raum. Es wird entweder ein Leerzeichen oder ein '!' (33 ist '!', Daher das '&1
' am Ende). Konzentrieren wir uns auf den Blob in der Mitte:Wie ein anderes Poster sagte,
__TIME__
ist dies die Kompilierungszeit für das Programm und eine Zeichenfolge. Es wird also eine Zeichenfolgenarithmetik durchgeführt und ein bidirektionaler Array-Index wird ausgenutzt: a [b] ist dasselbe wie b [a] für Zeichenarrays.Dadurch wird eines der ersten 8 Zeichen in ausgewählt
__TIME__
. Dies wird dann indiziert[">'txiZ^(~z?"-48]
(0-9 Zeichen sind 48-57 Dezimalstellen). Die Zeichen in dieser Zeichenfolge müssen für ihre ASCII-Werte ausgewählt worden sein. Dieselbe Zeichen-ASCII-Code-Manipulation wird durch den Ausdruck fortgesetzt, um entweder ein '' oder '!' abhängig von der Position innerhalb der Glyphe des Charakters.quelle
Das Hinzufügen zu den anderen Lösungen
-~x
ist gleich,x+1
weil gleich~x
ist(0xffffffff-x)
. Dies entspricht(-1-x)
in 2s Ergänzung, so-~x
ist-(-1-x) = x+1
.quelle
Ich habe die Modulo-Arithmetik so weit wie möglich verschleiert und die Rekursion entfernt
Erweitern Sie es ein bisschen mehr:
quelle