【问题标题】:Assembly x86 Core Wars Safe Challenge (Subtract Core)Assembly x86 Core Wars 安全挑战(减核)
【发布时间】:2020-12-17 12:00:43
【问题描述】:

我正在参加保险箱比赛,我得到了这个保险箱:

and al, 0FEh
push ax
clc
mul ax
xor ax, dx
or al, 1

loc_A:
    sub ds:0A2h, ax
    pop ax
    push ax
    jnz loc_A
    ends

据我了解,为了闯入保险柜,我需要在子操作后得到一个零,以便保险柜停止运行。

所以我想到的解决方案是在 sub 操作后取地址 0A2h 处的值并将其放入 ax 寄存器中,然后我在 ax 寄存器中具有保险库的 ax 的负值,即“ -ax”,那么我只需要做 neg ax,并在地址 0A2h 中将 ax 的值放在 neg 后面。然后 ax-ax = 0。所以这是我构建的代码:

nop
nop
nop
nop
nop
nop
nop
mov ax, [0x00A2]
neg ax
key:
    mov [0x00A2], ax
    jmp key

代码有效,但只有一半的时间:


safekey 的模拟是在 Core Wars 8086 engine 内完成的。 rules 如下,其中 safekey 都是战争中的幸存者:

幸存者不能在固定地址上加载,因为游戏 引擎每轮将它们加载到一个随机地址。那些节目 生成的必须是 COM 而不是 EXE,并且只包含 8086 指令。

每个幸存者都会收到一组自己的完整寄存器 (寄存器),其他幸存者无法访问。在 此外,每个幸存者都有一个 2048 字节的“个人”堆栈,即 其他幸存者也无法进入。

在运行第一轮游戏之前,游戏引擎 将 arena 中的所有字节初始化为值 0CCh(注意:这 字节值是“不受支持”的指令 - 详情如下)。那么发动机 将每个幸存者加载到竞技场内存中的随机位置,即 - 完全按原样复制幸存者文件的内容。这 两个幸存者之间的距离,以及两个幸存者之间的距离 幸存者和竞技场边缘,保证至少1024 字节。每个幸存者的代码最大为 512 字节。

在第一轮之前,游戏引擎初始化寄存器(的 每个幸存者)到以下值:

  • BX、CX、DX、SI、DI、BP - 重置。
  • 标志 - 重置。
  • AX,IP - 初始幸存者的位置,游戏引擎加载幸存者的竞技场中的随机偏移量。
  • CS、DS - 所有幸存者共有的竞技场部分。
  • ES - 同一组的幸存者共享内存的段(段)(请参阅高级技术)。
  • SS - 幸存者个人堆栈的开始部分。
  • SP - 偏移幸存者个人堆栈的开始。

此时游戏以回合开始,每一回合运行游戏引擎运行每个幸存者的下一条指令,直到结束 游戏结束:在 200,000 轮之后,或者当一个幸存者仍然存在时 在竞技场。幸存者在每轮比赛中的顺序 在游戏开始时随机确定,并且不 期间发生变化。

在以下情况下,幸存者将被取消资格:

  • 运行非法指令(例如:字节 060h,不翻译成任何汇编指令)。
  • 游戏引擎运行“不支持”指令(例如:“INT 021h”)。游戏引擎阻止尝试启动的运行指令 与操作系统或计算机硬件的直接通信。 尝试访问不在竞技场范围内的内存, 并且不在幸存者的“个人”堆栈范围内。
  • 攻击其他幸存者是通过在竞技场内存中写入有关他们的代码的信息来完成的(为了让他们执行其中一项 以上三项行动),并因此取消他们的资格。早些时候, 因此,必须找到它们的藏身之处:)

【问题讨论】:

  • 您的key 似乎放错了地方。我想你每次都想重新计算。
  • 在第二个循环之后,ax 寄存器值没有改变......无论如何,如果我每次都必须计算我是如何得到 50 50 的?

标签: assembly x86 nasm x86-16 corewars


【解决方案1】:

我认为你是在正确的轨道上。您已经注意到,在安全进入循环之前的所有计算都可以忽略(它们是红鲱鱼)。要理解的重要一点是,保险箱中的循环执行一次后,所有后续循环将始终减去相同的值。您需要做的是确保我们忽略第一个值安全写入 [0A2h],然后一旦我们知道它已被写入,一旦我们将 [0A2h] 清零,然后等待它写入到 [0A2h] 第二次,然后我们只是否定内存中的那个值。一旦被否定,safe 将退出循环,因为 safe 中的 SUBtraction 的结果将为 0,并且循环条件将退出。应该工作的 NASM 代码是:

start:
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    ; At this point the safe is guaranteed to have written to [0A2h] exactly once
    ; Zero out the value at [0A2h]
    mov word [0A2h], 0
    nop
    nop
    nop
    ; At this point the safe is guaranteed to have written to [0A2h] exactly twice
    ; Negate the value at [0A2h] so that safe will exit (SUB will result in value 0)
    neg word [0a2h]

    ; End in an infinite loop
    jmp $

MASM(6.x+)/TASM/JWASM 版本是:

.model tiny
.code

start:
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    ; At this point the safe is guaranteed to have written to [0A2h] exactly once
    ; Zero out the value at [0A2h]
    mov word ptr [ds:0A2h], 0
    nop
    nop
    nop
    ; At this point the safe is guaranteed to have written to [0A2h] exactly twice
    ; Negate the value at [0A2h] so that safe will exit (SUB will result in value 0)
    neg word ptr [ds:0a2h]

    ; End in an infinite loop
    jmp $

end

【讨论】:

    【解决方案2】:
    l: 
       mov bx, 0a2h 
       mov dx, 0xffff            
       mov word [bx], dx
       nop
       nop
       mov ax, word [bx]
       sub dx, ax 
       mov word [bx], dx 
       mov dx, 0xffff 
       jmp l  
    

    试试看。

    【讨论】: