8086 makine kodu (MS-DOS .COM), 83 bayt
DOSBox'ta veya favori buharla çalışan bilgi işlem motorunuzda çalıştırılabilir. Işınlanacak dize bir komut satırı argümanı olarak verilir.
İkili:
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 : ...
Okunabilir:
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
Bitkin
Aktif kısım çoğaltılır, böylece her zaman radyasyon tarafından dokunulmaz. Sağlıklı versiyonu atlamalarla seçiyoruz. Her atlama kısa bir atlamadır ve bu nedenle sadece iki bayt uzunluğundadır, burada ikinci bayt yer değiştirmedir (yani atlama mesafesi, işaret belirleme yönü ile).
Kodu ışınlanabilecek dört bölüme ayırabiliriz: atlama 1, kod 1, atlama 2 ve kod 2. Fikir her zaman temiz bir kod parçasının kullanıldığından emin olmaktır. Kod parçalarından biri ışınlanırsa, diğeri seçilmelidir, ancak atlamalardan biri ışınlanırsa, her iki kod parçası temiz olur, bu yüzden hangisinin seçildiği önemli değildir.
İki atlama parçasına sahip olmanın nedeni, ilk kısımdaki ışınlamayı üstünden atlayarak tespit etmektir. İlk kod parçası ışınlanırsa, işaretten bir bayt ulaşacağımız anlamına gelir. Böyle bir botlu inişin kod 2'yi ve uygun bir inişin kod 1'i seçtiğinden emin olursak, biz altınız.
Her iki sıçrama için de, her atlama parçasını 3 bayt uzunluğunda olacak şekilde deplasman baytını çoğaltırız. Bu, son iki bayttan birindeki ışınlamanın atlamayı hala geçerli kılmasını sağlar. İlk bayttaki ışınlama, sıçramanın gerçekleşmesini durduracaktır, çünkü son iki bayt tamamen farklı bir talimat oluşturacaktır.
İlk atlamayı yap:
EB 28 28 jmp +0x28 / db 0x28
Birini ise 0x28
bayt kaldırılır, hala aynı yere atlayacaktır. Eğer 0xEB
bayt kaldırılır, bunun yerine ile sona erecek
28 28 sub [bx + si], ch
Bu MS-DOS (diğer tatlar katılmayabilir) iyi huylu bir talimattır ve daha sonra hasar atlama 1 olduğu için temiz olması gereken kod 1'e düşer.
Atlama yapılırsa, ikinci atlamaya iniyoruz:
EB D7 D7 jmp -0x29 / db 0xd7
Bu bayt dizisi bozulmamışsa ve doğrudan işaretin üzerine indiğimizde, kod 1'in temiz olduğu ve bu talimatın bu kısma geri atladığı anlamına gelir. Çoğaltılmış yer değiştirme baytı, hasar gören bu yer değiştirme baytlarından biri olsa bile bunu garanti eder. Bir bayt çıkarırsak (hasarlı kod 1 veya atlama 1 nedeniyle) veya 0xEB
bayt hasarlı olan ise, kalan iki bayt da iyi huylu olacaktır:
D7 D7 xlatb / xlatb
Hangi durumda olursa olsun, bu iki talimatı uygularsak, atlama 1, kod 1 veya atlama 2'nin ışınlandığını biliyoruz, bu da kod 2'ye güvenli bir geçiş sağlıyor.
Test yapmak
Aşağıdaki program .COM dosyasının tüm sürümlerini otomatik olarak oluşturmak için kullanıldı. Ayrıca, her ışınlanmış ikili dosyayı çalıştıran ve çıktılarını ayrı metin dosyalarına bağlayan hedef ortamda çalıştırılabilen bir BAT dosyası oluşturur. Doğrulamak için çıktı dosyalarını karşılaştırmak yeterince kolaydır, ancak DOSBox yoktur fc
, bu nedenle BAT dosyasına eklenmemiştir.
#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);
}