前言
这里还没有到画堆栈图这个阶段,还是一个入门的讲解,其中比较绕的可能就是要自己去写一段代码去代替 push 和 pop,去了解这两个操作到底是干了什么,这个其实在滴水的公开课就讲过,但是我还是把它放在了这里面去讲
课堂
引出堆栈
windows 操作系统中的堆栈都是从高地址往低地址存入数据,所以从栈底到栈顶的地址依次从大到小
如果我们要临时存储一些数据,而且数量很少的话,可以将数据放到寄存器中
但是当数据数量很大时,我们需要存到内存中,那么现在我们想要一种内存,可以记录存了多少数据,并且能够非常快的找到数据,于是我们可以这样设计内存。用两个寄存器分别存储栈底和栈顶的内存地址,存数据的时候,TOP 值减 4,释放数据时 TOP 值加 4,如果想要读取中间的某个数值时可以通过 TOP 或者 BASE 加上偏移量的方式去读取
所以可以这么去设计
堆栈操作本质
下述过程就是汇编语言提供 push 和 pop 的变形,即用其他指令来达到和 push 和 pop 一样的功能,这样做对程序来说相对更加安全,让逆向的人花时间去读代码,如果直接用 push 或者 pop,就很容易知道在干什么
入栈
从栈顶压入数据,即往低内存地址存入数据,存入后栈顶的地址编号-4,按照这个原理我们可以写汇编代码来模拟此过程。我们规定 esp 中的值为栈顶地址;ebp 中的值为栈底地址
- 方式一:先将数据入栈,栈顶地址编号再-4
mov dword ptr ss:[esp-4],0x12345678
lea esp,dword ptr ss:[esp-4]
- 方式二:先将栈顶地址编号-4,再把数据存到栈顶指针所指的内存块中
lea esp,dword ptr ss:[esp-4]
mov dword ptr ss:[esp-4],0x12345678
- 方式三:使用 sub 来达到栈顶指针-4 的效果,还是先存数据再移指针
mov dword ptr ss:[esp-4],0x12345678
sub esp,4
- 方式四:使用 sub 来达到栈顶指针-4 的效果,还是先移指针再存数据
sub esp,4
mov dword ptr ss:[esp],0x12345678
查询
当我们想在堆栈中查找某个地址中数据时,可以通过栈底减偏移量或者栈顶加偏移量来得到数据所在地址
- 方式一:栈底减偏移量
mov esi,dword ptr ss:[ebp-4] #读第一个压入栈的数据(结果存入esi中)
mov esi,dword ptr ss:[ebp-0x10] #读取第四个压入栈的数据
- 方式二:栈顶加偏移量
mov esi,dword ptr ss:[esp+4] #读倒数第二个压入栈的数据
mov esi,dword ptr ss:[esp+8] #读倒数第三个压入栈的数据
出栈
出栈表示将一个或多个数据从栈中移出去,比如我想将栈顶中的值出栈,则最终栈顶的地址应该+4,即栈顶指针下移,但是出栈的那个值还是在内存中,不是说数据出栈就是将这个数据移出内存中,出栈只是此时表示栈的内存结构中没有存储此数据了,但是它还在内存中。下图所示
- 方式一:先将数据出栈存入寄存器中待使用,再将栈顶指针下移
mov eax,dword ptr ss:[esp]
lea esp,dword ptr ss:[esp+4]
- 方式二:向将栈顶指针下移,再将数据出栈存入寄存器中待使用
lea esp,dword ptr ss:[esp+4]
mov eax,dword ptr ss:[esp-4]
保留状态
pushad:将八个 32 位通用寄存器中存的值,存入堆栈中,按照顺序存:eax 中的值先入栈,接着是 ecx,edx,ebx,esp,ebp,esi,edi,起到一个记录现场的作用。接着你就可以对寄存器做任意操作,最后反正能还原
popad:将八个 32 位通用寄存器中的值还原成最初 pushad 存入堆栈中的八个 32 位通用寄存器的值。起到一个还原现场的作用。所以综上,pushad 加 popad 就起到一个保护现场的作用
作业
mov ebx,0x0019ff40 #栈底
mov edx,0x0019ff30 #栈顶
mov dword ptr ds:[edx-4],0x11111111
-------------------------------------
mov dword ptr ds:[edx-8],esi #004010F0
-------------------------------------
mov eax,dword ptr ss:[esp] #BBBBBBBB
mov dword ptr ds:[edx-0xc],eax
-------------------------------------
mov eax,dword ptr ss:[esp+8] #75b510f0
mov dword ptr ds:[edx-0x10],eax
-------------------------------------
mov dword ptr ds:[edx-0x14],0xFFDC
-------------------------------------
lea edx,dword ptr ds:[edx-0x14]
未添加数据前,栈结构如下图所示
连续添加五个数据后,栈结构如下图,栈顶地址变为 0x0019ff1c
后续的跟上上面的步骤一步一步操作就行