这是学习国资社畜的视频之后的整理
这是程序的源代码,接下来编译,保护全关。编译之后第一步,运行程序看一眼
当运行程序的时候,程序需要先把程序放进内存,程序在内存中的布局是什么样的呢,在gdb中输入vmmap查看
从低地址到高地址排列,上面从0x40000到0x405000是我们写的程序本身,0x405000这个蓝色的是堆,从0x7fff7c00000到0x7ffff7ffd000是外部的文件,0x7ffffffde000是栈。目前从上到下分成程序本身,堆,外部文件,栈四个部分。
然后拖进ida里看看
这个dofunc函数,这里介绍几个指令的意思,等下会用到,需要再回来看
重要的寄存器:rip(当前执行的指令),rbp(栈底),rsp(栈顶)
push rbp:rsp-8,把rbp放入rsp指的地方
pop rbp:把rsp指的地方赋值给rbp,rsp+8
mov rbp,rsp:赋值,rbp=rsp
jump:jump()就是mov rip,()
call dofunc:push rip;jump dofunc,这里的rip是call dofunc的下一条指令
leave:mov rsp,rbp;pop rbp
retn:pop rip
接下来通过动态调试看函数调用的过程
接下来即将执行call dofunc,会push 0x4011e8,现在rbp和rsp都是0x7fffffffdea0,下一步rsp会减8,最后两位变成98,并且指的地方变成push 0x4011e8,接下来si步入验证一下。
rsp确实减了8,指的地方变成了0x4011e8,并且可以看到rip变成了0x401199,成功跳转到了dofunc函数,不管这个endbr64,接下来要运行push rbp,也就是rsp要再减8,然后指的地方变成rbp。
确实如此,rsp最后两位变成了90,和刚刚比又减了8,然后rsp指的地方变成了a0,也就是rbp,接下来mov rbp,rsp,进行赋值。
现在rbp和rsp就都是90了,接下来sub rsp,0x10,这个的意思就是把rsp=rsp-0x10,进行一个赋值
rsp变成了80,和刚刚比减了4,此时rbp指的地方是曾经rbp的地址,rbp+0x8的地方是之前main函数call dofunc的下一条指令,这个dofunc函数的操作都在现在的rsp和rbp之间,不会影响rbp下面的东西,接下来我们看函数要结束时,leave和ret的操作
下一步是leave,也就是mov rsp,rbp,然后pop rbp。所以先是rsp等于rbp,都是90,之后让rbp等于rsp指的地方,也就是a0,然后rsp+8,从90变成了98
现在rsp变成98了,rbp是a0了,和我们预想一样,接下来执行ret,此时rsp指的地方是0x4011e8,那么接下来rip变成0x4011e8,rsp加8
可以看到rip和rsp都和我们预想的一样,调用结束,这就是函数调用的全过程了