网络安全实验室第九周学习内容(1)

一.函数调用栈的操作以及栈帧的概念。

文章知识引用于

PWN入门(1-1-1)-C函数调用过程原理及函数栈帧分析(Intel) (yuque.com)

C语言函数调用栈(一) - clover_toeic - 博客园 (cnblogs.com)

C语言函数调用栈(二) - clover_toeic - 博客园 (cnblogs.com)

1.基础知识

函数:就是一段封装了一段流程结构的代码。

在X86计算机中,内存空间栈主要用于保存函数的参数,返回值,返回地址,本地变量等。

2.寄存器

寄存器是处理器加工数据或运行程序的重要载体,用于存放程序执行中用到的数据和指令。因此函数调用栈的实现与处理器寄存器组密切相关。

3.栈是什么

栈是一种LIFO形式的数据结构,所有的数据都是先进后出,这种形式真好满足了我们调用函数的方式:父函数调用子函数,父函数在前,子函数在后;返回时,子函数先返回,父函数古后返回。

栈支持俩种操作方式:push将数据压入栈中,pop将栈中的数据弹出并存储到指定的寄存器或内存

栈的生长方向是由高地址到低地址;

pop操作后,栈中的数据没有被清空,只是该数据我们无法直接无法访问。

4.栈帧

其本质也是一种栈,只是这种栈专门用于保存函数调用过程中的各种信息(参数,返回地址,本地变量等)。栈帧有栈顶(地址最低)和栈底(地址最高)之分,SP(栈指针)就是一直指向栈顶的。用ebp指向栈底,用esp指向栈顶。

一般来说,将ebp和esp之间的区域叫做栈帧,并不是整个栈空间只有一个栈帧,每调用一个函数,就会生成一个新的栈帧。

5.函数调用操作

  函数调用时的具体步骤如下:

     1) 主调函数将被调函数所要求的参数,根据相应的函数调用约定,保存在运行时栈中。该操作会改变程序的栈指针。

     注:x86平台将参数压入调用栈中。而x86_64平台具有16个通用64位寄存器,故调用函数时前6个参数通常由寄存器传递,其余参数才通过栈传递。

     2) 主调函数将控制权移交给被调函数(使用call指令)。函数的返回地址(待执行的下条指令地址)保存在程序栈中(压栈操作隐含在call指令中)。

     3) 若有必要,被调函数会设置帧基指针,并保存被调函数希望保持不变的寄存器值。

     4) 被调函数通过修改栈顶指针的值,为自己的局部变量在运行时栈中分配内存空间,并从帧基指针的位置处向低地址方向存放被调函数的局部变量和临时变量。

     5) 被调函数执行自己任务,此时可能需要访问由主调函数传入的参数。若被调函数返回一个值,该值通常保存在一个指定寄存器中(如EAX)。

     6) 一旦被调函数完成操作,为该函数局部变量分配的栈空间将被释放。这通常是步骤4的逆向执行。

     7) 恢复步骤3中保存的寄存器值,包含主调函数的帧基指针寄存器。

     8) 被调函数将控制权交还主调函数(使用ret指令)。根据使用的函数调用约定,该操作也可能从程序栈上清除先前传入的参数。

     9) 主调函数再次获得控制权后,可能需要将先前的参数从栈上清除。在这种情况下,对栈的修改需要将帧基指针值恢复到步骤1之前的值。

     步骤3与步骤4在函数调用之初常一同出现,统称为函数序(prologue);步骤6到步骤8在函数调用的最后常一同出现,统称为函数跋(epilogue)。函数序和函数跋是编译器自动添加的开始和结束汇编代码,其实现与CPU架构和编译器相关。除步骤5代表函数实体外,其它所有操作组成函数调用。

二. 了解保护机制,栈溢出原理

摘自

 栈溢出原理 - CTF Wiki (ctf-wiki.org)

栈溢出指的是程序向栈中某个变量中写入的字节数超过了这个变量本身所申请的字节数,因而导致与其相邻的栈中的变量的值被改变。这种问题是一种特定的缓冲区溢出漏洞,类似的还有堆溢出,bss 段溢出等溢出方式。栈溢出漏洞轻则可以使程序崩溃,重则可以使攻击者控制程序执行流程。此外,我们也不难发现,发生栈溢出的基本前提是

  • 程序必须向栈上写入数据。
  • 写入的数据大小没有被良好地控制。

三. pwndbg基础动态调试的应用

1、gdb与pwndbg


GDB——The GNU Project Debugger.是Linux下面的一款强大的基于命令行的软件调试器。

GDB的所有操作都基于命令行进行,有别于windows上的各种调试器。

GDB的调试目标主要是带源代码的软件,即进行开发调试。若想要进行逆向工程调试,则需要GDB插件来提供额外的功能。pwndbg专门针对pwn题调试添加了额外的功能。


2.调试

1.编译某一程序:gcc  
                                gcc -m32 -o test test.c

                                或gcc test.c -o test

                                或gcc -Wall -g -o test test.c

-Wall 代表编译器在编译过程中会输出警告信息(Warning),比如有些变量你并没有使用,指针指向的类型有误,main 函数没有返回整数值等。

-g 代表编译器会收集调试(debug)信息,这样如果你的程序运行出错,就可以通过 gdb 或者 lldb 等工具进行逐行调试,方便找出错误原因。

-o 代表编译器会将编译完成后的可执行文件以你指定的名称输出到你指定的文件夹下。-o 的空格后的名称就是输出的文件的名称。如果不加这个参数,每次编译后生成的可执行文件都会放在根目录下,名字叫做 a.out。每次编译成功后都会把上一次的 a.out 文件覆盖。

-m32:编译32位程序

2.gdb test
3.反汇编:disass main
4.常用的调试命令
    1.b xx
        设置断点(b是breakpoint的缩写)

        b 函数名        //在指定函数的起始处设置断点

        b 行号        //在指定代码行设置断点

        b 文件名:函数名

        b 文件名:行号

        b +偏移量

        b -偏移量

        b *地址        //不建议使用

    2.r
        运行的意思(r是run的缩写),一般用来代码开始运行,或者重新运行(如果调试到一半又想从头开始运行)   

        n(不会进入函数内部)

        s(会执行到函数内部)

        c

        start(无断点时)


    3.c
        继续执行(c是continue的缩写),当执行r运行到某个断点后,后面想继续执行到下一个断点或者把剩下代码执行完毕,就可以使用c


    4.n
        next的意思,执行当前行代码


    5.s
        step的意思,当一行代码里有函数调用,那么执行s会跳入函数里执行,如果没有函数调用,那么效果和n相同


    6.info xx
        查看一些信息,如断点或者局部变量,分别是info b和info locals

        i r,查看寄存器

        查看断点信息:info br,简写:i b

info register $ebp 查看寄存器ebp中的内容 (简写为 i r ebp)

i r eflags 查看状态寄存器

i r ss 查看段寄存器

i functions 查看所有的函数

disas addr 查看addr处前后的反汇编代码

stack 20 查看栈内20个值

show args 查看参数

vmmap 查看映射状况 peda带有

readelf 查看elf文件中各个段的起始地址 peda带有

parseheap 显示堆状况 peda带有


    7.p xx
        p是print的缩写,打印某个变量的值。

p system/main 显示某个函数地址

p $esp 显示寄存器

p/x p/a p/b p/s。。。

p 0xff - 0xea 计算器

print &VarName 查看变量地址

p * 0xffffebac 查看某个地址处的值


    8.set xx
       
        设置某个变量的值

    9.x
        指定大小 起始内存地址,即查看起始内存地址上指定大小的内存里的值。如x /3b 0x11223344,就是查看以0x11223344开始的3个字节的值,也可以是x /3w 0x11223344,就是查看以0x11223344开始的3个word的值

命令格式:x/<n/f/u> <addr>

n是一个正整数,表示需要显示的内存单元的个数

f 表示显示的格式(可取如下值: x 按十六进制格式显示变量。d 按十进制格式显示变量。u 按十进制格式显示无符号整型。o 按八进制格式显示变量。t 按二进制格式显示变量。a 按十六进制格式显示变量。i 指令地址格式c 按字符格式显示变量。f 按浮点数格式显示变量。)

u 表示从当前地址往后请求的字节数 默认4byte,u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字节,g表示八字节

<addr>表示一个内存地址

x/xw addr 显示某个地址处开始的16进制内容,如果有符号表会加载符号表

x/x $esp 查看esp寄存器中的值

如x $ebp-0x2c

x/s addr 查看addr处的字符串

x/b addr 查看addr处的字符

x/i addr 查看addr处的反汇编结果

 10.bt
        backtrace的缩写,回溯,当使用s进入某个函数后,输入bt可以打印该函数的栈帧
    list,在命令行下显示源码,可以是list或者list 行号,后者是以指定行号为基准,显示该行号前后的代码


    11.q
        quit的意思,即退出gdb调试

     12. 删除断点
        delete <断点id>:删除指定断点        //也可简写delete为d

        delete:删除所有断点

        clear 函数名

        clear 行号

        clear 文件名:行号

        clear 文件名:函数名

13.finish 
   执行完当前函数返回到调用它的函数。运行程序,直到当前函数运行完毕返回再停止。例如进入的单步执行如果已经进入了某函数,而想退出该函数返回到它的调用函数中,可使用命令finish.  

14.(gdb) jump 5 
   跳转执行程序到第5行:这里,可以简写为"j 5"需要注意的是,跳转到第5行执行完毕之后,如果后面没有断点则继续执行,而并不是停在那里了。另外,跳转不会改变当前的堆栈内容,所以跳到别的函数中就会有奇怪的现象,因此最好跳转在一个函数内部进行。跳转的参数也可以是程序代码行的地址,函数名等等。

15.(gdb) return 
强制返回当前函数: 这样,将会忽略当前函数还没有执行完毕的语句,强制返回。return后面可以接一个表达式,表达式的返回值就是函数的返回值。

  • 24
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为什么名字不能重复呢?

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值