Active Members MrGrj Posted March 29, 2016 Active Members Report Posted March 29, 2016 (edited) Avem urmatoarea bucata de cod scris in C: main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1:10);} Programul poate fi compilat exact asa cum este (testat cu gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)), outputul fiind: [mrgrj@localhost tmp]# vim challangeRST.c [mrgrj@localhost tmp]# gcc challangeRST.c -o challangeRST [mrgrj@localhost tmp]# ./challangeRST !!!!!! !!!!!! !!!!!! !!!!!! !! !!!!!! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !!!!!! !! !!!! !!!! !! !! !!!! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !!!!!! !!!!!! !!!!!! !!!!!! !! !!!! Cum functioneaza programul ? (explicati output-ul) O sa va rog sa folositi buttonul de spoiler in momentul in care dati un raspuns decent. Challange-ul expira vineri la ora 23:59. Solvers: 1. @MasterLight 2. 3. Edited April 3, 2016 by MrGrj 1
Aghast Posted March 29, 2016 Report Posted March 29, 2016 What a clever use of bit-wise operators and bit masks
MasterLight Posted March 31, 2016 Report Posted March 31, 2016 (edited) Spoiler Am sa incep prin a preciza ca nu l-am "disecat" pe cat de mult ar trebui, deci nu pot explica anumite lucruri. 1.Am inceput prin a inlocui "_" folosit ca prim argument in functia main cu numele sau standard "argc". 2.Prima linie este foarte interesanta, ea utilizand recursivitatea pentru a-i modifica valoarea lui argc(care initial primeste valoarea 1) pana la 448, atunci cand acel && este fals si functia atinge un fel de "base case".De asemenea, acesta linie poate fi scrisa cu ajutorul unui loop. 3.Acum, acea expresi din functia putchar am s-o despart in mai multe expresii. exp1 = 32 | (-~7[__TIME__ - (argc / 8) % 8][">'txiZ^(~z?" - 48] >> ";;;====~$::199"[(argc*2 & 8) | argc / 64] / (argc & 2 ? 1:8) % 8 & 1): Rezultatul returnat de aceasta expresie(care foloseste integer division astfel rezultatul fiind trunchiat) este fie 32(fiind valoarea ascii pentru un spatiu " " ) fie 33(ascii: "!"). exp2 = 10, aceasta fiind valoarea ascii pentru un "\n". char result = --argc % 64 ? exp1 : exp2, decide ce caracter trebuie afisat: " ", "!", "\n" Ergo, expresia din putchar va afisa unul dintre caracterele: " ", "\n", "!" in functie de valoarea lui argc. Din pacate, nu am reusit sa-mi dau seama de ce este folosit 448 sau anumite lucruri ca acel bit field. Cateva note pe care le-am facut in timp ce investighat expresia sus numita: // __TIME__-argc/8%8 = __TIME__ will be a number of this form ddddddd and from those digits(because it gets converted) it will be // subtracted the value of (argc / 8)(int division so it gets truncated i.e all decimal points are lost) & 8 // achiving this: for eight values of argc the last digit of __TIME__-argc/8%8 will remain constant, after that it will be // incremented by 1. // [argc*2 & 8| argc / 64] = 4 bits are 0 then the next 4 bits are 8 and so on. // (argc & 2 ? 1:8) % 8 & 1 = (0 for the first two then 1 for the next two and so on. Asta este codul la care am ajuns dupa observatiile pe care le-am mentionat mai sus: #include <stdio.h> int main(void) { for(unsigned int i = 448; i > 0; i--) { // Don't modifiy the loop sentinel, use a temporary variable instead. unsigned int argc = i; // The result of this is either 0 or 1. int exp1 = -~7[__TIME__ - (argc / 8) % 8][">'txiZ^(~z?" - 48] >> ";;;====~$::199"[(argc*2 & 8) | argc / 64] / (argc & 2 ? 1:8) % 8 & 1; // After we | it we get either 32(space) or 33(!). exp1 |= 32; // We reached the end, so put a \n int exp2 = 10; char result = --argc % 64 ? exp1 : exp2; // Finally, put the char on the screen. putchar(result); } return 0; } O zi buna! Edited April 1, 2016 by MasterLight 1
Active Members MrGrj Posted April 2, 2016 Author Active Members Report Posted April 2, 2016 (edited) On 3/31/2016 at 0:28 AM, MasterLight said: Reveal hidden contents Am sa incep prin a preciza ca nu l-am "disecat" pe cat de mult ar trebui, deci nu pot explica anumite lucruri. 1.Am inceput prin a inlocui "_" folosit ca prim argument in functia main cu numele sau standard "argc". 2.Prima linie este foarte interesanta, ea utilizand recursivitatea pentru a-i modifica valoarea lui argc(care initial primeste valoarea 1) pana la 448, atunci cand acel && este fals si functia atinge un fel de "base case".De asemenea, acesta linie poate fi scrisa cu ajutorul unui loop. 3.Acum, acea expresi din functia putchar am s-o despart in mai multe expresii. exp1 = 32 | (-~7[__TIME__ - (argc / 8) % 8][">'txiZ^(~z?" - 48] >> ";;;====~$::199"[(argc*2 & 8) | argc / 64] / (argc & 2 ? 1:8) % 8 & 1): Rezultatul returnat de aceasta expresie(care foloseste integer division astfel rezultatul fiind trunchiat) este fie 32(fiind valoarea ascii pentru un spatiu " " ) fie 33(ascii: "!"). exp2 = 10, aceasta fiind valoarea ascii pentru un "\n". char result = --argc % 64 ? exp1 : exp2, decide ce caracter trebuie afisat: " ", "!", "\n" Ergo, expresia din putchar va afisa unul dintre caracterele: " ", "\n", "!" in functie de valoarea lui argc. Din pacate, nu am reusit sa-mi dau seama de ce este folosit 448 sau anumite lucruri ca acel bit field. Cateva note pe care le-am facut in timp ce investighat expresia sus numita: // __TIME__-argc/8%8 = __TIME__ will be a number of this form ddddddd and from those digits(because it gets converted) it will be // subtracted the value of (argc / 8)(int division so it gets truncated i.e all decimal points are lost) & 8 // achiving this: for eight values of argc the last digit of __TIME__-argc/8%8 will remain constant, after that it will be // incremented by 1. // [argc*2 & 8| argc / 64] = 4 bits are 0 then the next 4 bits are 8 and so on. // (argc & 2 ? 1:8) % 8 & 1 = (0 for the first two then 1 for the next two and so on. Asta este codul la care am ajuns dupa observatiile pe care le-am mentionat mai sus: #include <stdio.h> int main(void) { for(unsigned int i = 448; i > 0; i--) { // Don't modifiy the loop sentinel, use a temporary variable instead. unsigned int argc = i; // The result of this is either 0 or 1. int exp1 = -~7[__TIME__ - (argc / 8) % 8][">'txiZ^(~z?" - 48] >> ";;;====~$::199"[(argc*2 & 8) | argc / 64] / (argc & 2 ? 1:8) % 8 & 1; // After we | it we get either 32(space) or 33(!). exp1 |= 32; // We reached the end, so put a \n int exp2 = 10; char result = --argc % 64 ? exp1 : exp2; // Finally, put the char on the screen. putchar(result); } return 0; } O zi buna! Close enough. Uite la ce ma gandisem eu ca ar fi un raspuns complet: Se indenteaza putin codul: main(_) { _^448 && main(-~_); putchar(--_%64 ? 32 | -~7[__TIME__-_/8%8][">'txiZ^(~z?"-48] >> ";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1 : 10); } Se introduc ceva variabile pentru a face codul putin mai readable: main(int i) { if(i^448) main(-~i); if(--i % 64) { char a = -~7[__TIME__-i/8%8][">'txiZ^(~z?"-48]; char b = a >> ";;;====~$::199"[i*2&8|i/64]/(i&2?1:8)%8; putchar(32 | (b & 1)); } else { putchar(10); // newline } } A se nota ca -~i == i + 1 deci avem: main(int i) { if(i != 448) main(i+1); i--; if(i % 64 == 0) { putchar('\n'); } else { char a = -~7[__TIME__-i/8%8][">'txiZ^(~z?"-48]; char b = a >> ";;;====~$::199"[i*2&8|i/64]/(i&2?1:8)%8; putchar(32 | (b & 1)); } } Acum, a se nota faptul ca a[ b ] e acelasi lucru ca si b[ a ], iar aplicand -~ == 1+ avem: main(int i) { if(i != 448) main(i+1); i--; if(i % 64 == 0) { putchar('\n'); } else { char a = (">'txiZ^(~z?"-48)[(__TIME__-i/8%8)[7]] + 1; char b = a >> ";;;====~$::199"[(i*2&8)|i/64]/(i&2?1:8)%8; putchar(32 | (b & 1)); } } Facand trecere de la recursivitate la un loop + incercand sa simplificam putin codul, obtinem: main() { int i; for(i=447; i>=0; i--) { if(i % 64 == 0) { putchar('\n'); } else { char t = __TIME__[7 - i/8%8]; char a = ">'txiZ^(~z?"[t - 48] + 1; int shift = ";;;====~$::199"[(i*2&8) | (i/64)]; if((i & 2) == 0) shift /= 8; shift = shift % 8; char b = a >> shift; putchar(32 | (b & 1)); } } } Asta va afisa cate un caracter per iteratie. Fiecare al 64-lea caracter va printa un new-line. Altfel, foloseste o pereche de valori dintr-un table pentru a-si da seama ce sa printeze si pune ori caracterul 32(space) sau caracterul 33 ( '!' ). Primul tabel ( ">'txiZ^(~z?" ) este un set de 10 bitmaps care descriu aparitia fiecarui caracter, iar cel de-al doilea tabel: ( ";;;====~$::199" ) selecteaza bit-ul necesar din bitmap. Al doilea tabel: int shift = ";;;====~$::199"[(i*2&8) | (i/64)]; i/64 -> este numarul linie (6-0) i&2&8 -> 8 daca i = 4, 5, 7 mod 8. if((i & 2) == 0) shift /= 8; shift = shift % 8 - linia de mai sus selecteaza ori "the high octal digit" (pentru i%8 = 0,1,4,5) sau "the low octal figit" (pentru i%8 = 2,3,6,7). Deci tabelul va arata cam asa: rand col val 6 6-7 0 6 4-5 0 6 2-3 5 6 0-1 7 5 6-7 1 5 4-5 7 5 2-3 5 5 0-1 7 4 6-7 1 4 4-5 7 4 2-3 5 4 0-1 7 3 6-7 1 3 4-5 6 3 2-3 5 3 0-1 7 2 6-7 2 2 4-5 7 2 2-3 3 2 0-1 7 1 6-7 2 1 4-5 7 1 2-3 3 1 0-1 7 0 6-7 4 0 4-5 4 0 2-3 3 0 0-1 7 Sau, intr-o forma mai tabulara: 00005577 11775577 11775577 11665577 22773377 22773377 44443377 A se observa ca s-a folosit null terminator pentru primele doua valori din tabel Primul tabel: __TIME__ este un macro special definit de preprocesor. Aceasta este folosita ca un constant string continand timpul la care preprocesorul a fost rulat, in forma: "HH:MM:SS". Mai pe romaneste, odata cu fiecare compilare, programul va arata ora exacta a compilarii. A se observa ca ora nu se schimba atunci cand dati Run. De sesizat faptul ca HH:MM:SS contine exact 8 caractere. De notat ca 0-9 in ASCII inseamna 48-57 iar semnul ":" are valoarea 58 in tabelul cu valori ASCII. Outputul contine 64 caractere / linie => 8 chars / caracter din __TIME__. 7 - i/8%8 este indexul lui __TIME__ care este de fapt outputul ( 7- este necesar pentru ca iteram valoarea lui i invers). Deci, t este ceea ce __TIME__ printeaza. a sfarsteste prin a fi egal cu una din urmatoarele valori binare, in functie de inputul t: 0 00111111 1 00101000 2 01110101 3 01111001 4 01101010 5 01011011 6 01011111 7 00101001 8 01111111 9 01111011 : 01000000 Din moment ce caracterele sunt 7-bit ASCII, cel mai mare bit va fi mereu clearuit => 7 va fi printat mereu ca blank. Deci, al doilea tabel va arata asa, dupa ce 7 = blank 000055 11 55 11 55 116655 22 33 22 33 444433 Deci, de exemplu, 4 = 01101010 (bits 1,3,5, si 6 set) care e printat astfel: ----!!-- !!--!!-- !!--!!-- !!!!!!-- ----!!-- ----!!-- ----!!-- Ca sa vedem ca am inteles cu adevarat codul, sa ajustam putin outputul folosind acest tabel: 00 11 55 11 55 66 22 33 22 33 44 Asta este encodat ca: "?;;?==? '::799\x07" In scop artistic, vom adauga 64 la cateva caractere (din moment ce doar ultimii 6 biti sunt folositi, asta nu va afecta ouputul); asta va rezulta in: "?{{?}}?gg::799G" ( de notat ca al 8-lea caracter nu este folosit -> deci practic putem sa il transformam in orice dorim). Edited April 2, 2016 by MrGrj 2 1
Byte-ul Posted April 2, 2016 Report Posted April 2, 2016 (edited) Hai ba garaj... sa pui challenge-ul ala e o chestie, dar sa copiezi rezolvarea cuvant cu cuvant de pe stackoverflow e aiurea @MasterLight a facut macar singur rezolvarea, chiar daca e incompleta.. (cel putin nu am gasit rezolvarea lui pe net) Edited April 2, 2016 by Byte-ul
Webz Posted April 2, 2016 Report Posted April 2, 2016 (edited) 19 hours ago, Byte-ul said: Hai ba garaj... sa pui challenge-ul ala e o chestie, dar sa copiezi rezolvarea cuvant cu cuvant de pe stackoverflow e aiurea @MasterLight a facut macar singur rezolvarea, chiar daca e incompleta.. (cel putin nu am gasit rezolvarea lui pe net) ahhaha Edited April 3, 2016 by Webz
H3xoR Posted April 2, 2016 Report Posted April 2, 2016 http://stackoverflow.com/questions/15393441/obfuscated-c-code-contest-2006-please-explain-sykes2-c 1
Active Members MrGrj Posted April 3, 2016 Author Active Members Report Posted April 3, 2016 Ba, nu inteleg de ce va cacati atat pe voi. Am explicat si la @Byte-ul In cazul in care un chall e facut de tine, evident vei veni cu o solutie personala. In cazul de fata, chall-ul nu a fost al meu, insa mi s-a parut extrem de nice, asa ca l-am postat La fel si cu rezolvarea: aia a fost cea mai completa pe care am gasit-o, deci am postat-o. Puteam sa vin cu solutia mea, insa era cu mult mai putine detalii fata de ceea ce am postat mai sus. Poti sa-l inchizi