images/logo.png
SHWB na blogspot  | Uživatel: Nepřihlášen

O programování 11 - Minimalistické programy a Java

V tomto díle se pokusím zodpovědět otázku, zda lze v Javě napsat minimalistický program podobně jako v Perlu nebo Céčku. Je to spíše nevážně míněná úvaha, protože kód, ke kterému jsem nakonec došel, bych v reálném programu opravdu nechtěl použít.

Nejdříve musím vysvětlit, co myslím minimalistickým programem. V některých jazycích lze psát tak hutný kód, že je až na hranici srozumitelnosti. Dokonce se pořádají soutěže v "nečitelnosti" programů, kritéria jsou různá, třeba velikost zdrojového kódu, kdy jde o stovky bajtů maximálně jednotky kilobajtů. Nebo musí být program co nejméně čitelný, což je subjektivní kritérium, případně různě formátovaný, zde by se dalo mluvit o "kubistickém" programu. Kubistický program je analogií kubistické básně, pro niž není podle wikipedie rozhodující význam ani melodičnost, ale obraz; proto jsou básně kubistů netradiční z hlediska svého tvaru (často tvořily z písmen obrazce, které byly ve vztahu k dané básni). Kubistický přístup lze použít ve většině programovacích jazyků, snad kromě Pythonu, protože ten má mezery jako řídící znaky. Důležitým kritériem všech těchto soutěží je totiž to, že daný program je syntakticky správně a je nejen spustitelný, ale i něco dělá :)

A ještě bych chtěl poznamenat, že vše výše uvedené se týká standardních programovacích jazyků, nikoli tzv. esoterických programovacích jazyků typu brainfuck nebo whitespace, které jsou nečitelné záměrně, by design.

Perl

Abych vysvětlil, co mám vlastně na mysli, když mluvím o minimalistickém programu, tak uvedu pár (komentovaných) odkazů a začneme Perlem, nekorunovaným králem tohoto typu programování. Odkážu na čtvrtý ročník soutěže v obfuskaci. Moje znalosti Perlu nejsou bohužel takové, abych tyto programy analyzoval, ale vím, že Perl nepotřebuje moc syntaktického cukru a má (syntaktické) zkratky přímo pro práci se zásobníkem a argumenty, i když se tomu v Perlu myslím říká jinak. A když k tomu přidám regulární výrazy, tak je možné psát pěkně nečitelný a kryptický kód.

5. ročníku mě zaujalo to, že programy mají jen pár set bytů. Nevěřil bych, že to jde ve vyšším programovacím jazyku bez samogenerujícího se kódu (obvyklý trik v assembleru, kde není rozdíl mezi daty a instrukcemi). Vrátím se ještě ke "kubistickým" programům, kde bych mluvil i o estetické hodnotě zdrojového kódu. Poslední odkaz přináší opravdu jen změť znaků a docela by mě zajímalo, jak takový program vzniká. Zda ho někdo opravdu dá takhle přímo z hlavy nebo napíše nejdříve čitelný program a pak použije textové náhrady a znečitelňující refactoring. Myslím si, že je potřeba i určitý tvůrčí přístup a o tom, že to jde jsem se sám přesvědčil, když jsem vymýšlel, jak zesložitit zápas programu, viz závěr článku.

C a další jazyky

Po Perlu se podíváme i na Céčko, kde existuje The International Obfuscated C Code Contest. Zde naleznete programy různého charakteru, od změti znaků přes různě zmatenou logiku až po kubistické programy. Pro tyto programy je charakteristické časté používání define. Další informace o této soutěži naleznete na wikipedii nebo v článku s příznačným jménem What is the most obfuscated C code you have ever seen - fakt pěkný.

Obfuskovat se dá i PL/SQL ale pokud si pamatuji dobře, tak databázový server od Oracle má přímou podporu pro obfuskaci, protože PL/SQL je ve skutečnosti interpretovaný byte code. Proto neměl Oracle až takový problém přidat podporu Javy do svého databázového serveru, prostě k jednomu interpretu přidali druhý. Zřejmě udělali PL/SQL interpret pro JVM nebo naopak, detaily jsem nezkoumal a ono se to neujalo tolik, jak čekali, byť potenciál byl velký. Každopádně bych chtěl rozlišovat mezi obfuskací a (záměrně) nečitelným zápisem programu.

Příkladů, jak znečitelnit "Hello world" v různých jazycích, je na stackowerflow dost a dost, např. zdezde. V těch příkladech se dá načerpat pár zajímavých triků a postupů, tohle je opravdové a kreativní programování a ne lepení prezentační logiky z existujících frameworků a příkladů na stackoverflow, což bohužel dělá většina "programátorů" osmdesát procent svého času. A zbylých dvacet procent času pijí kafe :)

Sice bych takový kód bych v projektu nechtěl, ale programátora, který ho umí napsat asi ano...

Java

Tolik úvodem, mě však zajímalo, jak na podobné věci v Javě. Když pominu ostrajavu, tak jsem toho moc nenašel. Ono to bude zřejmě tím, že výše uvedené programy se píší dobře v jazyku, kde jsou makra a kde je možné napsat jednoduchý program úsporně. Jenže v Javě vypadá nejmenší program, který vůbec nic nedělá, ale aspoň se spustí, zhruba takto:



public class Empty {public static void main(String[] args) {}}

V céčku je to podobné ale tam jsem schopen to přes #define změnit a předefinovat, kdežto v Javě s tím podle mě nic nedělám.

Ale i Javě lze napsat konstrukce typu:



x+=x+++x++<<2>>+x+++x++;

nebo ternární operátor v podobě:



(1<2)?(3<4):(5<6) (0<0)?(0<0):(0<0)

Což jsou ale jen takové hrátky a připadá mi, že v silně typovém jazyce, bez maker a hash polí se nečitelný kód píše špatně - on to byl vlastně záměr a cíl návrhu Javy. Samozřejmě, že jde i v Javě prasit kód, ale ... vidím zde určitý principiální rozdíl.

Ovšem i tak jsem v Javě schopen napsat následující fragment kódu, který vypíše znaky URC.



x=2<<5; System.out.printf("%c%c%c\n",(char)(x+(x>>2)+(x>>4)+(x>>6)),(char)(x+(x>>2)+(x>>5)),(char)(++x+(x>>5)));

Když si s tímto kódem trochu pohraju, získám:



int a=0; int b=a+++a+++a+++a; int c=--a<<--b; System.out.printf("%c%c%c\n",(char)((c+(c>>2)+(c>>4)+(c>>6))),(char)((c+(c>>2)+(c>>5))),(char)(++c+(c>>5)));

Proměnné můžu přejmenovat na O, l (využívám vizuální podobnosti O s 0 a l s 1) a i pouhé podtržítko je validní název proměnné. Takže můžu napsat následující program:



public class Test { public static void main(String[] args) { int O=0;int l=O+++O+++O+++O;int _=--O<<--l; System.out.printf("%c%c%c\n",(char)((_+(_>>2)+(_>>4)+(_>>6))),(char)((_+(_>>2)+(_>>5))),(char)(++_+(_>>5))); } }

Ovšem nejen podtržítko je validní název proměnné, dokonce i dvě a tři podtržítka jsou korektní, takže můžu napsat:



public class Test { public static void main(String[] args) { int _=0;int __=_+++_+++_+++_;int ___=--_<<--__; System.out.printf("%c%c%c\n",(char)((___+(___>>2)+(___>>4)+(___>>6))),(char)((___+(___>>2)+(___>>5))),(char)(++___+(___>>5))); } }

Také dolar je validní název proměnné v Javě, takže další varianta je:



public class Test { public static void main(String[] args) { int O=0;int l=O+++O+++O+++O;int $=--O<<--l; System.out.printf("%c%c%c\n",(char)(($+($>>2)+($>>4)+($>>6))),(char)(($+($>>2)+($>>5))),(char)(++$+($>>5))); } }

Lze si pohrát i s aritmetikou počítání ASCII hodnoty:



public class Test { public static void main(String[] args) { int O=0;int l=O+++O+++O+++O;int $=--O<<--l; System.out.printf("%c%c%c\n",(char)(($+($>>l/2)+($>>--l)+($>>++l)-1)),(char)(($+($>>l/2)+($>>l))),(char)(++$+($>>l))); } }

A samozřejmě se můžu zbavit přetypování na char, byť za cenu warningů:



public class Test { public static void main(String[] args) { int O=0;int l=O+++O+++O+++O;int $=--O<<--l; System.out.printf("%c%c%c\n",$+($>>l/2)+($>>--l)+($>>++l)-1,$+($>>l/2)+($>>l),++$+($>>l)); } }

V jazyku bez silné typové kontroly bych mohl použít i následující konstrukce: int a=false, resp. int O = (0<0)?(0<0):(0<0);

Ale stejně je to pořád jen hraní si s obskurními názvy proměnných a obskurním zápisem čísla pomocí mocnin dvou. Důležité je si uvědomit, co dělá ++aa++ a že ten řetězec plusů po zformátování vypadá takto: int b = a++ + a++ + a++ + a;

Myslím si, že klíčových slov a knihovních funkcí typu System.out se už jednoduše nezbavím, takže bych jen těžko napsal obskurní řídící sekvenci, i když jsem slyšel o ternárním operátoru vnořeném do ternárního operátoru a to dohromady asi dvacetkrát, a to bohužel v reálném C# kódu. Každopádně tohle si nechám na případné pokračování...

PS: Hraním si se zde uvedeným kódem jsem strávil tak dvě hodiny, proto věřím, že by šlo vymyslet něco mnohem zajímavějšího...

08.04.2017
Přidat názor:
Vyhrazuji si právo libovolný komentář smazat bez udání důvodu. Kritika mi nevadí, ale chci omezit anonymní výkřiky, které nemají s tématem nic společného.
V textu je možné používat HTML tagy a tuto zjednodušenou MarkDown syntaxi
Jméno
Text
Postřehy:
31.07.2019: Arduino 01 - Motivace k elektrotechnice
To jsem se jednou, nechci říct nudil, ale zkrátka jsem narazil na knihy "Porty, bajty, osmibity" a "Hradla, volty, jednočipy" od Martina Malého z produkce sdružení NIC.CZ, které jsou volně dostupné na knihy.nic.cz.
extravaganza.controverso@seznam.cz: Zdravím, krásný a informacemi nabitý blog. Musím pochválit. Plánuji rozjet undergroundový zin, co by se týkal black matalu, ambientu, satanismu, left hand
Poslední diskuse Postřehy
O programování 06 - Návrhové vzory - síla i slabina Javy
P.S. samozrejme "Context" mel byt "Client" .. To jsem jen narazil na nejak divne pojmenovany diagram.. (Context je samozrejme trosku neco jineho...)
...
David | 25.02.2017
O programování 06 - Návrhové vzory - síla i slabina Javy
To k cemu jsi dosel (tedy implementace LooperRunner + ILoopMethod), tak je ta prava Strategy by GoF :) To co je tam dulezite je ze Context (LooperRunner) je oddeleny od Strategy (ILoopMethod),
...
David | 25.02.2017
O programování 03 - Přehlednost funkcionálního zápisu v Java 8
Máš pravdu, to map je tam zbytečné. Odněkud jsem to opsal a nezkontroloval. Tím ovšem trochu padá pointa celého článku.
...
Saha | 14.12.2016
O programování 03 - Přehlednost funkcionálního zápisu v Java 8
Jen takova otazka k tomu druhemu prikladu:
Proc tam tu cast s "map" ktera de facto s prvky toho streamu nic nedela? Nestacilo by
list.stream().reduce(0, Integer::sum);
?
Ja teda moc
...
David P. | 13.12.2016
Paleo na půl - 01 - První tři dny bez mléka
Kvalitní hořké čokolády jsou bez mléka.. :) (a to i ty méně "kvalitní"). Mléko bývá součástí jen těch "sladkých".
...
David | 04.05.2015
Statistiky
Aktualizováno: 21.08.2019
Počet článků/fotek: 1374/13795
(C) Saha - 1990 - 2019 - Verze 1.3.32 - 11.05.2019 - Generated by SHREC 2.214
Veškeré zde uvedené materiály vyjadřují pouze moje soukromé názory (s výjimkou knihy návštěv a diskusí, kam může přispívat kdokoliv), a pokud s nimi někdo nesouhlasí, tak je to jeho problém, nikoliv můj.