【问题标题】:Assembly safes and keys- why it won't work?组装保险箱和钥匙 - 为什么它不起作用?
【发布时间】:2020-04-18 02:51:36
【问题描述】:

所以我们在组装中遇到了这样的保险箱挑战,您需要创建保险箱和钥匙来破坏它们并结束无限循环。 以下是保险箱的示例:

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需要“单词”)

【问题讨论】:

  • 你的“钥匙”永远不会退出。这不是问题吗?它应该只需要运行一次,就可以永远解锁“安全”循环。除非您在多任务操作系统下运行多个进程,否则无限循环是不好的。
  • 你的“保险箱”太复杂了,我无法在脑海中模拟。当您在调试器中单步执行它时,您是否看到它从[5768h] 加载10?如果是这样,那么它最终不会以ax == 350 结束吗?对于minimal reproducible example,“不起作用”不够详细。
  • 我的密钥应该无限循环运行。它在 codeguru 的程序中运行,并且密钥应该获胜,这意味着它应该打破保险箱的无限循环。但是,它总是以平局告终。表示钥匙不起作用..

标签: debugging assembly reverse-engineering x86-16 corewars


【解决方案1】:

dx 中用作loop 指令计数器的值来自第一条mul 指令。

这个乘法只是将键加倍,所以dx 要么是 0 要么是 1(理解这一点的一种简单方法是将乘法视为左移 1 或记住两个 n 位的和numbers 最多有 n+1 位)


如果dx 为零,则整个loopy1 块不执行任何操作(因为dx 也设置ax)并且保险箱末尾ax 中的值是7*(5 +2k)其中 k 是关键(请参阅下面的注释代码)。

那么很容易看出 350 = 7*(5+2k) => 2k = 45 没有解。因此,dx 为零的任何钥匙都无法解锁保险箱。
一个键有dx 0 如果它的值小于 32768(同样,当将乘法视为左移一时很容易看出这一点)。

推论: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
如果将第一个 mul 包裹在 push dx / pop dx 中(或者只是将 mov dx, 5 移动到它之后),那么在保险箱的末尾,您会得到 ax 中的值等于 7*(30 +2k)确实意味着 k = 10

【讨论】:

  • 非常感谢您对我的帮助!你不知道我有多喜欢它!
猜你喜欢
  • 2018-02-05
  • 1970-01-01
  • 2018-02-02
  • 2017-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-28
  • 2019-12-11
相关资源
最近更新 更多