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