8086 मशीन कोड (MS-DOS .COM), 83 बाइट्स
DOSBox या अपने पसंदीदा भाप संचालित कंप्यूटिंग इंजन में चलने योग्य। इर्रिरेज करने के लिए स्ट्रिंग को कमांड लाइन तर्क के रूप में दिया गया है।
बाइनरी:
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 : ...
पठनीय:
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
मंद होना
सक्रिय भाग को डुप्लिकेट किया जाता है ताकि विकिरण से हमेशा एक अछूता रहे। हम जंप के माध्यम से स्वस्थ संस्करण का चयन करते हैं। प्रत्येक कूद एक छोटी छलांग है, और इसलिए केवल दो बाइट्स लंबा है, जहां दूसरा बाइट विस्थापन है (यानी कूदने की दूरी, संकेत निर्धारण दिशा के साथ)।
हम कोड को चार भागों में विभाजित कर सकते हैं जिन्हें विकिरणित किया जा सकता है: कूद 1, कोड 1, कूद 2 और कोड 2। विचार यह है कि यह सुनिश्चित करने के लिए कि एक साफ कोड भाग हमेशा उपयोग किया जाता है। यदि कोड भागों में से एक को विकिरणित किया जाता है, तो दूसरे को चुना जाना चाहिए, लेकिन अगर एक जंप का विकिरण किया जाता है, तो दोनों कोड भाग साफ होंगे, इसलिए यह कोई फर्क नहीं पड़ेगा कि कौन सा चुना गया है।
दो जंप भागों के होने का कारण इसके पहले भाग में विकिरण का पता लगाना है। यदि पहला कोड भाग विकिरणित है, तो इसका मतलब है कि हम निशान से एक बाइट तक पहुंच जाएंगे। यदि हम यह सुनिश्चित करते हैं कि इस तरह का एक बॉटेड लैंडिंग कोड 2 का चयन करता है, और एक उचित लैंडिंग कोड 1 का चयन करता है, तो हम सुनहरे हैं।
दोनों छलांगों के लिए, हम विस्थापन बाइट की नकल करते हैं, प्रत्येक कूद भाग 3 बाइट्स लंबा बनाते हैं। यह सुनिश्चित करता है कि दो अंतिम बाइट्स में से एक में विकिरण अभी भी कूद को वैध बना देगा। पहली बाइट में विकिरण, कूद को बिल्कुल भी होने से रोक देगा, क्योंकि अंतिम दो बाइट्स पूरी तरह से अलग निर्देश बनाएंगे।
पहली छलांग लें:
EB 28 28 jmp +0x28 / db 0x28
यदि किसी भी 0x28
बाइट को हटा दिया जाता है, तो यह अभी भी उसी स्थान पर कूद जाएगा। यदि 0xEB
बाइट हटा दी जाती है, तो हम इसके साथ समाप्त हो जाएंगे
28 28 sub [bx + si], ch
जो MS-DOS पर एक सौम्य निर्देश है (अन्य जायके असहमत हो सकते हैं), और फिर हम कोड 1 के माध्यम से गिर जाते हैं, जो कि साफ होना चाहिए, क्योंकि क्षति कूद 1 में थी।
यदि कूद लिया जाता है, तो हम दूसरी छलांग पर उतरते हैं:
EB D7 D7 jmp -0x29 / db 0xd7
यदि यह बाइट अनुक्रम बरकरार है, और हम निशान पर सही उतरते हैं, तो इसका मतलब है कि कोड 1 साफ था, और यह निर्देश उस हिस्से पर वापस कूदता है। डुप्लिकेट किए गए विस्थापन बाइट इसकी गारंटी देता है, भले ही यह इन विस्थापन बाइट्स में से एक है जो क्षतिग्रस्त हो गए थे। यदि हम या तो एक बाइट को बंद कर देते हैं (एक क्षतिग्रस्त कोड 1 या कूद 1 के कारण) या 0xEB
बाइट क्षतिग्रस्त है, तो दो शेष बाइट भी सौम्य होंगे:
D7 D7 xlatb / xlatb
जो भी मामला है, अगर हम उन दो निर्देशों को निष्पादित करते हैं, तो हम जानते हैं कि या तो कूद 1, कोड 1, या कूद 2 को विकिरणित किया गया था, जो एक गिरावट के माध्यम से कोड 2 को सुरक्षित बनाता है।
परिक्षण
.COM फ़ाइल के सभी संस्करणों को स्वचालित रूप से बनाने के लिए निम्न प्रोग्राम का उपयोग किया गया था। यह एक BAT फ़ाइल भी बनाता है जिसे लक्ष्य वातावरण में चलाया जा सकता है, जो प्रत्येक विकिरणित बाइनरी को चलाता है, और पाठ फ़ाइलों को अलग करने के लिए अपने आउटपुट को पाइप करता है। मान्य करने के लिए आउटपुट फ़ाइलों की तुलना करना काफी आसान है, लेकिन DOSBox के पास नहीं है fc
, इसलिए इसे 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);
}