Bomb Lab phase_2 汇编解析:如何推导需输入的6个校验数字
从汇编推导Phase_2输入的完整步骤
基础概念对齐
read_six_numbers的固定作用是把用户输入的6个32位整数,按输入顺序连续存储在栈空间中,起始地址就是传入的%rsp。我们把这组数字按顺序记为num[0]到num[5],每个数字占4字节,对应的内存偏移为:
num[0]: 地址(%rsp),偏移0num[1]: 地址0x4(%rsp),偏移4num[2]: 地址0x8(%rsp),偏移8num[3]: 地址0xc(%rsp),偏移12num[4]: 地址0x10(%rsp),偏移16num[5]: 地址0x14(%rsp),偏移20
栈金丝雀相关的代码(%fs:0x28的读写、最后的异或校验)是系统的栈溢出保护逻辑,和输入校验完全无关,可以直接忽略。
第一步:拆解前置硬校验逻辑
读入6个数字后,代码的两次判断触发爆炸的分支非常明确,绕开objdump的地址偏移误导后,实际规则为:
- 第一个判断:比较
num[0]和0,不相等直接触发爆炸,也就是num[0]必须等于0。 - 第二个判断:比较
num[1]和1,不相等直接触发爆炸,也就是num[1]必须等于1。
很多人卡在这里是被跳转目标的偏移误导,误以为num[0]非0可以跳过校验,实际上两个判断是串联的硬约束,只要不满足就会炸。
第二步:拆解循环校验的递推规则
完成前置校验后,代码初始化两个指针:
%rbx被设置为栈数组的起始地址,也就是指向num[0]%rbp被设置为%rbx + 0x10,也就是指向num[4]的地址,作为循环的终止边界
逐行拆解循环内的执行逻辑:
- 取当前
%rbx指向位置的下一个数字存入%eax:如果当前%rbx指向num[i],取到的值就是num[i+1] - 把
%rbx指向的当前数字加到%eax中,此时%eax的值为num[i] + num[i+1] - 比较
%rbx指向位置的下下一个数字(也就是num[i+2])和%eax的值,不相等直接触发爆炸 - 比较通过后,把
%rbx的值加4,也就是指针往后移动一个元素的位置,指向num[i+1] - 检查当前指针是不是已经到达边界
num[4]的位置,如果到达就跳出循环,否则继续下一轮校验
把循环执行的所有校验项列出来:
- 第一轮:校验
num[2] == num[0] + num[1],校验通过后指针移到num[1]位置 - 第二轮:校验
num[3] == num[1] + num[2],校验通过后指针移到num[2]位置 - 第三轮:校验
num[4] == num[2] + num[3],校验通过后指针移到num[3]位置 - 第四轮:校验
num[5] == num[3] + num[4],校验通过后指针移到num[4]位置,此时指针到达边界,跳出循环,关卡通过
第三步:计算最终的输入序列
结合前置硬约束和循环递推关系,逐个数计算:
num[0] = 0(硬约束)num[1] = 1(硬约束)num[2] = num[0] + num[1] = 0 + 1 = 1num[3] = num[1] + num[2] = 1 + 1 = 2num[4] = num[2] + num[3] = 1 + 2 = 3num[5] = num[3] + num[4] = 2 + 3 = 5
最终满足要求的6个输入数字依次为0 1 1 2 3 5。
内容的提问来源于stack exchange,提问作者user15278585
相关产品推荐
相关产品推荐

