2023-2024-2 20232801 刘莹《Linux内核原理与分析》第二周作业

实验一:反编译一个简单的C程序

第一步

创建编辑一个 mian.c文件 ,内容图二所示。

第二步:

使用 gcc -S -o mian.s main.c 32命令将C程序编译成汇编代码。

打开main.s文件如图所示。

第三步:

将  . 开头的文件,删掉。因为他是链接产生的临时性文件,对程序无影响,留下来的就是纯汇编代码。

X86汇编指令

执行分析代码:

1、eip寄存器:指向指令。从main指令的第一条开始

2、ebp寄存器:指向堆栈的栈底(对某一条函数相对来说的栈底)

3、esp寄存器:总是指向堆栈的栈顶。

4、eax寄存器:将函数的默认返回值使用eax寄存器存储返回给上一级函数。

分析:eip寄存器的值,指向main()函数的命令,执行程序。注意压栈是往低地址走,出栈是往高地址走。

  • pushl %ebp:ebp寄存器的值压入栈中,esp的值向下移动4个字节(地址位置-4)
  • movl %esp,%ebp:ebp位置更新,将ebp位置移到esp位置。
  • subl $4,%esp:esp寄存器中的内容-4( ‘$’表示立即数),即再将esp寄存器中的内容改为刚才内容(刚才记录的栈顶地址,也是刚才的基地址)的下面一个单元(低4字节)作为esp寄存器中心的内容。
  • movl 8(%ebp),通过ebp寄存器变址寻址,ebp寄存器的值加8(注意是加,是向栈顶跑,而且实际不存,只是算一下,不改变ebp存入的值),当前ebp寄存器的内容为栈的第四个单元的地址,加8后ebp寄存器的内容为栈的第二个单元的地址,而此时那个地址里的内容是立即数“8”(也就是说"8(%ebp)"得到的结果是立即数“8”),然后把立即数"8"存入eax寄存器就好。
  • call f  :表示调用f函数。对应两条指令 push eip  move f eip   esp寄存器的值-4(存的内容是下一个单元的地址),将eip中的值“23”(eip中的值“23”是因为执行到“22”,在执行call命令时eip自动+1,eip里面始终存的是下一条指令的地址,如此一来函数f调用结束的时候,就可以找到回来的路,函数调用结束后从23条命令继续执行)存入第3个栈单元(第1个栈单元里存着栈顶地址,为ebp最初的值,第2个栈单元里存着立即数“8”),保存好之后,eip内存的值就可以更换成“9”了,因为“9”为f的第一条指令。所以,call指令改变了三个内容:1、栈空间(存入了回去的路,eip的旧值“23”);2、esp寄存器的值(由第二个栈单元的地址变为第三个栈单元的地址);3、eip寄存器的值(旧值“23”,新值为“9”,定位到函数f的第一条指令的位置)。
  • 进入f函数,开始执行。pushl %ebp,此时也类似main第一句的情况,先让esp内容减4(指向栈的第四个单元),再把ebp的值(为栈顶地址-4,即第一个单元的位置,和开始压栈完后保持一致)放入栈的第4个单元中。movl %esp,%ebp就是同main的第二句,用栈的第四个单元的地址替换了ebp中原先存的栈的第一个单元的地址。subl $4,%esp同main的第三句,让esp里存的内容改为栈的第五个单元的地址。movl 8(%ebp),%eax中是说通过ebp寄存器变址寻址,ebp寄存器的值加8(向栈顶跑,不改变ebp存入的值),当前ebp寄存器的内容为栈的第四个单元的地址,加8后ebp寄存器的内容为栈的第二个单元的地址,而此时那个地址里的内容是立即数“8”(也就是说"8(%ebp)"得到的结果是立即数“8”),然后把立即数"8"存入eax寄存器就好。movl %eax,(%esp)就是说把eax中的立即数"8",放入esp中地址所指向的那个栈单元,那个栈单元显然是栈的第5个单元的地址,所以栈的第5个单元里的内容为立即数"8"。call g,调用G函数 。1、栈的第6个单元存入了回去的路,即eip旧值“15”;2、esp寄存器的值(由第5个栈单元的地址变为第6个栈单元的地址);3、eip寄存器的值(旧值为“15”,新值为“2”,定位到函数g的第一条指令的位置)
  • 进入g函数,开始执行。g函数的第一句,esp-4(方便esp存的那个地址指向的那个栈的第七个单元去存ebp的值),把ebp的值(为第4个栈单元的地址存入第7个栈单元中,如此是为了保存现场,这也是从函数g“回去”函数f之后,需要使用的栈基址的值(为第四个栈单元的地址)第二句让ebp的值改为第7个栈单元的地址,第三句eax最后取出的为第五个栈单元的内容立即数"8"(第7个栈单元的地址加8,也即向上两个单元),第四句就是让立即数"8"和立即数"3"做加法,得到的结果"11"存入eax寄存器(暂存器)中。第五句和第六句popl %ebp,ret的作用就是拆除函数g的调用堆栈,并返回到调用函数f的位置。popl %ebp实际上就是把第7个栈单元的内容(ebp旧内容"第4个栈单元的地址")放回ebp寄存器,就是恢复函数f的函数调用堆栈基址ebp寄存器,效果是ebp寄存器的内容变为原来第4个栈单元的地址,同时esp寄存器也要加4个字节指向第6个栈单元的位置。 所以popl的两个作用和pushl的两个作用是对称的,popl先把ebp旧址还原,然后栈向上加4个字节(一个单元)。 ret实际上就是popl %eip,也就是把esp寄存器所指向的栈空间存储单元——第六个栈单元的内容(eip旧址“15”)放回到eip中,同时esp寄存器加4个字节到第5个栈单元的位置,总之ret的作用还原eip旧址,同时esp自动加4
  • 跳回到函数f的倒数第二句leave,leave指令的作用等价于movl %ebp,%esp和popl %ebp两条指令它的目的是撤销函数的堆栈,把esp的值改为ebp的值(基址),再把ebp旧址还原,栈再向上加4个字节,此时的esp的内容为第3个栈单元的地址。
  • 函数f的ret同之前ret的作用.
  • 再返回到main函数的leave以及ret,同上。

过程展示

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值