{"id":46,"date":"2010-07-09T18:00:54","date_gmt":"2010-07-09T16:00:54","guid":{"rendered":"http:\/\/www.anginf.de\/?p=46"},"modified":"2014-07-10T17:15:46","modified_gmt":"2014-07-10T15:15:46","slug":"signature-programme","status":"publish","type":"post","link":"https:\/\/www.anginf.de\/?p=46","title":{"rendered":"Signature-Programme"},"content":{"rendered":"<p>Eine Signatur im Usenet soll maximal 4 Zeilen lang und je Zeile maximal 80 Zeichen umfassen. Statt aber nur langweilig seinen Namen\/Anschrift\/Adresse zu nennen, kann man diesen Platz auch dazu nutzen, um mehr oder weniger sinnfreie Programme dort zu hinterlegen.<\/p>\n<p>Klassischer Weise wurden die meisten Signatur-Programme in der Programmiersprache C geschrieben, da diese f\u00fcr viele der sonst nur (platz)aufwendig beschreibbaren Strukturen auch k\u00fcrzere Varianten m\u00f6glich waren. Wer zudem noch auf die korrekten Reihenfolge der Interpretierung achtet, kann hier enorm viel Quellcode-Speicherplatz sparen.<\/p>\n<p>Durch das Ausreizen der F\u00e4higkeiten der Programmiersprache werden solche Programme auch h\u00e4ufig recht schwierig zu lesen oder zu verstehen, man bezeichnet solche Programme als Obfuscated.<\/p>\n<p>Im laufe der Zeit habe ich haupts\u00e4chlich zwei Signature-Programs genutzt, beide sind in C geschrieben und zumindest auf einer Unix\/Linux-Konsole mit einem GNU C-Compiler (gcc) compilierbar und anschliessend ausf\u00fchrbar.<\/p>\n<p>Einfache verschleierte Ausgabe einer URL<\/p>\n<pre lang=\"c\">main(a,b){char*c=\"ji3yijyxwjlfr44?uyymm\";for(;a++<21;)putchar(c[21-a]-5);}<\/pre>\n<p>Zugegeben, das war nicht unbedingt ein sehr schwieriges Programm, aber es verschleierte zumindest ein wenig seine Herkunft. Sicherlich sieht man sofort, dass dies eindeutig das \u00e4ltere Programm ist. :)<br \/>\nVertikaler geschwungener Scroller der Initialien<\/p>\n<pre lang=\"c\">main(a,b){int c=0,d=0,e[10]={70,137,145,98,0,255,4,8,4,255};for(;++d;c=0){puts\r\n(\"\\e[2J\");while(c<10){for(b=a=abs((c+++d)%16-8)+1;--a>1\/(10-b)-1\/b;)putchar(32)\r\n;for(a=8;a>0;putchar((e[c-1]>>--a&1)*3+32));puts(\"\");}usleep(34567);}}<\/pre>\n<p>Wie man sieht konnte ich mich auch mit drei Zeilen begn\u00fcgen. Es gibt auch noch Stellen im Programm, welche weiter optimierbar w\u00e4ren, aber da ich sowieso nicht mehr soviel im Usenet aktiv bin, fehlt mir auch der Reiz.<\/p>\n<p>Da ich \u00f6fters darauf angesprochen wurde, erkl\u00e4re ich gerne die Funktionsweise en detail. Etwas klarer wird das Programm, wenn man es zun\u00e4chst einmal formatiert darstellt. Ich habe bereits f\u00fcr die einzelnen Bl\u00f6cke ein grobe Erkl\u00e4rung als Kommentar hinzugef\u00fcgt:<\/p>\n<pre lang=\"c\">main(a,b)\r\n{\r\n  \/* Declaration of variables and data structure (the Initials) *\/\r\n  int c=0,d=0,e[10]={70,137,145,98,0,255,4,8,4,255};\r\n  \/* Endless for, initializes c to 0 and increases \"d\" everytime *\/\r\n  for(;++d;c=0)\r\n  {\r\n    \/* Clear screen *\/\r\n    puts(\"\\e[2J\");\r\n    \/* Ten lines to show (according to 10 data items in e[] *\/\r\n    while(c<10) {   \/* How many spaces are needed in front of each data item *\/\r\n      for(b=a=abs((c+++d)%16-8)+1;--a>1\/(10-b)-1\/b;)\r\n        putchar(32);\r\n      \/* Print the field according to the data with stars or spaces *\/\r\n      for(a=8;a>0;putchar((e[c-1]>>--a&1)*3+32));\r\n      \/* Newline *\/\r\n      puts(\"\");\r\n    }\r\n  usleep(34567);\r\n  }\r\n}<\/pre>\n<p>Das besondere liegt offensichtlich in den for()-Schleifen, daher ist es sinnvoll, sich diese noch einmal etwas genauer zu betrachten. Eine for()-Schleife besteht aus drei Teilen, der Initialisierung, der Abbruchbedingung und der Schrittweite. Das besondere ist, dass jeder dieser Teile auch ganz \"regul\u00e4ren\" Code ausf\u00fchren kann. Die Initialisierung wird nur einmalig ausgef\u00fchrt, die Bedingung und die Schrittweite bei jedem Durchlauf. Hier also zun\u00e4chst die erste Schleife:<\/p>\n<pre lang=\"c\">\r\nfor(\r\n  b=a=abs((c+++d)%16-8)+1;\r\n  --a>1\/(10-b)-1\/b;\r\n)<\/pre>\n<p>Initial werden b und a auf das Ergebnis aus<\/p>\n<pre lang=\"c\">abs((c+++d)%16-8)+1<\/pre>\n<p>gesetzt. c gibt dabei die aktuelle Zeile wieder, d ver\u00e4ndert sich erst nach jedem vollst\u00e4ndigen Bild, wird also erst nach dem n\u00e4chsten \"Clear screen\" wieder ver\u00e4ndert. Die Teilanweisung<\/p>\n<pre lang=\"c\">c+++d<\/pre>\n<p>erh\u00f6ht dabei erst das c und f\u00fchrt anschliessend die Addition aus. Die l\u00e4ngere Schreibweise daf\u00fcr w\u00e4re:<\/p>\n<pre lang=\"c\">c = c + 1;\r\nc + d;<\/pre>\n<p>Der R\u00fcckgabewert dieser Funktion wird nun modulo 16 gerechnet, somit erhalten wir einen Wert zwischen 0 und 15. Durch das Abziehen der 8 (ergibt -8 bis 7) und das anschliessende Verwenden der Funktion<\/p>\n<pre lang=\"c\">abs()<\/pre>\n<p>erh\u00e4lt man einen Wert zwischen 0 und 8, das +1 verschiebt das wieder auf den Bereich 1 und 9.<\/p>\n<p>Durch die Initialisierung haben nun beide Variablen denselben Wert zwischen 1 und 8. Der Bedingungsteil wird leichter verst\u00e4ndlich, wenn man sich die Formel einfach etwas getrennter anschaut:<\/p>\n<pre lang=\"c\">--a > 1\/(10-b) - 1\/b<\/pre>\n<p>Die Pr\u00fcfung lautet also: \"Ist (das zuvor verkleinerte) a noch gr\u00f6sser als die Subtraktion der Br\u00fcche? Wenn ja, dann noch eine Schleife durchlaufen. Da in dem \"Schrittweite\"-Bereich die Variable a immer um eins reduziert wird, ist diese Bedingung irgendwann nicht mehr korrekt. Das ganze dient einfach dazu, die hohen und die kleinen Werte von a ein wenig zu d\u00e4mpfen. Nimmt b die Werte 1 oder 2 an, wird die Schleife immer zweimal durchlaufen, bei b=8 oder b=9 immer achtmal. Auf diese Weise sieht die Animation etwas \"fl\u00fcssiger\" aus, da es mehr an die Sinus-Kurve erinnert, ohne dass ein Sinus gerechnet werden muss.<\/p>\n<p>Bei jedem Durchlauf dieser Schleife wird ein Leerzeichen ausgegeben.<\/p>\n<p>Die zweite for()-Schleife hat Ihren besondern Reiz in dem \"Schrittweite\"-Part:<\/p>\n<pre lang=\"c\">for(\r\n  a=8;\r\n  a>0;\r\n  putchar((e[c-1]>>--a&1)*3+32)\r\n);<\/pre>\n<p>Die Schleife soll offensichtlich achtmal durchlaufen werden, normalerweise w\u00fcrde man einfach ein a-- als Schrittweite-Part nehmen. Durch das Voranstellen der Minuszeichen vor dem a wird das dekrementieren bereits vor der Auswertung durchgef\u00fchrt.<\/p>\n<p>Der Teil<\/p>\n<pre lang=\"c\">e[c-1]<\/pre>\n<p>greift banal auf das Datenfeld zu, welches f\u00fcr die cte Zeile zust\u00e4ndig ist. Das -1 wird gebraucht, weil bei Arrays in c das erste Element mit 0 indexiert wird.<\/p>\n<p>Der ausgelesene Werte aus dem Array wird nun mittels &gt;&gt; geshiftet. Der Wert in dem Datenfeld ist ein Wert zwischen 0 und 255, l\u00e4sst sich also in 8 Bit darstellen. Der erste Wert \"70\" wird in der Bin\u00e4rschreibweise zu: 01000110. Wir verschieben (\"shiften\") nun diesen Bitvektor um a-1 nach \"rechts\". a durchl\u00e4uft in unserer Schleife die Werte 8 bis 1, also shiften wir zun\u00e4chst um 7:<\/p>\n<p>Shifting bei a=7 und Bitvektor 01000110:<\/p>\n<pre>01000110 (0)\r\nx0100011 (1)\r\nxx010001 (2)\r\nxxx01000 (3)\r\nxxxx0100 (4)\r\nxxxxx010 (5)\r\nxxxxxx01 (6)\r\nxxxxxxx0 (7)<\/pre>\n<p>Von links wird tats\u00e4chlich immer eine \"0\" nachgeschoben, durch das \"x\" versuche ich nur zu verdeutlichen, dass man sich einfach nur das h\u00f6chste Bit geholt hat. Es ist eine 0. Der Rest des Schrittweite-Parts wertet nun diesen gewonnenen Wert aus:<\/p>\n<pre lang=\"c\">(0 & 1) * 3 + 32<\/pre>\n<p>0 UND 1 (als Bitvergleich gesehen) ergibt \"Falsch\", also eine 0.<br \/>\n0 multipliziert mit 3 ergibt 0, plus 32 eine 32.<br \/>\nUnd diese 32 wird nun als putchar(32); ausgegeben - ein Leerzeichen.<\/p>\n<p>Bei a=6 resultiert aus dem Bitvektor 01000110 allerdings:<\/p>\n<pre>xxxxxx01<\/pre>\n<p>01 UND 1 ergibt ein \"Wahr\", also eine 1. (Wir pr\u00fcfen mit diesem Bitvergleich offensichtlich nur den kleinsten Bitteil)<br \/>\n1 multipliziert mit 3 ergibt 3, plus 32 eine 35.<br \/>\nputchar(35) liefert - richtig - das Zeichen \"#\".<\/p>\n<p>Die zweite for()-Schleife hat keinen Ausf\u00fchrungsteil und durchl\u00e4uft sich daher einfach nur selbst. (Sie hat ja auch schon genug zu tun...)<\/p>\n<p>Insgesamt kann man also sehen, dass dieses kleine Programm die eine oder andere Programmierkenntnis schon erfordert:<\/p>\n<ul>\n<li>Steuerzeichencodes der Shell: puts(\"\\e[2J\");<\/li>\n<li>Relevanz der Reihenfolge von Evaluierung und Berechnung (a-- und --a)<\/li>\n<li>Shifting von Werten<\/li>\n<li>Priorit\u00e4ten von Anweisung, zur Vermeidung von unn\u00f6tigen Klammern: c+++d<\/li>\n<li>Lustige \"Simulation\" komplexer mathematischer Funktionen wie sin()<\/li>\n<\/ul>\n<p>Da man in einem C-long 32 Bit speichern kann, l\u00e4sst sich das Programm mit ein paar kleinen Modifikationen auch dazu nutzen, z.B. meinen Vornamen in horizontaler Schreibweise darzustellen. Allerdings ist es dann nicht mehr so kompakt. \ud83d\ude42<\/p>\n<pre lang=\"c\">main(a){long long b,c,d=0,f;char*e[9]={\"QINgW1\",\"AU@4A2\",\"9U@412\",\"9mL611\",\"9UH\"\r\n\"6Q0\",\"9U@4A0\",\"5U@4A2\",\"3U@7Q1\"};for(;++d;c=0){puts(\"\\e[2J\");for(;c<8;f=1){for\r\n(a=b=0;a<7;f*=64)b+=(e[c][a++]-48)*f;for(a=(a=abs((c+++d)%16-8))-(a>>3);a>1;\r\nprintf(\" \",a--));for(a=64;a>0;putchar((b>>--a\/2&1)*3+32));puts(\"\");}usleep(34567);}}<\/pre>\n<p>Mithilfe von atoi(), also des Wandeln von \"ASCII-Zeichen zu Integer\" kann man noch eine deutlich kompaktere Darstellungsform finden, auch f\u00fcr das urspr\u00fcngliche Programm - allerdings muss man dann pr\u00fcfen, ob durch die zus\u00e4tzliche Verwendung von atoi() und die evtl. notwendigen zus\u00e4tzlichen Rechenoperationen zuviel Byte verschwendet werden und entsprechend die \"Optimierung\" zu einer Deoptimierung wird... \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Eine Signatur im Usenet soll maximal 4 Zeilen lang und je Zeile maximal 80 Zeichen umfassen. Statt aber nur langweilig seinen Namen\/Anschrift\/Adresse zu nennen, kann man diesen Platz auch dazu nutzen, um mehr oder weniger sinnfreie Programme dort zu hinterlegen. Klassischer Weise wurden die meisten Signatur-Programme in der Programmiersprache C geschrieben, da diese f\u00fcr viele &hellip; <a href=\"https:\/\/www.anginf.de\/?p=46\" class=\"more-link\"><span class=\"screen-reader-text\">Signature-Programme<\/span> weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-46","post","type-post","status-publish","format-standard","hentry","category-allgemein"],"_links":{"self":[{"href":"https:\/\/www.anginf.de\/index.php?rest_route=\/wp\/v2\/posts\/46","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.anginf.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.anginf.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.anginf.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.anginf.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=46"}],"version-history":[{"count":10,"href":"https:\/\/www.anginf.de\/index.php?rest_route=\/wp\/v2\/posts\/46\/revisions"}],"predecessor-version":[{"id":60,"href":"https:\/\/www.anginf.de\/index.php?rest_route=\/wp\/v2\/posts\/46\/revisions\/60"}],"wp:attachment":[{"href":"https:\/\/www.anginf.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=46"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.anginf.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=46"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.anginf.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=46"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}