2017-2018-1 20155239 《信息安全系统设计基础》第五周学习总结+mybash的实现
mybash的实现
- 使用fork,exec,wait实现mybash
- 写出伪代码,产品代码和测试代码
- 发表知识理解,实现过程和问题解决的博客(包含代码托管链接)
首先通过man命令了解fork、exec和wait
命令行输入:man fork
命令行输入:man exec
命令行输入:man wait
-
伪代码
while(1) { fgets(命令行输入); if(内置的shell命令) { 解释命令; } else if(可执行文件) { 新的子进程加载并运行文件; } }
产品代码
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#define MAX 128
void eval(char *cmdline);
int parseline(char *buf, char **argv);
int builtin_command(char **argv);
int main()
{
char cmdline[MAX];
printf("This is 20155212's bash!
");
while(1)
{
printf("> ");
fgets(cmdline, MAX, stdin);
if(feof(stdin))
exit(0);
eval(cmdline);
}
}
void eval(char *cmdline)
{
char *argv[MAX];
char buf[MAX];
int bg;
pid_t pid;
strcpy(buf,cmdline);
bg = parseline(buf,argv);
if(argv[0]==NULL)
return;
if(!builtin_command(argv))
{
if((pid=fork()) == 0)
{
if(execvp(argv[0],argv) < 0)
{
printf("%s : Command not found.
",argv[0]);
exit(0);
}
}
}
if(!bg)
{
int status;
if(waitpid(-1,&status,0) < 0)
printf("waitfg: waitpid error!");
}
else
{
printf("%d %s",pid, cmdline);
return;
}
}
int builtin_command(char **argv)
{
if(!strcmp(argv[0], "quit"))
exit(0);
if(!strcmp(argv[0],"&"))
return 1;
return 0;
}
int parseline(char *buf,char **argv)
{
char *delim;
int argc;
int bg;
buf[strlen(buf)-1]=' ';
while(*buf && (*buf == ' '))
buf++;
argc=0;
while( (delim = strchr(buf,' ')))
{
argv[argc++] = buf;
*delim= ' ';
buf = delim + 1;
while(*buf && (*buf == ' '))
buf++;
}
argv[argc] = NULL;
if(argc == 0)
return 1;
if((bg=(*argv[argc-1] == '&')) != 0)
argv[--argc] = NULL;
return bg;
}
测试代码
ls
ls -a
git --version
运行结果如下:
代码链接: https://gitee.com/bestiisjava2017/lvyuxuan20155239/blob/master/mybash.c
学习目标
-
理解逆向的概念
-
掌握X86汇编基础,能够阅读(反)汇编代码
-
了解ISA(指令集体系结构)
-
理解函数调用栈帧的概念,并能用GDB进行调试
教材学习内容总结
一、简单的汇编程序
-
汇编代码的特点:用可读性更好的文本格式来表示。
-
程序计数器(CS:IP)
-
整数寄存器(AX,BX,CX,DX)
-
条件码寄存器(OF,SF,ZF,AF,PF,CF)
学习了书上的代码例子
long mult2(long,long);
void multstore(long x,long y,long *dest){
long t= mult2(x,y);
*dest = t;
}
- 在命令行上使用“-S”选项,编译器产生的汇编代码:gcc -Og -S mstore.c
- “-c”命令行选项,则会编译并汇编该代码:gcc -Og -c mstore.c
如图所示:
以下面这段简单的汇编代码为例
.section .data
.section .text
.globl _start
_start:
movl $1, %eax
movl $4, %ebx
int $0x80
将这段程序保存为demo.s,然后用汇编器as把汇编程序中的助记符翻译成机器指令(汇编指令与机器指令是对应的)生成目标文件demo.o。然后用链接器ld把目标文件demo.o链接成可执行文件demo(虽然只有一个目标文件但是也需要经过链接才能成为可执行文件因为链接器要修改目标文件中的一些信息)。这个程序只做了一件事就是退出,退出状态为4。shell中可以echo$?得到上一条命令的退出状态。
运行如下:
二、寻址方式
访问内存时在指令中可以用多种方式表示内存地址。内存寻址在指令中可以表示成如下的通用格式:
ADDRESS_OR_OFFSET(%BASE_OR_OFFSET,%INDEX,MULTIPLIER)
它所表示的地址可以这样计算出来:
FINAL ADDRESS = ADDRESS_OR_OFFSET + BASE_OR_OFFSET + MULTIPLIER * INDEX
其中ADDRESS_OR_OFFSET和MULTIPLIER必须是常数,BASE_OR_OFFSET和INDEX必须是寄存器。在有些寻址方式中会省略这4项中的某些项,相当于这些项是0。
直接寻址:只使用ADDRESS_OR_OFFSET寻址,例如movl ADDRESS, %eax把ADDRESS地址处的32位数传送到eax寄存器。
变址寻址:movl data_items(,%edi,4), %eax就属于这种方式,用于访问数组很方便
间接寻址:只使用BASE_OR_OFFSET寻址,例如movl (%eax), %ebx,把eax寄存器的值看作地址,把这个地址处的32位数传送到ebx寄存器。
基址寻址:只使用ADDRESS_OR_OFFSET和BASE_OR_OFFSET寻址,例如movl 4(%eax), %ebx,用于访问结构体成员比较方便,例如一个结构体的基地址保存在eax寄存器中,其中一个成员在结构体内偏移量是4字节,要把这个成员读上来就可以用这条指令。
立即数寻址:就是指令中有一个操作数是立即数,例:movl $3, %eax。
寄存器寻址:就是指令中有一个操作数是寄存器。在汇编程序中寄存器用助记符来表示,在机器指令中则要用几个Bit表示寄存器的编号,这几个Bit与可以看做寄存器的地址,但是和内存地址不在一个地址空间。
教材学习中的问题和解决过程
老师提过反汇编的使用,我一直没有理解,上网学习了一些资料,首先要知道什么是反汇编?
这里我必须要学习下总结一下汇编和反汇编的区别了:
汇编:
-
动词,指的是把汇编语言翻译成机器语言的过程。
就是图中hello.s文件经过汇编器变成二进制hello.o文件的过程。 -
名词,指的便是汇编语言
就是hello.c经过预处理器,再经过编译器生成的hello.s文件。这个文件里的东西就叫汇编程序(汇编语言)。 -
在linux查看.s文件(Ps:源程序为test.c)
我们可以输入gcc-O -S test.c直接生成test.s文件,然后用vim编辑器打开它:gcc -O -S test.c
反汇编
- 动词,指的是由已生成的机器语言(二进制语言)转化为汇编语言的过程,也可以说是汇编的逆向过程。
- 名词,指的是有机器语言经过反汇编过程生成的汇编语言。
- 在linux下对利用反汇编器对.o文件进行反汇编。
objdump -d test.o
可以发现,反汇编生成的汇编代码,每一行前面都有一串16进制的数字。这些数字就是每一行汇编代码对应的机器代码。
代码调试中的问题和解决过程
- 问题1:P107
利用vim编写一个xxx.c文件
gcc -S xxx.c得到汇编文件xxx.s
代码:
int accm = 0;
int sum(int x,int y)
{
int t = x + y;
accm += t;
return t;
}
运行如下:
问题:生成的汇编文件打开的是空的,发现-s应该是大写-S
代码托管
(statistics.sh脚本的运行结果截图)
上周考试错题总结
- 错题1及原因,理解情况
- 错题2及原因,理解情况
- ...
结对及互评
点评模板:
- 博客中值得学习的或问题:
- xxx
- xxx
- ...
- 代码中值得学习的或问题:
- xxx
- xxx
- ...
- 其他
本周结对学习情况
- [结对同学学号1](博客链接)
- 结对照片
- 结对学习内容
- XXXX
- XXXX
- ...
其他(感悟、思考等,可选)
xxx
xxx
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 200/200 | 2/2 | 20/20 | |
第二周 | 300/500 | 2/4 | 18/38 | |
第三周 | 500/1000 | 3/7 | 22/60 | |
第四周 | 300/1300 | 2/9 | 30/90 |
尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。
-
计划学习时间:XX小时
-
实际学习时间:XX小时
-
改进情况:
(有空多看看现代软件工程 课件
软件工程师能力自我评价表)