Core Wars 8086 安全挑战(Safe 在内存地址上使用加法)

Core Wars 8086 safe challenge (Safe uses addition on a memory address)

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

start:
add     ds:0DEDh, ax
xor     cx, cx
loop    start

根据我的理解,cx 在循环结束时将为 0,并在下一次迭代时变为 FFFF。 我也知道 0xCCh 是一条非法指令,会停止程序。我怎样才能破解这个保险箱?

**编辑: 这里的目标是停止这个无限循环。该循环没有停止项,我需要以某种方式使其停止使用逆向工程。 例如: 这是一个简单的保险箱

safe:
  mov     ax, ds:4D2h
  cmp     ax, 1000h
  jl      safe 

这是它的密钥,使用逆向工程编写:

mov bx, 1000h
mov [4D2h], bx    
l:
    jmp l

这个 safekey 的模拟是在 Core Wars 8086 engine. The rules 内部完成的,其中 safekey 是 war:

中的幸存者

The survivors cannot place a load on fixed addresses, because the game engine loads them every turn to a random address. The programs that are generated must be COM and not EXEs and contain only 8086 instructions.

Each survivor receives a set of its own complete registers (registers), which is not accessible to the other survivors. In addition, each survivor has a "personal" stack of 2048 bytes, which is also inaccessible to the other survivors.

Before running the first round of the game, the game engine initializes all the bytes in the arena to the value 0CCh (note: this byte value is an "unsupported" instruction - details below). The engine then loads each survivor to a random location in the arena memory, ie - copies the contents of the survivor file exactly as it is. The distance between two survivors, as well as the distance between the survivor and the edge of the arena, is guaranteed to be at least 1024 bytes. The code for each survivor has a maximum of 512 bytes.

Before the first round, the game engine initializes the registers (of each survivor) to the following values:

  • BX, CX, DX, SI, DI, BP - Reset.
  • Flags - Reset.
  • AX, IP - The position of the initial survivor, the random offset in the arena to which the survivor is loaded by the game engine.
  • CS, DS - The segment of the arena common to all survivors.
  • ES - A segment (segment) for the memory shared by survivors of the same group (see Advanced Techniques ).
  • SS - Beginning section of the personal stack of the survivor.
  • SP - Offset The start of the personal stack of the survivor.

At this point the game begins in rounds, with each round running the game engine running the next instruction of each survivor, until the end of the game: after 200,000 rounds, or when a single survivor remains in the arena. The order in which the survivors will play in each round is determined at the beginning of the game at random, and does not change during it.

A survivor is disqualified in the following cases:

  • Running an illegal instruction (example: byte 060h that does not translate into any assembly instruction).
  • Running an "unsupported" instruction by the game engine (example: "INT 021h"). The game engine prevents running instructions that try to initiate direct communication with the operating system or computer hardware. Attempt to access memory that is not within the realm of the arena, and not within the realm of the "personal" stack of the survivor.
  • Attacking other survivors is done by writing information about their code in the arena memory (in order to get them to perform one of the above three actions), and consequently to disqualify them. Earlier, therefore, one has to find where they are hiding :)

the goal here is to stop this infinite loop. the loop has no stopping term and I need to somehow make it stop using reverse engineering

不太清楚您可以不能做什么。以下是一个只需要改变一个字节的解决方案。

xor cx, cx到无害的mov cx, cx将不再重置循环计数器,因此循环将在一段时间后结束(取决于我们CX的初始值不知道)。
mov cx, cx 的操作码是 89h。我们不需要更改 modr/m 字节,因为它的值对于两条指令都是相同的。

mov byte [cs:start+4], 89h

验证汇编程序是否不包含多余的 DS: 段覆盖前缀可能很有用,因为如果是这种情况,您将不得不编写 mov byte [cs:start+5], 89h.

虽然AX有一个随机值,但它确实有意义。那意思就是:

  • AX, IP - The position of the initial survivor, the random offset in the arena to which the survivor is loaded by the game engine.

AX=IP 这是 safe 被加载到内存中的指令指针.我们所要做的就是更新循环中的第一条指令,并强制 safe 退出(死亡)。根据文档,这可以通过将字节值 0x601 写入该内存地址来完成。由于 safe 的循环也是程序的开始,我们只需要检索 safeAX 值并用它来覆盖该内存地址。

获得 safeAX 如果他们只是将它写入内存地址 0x0DED 但他们不断添加 AX 到内存中的前一个 WORD(16 位值)。这意味着为了弄清楚 safeAX 值是什么,我们需要读取它两次并从第二个中减去第一个读取的值值读取。我们还必须以这样一种方式进行 2 次读取,即我们知道 safe 在两次读取之间恰好更新了一次。 Core Ware 引擎的规则是:

At this point the game begins in rounds, with each round running the game engine running the next instruction of each survivor, until the end of the game: after 200,000 rounds, or when a single survivor remains in the arena. The order in which the survivors will play in each round is determined at the beginning of the game at random, and does not change during it.

这意味着每一轮一条指令由safekey执行。由于 safe 的循环是 3 条指令:

start:
    add     ds:0DEDh, ax ; Instruction 1
    xor     cx, cx       ; Instruction 2
    loop    start        ; Instruction 3

我们保证每 4 条指令在 [0x0DED] 读取 2 个不同的值。既然我们知道了这一点,它就变得相对容易了。我们可以通过意识到 secondreadAX - firstreadAX(-firstreadAX) + secondreadAX 相同来简化汇编代码。考虑到这一点,执行 2 的解决方案分开读取四个指令并用 0x60 更新 safe 代码的开始(及其循环的开始)可能看起来像(在 NASM语法):

; Assemble with:
;     nasm -f bin key.asm -o key

start:
    mov bx, [0x0DED] ; Get the WORD from [0x0DED]
    neg bx           ; Negate it. BX=(-firstreadAX)
    nop              ; Need to wait at least one more instruction (3 total)
                     ;     before trying to read 0x0DED again
    add bx, [0x0DED] ; Add the current WORD value at [0x0DED] with BX
                     ;     safeAX = -BX+[0x0DED] = [0x0DED]-BX
                     ;  or safeAX=(-firstreadAX)+secondreadAX = secondreadAX-firstreadAX
    mov byte [bx], 0x60
                     ; Overwrite the first instruction of safe with 0x60
                     ;     to terminate the safe.
    jmp $            ; Infinite loop

在 TASM/MASM(v6.00+)/JWASM 中,代码如下所示:

.model tiny
.code

start:
    mov bx,[ds:0DEDh]; Get the WORD from [0DEDh]
    neg bx           ; Negate it. BX=(-firstreadAX)
    nop              ; Need to wait at least one more instruction (3 total)
                     ;     before trying to read 0DEDh again
    add bx,[ds:0DEDh]; Add the current WORD value at [0DEDh] with BX
                     ;     safeAX=-BX+[0DEDh]=[0DEDh]-BX
                     ;  or safeAX=(-firstreadAX)+secondreadAX = secondreadAX-firstreadAX
    mov byte ptr [bx], 060h
                     ; Overwrite the first instruction of safe with 060h
                     ;     to terminate the safe.
    jmp $            ; Infinite loop

END

脚注

  • 18086 不支持的任何操作码都会终止幸存者,其中包括 0x60、0x66、0x67 等。像 0xcc (INT3), 0xce (INTO) and 0xf1 (INT1) 这样的有效 8086 单字节操作码也会退出,因为它们是 Core Wars 引擎中不受支持的陷阱。调用 Core Wars 引擎(如 DOS INT 21h)不支持的软件中断也会导致幸存者失败。