8086 codice macchina (MS-DOS .COM), 83 byte
Eseguibile in DOSBox o il tuo motore di elaborazione preferito alimentato a vapore. La stringa da irradiare viene fornita come argomento della riga di comando.
Binario:
00000000 : EB 28 28 8A 0E 80 00 49 BD 83 00 B4 02 51 8A 0E : .((....I.....Q..
00000010 : 80 00 BE 82 00 AC 39 EE 74 04 88 C2 CD 21 E2 F5 : ......9.t....!..
00000020 : 59 45 B2 0A CD 21 E2 E5 C3 90 EB D7 D7 8A 0E 80 : YE...!..........
00000030 : 00 49 BD 83 00 B4 02 51 8A 0E 80 00 BE 82 00 AC : .I.....Q........
00000040 : 39 EE 74 04 88 C2 CD 21 E2 F5 59 45 B2 0A CD 21 : 9.t....!..YE...!
00000050 : E2 E5 C3 : ...
Leggibile:
cpu 8086
org 0x100
jmp part2
db 0x28
part1:
mov cl, [0x80]
dec cx
mov bp, 0x83
mov ah, 0x02
.l:
push cx
mov cl, [0x80]
mov si, 0x82
.k:
lodsb
cmp si, bp
je .skip
mov dl, al
int 0x21
.skip:
loop .k
pop cx
inc bp
mov dl, 10
int 0x21
loop .l
ret
nop
part2:
jmp part1
db 0xd7
mov cl, [0x80]
dec cx
mov bp, 0x83
mov ah, 0x02
.l:
push cx
mov cl, [0x80]
mov si, 0x82
.k:
lodsb
cmp si, bp
je .skip
mov dl, al
int 0x21
.skip:
loop .k
pop cx
inc bp
mov dl, 10
int 0x21
loop .l
ret
Corri giù
La parte attiva viene duplicata in modo tale che ne rimanga sempre una non trattata dalle radiazioni. Selezioniamo la versione sana per mezzo di salti. Ogni salto è un salto breve, e quindi è lungo solo due byte, dove il secondo byte è lo spostamento (ovvero la distanza da saltare, con segno che determina la direzione).
Possiamo dividere il codice in quattro parti che potrebbero essere irradiate: salto 1, codice 1, salto 2 e codice 2. L'idea è quella di assicurarsi che venga sempre usata una parte pulita del codice. Se una delle parti del codice viene irradiata, l'altra deve essere scelta, ma se uno dei salti viene irradiato, entrambe le parti del codice saranno pulite, quindi non importa quale verrà scelta.
La ragione per avere due parti di salto è rilevare l'irradiazione nella prima parte saltandola. Se la prima parte di codice viene irradiata, significa che arriveremo a un byte fuori dal segno. Se ci assicuriamo che un atterraggio di questo tipo selezioni il codice 2 e un atterraggio corretto selezioni il codice 1, siamo d'oro.
Per entrambi i salti, dupliciamo il byte di spostamento, rendendo ogni salto parte di 3 byte. Ciò garantisce che l'irradiazione in uno degli ultimi due byte renderà comunque valido il salto. L'irradiazione nel primo byte impedirà che si verifichi il salto, poiché gli ultimi due byte formeranno un'istruzione completamente diversa.
Fai il primo salto:
EB 28 28 jmp +0x28 / db 0x28
Se uno dei 0x28
byte viene rimosso, salterà comunque nella stessa posizione. Se il 0xEB
byte viene rimosso, finiremo invece con
28 28 sub [bx + si], ch
che è un'istruzione benigna su MS-DOS (altri gusti potrebbero non essere d'accordo), e quindi passiamo al codice 1, che deve essere pulito, poiché il danno era nel salto 1.
Se il salto viene eseguito, atterriamo al secondo salto:
EB D7 D7 jmp -0x29 / db 0xd7
Se questa sequenza di byte è intatta e atterriamo sul segno, significa che il codice 1 era pulito e questa istruzione torna a quella parte. Il byte di spostamento duplicato lo garantisce, anche se è uno di questi byte di spostamento che sono stati danneggiati. Se atterriamo un byte fuori (a causa di un codice danneggiato 1 o salta 1) o il 0xEB
byte è quello danneggiato, anche i due byte rimanenti saranno benigni:
D7 D7 xlatb / xlatb
In ogni caso, se finiamo per eseguire queste due istruzioni, sappiamo che il salto 1, il codice 1 o il salto 2 sono stati irradiati, il che rende sicuro il passaggio al codice 2.
analisi
Il seguente programma è stato utilizzato per creare automaticamente tutte le versioni del file .COM. Crea inoltre un file BAT che può essere eseguito nell'ambiente di destinazione, che esegue ogni binario irradiato e convoglia i loro output in file di testo separati. Confrontare i file di output da convalidare è abbastanza semplice, ma DOSBox non ha fc
, quindi non è stato aggiunto al file BAT.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
FILE *fin, *fout, *fbat;
int fsize;
char *data;
if (!(fin = fopen(argv[1], "rb")))
{
fprintf(stderr, "Could not open input file \"%s\".\n", argv[1]);
exit(1);
}
if (!(fbat = fopen("tester.bat", "w")))
{
fprintf(stderr, "Could not create BAT test file.\n");
exit(2);
}
fseek(fin, 0L, SEEK_END);
fsize = ftell(fin);
fseek(fin, 0L, SEEK_SET);
if (!(data = malloc(fsize)))
{
fprintf(stderr, "Could not allocate memory.\n");
exit(3);
}
fread(data, 1, fsize, fin);
fprintf(fbat, "@echo off\n");
for (int i = 0; i < fsize; i++)
{
char fname[512];
sprintf(fname, "%03d.com", i);
fprintf(fbat, "%s Hello, world! > %03d.txt\n", fname, i);
fout = fopen(fname, "wb");
fwrite(data, 1, i, fout);
fwrite(data + i + 1, 1, fsize - i - 1, fout);
fclose(fout);
}
free(data);
fclose(fin);
fclose(fbat);
}