Я участвую в соревнованиях по сейфам, и мне достался вот такой сейф:
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
Насколько я понимаю, чтобы взломать сейф, мне нужно получить ноль после подоперации, чтобы сейф перестал работать.
Поэтому решение, которое я решил сделать, состоит в том, чтобы взять значение по адресу 0A2h после подоперации и поместить его в регистр топора, тогда у меня в регистре топора будет отрицательное значение топора хранилища, то есть «-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
Код работает, но только в половине случаев:
Эта симуляция сейфа и ключа выполнена внутри движка Core Wars 8086 . Правила таковы, когда и сейфом, и ключом являются выжившие на войне:
Выжившие не могут размещать нагрузку на фиксированные адреса, потому что игра движок загружает их каждый ход по случайному адресу. Программы, которые должны быть COM, а не EXE и содержать только 8086 инструкций.
Каждый выживший получает набор собственных полных регистров. (регистры), который не доступен для других выживших. В Кроме того, у каждого выжившего есть «личный» стек размером 2048 байт, что составляет также недоступны для других выживших.
Перед запуском первого раунда игры движок игры инициализирует все байты на арене значением 0CCh (примечание: это значение байта является «неподдерживаемой» инструкцией — подробности ниже). Затем двигатель загружает каждого выжившего в случайное место в памяти арены, т.е. копирует содержимое файла оставшегося в живых точно так, как оно есть. расстояние между двумя выжившими, а также расстояние между выживший и край арены, гарантировано не менее 1024 байт. Код для каждого выжившего имеет максимум 512 байт.
Перед первым раундом игровой движок инициализирует регистры (из каждого выжившего) до следующих значений:
- BX, CX, DX, SI, DI, BP - сброс.
- Флаги - Сбросить.
- AX, IP - Позиция начального выжившего, случайное смещение на арене, в которое выживший загружается движком игры.
- CS, DS - Сегмент арены общий для всех выживших.
- ES — Сегмент (сегмент) для памяти, разделяемой выжившими из одной группы (см. Advanced Techniques).
- СС - Начальный раздел личного стека выжившего.
- SP - Offset Начало личного стека выжившего.
С этого момента игра начинается в раундах, в каждом раунде игровой движок запускает следующую инструкцию для каждого выжившего до конца. игры: после 200 000 раундов или когда остался хоть один выживший на арене. Порядок, в котором выжившие будут играть в каждом раунде определяется в начале игры случайным образом, а не меняться во время него.
Оставшийся в живых дисквалифицируется в следующих случаях:
- Запуск недопустимой инструкции (пример: байт 060h, который не транслируется ни в какую ассемблерную инструкцию).
- Запуск «неподдерживаемой» инструкции игровым движком (пример: «INT 021h»). Игровой движок предотвращает запуск инструкций, которые пытаются инициировать прямая связь с операционной системой или компьютерным оборудованием. Попытка получить доступ к памяти, которая находится за пределами области арены, и не входит в сферу «личного» стека выжившего.
- Атака других выживших осуществляется путем записи информации об их коде в память арены (чтобы заставить их выполнить одно из действий). выше трех действий), и, следовательно, их дисквалификацию. Ранее, значит надо найти где они прячутся :)
После второго цикла значение регистра оси не меняется... В любом случае, если мне нужно каждый раз вычислять, как я получил 50 50?





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
попробуй это.
Я думаю, вы на правильном пути. Вы заметили, что все вычисления до входа сейфа в цикл можно игнорировать (это отвлекающий маневр). Важно понимать, что после того, как цикл в сейфе будет выполнен один раз, все последующие циклы всегда будут вычитать одно и то же значение. Что вам нужно сделать, так это убедиться, что мы игнорируем первое значение, которое сейф записывает в [0A2h], затем, как только мы узнаем, что оно было записано в один раз, мы обнуляем [0A2h], а затем ждем, пока оно запишет в [0A2h] во второй раз. а затем мы просто отрицаем это значение в памяти. После инвертирования сейф выйдет из цикла, так как результат ВЫЧИТАНИЯ в сейфе будет равен 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
Ваш
keyкажется не на своем месте. Я думаю, что вы хотите, чтобы заново сделать расчет каждый раз.