Debugging 装配保险箱和钥匙-为什么它赢了';不行?
因此,我们在组装中遇到了类似保险柜的挑战,您需要创建保险柜和钥匙,以打破它们并结束无限循环。 下面是一个保险箱的示例:Debugging 装配保险箱和钥匙-为什么它赢了';不行?,debugging,assembly,reverse-engineering,x86-16,corewars,Debugging,Assembly,Reverse Engineering,X86 16,Corewars,因此,我们在组装中遇到了类似保险柜的挑战,您需要创建保险柜和钥匙,以打破它们并结束无限循环。 下面是一个保险箱的示例: 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,
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需要“字)用作
循环
指令计数器的dx
中的值来自第一条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 iif(同样,当将乘法看作左移1时,很容易看出这一点)
推论: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
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
如果有钥匙打开保险柜,则钥匙必须大于或等于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 (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
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
?如果您将第一个
mul
包装在push dx/pop dx
中(或者只移动mov dx,5
),则在保险箱的末尾,ax
中的值等于7*(30+2k)这实际上意味着k=10。用作循环
指令计数器的dx
中的值来自第一条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 iif(同样,当将乘法看作左移1时,很容易看出这一点)
推论: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
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
如果有钥匙打开保险柜,则钥匙必须大于或等于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 (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
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
?如果您将第一个
mul
包装在push dx/pop dx
中(或者只移动mov dx,5
),您将在保险箱末端得到ax
中的值等于7*(30+2k),这意味着k=10。您的“钥匙”永远不会退出。这不是问题吗?它应该只需要运行一次,就可以永远解锁“安全”循环。除非你在一个多任务操作系统下运行多个进程,否则无限循环是不好的。你的“安全”太复杂了,我无法在脑海中模拟。在调试器中单步执行时,是否看到它从[5768h]
加载10
?如果是这样,那么它最终不是以ax==350而结束吗?“不起作用”的细节不够详细。我的密钥应该在无限循环中运行。它运行在codeguru的程序中,密钥应该是赢的,这意味着它应该打破保险箱的无限循环。然而,结果总是平局。意味着钥匙不起作用,你的“钥匙”永远不存在。这不是问题吗?它应该只需要运行一次,就可以永远解锁“安全”循环。除非你在一个多任务操作系统下运行多个进程,否则无限循环是不好的。你的“安全”太复杂了,我无法在脑海中模拟。在调试器中单步执行时,是否看到它从[5768h]
加载10
?如果是这样,那么它最终不是以