Phase 6
Phase 6 的汇编又臭又长,先把 Phase 6 反汇编出来
完整的代码就不放了,先来一段段分析
Section 1
这一段是函数调用相关的,不用过多的在意,不过注意最后一行调用了 read_six_numbers
,根据之前的练习中,这个函数会读取 6 个数字并放在 %rsp~%rsp+0x14
中(这里可以用 GDB 的 x/d
打印检查)
Section 2
下面开始正文了,先上代码
最后一行的 401151
可以看出外层嵌套了一个大的循环,401117
中,将 eax
赋值为 r13
指向的地址,也就是第r12d
个输入变量,然后 40111e
的比较确保了输入变量是小于 6 的
内层循环中,则是取出第 r12d
个输入变量后边的,依次与 eax
比较,确保每个变量都不相同
Section 3
rax
每次增加 4 个 Byte 来读取下一个 Int ,并且将 rax
与 rsp+0x18
比较
每次用 0x7
减去
Section 4
这里就开始比较恶心了,先看里边有个 Magic Number 0x6032d0 ,用 GDB 打印出来发现是这样的:
1 | (gdb) x/24 0x6032d0 |
说实话我也不懂这个是什么(???),一番百度 Google 后发现这是一个链表,结构大概是这样的
注意这里的Next地址
是十进制表示的,要记得把它转换成十六进制
地址 | 值 | 序号 | Next地址 |
---|---|---|---|
0x6032d0 | 332 | 1 | 0x6032e0 |
0x6032e0 | 168 | 2 | 0x6032f0 |
0x6032f0 | 924 | 3 | 0x603300 |
0x603300 | 691 | 4 | 0x603310 |
0x603310 | 477 | 5 | 0x603320 |
0x603320 | 443 | 6 | 0 |
循环中, ecx
用来存取当前所读取的输入变量,最后一行跳转到 401176
,因为链表的每个 Node 都是两个 Int 和一个 Pointer 组成的,所以 401176
中获得下一个 Node 的地址,并且用 eax
来做计数变量,可以看出这几行的作用就是使得 rdx
中存的是第 ecx
个链表元素
然后下边的就是在 0x20+rsp+rsi*2
后边添加上第 ecx
个 Node 的地址
举个例子,如果输入是 6 5 4 3 2 1
这一步就会把链表第六个 Node 的地址放到栈顶第一位,第五个放到第二位…
Section 5
这里的工作就像注释所说的:把新的链表重新连接起来
Section 6
这里比较的是新链接的链表的前一个元素的 Value 大于后一个元素的
Final
综上,这个逻辑总算是理清楚了:首先从输入读取 6 个数字,确保每个数字都是小于等于 6 并且只出现一次,然后将链表重新排序为按照输入的顺序,最后验证新的链表的前一项大于后一项
链表中的值分别是 332 168 924 691 477 433
,所以输入就是 4 3 2 1 6 5
有时间把之前的 Phase 补齐吧(Flag)
EOF.