Python Obfuscation

Code-Stücke können hier veröffentlicht werden.
Antworten
MrVirus
User
Beiträge: 8
Registriert: Samstag 25. Februar 2012, 12:31

Hallo zusammen!

Ich habe mal aus Spaß für einen Freund ein Programm geschrieben, dessen Sinn möglichst schwer zuerraten sein soll. Falls sich hier jemand für sowas interessiert würde ich mich über eine "Bewertung" sehr freuen.

Code: Alles auswählen

_="O!n4int()effX!t[ i] A.ea+chr(i)%(i<<2)n*yd(u)e[]LoexecPdef i()"
_1=(chr(35)+"b=raw_input()[::-1]\n#exec _[24:37]\n")
exec"]:[)])(s%,'46'[,tni(pam=b,a"[::-1]%'0tXuzp3nMi[_1w]a?r'[::-int(_[36])]
exec[_,(_1+"%s=[1,a-b];"%_[a%58]+"x=ord;t+=t[-1]+t[-2],;"*(a-44))][bool(_1)]
r=[(i%61)for i in t]
t=r.remove(x(_[25])-80)if(x(";")%((2<<4)+8))in(r,[0x73],_1)[bool(a)-1]else None
print _[1:0].join([_[cmd]for cmd in r])[::-1]
print "Hello, World!"
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

Gibt es da überhaupt einen Sinn?

Edit: Ich fand das nicht so schwer, in normales Python umzuwandeln … Immerhin gibt es den interaktiven Interpreter. ;)
Mein größter Fehler war, dass ich beim Editieren aus Versehen in „_“ ein „s“ hinzugefügt habe …

Edit #2: Ah … Hab jetzt den Sinn verstanden. :P
Zuletzt geändert von nomnom am Samstag 25. Februar 2012, 13:46, insgesamt 1-mal geändert.
MrVirus
User
Beiträge: 8
Registriert: Samstag 25. Februar 2012, 12:31

Ja es gibt ne bestimmte Menge von Eingabewerten, die eine richtige Ausgabe liefern (das erkennt man dann an der Ausgabe). Hast du denn auch raus, WAS das Programm genau macht?
print "Hello, World!"
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

MrVirus hat geschrieben:Ja es gibt ne bestimmte Menge von Eingabewerten, die eine richtige Ausgabe liefern (das erkennt man dann an der Ausgabe).
Nämlich unendlich? ;)
MrVirus hat geschrieben:Hast du denn auch raus, WAS das Programm genau macht?
Ja, hab es jetzt verstanden.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

OK, I'll bite.

Die ersten zwei Zeilen weisen einfach den Variablen "_" und "_1" zwei Strings zu.

Die dritte Zeile führt den String "a,b=map(int,['64',%s()])[:]" aus, wobei -- verdammt -- das %s durch 'raw_input' ersetzt wird. Da musste ich doch im ersten String 36 Zeichen abzählen. Also "a,b=map(int,['64',raw_input()])[:]". Also a=64 und b= was immer der Benutzer auch eingibt.

OBdA sage ich mal "Hallo". Wahrscheinlich soll man eine Zahl eingeben, aber den Gefallen tue ich euch nicht. Also stürzt das Programm hier ab. Na, gut, ich gebe mal gedanklich eine 1 ein.

Die vierte Zeile führt jetzt -- arg, das ist unübersichtlich -- 64 module 58 ist 6, da steht ein t, also "t=[1,a-b];" aus. In _1 stehen davor nur zwei Kommentare, die sind egal. Außerdem ist x die ord-Funktion (was egal zu sein scheint) und zu t wird dann ein 1-Tupel mit der Summe der beiden letzten Zahlen aus t addiert.Da a 64 ist, wird das 20 mal gemacht. Es beginnt also mit t=[1,63] und geht dann weiter mit 64, 127, usw.

Das habe ich mir doch mal ausrechnen lassen: [1, 63, 64, 127, 191, 318, 509, 827, 1336, 2163, 3499, 5662, 9161, 14823, 23984, 38807, 62791, 101598, 164389, 265987, 430376, 696363]

Nun wird in der fünften Zeile jeder Wert aus t module 61 genommen - warum auch immer. Damit gilt r=[1, 2, 3, 5, 8, 13, 21, 34, 55, 28, 22, 50, 11, 0, 11, 11, 22, 33, 55, 27, 21, 48]. Hier kann man übrigens die runden Klammern weglassen. Das spart zwei Zeichen.

In der sechsen Zeile wird ein Wert aus t entfernt, falls der komplizierte Ausdruck wahr ist oder t=None gesetzt. "bool(a)-1" ist kompliziert für 0. Also wird in r gesucht. 2<<4 ist 16, plus 8 ist 40, also ord(';') oder 59 modulo 40, also 19. Das sehe ich so, das der Wert nicht in r ist. Damit ist t=None. Die ganze Zeile hätte man weglassen können, denn t wird danach nicht mehr benutzt. Wie dumm von mir, die dennoch zu entschlüsseln.

Zeile 7 ist wieder einfach. [1:0] gibt immer den leeren String, also werden die durch r indizierten Zeichen aus _ zu einem String, dieser wird umgedreht und ausgegeben. Das könnte ich jetzt abzählen, doch wo ich schon "r" in der Konsole habe...

L.rdieffOfee(d<.!)n4n!'

Hm, wenig beeindruckend.

Soll man jetzt das richtige "b" raten?

Stefan
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

sma hat geschrieben:2<<4 ist 16, plus 8 ist 40, also ord(';') oder 59 modulo 40, also 19.
Korrektur: 2 << 4 ist 32. ;)
sma hat geschrieben:Soll man jetzt das richtige "b" raten?
Ja, ich denke schon. Bei einem bestimmten „b“ ≤ 61 kommt da ein sinnvoller String raus …
MrVirus
User
Beiträge: 8
Registriert: Samstag 25. Februar 2012, 12:31

@sma: Schön, dass es dir Spaß gemacht hat. Naja, raten soll derjenige für den es gedacht ist nicht, es gibt einen kleinen Hinweis, der sich aus einer älteren Geschichte zwischen mir und meine Kollegen ergibt. Wichtiger ist zu verstehen, WARUM das Programm ausgibt, was es ausgibt, was also die verschiedenen Werte, die wärend der Programmausführung auftauchen, für eine Bestimmung haben. Das hast du bist jetzt noch nicht geschrieben. Alle berechneten Werte haben auch einen bestimmten Sinn. Dass der dabei genutzte Weg der leichteste ist sage ich nicht ;)

@nomnom: Du hast die korrekte Eingabe anscheinend herausgefunden :) Danke für's Testen.

Mal allgemein, macht euch sowas Spaß oder nervt es eher?
print "Hello, World!"
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

MrVirus hat geschrieben:Mal allgemein, macht euch sowas Spaß oder nervt es eher?
Ich finde Code-Golf wesentlich beeindruckender. Außer natürlich wenn Code-Obfuscation so elegant daherkommt: Pi.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

55

Stefan
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

webspider hat geschrieben:Außer natürlich wenn Code-Obfuscation so elegant daherkommt: Pi.
Nett :) Aber so sehr wird da doch nicht obfuscated. :P

Edit: Nett ist auch, dass das Programm beim Kompilieren mit clang 207 Warnungen ausspuckt …
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

Der Code ist ja auch verhältnismäßig alt.
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

webspider hat geschrieben:Der Code ist ja auch verhältnismäßig alt.
Dass es Kernighan & Ritchie-C ist, ist nicht der ausschlaggebende Punkt: Durch das 202-fach genutzte Makro kommen 202 Warnungen zustande, weil das Ergebnis nie benutzt wird: Das hat also nichts mit dem Standard zu tun.
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

Deobfuscated:

Code: Alles auswählen

# include <stdio.h>

int main(void) {
    long F = -202, OO = -16;
    printf("%1.3f\n", 4.*-F/OO/OO);
    return 0;
}
Sieht irgendwie nicht so schön aus, wie die Kugel aus „pi.c“ …

In jeder Zeile, wo das Makro genutzt wird, wird einmal „--F<00 || F-OO--“ und sonst „---F<00 || F-OO--“ eingefügt. Dadurch, dass bei C beim Operator „||“ immer die linke Seite ausgewertet wird, die rechte allerdings nicht, falls die linke schon wahr sein sollte, wird die rechte Seite nur 16 mal (die Kugel geht von Zeile 5 bis Zeile 21) und die linke 202 mal ausgeführt …
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Wer Spaß an sowas hat, könnte auch an http://www.pythonchallenge.com/ Gefallen finden.
MrVirus
User
Beiträge: 8
Registriert: Samstag 25. Februar 2012, 12:31

Das ist interessant...

Hier mal ein neuer (hoffentlich nicht so leicht zu knackender Code):

Code: Alles auswählen

PWD="00--Hier Passwort eingeben--00"
_=[lambda _:_&_1-1]*0x10
_1=0x124c74124c74124cf41b3d61031d6d035d60032c46030d711bdd70032d71027c74
__=lambda _=_[:]:lambda*__:_[15]
_,_0=sum(map(ord,PWD[:-2]*int(PWD[-__()(_1)(1)-1:])*55)),0;i=0;
exec"_0=(_0<<24)+((_1&(0xffffff<<24*(10-i)))>>24*(10-i))^_;i+=1;"*11
_=int(str(hex(_0))[__()(_0)(2>>1)+1:-1]);out=""
exec"_,n=divmod(_,1000);out+=chr(n);"*(len(str(_))/3+1)
print out[::-1] 
Edit: Das "&" in der zweiten Zeile einfach durch ein "&" ersetzen.
print "Hello, World!"
BlackJack

@MrVirus: Das ist nicht lauffähig: ValueError: invalid literal for int() with base 10: '124c74124c74124cf41b3d61031d6d035d60032c46030d711bdd70032d71027c74'

Worauf die dritte Zeile von unten hinausläuft ist so etwas hier:

Code: Alles auswählen

In [208]: hex(255)
Out[208]: '0xff'

In [209]: hex(255)[2:-1]
Out[209]: 'f'

In [210]: int(hex(255)[2:-1])
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)

/home/bj/<ipython console> in <module>()

ValueError: invalid literal for int() with base 10: 'f'
MrVirus
User
Beiträge: 8
Registriert: Samstag 25. Februar 2012, 12:31

@MrVirus: Das ist nicht lauffähig: ValueError: invalid literal for int() with base 10: '124c74124c74124cf41b3d61031d6d035d60032c46030d711bdd70032d71027c74'
Ich weiß :) Funktionieren tut der Code nur mit dem gültigen Passwort
print "Hello, World!"
Antworten