[英]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
這種保險櫃和鑰匙的模擬是在Core Wars 8086 引擎內部完成的。 安全和鑰匙都是戰爭幸存者的規則如下:
幸存者無法在固定地址上加載,因為游戲引擎每輪都將它們加載到隨機地址。 生成的程序必須是 COM 而不是 EXE,並且只包含 8086 條指令。
每個幸存者都會收到一組自己的完整寄存器(寄存器),其他幸存者無法訪問。 此外,每個幸存者都有一個 2048 字節的“個人”堆棧,其他幸存者也無法訪問。
在運行第一輪游戲之前,游戲引擎將競技場中的所有字節初始化為值 0CCh(注意:該字節值是“不支持”的指令 - 詳情如下)。 然后引擎將每個幸存者加載到競技場 memory 中的隨機位置,即 - 完全按原樣復制幸存者文件的內容。 兩個幸存者之間的距離,以及幸存者與競技場邊緣之間的距離,保證至少為 1024 字節。 每個幸存者的代碼最多有 512 個字節。
在第一輪之前,游戲引擎將(每個幸存者的)寄存器初始化為以下值:
- BX、CX、DX、SI、DI、BP - 重置。
- 標志 - 重置。
- AX, IP - 初始幸存者的 position,游戲引擎加載幸存者的競技場中的隨機偏移量。
- CS, DS - 所有幸存者共有的競技場部分。
- ES - 同一組的幸存者共享的 memory 的段(段)(參見高級技術)。
- SS - 幸存者個人堆棧的開始部分。
- SP - 偏移 幸存者個人堆棧的開始。
此時游戲以回合開始,每一回合運行游戲引擎運行每個幸存者的下一條指令,直到游戲結束:在 200,000 回合之后,或者當單個幸存者留在競技場時。 幸存者在每一輪中的出場順序是在游戲開始時隨機確定的,在游戲中不會改變。
在以下情況下,幸存者將被取消資格:
- 運行非法指令(例如:字節 060h,它不會翻譯成任何匯編指令)。
- 游戲引擎運行“不支持”指令(例如:“INT 021h”)。 游戲引擎會阻止試圖啟動與操作系統或計算機硬件的直接通信的運行指令。 嘗試訪問不在競技場的 realm 內的 memory,也不在幸存者的“個人”堆棧的 realm 內。
- 通過在競技場 memory 中寫入有關其代碼的信息來攻擊其他幸存者(以使他們執行上述三個動作之一),從而取消他們的資格。 因此,早些時候,人們必須找到他們藏身的地方:)
雖然AX有一個隨機值,但它確實有意義。 那意思是:
- AX, IP - 初始幸存者的 position,游戲引擎加載幸存者的競技場中的隨機偏移量。
AX = IP這是在 memory 中加載保險箱的指令指針。 我們所要做的就是用強制安全退出(死)的東西來更新循環中的第一條指令。 這可以通過根據文檔將字節值 0x60 1寫入 memory 地址來完成。 由於safe的循環也是程序的開始,我們只需要檢索safe的AX值並使用它來覆蓋 memory 地址。
如果他們只是將其寫入 memory 地址 0x0DED,那么獲得safe的AX將是微不足道的,但他們不斷將AX添加到 memory 中的前一個 WORD(16 位值)。 這意味着為了弄清楚safe的AX值是多少,我們需要讀取兩次,然后從讀取的第二個值中減去讀取的第一個值。 我們還必須以這樣一種方式進行 2 次讀取,以使我們知道safe在兩次讀取之間准確地更新了一次。 Core Ware引擎的規則說:
此時游戲以回合開始,每一回合運行游戲引擎運行每個幸存者的下一條指令,直到游戲結束:在 200,000 回合之后,或者當單個幸存者留在競技場時。 幸存者在每一輪中的出場順序是在游戲開始時隨機確定的,在游戲中不會改變。
這意味着每一輪指令都由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
這里的目標是停止這個無限循環。 循環沒有停止項,我需要以某種方式使其停止使用逆向工程
目前還不清楚你能做什么和不能做什么。 以下是只需要您更改單個字節的解決方案。
從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
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.