系列文章目录
第一章 汇编学习记录-二进制炸弹-x86架构
 第二章 汇编学习记录-二进制炸弹-arm64架构
 第三章 汇编学习记录-简单总结
文章目录
前言
学校课程计算机系统的实验二:二进制炸弹
 这里记录一下破解过程
 ps:答案仅供参考,拿走也没用,据老师说是根据我们的学号生成的
一、炸弹1
密码如下:I am for medical liability at the federal level.
 破解过程:
 

 <phase_1>中另一个参数放入%esi并一起作为<strings_not_equal>的参数,我们可以知道该参数即为炸弹1的密码
 接下来通过gdb来查看该参数,过程如下
 
 
二、炸弹2
密码如下:1 2 4 7 11 16
 首项为一个非负数,后面+1,+2,+3……
 破解过程:

首先看方法中,将<read_line>的返回值放入%rdi,充当参数
 
然后看<pharse_2>中,将栈指针先移动20字节,再将栈指针的值作为参数,传给<read_six_numbers>
 
在<read_six_numbers>中,我们读入了6个数,并放在<pharse_2>中开拓出的栈空间里
 
 回到<pharse_2>中,接下来是一个循环,用c语言表示大致为
int ebx = 1;
do{
	if(ebx>5)break;
	rax=ebx;
	edx=rbx-1;
	rdx=edx;
	ecx=ebx;
	ecx+=M[rsp+4*rdx];
	ebx++;
}while((M[rsp+4*rax]-ecx)!=0);
 
将其简化,我们知道若M[rsp+4*ebx]-M[rsp+4*(ebx-1)]==0,则符合条件。
 若将我们输入的数放在数组M中,那么其应该满足条件M[i-1]+i==M[i]
三、炸弹3
密码如下:
 0 236或1 -509或2 28或3 -945或4 0或5 -945
 破解过程:
 
 在<pharse_3>中,可以看到将$0x40334f放到%esi中作为scanf函数的参数,所以我们可以知道这个代表密码的格式
 
 通过gdb查看该字符出得到”%d %d”,可知密码是两个整数
 
 由jmpq *0x4031c0(,%rax,8)知道这里是使用switch进行跳转。当读入的第一个数>7时,破解失败
 
 
 通过gdb我们可以看到跳转表的内容
 
 通过跳转表,我们可以对其进行标记并分析
 当读入的第一个数为
又因为读入第一个数应<=5,排除后两个
四、炸弹4
密码如下:
 176 2或264 3或352 4
 破解过程:
 
 首先我们查看要求输入的字符串格式
 
 接下来,进入
 
 将整理为类似c语言的形式
 fun4(edi, esi){
//若将edi中定为n,esi中定为x
	//若x<=0,返回0
	if(edi<=0)return 0;
	else{
		push r12,rbp,rbx;
		ebp = edi;
		ebx = esi;
		if(edi==1){
			//若n==1,返回x
			eax=esi;
			pop r12,rbp,rbx;
		}else{
		//构造fun4(n-1,x)
		edi--;
		fun4(edi,esi);
		//将返回值+x保存
		r12d=rax+rbx;
		//构造fun4(n-2,x)
		edi=rbp-2;
		esi=ebx;
		fun4(edi,esi);
		//将返回值加上之前保存的值
		eax+=r12d;
		pop r12,rbp,rbx;
		//返回fun4(n-1,x)+x+ fun4(n-2,x)
		return rax;
		}
	}
}
 
进一步整理得到
int fun4(int n, int x){
	if(n<=0)return 0;
	else{
		if(n==1)return x;
		else{
			return fun4(n-1,x)+fun4(n-2,x)+x;
		}
	}
}
 
容易知道当n(%edi)=9时,fun4最终返回的值为88*x(%esi)
 
 回到<pharse_4>,可知输入的第1个数应为第2个数的88倍,且第2个数应为2、3、4
五、炸弹5
密码如下:
 5 115
 破解过程:
 
 先看输入答案的格式,为两个整数
 
 这段代码大致有几个过程
 将输入的第1个数对16求模
 进入循环
 将读入第1个数求模后记为x1,第2个数记为x2
 则循环可写成
edx =0;
ecx=0;
while(x1!=15){
	x1=M[x1];
	ecx+=x1;
}
 

 其中M是一个数组,通过gdb可查看其中的值{a,2,e,7,8,c,f,b,0,4,1,d,3,9,6,5}
 由简单的代入知道,若不停循环x1的值会形成一个不断重复的序列,a,1,2,e,6,f,5,c,3,7,b,d,9,4,8,0……
 由后面条件知,若循环完成后,edx不为15,则会爆炸
 那么x1只能在循环第15次时取f,所以x1的初始值应为5,同时经过简单的计算可知,此时ecx应为115,那么输入的第2个数也应该为115
六、炸弹6
密码如下:5 2 3 1 4 6
 破解过程:
 
 先读入6个数

 接下来时一个循环,整理这个循环
ebp=0;
while(ebp<=5){
	eax=M[ebp];
	eax--;
	if(eax>5)call<explode_bomb>;
	r12d=rbp+1;
	ebx=r12d;
	while(ebx<=5){
		rax=ebp;
		rdx=ebx;
		edi=M[rdx];
		if(edi==M[rax]) call<explode_bomb>;
		ebx++;
	}
	ebp=r12d;
}
 
我们可以知道这个二重循环的作用是确保读入的6个数字全都不同
 
 接下来还是循环
eax=0;
while(eax<=5){
	rcx=eax;
	edx=7;
	edx-=M[rcx];
	M[rcx]=edx;
	eax++;
}
 
这个循环是在将我们输入的每个数都对7求补,并放回原位
 
 
esi=0;
while(esi<=5){
	eax=1;
	edx=0x4052d0;
	rcx=esi;
	while(M[rcx]>eax){
		rdx=(rdx+8);
		eax++;
		rcx=esi;
	}
	rsp[rcx]=rdx;
	esi++;
}
rbx=(rsp);
rcx=rbx;
 

 通过gdb我们知道0x4052d0指向一个链表
 node1(0x39)->node2(0x3e5)->node3(0xc7)->node4(0x334)->node5(0x3ad)->node6(0xef)->null
 这个循环的效果是将链表各节点的地址以数组中数的顺序放到栈中
 
eax=1;
while(eax<=5){
	rdx=eax;
	rdx=rsp[rdx];
	(rcx+8)=rdx;// rcx=(rsp);
	eax++;
	rcx=rdx;
}
(rcx+8)=0;
 
进一步简化
rcx=rsp[0];
eax=1;
while(eax<=5){
	rdx=rsp[eax];
	rcx->next=rdx;
	rcx=rdx;
	eax++;
}
 
这个循环,将链表的结点按照栈中的顺序重新连接;
 
ebp=0;
while(ebp<=4){
	rax=(rbx+8);// rbx=(rsp);
	eax=(rax);
	if((rbx)>=eax){
	rbx=(rbx+8);
	ebp++;
	}else call<explode_bomb>
}
 
进一步简化
ebp=0;
rbx=rsp[0]
while(ebp<=4){
	rax=rbx->next;
	eax=rax->num;
	if(rbx->num>=eax){
	rbx=rbx->next;
	ebp++;
	}else call<explode_bomb>
}
 
这个循环检测重新排列的链表是否按照降序排列
 综上,我们应该将链表节点按照其中数字降序排序得到2 5 4 6 3 1,再对其与7求补,得到5 2 3 1 4 6
七、隐藏关
密码如下:7
 破解过程:
 
 先看<phase_defused>我们知道其与0x40576c处比较以决定是否跳转;
 通过gdb查看该处的值
 
 当输入字符串后,值发生变化
 
 
 我们可以知道,当输入六个字符串时,该函数才会继续分析,才有可能进入<secret_pharse>
 
 接下来,读入了三个值,且通过gdb可以看到其格式
 
 格式为两个整数和一个字符串
 查看0x405870处的值,
 在输入第四个字符串前
 
 在输入第四个字符串后
 
 可以看到0x405870处保存了输入的第四个字符串的值,
 
 接下来将读入的字符串与0x4033a2字符串进行比较
 
 
 在检测完字符串后,会输出特定字符串,并且进入<secret_pharse>
 综上,我们知道,在第四个炸弹输入密码时,在后面增加DrEvil,在完成六个炸弹后,即可进入<secret_pharse>

 将0x4050f0作为参数传给了,用gdb查看0x4050f0
 
 可以推测这里是一种二叉树
 
接下来进入,整理得到
fun7(rdi , esi){
	If(rdi==null){call<explode_bomb>}
	eax=rdi->num;
	if(eax>esi){
		rdi=rdi->lchild
		return 2*fun7(rdi , esi)
		
	}else if(eax <esi){
	rdi=rdi->rchild
	return 2*fun7(rdi , esi)+1
	}else return 0;
}
 

 通过后面分析知道的返回值应该为4
 我们算出
 
 由此知道,密码应为7










