Tutorial
目录
本教程将带您了解我们的调试器,并在通关的过程中逐步解释一切是如何工作的。强烈建议您完成它(我们保证不到15分钟),但不是必须的。只要您不刷新页面,就随时可以返回本教程。
欢迎
世界各地锁着的仓库里散落着装满Cy Yombinator无记名债券的公文包,这些债券可能价值数十亿美元。你会帮忙偷公文包的。
Cy Yombinator巧妙地用Lockitall电子锁设备保护了仓库。Lockitall锁可以通过应用程序解锁。我们在每个仓库附近都安排了特工;每个人都在等着你通过解开锁来成功解锁仓库。
Lockitall设备通过接受来自Lockitall LockIT Pro应用程序的蓝牙连接来工作。我们已经为您做了艰苦的工作:我们花了15000美元购买了一个开发工具包,其中包括可供您练习的远程控制锁,并对其进行了逆向工程,以构建一个原始调试器。
使用调试器,您将能够单步调试代码,设置断点,检查内存。您将使用调试器来找到一个解锁测试锁的输入,然后将其重播为一个真正的锁。
简而言之, 就是你现在在用调试器调试一个智能锁,试着解开这个锁吧。
汇编代码窗口
这是反汇编的对象文件。
它包含LockIT Pro将执行的所有汇编指令。使用鼠标滚轮查看说明。
调试控制台
这是调试器的输入。
在此处输入命令。首先键入“help”
可以看到代码的回显,最下方输入框是输入命令的地方,我们先输入一个help
这是调试器控制台。
它包含您输入的命令的输出。向后滚动并阅读帮助。
启动程序
运行程序。
键入“continue”或“c”以启动。
这是IO控制台。
在这里我们可以看到锁的输出。现在,它希望我们输入密码。
这里是输入密码的地方,与刚刚的调试控制台不同,这里输入的内容会被当成数据来交互,而不是命令
输入密码
你可以在这里进行输入,然后锁会识别你的输入,现在输入
test
然后点击send提交
按c
启动
CPU输出也在这里。
注意,这里也显示了CPU的输出。此时,您输入的密码不正确
这里提示 我们输入的密码不正确
这意味着程序已结束执行
重置CPU
重置CPU
让我们再试一次,但这次我们要通过CPU查看发生了什么,输入reset
来重置cpu状态
设置断点
设置一个断点
为了 了解发生了什么,我们将设置一个断点。当到达特定位置时,这将停止CPU执行。现在,输入“break-main”来中断名为“main”的函数。
输入break-main
,可以使cpu在运行到main函数的时候进入暂停状态。
然后再输入c
可以发现cpu会停在主函数上
CPU已暂停。
您可以看到蓝色背景设置了一个断点。通过单击指令删除断点,这样下次运行程序时,CPU就不会停在这里。您可以通过单击指令来添加任何断点(但在本教程中不可以)。
可以看到现在代码停在了主函数上,我们单击一下,就可以取消掉它(但在本关教程无法取消)
寄存器
这里是寄存器
他们显示此时cpu的状态
这个是 pc (Program counter)
它以16进制 展示了当前执行命令的地址。(在debug调试中 所有数字都是16进制)
这里是当前的指令
pc指向的内存的值展示在这里,你也可以在左侧的 汇编代码窗口看到这条指令。
继续执行程序
让我们单步运行程序,输入
step
ors
输入s
执行单步操作
我们运行了一个指令
我们正在执行的指令(红色指令)位于设置断点的位置之后。我们前进了一步。
可以看到我们只运行了一行命令,我们的断点在4438,现在单步执行完,cpu停在了443c
多次 单步操作
单步调试的方式,太缓慢了。键入step 5a
以执行一系列指令。记住:这个数字是16进制的——我们实际上要执行90行指令。
s 5a
或者 step 5a
执行90次单步操作(如果没遇到断点或代码结束,则会执行到当前行后的90行)
INT函数
这是INT函数(interrupt)
这是锁与用户交互的方式。通过发出中断,可以回显字符、请求输入或执行其他任何操作。
部分输出
程序的部分输出如图所示。
再次继续
输入continue
来运行到需要输入密码为止
你仍然不知道密码
但让我们再次输入test
来看看程序究竟发生了什么吧
从函数里走出去
您可以通过输入
out
退出当前函数。它一直运行到遇到下一个ret
(return)指令。所有函数都以“ret”指令结束,将它们返回给调用者。
您还没有退出到main函数,
out
可以缩写为f
表示finish
:请使用它。
再来一次
check_password函数
这个 check_password 函数看起来很有趣
设置断点
让我们在哪儿停下
输入break check_password
来设置这个检查密码函数的断点
运行到断点
输入c
或continue
分析函数指令
这看起来很像。。。
看起来是在检查你的密码是否正确
分析指令中
接下来要执行的指令是`mov.b @r15,r14`
这条命令的意思是 将r15指向内存的值逐字节的传给r14,注意看r15
在内存中查找r15的值(它的位置是0x439c)。注意到您输入的密码是如何存在的吗?
输入
s
执行单步操作来看cpu将值传给r14
注意看r14的值已被更改。0x74是字母t的16进制
现在再输入一个
s
,看看下一条指令,这会让r15的值增加 1
注意看r15的值已被增加
接下来的命令是让r12的值加1,输入
s
看它这样做
注意看r12的值也增加了1
test指令(如果不是零,则进行测试)
测试函数将r14中的值与常数0进行比较。然后,它将相应地在状态寄存器中设置flag 0。
输入
s
,看看比较的结果
jnz指令 (非零跳转指令)
这是一个条件跳转,它将在未设置flag 0时移动程序计数器pc
向回跳了8个字节。
非0跳,如果寄存器中sr
不是0, 则会将当前指令地址向上跳8字节 (448c
-8
=4484
4484是检查密码函数的起始地址)也就是再次执行检查密码函数
将鼠标悬停在
sr
上面可以查看已设置的标志。‘c’表示设置了Carry flag(进位)。如果最后一条指令的执行结果为0,则会设置flag 0。但事实并非如此。
输入
s
,让我们看看这个跳转
我们回到了起点
但别忘了,我们现在已经处理了一个字节的输入,并且使r12增加了1
虽然我们又回到了函数开头,但我们之前执行的那些指令结果不会撤销掉。
循环终将结束。
当r14为0时,跳转不会发生,我们将在地址0x448e处结束。用`break 448e`在那里设置一个断点。请注意,这是一个以16进制的地址。在调试器中输入的所有数字都是16进制
循环总是会结束的,这个循环的结束条件就是让jnz
不执行跳转。
理一下逻辑:
- 想让
jnz
不跳转,那就要让jnz
执行时,寄存器sr
值为 0. tst
指令控制了sr
,如果tst r14
执行成功(判断r14为0),则sr
为0r14
的值是从r15
传来的,而r15
的值是一个地址,在每次循环时都增加1,也就是向后读取一个字节
总结:函数会逐字节读取字符串写入r14中,在当前读取的字符为0x00时,tst r14
会将sr
设为0,jnz
也就不会跳转,循环就终止了。
取消断点
您还需要取消设置其他断点。输入unbreak check_password
输入unbreak check_password
取消掉 检查密码函数 的断点,方便我们查看调试结果。
输入
c
我们不再需要这个断点了,输入
unbreak 448e
取消掉
因为这里没有循环,所以要不要这个断点都没有意义了。
cmp指令(比较两个值)。
比较指令将r12中的值与常数9进行比较。请注意,r12现在是5。这是因为我们输入了一个4个字符的密码,其中一个额外的字符用于空字节。
jeq/jz指令(如果相等则跳转/如果为零则跳转)
如果比较为true(如果r12为9),则此函数将向前跳过4个字节。如果相等则跳转和如果零则跳转指令实际上是等效的:这是因为“cmp”在值相等时设置零标志。
没有设置flag0,所以跳转不会发生
输入 `s`
如果我们跳转成功会怎么样
来看看如果我们跳转成功会发生什么吧
改变pc的值
输入let pc=4498
来改变pc指针
如果4492的jz语句跳转成功则会跳到4498,我们作弊一下看看成功跳转会发生什么
输入
out
或f
看看接下来会发生什么
我们再次执行了test指令,它会检查r15是否为非0,并设置相应的状态标志
输入
s
继续
继续
s``r15
是1,是非零的,所以现在能够触发jnz
指令的跳转,我们再次输入s
完成!
我们正在移动授予访问权限的字符串,然后调用put,然后调用unlock_door。这意味着我们完成了开锁动作。
输入
c
让CPU继续执行
门已解锁
耶!
但别忘了,我们作弊了,我们将pc修改到了我们想要执行的位置。现在,让我们重新再来一次,但这次我们要输入正确的密码。
输入
reset
重置CPU
输入
c
继续运行
中断请求还有其他选项。
此复选框允许您输入十六进制编码的值,以便在需要输入特殊字符时使用。举个例子,当你想输入“test”的时候,必须输入“74657374”而不是“test”。
中断请求还有其他选项。
此按钮允许您关闭弹出窗口并返回调试器进行更多调查。您可以用“继续”来恢复CPU,这将返回此弹出窗口。
开始破解
现在让我们来解决它。我们知道如何使密码正确!
还记得r12需要是9吗?它为我们键入的每个字符增加一次,为结尾的空字节增加一次?所以我们只需要输入一个8个字符的密码。尝试将“password”作为输入。
在你提交了你的输入后,CPU会自动中断。这样可以更容易地调试正在发生的事情。(以前每次都会发生这种情况。)
继续,让我们看看一切是如何工作的
耶!
请记住,这是在调试器锁上。现在让我们对真正的锁做同样的事情,让我们的特工进入第一个仓库。
去干掉真正的锁
现在我们要在真正的锁上执行它。键入“solve”结束教程并执行此操作。您将无法运行任何调试命令,只需输入解决方案即可。
意思就是说,你不再可以单步运行,或是操作寄存器,你仅能够完成输入密码操作。
输入password