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
这个 safe 和 key 的模拟是在 Core Wars 8086 engine. The rules 内部完成的,其中 safe 和 key 是 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 的循环也是程序的开始,我们只需要检索 safe 的 AX 值并用它来覆盖该内存地址。
获得 safe 的 AX 如果他们只是将它写入内存地址 0x0DED 但他们不断添加 AX 到内存中的前一个 WORD(16 位值)。这意味着为了弄清楚 safe 的 AX 值是什么,我们需要读取它两次并从第二个中减去第一个读取的值值读取。我们还必须以这样一种方式进行 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.
这意味着每一轮一条指令由safe和key执行。由于 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
脚注
我正在参加保险箱比赛,我得到了这个保险箱:
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
这个 safe 和 key 的模拟是在 Core Wars 8086 engine. The rules 内部完成的,其中 safe 和 key 是 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 的循环也是程序的开始,我们只需要检索 safe 的 AX 值并用它来覆盖该内存地址。
获得 safe 的 AX 如果他们只是将它写入内存地址 0x0DED 但他们不断添加 AX 到内存中的前一个 WORD(16 位值)。这意味着为了弄清楚 safe 的 AX 值是什么,我们需要读取它两次并从第二个中减去第一个读取的值值读取。我们还必须以这样一种方式进行 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.
这意味着每一轮一条指令由safe和key执行。由于 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