当前位置:网站首页>探究CSAPP实验二-bomb lab-第一节
探究CSAPP实验二-bomb lab-第一节
2022-07-30 16:12:00 【代玛无能人士】
前言
之前学过一点汇编但是已经忘了,在工作中遇到所以重新开始学习,bomb lab即有趣又可以学习gdb的调试以及汇编代码的阅读,所以重点学习。此项目的地址为csapp实验地址以下为学习笔记。计划分为三篇文章来详细记录过程,本文为系列中的第一篇。
项目介绍
下载好项目后里面有个pdf文档,对这个项目进行了讲解。
意思概括为要成功拆除一个炸弹分为几个阶段,每个阶段都要输入相应的字符串才能拆除成功(stdin-标准输入),如果中间一个阶段拆除失败则炸弹爆炸。
文件目录如下:
来看看bomb.c里面的代码:
/*************************************************************************** * Dr. Evil's Insidious Bomb, Version 1.1 * Copyright 2011, Dr. Evil Incorporated. All rights reserved. * * LICENSE: * * Dr. Evil Incorporated (the PERPETRATOR) hereby grants you (the * VICTIM) explicit permission to use this bomb (the BOMB). This is a * time limited license, which expires on the death of the VICTIM. * The PERPETRATOR takes no responsibility for damage, frustration, * insanity, bug-eyes, carpal-tunnel syndrome, loss of sleep, or other * harm to the VICTIM. Unless the PERPETRATOR wants to take credit, * that is. The VICTIM may not distribute this bomb source code to * any enemies of the PERPETRATOR. No VICTIM may debug, * reverse-engineer, run "strings" on, decompile, decrypt, or use any * other technique to gain knowledge of and defuse the BOMB. BOMB * proof clothing may not be worn when handling this program. The * PERPETRATOR will not apologize for the PERPETRATOR's poor sense of * humor. This license is null and void where the BOMB is prohibited * by law. ***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "support.h"
#include "phases.h"
/* * Note to self: Remember to erase this file so my victims will have no * idea what is going on, and so they will all blow up in a * spectaculary fiendish explosion. -- Dr. Evil */
FILE *infile;
int main(int argc, char *argv[])
{
char *input;
/* Note to self: remember to port this bomb to Windows and put a * fantastic GUI on it. */
/* When run with no arguments, the bomb reads its input lines * from standard input. */
if (argc == 1) {
infile = stdin;
}
/* When run with one argument <file>, the bomb reads from <file> * until EOF, and then switches to standard input. Thus, as you * defuse each phase, you can add its defusing string to <file> and * avoid having to retype it. */
else if (argc == 2) {
if (!(infile = fopen(argv[1], "r"))) {
printf("%s: Error: Couldn't open %s\n", argv[0], argv[1]);
exit(8);
}
}
/* You can't call the bomb with more than 1 command line argument. */
else {
printf("Usage: %s [<input_file>]\n", argv[0]);
exit(8);
}
/* Do all sorts of secret stuff that makes the bomb harder to defuse. */
initialize_bomb();
printf("Welcome to my fiendish little bomb. You have 6 phases with\n");
printf("which to blow yourself up. Have a nice day!\n");
/* Hmm... Six phases must be more secure than one phase! */
input = read_line(); /* Get input */
phase_1(input); /* Run the phase */
phase_defused(); /* Drat! They figured it out! * Let me know how they did it. */
printf("Phase 1 defused. How about the next one?\n");
/* The second phase is harder. No one will ever figure out * how to defuse this... */
input = read_line();
phase_2(input);
phase_defused();
printf("That's number 2. Keep going!\n");
/* I guess this is too easy so far. Some more complex code will * confuse people. */
input = read_line();
phase_3(input);
phase_defused();
printf("Halfway there!\n");
/* Oh yeah? Well, how good is your math? Try on this saucy problem! */
input = read_line();
phase_4(input);
phase_defused();
printf("So you got that one. Try this one.\n");
/* Round and 'round in memory we go, where we stop, the bomb blows! */
input = read_line();
phase_5(input);
phase_defused();
printf("Good work! On to the next...\n");
/* This phase will never be used, since no one will get past the * earlier ones. But just in case, make this one extra hard. */
input = read_line();
phase_6(input);
phase_defused();
/* Wow, they got it! But isn't something... missing? Perhaps * something they overlooked? Mua ha ha ha ha! */
return 0;
}
argc指的是参数个数,比如如下:
这个./bomb就是一个参数,这里的argc为1,argv[0]=“./bomb”。那么根据代码
我们可以直接运行bomb文件,也可以后面跟上文件名,比如命令行中输入./bomb 1.txt的格式1.txt里面应该写入6个阶段对应字段,这里argc=2,argv[0]=“./bomb”,argv[1]=“1.txt”。从代码可以看出一共有六个阶段。
接下来开始我们的摸索之旅。
阶段1
使用gdb进行调试。
首先看看initialize_bomb函数。可以看看它的汇编代码,使用disassemble initialize_bomb命令。
从rsp寄存器大致可以看出这是64位汇编(32位汇编的栈顶寄存器是esp),需要注意的栈是后进先出的结构,在系统中栈是高地址往低地址走的,所以这里是sub,还需要注意的是在linux中是AT&T汇编格式,与intel稍有不同,比如mov A,B是A移到B。以上汇编其实没啥亮点,调用了信号量。
接下来看看phase_1汇编代码:
这里调用了strings_not_equal函数,所以输入的是一个字符串与它内置的字符串进行比较,这里test如果结果为0(即相同)就je(跳转)到add $0x8,%rsp指令,若不同则调用explode_bomb。在调用strings_not_equal函数前执行的汇编是mov指令,来看看$0x402400是什么值,已知是字符串,可以使用x/s查看(x可以查看内存地址中的值)。
来验证一下:
可以看到一阶段成功拆除。
答案:
Border relations with Canada have never been better.
阶段2
来查看phase_2函数的汇编代码,可在gdb中输入disasse phase_2。
前三行push %rbp; push %rbx; sub %0x28,%rsp与倒数二三四行对称(pop %rbp; pop %rbx; add %0x28,%rsp),可以看到在汇编指令中前面行中出现了+52而后面行中中出现了+27,所以一定是有循环的。如果想调试寄存器的变化情况可以在phase_2打入断点(b phase_2),然后运行,si是汇编语言级别的单步调试,i r可以显示寄存器信息,若想看具体的寄存器信息如rsp,可以i r rsp查看。x/i 地址可以看到这行地址对应的汇编代码。
以上汇编代码中调用了地址在0x40145c的read_six_numbers函数。我们可以来看看read_six_numbers函数的汇编代码:
前面的sub,mov,lea就不用看了,到地址0x0000000000401480地址处的汇编代码mov $0x4025c3,%esi,来看看地址0x4025c3装了什么东西,使用x/s 0x4025c3命令(以下是输入的格式,中间是空格)。
<+41>那里eax寄存器的值置为0x0,然后调用库函数(从plt可以知道)sscanf,结束后再<+51> eax与0x5进行比较,再jg(大于,即eax>0x5后这个函数结束),我分析是这里每输入一个整数(%d)eax加1,有六个所以输入后从0x0到0x6,输入六个后结束这个函数否则调用炸弹爆炸函数。
现在仔细分析下phase_2的汇编
0x0000000000400efc <+0>: push %rbp
0x0000000000400efd <+1>: push %rbx
0x0000000000400efe <+2>: sub $0x28,%rsp
0x0000000000400f02 <+6>: mov %rsp,%rsi
0x0000000000400f05 <+9>: call 0x40145c <read_six_numbers>
0x0000000000400f0a <+14>: cmpl $0x1,(%rsp)
0x0000000000400f0e <+18>: je 0x400f30 <phase_2+52>
0x0000000000400f10 <+20>: call 0x40143a <explode_bomb>
0x0000000000400f15 <+25>: jmp 0x400f30 <phase_2+52>
0x0000000000400f17 <+27>: mov -0x4(%rbx),%eax
0x0000000000400f1a <+30>: add %eax,%eax
0x0000000000400f1c <+32>: cmp %eax,(%rbx)
0x0000000000400f1e <+34>: je 0x400f25 <phase_2+41>
0x0000000000400f20 <+36>: call 0x40143a <explode_bomb>
0x0000000000400f25 <+41>: add $0x4,%rbx
0x0000000000400f29 <+45>: cmp %rbp,%rbx
0x0000000000400f2c <+48>: jne 0x400f17 <phase_2+27>
0x0000000000400f2e <+50>: jmp 0x400f3c <phase_2+64>
0x0000000000400f30 <+52>: lea 0x4(%rsp),%rbx
0x0000000000400f35 <+57>: lea 0x18(%rsp),%rbp
0x0000000000400f3a <+62>: jmp 0x400f17 <phase_2+27>
0x0000000000400f3c <+64>: add $0x28,%rsp
0x0000000000400f40 <+68>: pop %rbx
0x0000000000400f41 <+69>: pop %rbp
0x0000000000400f42 <+70>: ret
调用完read_six_numbers函数后,先比较0x1与(%rsp),(%rsp)是rsp指针指向的值,之前输入了六个整数,又栈是后进先出的结构,所以第一个数应该在esp位置,那么第一个整数就是1,才会执行jmp(跳转到<+52>),否则会爆炸。
大致画一下栈的图(六个整数):
0x4(%rsp)就是rsp的位置加上0x4即往高地址走(需要注意的是int型占4字节)。那么这里就是rsp移到第二个整数的位置,将地址加载到rbx,然后rsp的地址向上移动0x18,加载到rbp。再到<+27>,这已经很明显是一个循环程序了。重点解释下如下汇编(这里的编号为自定):
1 mov -0x4(%rbx),%eax
2 add %eax,%eax
3 cmp %eax,(%rbx)
4 je 0x400f25 <phase_2+41>
5 call 0x40143a <explode_bomb>
6 add $0x4,%rbx
7 cmp %rbp,%rbx
8 jne 0x400f17 <phase_2+27>
9 jmp 0x400f3c <phase_2+64>
现在的rbx的地址就是之前的0x4(%rsp)也就是第二个整数的地址,第一行第二个整数地址又回到第一行的地址,并将第一个整数地址对应的值赋值给eax,现在eax=1,再执行第二行 add %eax,%eax,现在的eax=2。将eax=2与rbx的地址里面的值进行比较((%rbx)相当于*(int *) rbx),如果相等跳到add $0x4,%rbx,即%rbx往高地址走,再rbp与rbx进行比较,如果二者不等跳到mov -0x4(%rbx),%eax,否则跳出循环(到<+64>)。
所以以上流程其实大致可以推测就是如下代码逻辑:
//1.输入六个数
array[0]=1;
//如果第一个不为1爆炸
for(int i=1;i<6;i++){
array[i]=array[i-1]+array[i-1];
//如果不等爆炸
}
那么这六个整数就是1 2 4 8 16 32。
验证一下,在phase_2处打断点(使用b phase_2指令,并且先要拆除phase_1),然后r起来,一行一行调试(汇编级别调试是si与ni指令,如果想进入read_six_numbers函数建议si)
这里eax,rbx的值都是地址,比如0x2,右边的2是0x2的十进制。
现在进行验证:
总结
看来以后见到mov 某个地址,esi的指令可以看看这个地址里的值是什么,阶段1与阶段2都用到了,还需要注意的是比如(%rbx)的意义。
边栏推荐
- @Bean注解详解
- Data Analysis Tools - DDL operations & DML operations in HQL
- arcpy使用教程
- Databases - create databases, tables, functions, etc.
- 【Linux Operating System】 Virtual File System | File Cache
- 【SOC FPGA】外设KEY点LED
- 初识二叉搜索树
- (一)云计算技术学习--虚拟化vSphere学习
- SocialFi 何以成就 Web3 去中心化社交未来
- Public Key Retrieval is not allowed报错解决方案
猜你喜欢
随机推荐
Qt 容器控件Tool Box 使用详解
Nervegrowold d2l (7) kaggle housing forecast model, numerical stability and the initialization and activation function
Horizontal Pod Autoscaler(HPA)
AI遮天传 DL-CNN
C语言学习之旅 【函数(二)】
详解最实用的几种dll注入方式
【HMS core】【FAQ】push kit、分析服务、视频编辑服务典型问题合集3
MySql 和 PostgreSQL 数据库 根据一张表update另一张表数据
Goland opens file saving and automatically formats
CAD几个优化设置
配置Path环境变量
PyQt5快速开发与实战 9.2 数据库处理
围绕用户思维,木鸟与途家如何实现乡村民宿下的用户运营
Scheduling_Channel_Access_Based_on_Target_Wake_Time_Mechanism_in_802.11ax_WLANs
go 学习03 基础知识变量类型
如何写一份高可读性的软件工程设计文档
游戏多开检测的几种实现方法及破解方法参考
SMI 与 Gateway API 的 GAMMA 倡议意味着什么?
win下搭建php环境的方法
How to intercept the first few digits of a string in php