因此,我们在组装时遇到了这种保险柜挑战,您需要创建保险柜和钥匙以破坏它们并结束无限循环。 这是一个安全的示例:
loopy:
mov ax, [1900]
cmp ax,1234
jne loopy
和一个键:
loopy2:
mov ax, 1234
mov [1900],ax
jmp loopy2
所以我有一个保险柜和一把钥匙,而且我不明白为什么它不起作用:
这是我的保险箱:
org 100h
mySafe:
mov dx,5
mov ax, [5768h]
mov bx,7
mov word [180h],2
mul word [180h]
mov [180h],bx
push ax
dec bx
mov cx,dx
mov ax,dx
loopy1:
add bx,ax
loop loopy1
dec bx
pop ax
add ax,bx
mul word [180h]
cmp ax,350
jne mySafe
这是我的钥匙:
org 100h
loopy:
mov word [5768h],10
jmp loopy
ret
打破循环的正确答案应该是10,当我把它放在保险柜上时,它会起作用,用某种方式,钥匙不起作用,我也不知道为什么。 (nasm需要“ word”)
答案 0 :(得分:2)
dx
中用作loop
指令计数器的值来自第一条mul
指令。
此乘法只是将键加倍,因此dx
可以是0或1(一种简单的方法是将乘法视为左移1或记住两个n的和位数字最多具有 n + 1 位)
如果dx
为零,则整个loopy1
块不执行任何操作(因为dx
也设置了ax
),并且ax
中的值在末尾保险柜是7 *(5 + 2k),其中 k 是钥匙(请参见下面的注释代码)。
然后很容易看出350 = 7 *(5 + 2k)=> 2k = 45没有解。因此,dx
为零的任何密钥都无法解锁保险箱。
如果键的值小于32768,则键的dx
为0(同样,当将乘法视为左移一位时,很容易看到)。
推论:10不能解决。
safe:
mov dx,5
mov ax, [k] ;ax = k (key)
mov bx,7
mov word [aux],2
mul word [aux] ;dx = 0 ax = 2k
mov [aux],bx ;aux = 7
push ax ;ax = 2k
dec bx ;bx = 6
dec bx ;bx = 5
pop ax ;ax = 2k
add ax,bx ;ax = 5 + 2k
mul word [aux] ;ax = 7*(5 +2k)
cmp ax,350
ret
如果有一个可以打开保险箱的钥匙,那么它必须大于或等于32768,以便在第一次乘法之后dx
为1。
在这种情况下,保险柜末端ax
中的值可以写为7 *(6 +(2k&0xffff))=> k&0x7fff =22。
加上本节开头所述的条件, k的最终值为32768 + 22 = 32790或十六进制的0x8016 。
在处理方程式和形成结果时,我已经跳了相当多的逻辑步骤,但再次将2k
视为转变可能会帮助他们可视化。
推论:由于所涉及的代数结构,这是唯一的解决方案。
safe:
mov dx,5
mov ax, [k] ;ax = k
mov bx,7
mov word [aux],2
mul word [aux] ;dx:ax = 2k
mov [aux],bx ;[aux] = 7
push ax ;dx = 1 ax = 2k & 0xffff
dec bx ;bx = 6
mov cx,dx ;cx = 1
mov ax,dx ;ax = 1
loopy1:
add bx,ax ;bx = 6 + 1
dec cx
jnz loopy1
dec bx ;bx = 6
pop ax ;ax = 2k & 0xffff
add ax,bx ;ax = 6 + (2k & 0xffff)
mul word [aux] ;ax = 7*(6 + (2k & 0xffff))
cmp ax,350
ret
考虑到在第一次乘法之前您有mov dx, 5
,您(或保险柜的作者)是否忘记了mul
影响dx
?< br />
如果将第一个mul
包裹在push dx / pop dx
中(或仅将其后移mov dx, 5
),则在保险柜的末尾,ax
中的值等于7 *(30 + 2k),这实际上意味着 k = 10 。