一、汇编指令介绍
1.数据传送指令(movl)
其中:
Imm
表示操作数,Reg
表示寄存器,Mem
表示存储器,
(%eax)
表示%eax寄存器的内存地址。
注意:不能两个操作数都为内存地址;
总结:
- movl %eax, %ebx 意思是把32位的EAX寄存器值传送给32为的EBX寄存器值。
- 其中%eax可理解成c语言的一个变量temp,(%eax)这种形式的可理解成一个指针变量*p。
- 若遇到8(%ebp) ,可理解地址[ebp+8],%ebp表示起始地址,8可理解为偏移量。
- 指令格式多采用小写, 寄存器名的前面加”%”前缀,立即数前加”$”前缀。
- 很多指令带后缀(如上面代码中的 movl,addl中的l就是后缀),用来表示指令访问的操作数的宽度。对于32位的机器,后缀”b”表示8位,”w”表示16位,”l”表示32位。
2.cmp指令
- cmpl b, a
- 相当于计算a-b,但并不保存结果
- 主要是为了设置标志寄存器的标志位
- 比如如果a==b,则ZF被设置
3.jmp:无条件跳转
4.jz/jnz:如果a==b/a!=b则跳转
- je 或jz 若相等则跳转(机器码74 或0F84)
5.call指令与ret指令
- call指令:保存现场(返回地址,标志寄存等 )并跳转。
- ret指令:得到返回地址并返回。类似于return 。
6.sub指令
- 比如: sub $0x10,%esp
表示 为esp分配了16个字节空间. 可理解为c语言中的 int a ;进行初始化。
7.test指令
- 将两个操作数进行逻辑与运算,并根据运算结果设置相关的标志位。
- Test的一个非常普遍的用法是用来测试一方寄存器是否为空:
test ecx, ecx jz somewhere 如果ecx为零,设置ZF零标志为1,Jz跳转
二、 题目分析
08048b90 <phase_1>:
sub $0x1c,%esp //为phase_1函数的栈分配28字节的空间
mov $0x804a204, 0x4(%esp)//将地址0x804a204中存的东西入栈。
mov 0x20(%esp), %eax //把%ebp+0x20位置存放的东西赋给%eax。
mov %eax, (%esp) //把%eax存到%esp指向的位置,即栈顶
call 80490da <strings_not_equal> //调用这个函数
test %eax, %eax
je 8048bb0 <phase_1+0x20> //test 与je一起用,进行判断是否%eax为0,如果为0,就执行下一个函数。
call 80491e5 <explode_bomb> //执行explode_bomb函数
add $0x1c, %esp //返回栈顶
ret
- ` mov 0x20(%esp), %eax `
mov %eax, (%esp)
最开始不太明白为什么要这样赋值,0x20(%esp)中的应该是存放的用户输入,为什么先赋给%eax,再把%eax存放到%esp指向的位置。 后来我知道了,可见上面的注意: 不能两个操作数都为内存地址; *call 80490da <strings_not_equal>
根据函数名可知,这应该是判断两个字符串是否相等的函数,如果不相等返回1,如果相等返回0;具体函数代码还没有仔细分析,明天接着看! test %eax, %eax
je 8048bb0 <phase_1+0x20>
这两个语句往往搭配一起使用,如果%eax为0,设置ZF零标志为1,Je跳转,就是跳转到下一个程序的地址,即执行下一个phase程序。call 80491e5 <explode_bomb>
上面跳转条件不成立时,即%eax不为0,就执行explode_bomb,根据名字可知这是一个引爆程序。
总结
解决此题的关键是找出0x804a204
存放的字符串,然后输入一个与其相同的,即可进入下一个phase程序。
三、gdb调试器的使用
-
输入gdb bomb 即可加载bomb程序
可以使用examine命令(简写是x)来查看内存地址中的值。x命令的语法如下所示:
x/<n/f/u> <addr>
n、f、u是可选的参数。
-
n是一个正整数,表示需要显示的内存单元的个数,也就是说从当前地址向后显示几个内存单元的内容
- f 表示显示的格式,参见下面。
- u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes。u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字 节,g表示八字节。当我们指定了字节长度后,GDB会从指内存定的内存地址开始,读写指定字节,并把其当作一个值取出来
x系列
x/xw addr 显示某个地址处开始的16进制内容,如果有符号表会加载符号表
x/x $esp 查看esp寄存器中的值
x/s addr 查看addr处的字符串
x/b addr 查看addr处的字符
x/i addr 查看addr处的反汇编结果
四、遇到问题:
我发现 ubuntu命令行下 输入./无法打开bomb可执行文件,但是我ls查看明明存在bomb程序,可执行文件存在但是不能执行,一般都是报错No such file or directory觉得很奇怪,怎么也发现不了问题所在,最后我找到了原因:
在64位系统上,出问题的可执行文件是32位的。通过file
命令可以看到这个可执行程序的位数,通过ldd
可以查看这个可执行文件需要的动态链接库,比如:
# ldd xxx
linux-gate.so.1 (0xf7f44000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7d4b000)
/lib/ld-linux.so.2 (0xf7f46000)
如果这个文件却是存在,但是不能执行,而文件又没有损坏,那很可能就是因为依赖的动态库不存在,一般是这个:
/lib/ld-linux.so.2
有这个库才能在64位的系统上执行32位的程序,所以根据你的系统,把这个库安装上即可。命令就是:
sudo dpkg --add-architecture i386
sudo apt install libc6:i386