$@='NOT ';print"$@CORRUPTED"__DATA__ =®®”print"$@CORRUPTED"__DATA__ =®®”Ê®›~
Ce programme contient quelques octets parasites qui ne sont pas valides UTF-8. En tant que tel, il est affiché tel qu'il apparaît dans Windows-1252. (Par défaut, si A Pear Tree voit un octet non ASCII dans un littéral de chaîne ou similaire, il le traite comme un objet opaque et n'essaie pas de le comprendre au-delà de la connaissance de son code de caractère; ce comportement peut être modifié via une déclaration d'encodage mais le programme n'en a pas. Le programme est donc logiquement dans "un jeu de caractères compatible ASCII non spécifié". Tous les octets non ASCII sont dans les commentaires de toute façon, donc cela n'a pas vraiment d'importance.)
Explication
Un poirier vérifie le programme, recherchant la plus longue sous-chaîne possédant un CRC-32 00000000
. (S'il y a égalité, il choisit l'octetbétique en premier.) Ensuite, le programme est tourné pour le mettre au début. Enfin, le programme est interprété comme un langage qui est presque un surensemble de Perl, définissant quelques éléments qui ne sont pas définis en Perl pour fonctionner de la même manière qu'en Python (et avec quelques modifications mineures, par exemple, print
imprime une nouvelle ligne finale dans A Pear Tree mais pas en Perl). Ce mécanisme (et le langage dans son ensemble) a été conçu pour le polyglotte et le durcissement par rayonnement problèmes de ; ce n'est pas le premier, mais c'est définitivement le dernier.
Dans ce programme, nous avons deux sous-chaînes notables que CRC-32 00000000
; tout le programme le fait, tout comme print"$@CORRUPTED"__DATA__ =®®
lui-même (qui apparaît deux fois). En tant que tel, si le programme n'est pas corrompu, il sera défini $@
sur NOT
puis l'imprimera suivi de CORRUPTED
. Si le programme est corrompu, le CRC-32 du programme dans son ensemble ne correspondra pas, mais l'une des sections les plus courtes ne sera pas corrompue. Celui qui est tourné au début du programme s'imprime CORRUPTED
, tout $@
comme la chaîne nulle.
Une fois la chaîne imprimée, __DATA__
est utilisée pour empêcher l'exécution du reste du programme. (Cela me vient à l'esprit d'écrire ceci qui __END__
pourrait être utilisé à la place, ce qui permettrait clairement d'économiser deux octets. Mais je peux aussi poster cette version maintenant, car j'ai passé beaucoup de temps à la vérifier, et une version modifiée devrait être revérifié en raison des modifications apportées au CRC, et je n'ai pas encore déployé beaucoup d'efforts pour jouer à la "charge utile", donc je veux voir si quelqu'un a d'autres améliorations dans les commentaires que je peux intégrer en même temps. Notez que #
cela ne fonctionne pas dans le cas où un personnage est corrompu dans une nouvelle ligne.)
Vous vous demandez peut-être comment j'ai réussi à contrôler le CRC-32 de mon code en premier lieu. Ceci est une astuce mathématique assez simple basée sur la façon dont le CRC-32 est défini: vous prenez le CRC-32 du code, l'écrivez dans un ordre peu-endian (l'inverse de l'ordre des octets qui est normalement utilisé par le calcul du CRC-32 programmes) et XOR avec 9D 0A D9 6D
. Ensuite, vous ajoutez cela au programme, et vous aurez un programme avec un CRC-32 de 0. (Comme l'exemple le plus simple possible, la chaîne nulle a un CRC-32 de 0, donc a 9D 0A D9 6D
également un CRC-32 de 0 .)
Vérification
Un poirier peut gérer la plupart des types de mutations, mais je suppose que «changé» signifie «remplacé par un octet arbitraire». Il est théoriquement possible (bien que peu probable dans un programme aussi court) qu'il puisse y avoir une collision de hachage quelque part qui conduise à un mauvais programme, donc j'ai dû vérifier par force brute que toutes les substitutions d'octets possibles laisseraient le programme fonctionner correctement. Voici le script de vérification (écrit en Perl) que j'ai utilisé:
use 5.010;
use IPC::Run qw/run/;
use warnings;
use strict;
undef $/;
$| = 1;
my $program = <>;
for my $x (0 .. (length $program - 1)) {
for my $a (0 .. 255) {
print "$x $a \r";
my $p = $program;
substr $p, $x, 1, chr $a;
$p eq $program and next;
alarm 4;
run [$^X, '-M5.010', 'apeartree.pl'], '<', \$p, '>', \my $out, '2>', \my $err;
if ($out ne "CORRUPTED\n") {
print "Failed mutating $x to $a\n";
print "Output: {{{\n$out}}}\n";
print "Errors: {{{\n$err}}}\n";
exit;
}
}
}
say "All OK! ";