online - javascript obfuscator decode




Obfuscated C Code Contest 2006. Veuillez expliquer sykes2.c (3)

Ajoutant aux autres solutions, -~x est égal à x+1 car ~x est équivalent à (0xffffffff-x) . Ceci est égal à (-1-x) en complément de 2s, donc -~x est -(-1-x) = x+1 .

Comment fonctionne ce programme C?

main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1:10);}

Il compile tel quel (testé sur gcc 4.6.3 ). Il imprime l'heure lorsqu'il est compilé. Sur mon système:

    !!  !!!!!!              !!  !!!!!!              !!  !!!!!! 
    !!  !!  !!              !!      !!              !!  !!  !! 
    !!  !!  !!              !!      !!              !!  !!  !! 
    !!  !!!!!!    !!        !!      !!    !!        !!  !!!!!! 
    !!      !!              !!      !!              !!  !!  !! 
    !!      !!              !!      !!              !!  !!  !! 
    !!  !!!!!!              !!      !!              !!  !!!!!!

Source: sykes2 - Une horloge en une ligne , des indices d'auteur sykes2

Quelques conseils: Pas d'avertissement de compilation par défaut. Compilé avec -Wall , les avertissements suivants sont émis:

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]

Débranchons-le.

Indentation:

main(_) {
    _^448 && main(-~_);
    putchar(--_%64
        ? 32 | -~7[__TIME__-_/8%8][">'txiZ^(~z?"-48] >> ";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1
        : 10);
}

Introduire des variables pour démêler ce gâchis:

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
    }
}

Notez que -~i == i+1 raison de deux-complément. Par conséquent, nous avons

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));
    }
}

Maintenant, notez que a[b] est le même que b[a] , et appliquez de nouveau le changement -~ == 1+ :

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));
    }
}

Convertir la récursivité en boucle et se faufiler dans un peu plus de simplification:

// please don't pass any command-line arguments
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));
        }
    }
}

Cela génère un caractère par itération. Chaque 64ème caractère, il sort une nouvelle ligne. Dans le cas contraire, il utilise une paire de tables de données pour déterminer ce qu'il doit sortir et place le caractère 32 (un espace) ou le caractère 33 (a ! ). La première table ( ">'txiZ^(~z?" ) Est un ensemble de 10 bitmaps décrivant l'apparence de chaque caractère, et la deuxième table ( ";;;====~$::199" ) sélectionne le bit approprié à afficher à partir de l'image bitmap.

La deuxième table

Commençons par examiner la deuxième table, int shift = ";;;====~$::199"[(i*2&8) | (i/64)]; int shift = ";;;====~$::199"[(i*2&8) | (i/64)]; . i/64 est le numéro de ligne (6 à 0) et i*2&8 est 8 ssi i est 4, 5, 6 ou 7 mod 8.

if((i & 2) == 0) shift /= 8; shift = shift % 8 if((i & 2) == 0) shift /= 8; shift = shift % 8 sélectionne le chiffre octal haut (pour i%8 = 0,1,4,5) ou le chiffre octal bas (pour i%8 = 2,3,6,7) de la valeur de la table. La table de décalage finit par ressembler à ceci:

row 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

ou sous forme de tableau

00005577
11775577
11775577
11665577
22773377
22773377
44443377

Notez que l'auteur a utilisé le terminateur null pour les deux premières entrées de la table (sournoise!).

Ceci est conçu après un affichage à sept segments, avec 7 s comme des blancs. Ainsi, les entrées de la première table doivent définir les segments qui s'allument.

La première table

__TIME__ est une macro spéciale définie par le préprocesseur. Il se développe en une constante chaîne contenant l'heure à laquelle le préprocesseur a été exécuté, sous la forme "HH:MM:SS" . Observez qu'il contient exactement 8 caractères. Notez que 0-9 ont des valeurs ASCII 48 à 57 et : a une valeur ASCII 58. La sortie est de 64 caractères par ligne, ce qui laisse 8 caractères par caractère de __TIME__ .

7 - i/8%8 est donc l'index de __TIME__ qui est en train de sortir (le 7- est nécessaire car nous itérons i vers le bas). Donc, t est le caractère de __TIME__ en sortie.

a finit par égaler le suivant en binaire, en fonction de l'entrée t :

0 00111111
1 00101000
2 01110101
3 01111001
4 01101010
5 01011011
6 01011111
7 00101001
8 01111111
9 01111011
: 01000000

Chaque nombre est un bitmap décrivant les segments qui sont allumés dans notre affichage à sept segments. Comme les caractères sont tous ASCII 7 bits, le bit haut est toujours effacé. Ainsi, 7 dans la table des segments s'imprime toujours en blanc. La deuxième table ressemble à ceci avec les 7 s comme des blancs:

000055  
11  55  
11  55  
116655  
22  33  
22  33  
444433  

Ainsi, par exemple, 4 est 01101010 (bits 1, 3, 5 et 6 ensemble), qui imprime comme

----!!--
!!--!!--
!!--!!--
!!!!!!--
----!!--
----!!--
----!!--

Pour montrer que nous comprenons vraiment le code, ajustons un peu la sortie avec cette table:

  00  
11  55
11  55
  66  
22  33
22  33
  44

Ceci est codé comme "?;;?==? '::799\x07" . À des fins artistiques, nous ajouterons 64 à quelques-uns des caractères (puisque seuls les 6 bits inférieurs sont utilisés, cela n'affectera pas la sortie); cela donne "?{{?}}?gg::799G" (notez que le 8ème caractère est inutilisé, donc nous pouvons en faire ce que nous voulons). Mettre notre nouvelle table dans le code original:

main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>"?{{?}}?gg::799G"[_*2&8|_/64]/(_&2?1:8)%8&1:10);}

on a

          !!              !!                              !!   
    !!  !!              !!  !!  !!  !!              !!  !!  !! 
    !!  !!              !!  !!  !!  !!              !!  !!  !! 
          !!      !!              !!      !!                   
    !!  !!  !!          !!  !!      !!              !!  !!  !! 
    !!  !!  !!          !!  !!      !!              !!  !!  !! 
          !!              !!                              !!   

comme nous l'espérions. Ce n'est pas aussi solide que l'original, ce qui explique pourquoi l'auteur a choisi d'utiliser la table qu'il a faite.


J'ai désobscuqué autant que possible l'arithmétique modulo et j'ai enlevé la reccursion

int pixelX, line, digit ;
for(line=6; line >= 0; line--){
  for (digit =0; digit<8; digit++){
    for(pixelX=7;pixelX > 0; pixelX--){ 
        putchar(' '| 1 + ">'txiZ^(~z?"["12:34:56"[digit]-'0'] >> 
          (";;;====~$::199"[pixel*2 & 8  | line] / (pixelX&2 ? 1 : 8) ) % 8 & 1);               
    }
  }
  putchar('\n');
}

L'élargir un peu plus:

int pixelX, line, digit, shift;
char shiftChar;
for(line=6; line >= 0; line--){
    for (digit =0; digit<8; digit++){
        for(pixelX=7;pixelX >= 0; pixelX--){ 
            shiftChar = ";;;====~$::199"[pixelX*2 & 8 | line];
            if (pixelX & 2)
                shift = shiftChar & 7;
            else
                shift = shiftChar >> 3;     
            putchar(' '| (">'txiZ^(~z?"["12:34:56"[digit]-'0'] + 1) >> shift & 1 );
        }

    }
    putchar('\n');
}






deobfuscation