逆向06:堆栈图

前置条件

  • 下载HelloWorld程序(压缩包需要进行解压)
  • OllyDBG
    • 调整OptionsPreferencesEventsBreak on中取消勾选System Breakpoint

OllyDBG Break-on

  • 测试初始断点是否与下图一致

OllyDBG First Pause

任务位置

  • 0x401168 (演示)
  • 0x401174
  • 0x401182
  • 0x40118E

跳转到上述地址后,在运行前画出堆栈图,分析代码的功能。

演示:0x401168

跳转到任务地址

OllyDBG中使用Ctrl+G快捷键或者右键当前断点选择Go toExpression,输入0x401168后点击OK

找到任务位置

移动到任务位置后,使用F2快捷键下断点。

下任务位置断点

然后使用F9,或者菜单中DebugRun使程序运行至该断点。

运行到任务位置

观察栈顶、栈底地址

此处演示的地址可能与实际运行时存在差异。

记录上一步中程序的栈顶、栈底地址。

地址 描述
0019FEE8 ESP 栈顶
0019FF34 EBP 栈底

行为分析

F8单步执行后

EIP 0040116A

可以观察到,PUSH 2指令执行后,ESP位置发生了改变,从0019FEE8变为了0019FEE4,栈顶位置中已经存入2,这个步骤称之为压栈

地址 描述
0019FEE4 2 ESP 栈顶
0019FEE8 指令执行前ESP位置
0019FF34 EBP 栈底

再次单步执行

EIP 0040116C

可以观察到,PUSH 1指令执行后,ESP位置发生了改变,从0019FEE4变为了0019FEE0,栈顶位置中已经存入1

地址 描述
0019FEE0 1 ESP 栈顶
0019FEE4 2
0019FEE8
0019FF34 EBP 栈底

CALL运行前分析

运行完PUSH 1PUSH 2指令后,再次单步运行后程序将执行CALL指令,但是F8单步运行后,程序将直接运行至00401171,所以下一步使用F7或菜单中的DebugSetp into步入。

CALL指令与JMP指令不同,JMP指令相当于MOV地址到EIP ,但是CALL不但修改EIP的值,还会将其下一行指令的地址压入栈。

  • 结果/行为预测
地址 描述
0019FEDC 00401171 ESP 栈顶, CALL返回地址(斜体)
0019FEE0 1
0019FEE4 2
0019FEE8
0019FF34 EBP 栈底

EIP:0040100A

  • F7步入后结果如下

EIP 0040100A

进入CALL的函数后

通过观察,EIP指向的指令为JMP,使用Enter键进入其跳转的地址(此时CPU尚未执行到JMP的地址,需要通过F8进行跳转)。

EIP 00401040

此时可以观察到EIP的值发生了变化(JMP修改)。

PUSH EBP

地址 描述
0019FED8 0019FF34 ESP
0019FEDC 00401171
0019FEE0 1
0019FEE4 2
0019FEE8
0019FF34 EBP

EIP 00401041

MOV EBP, ESP

地址 描述
0019FED8 0019FF34 ESP, EBP
0019FEDC 00401171
0019FEE0 1
0019FEE4 2
0019FEE8
0019FF34 EBP

EIP 00401043

SUB ESP, 40

地址 描述
0019FE98 ESP,缓冲区
缓冲区
0019FED8 0019FF34 EBP
0019FEDC 00401171
0019FEE0 1
0019FEE4 2
0019FEE8
0019FF34 EBP

缓冲区的大小是不确定的,一般比用户需要的多一些。

EIP 00401046

PUSH EBX/ESI/EDI

  • PUSH EBX
地址 描述
0019FE94 002C3000 ESP,EBX的值
0019FE98 缓冲区
缓冲区
0019FED8 0019FF34 EBP
0019FEDC 00401171
0019FEE0 1
0019FEE4 2
0019FEE8
0019FF34 EBP

EIP 00401047

  • PUSH ESI
地址 描述
0019FE90 00401220 ESP,ESI的值
0019FE94 002C3000 EBX的值
0019FE98 缓冲区
缓冲区
0019FED8 0019FF34 EBP
0019FEDC 00401171
0019FEE0 1
0019FEE4 2
0019FEE8
0019FF34 EBP

EIP 00401048

  • PUSH EDI
地址 描述
0019FE8C 0019FF34 ESP,EDI的值
0019FE90 00401220 ESI的值
0019FE94 002C3000 EBX的值
0019FE98 缓冲区
缓冲区
0019FED8 0019FF34 EBP
0019FEDC 00401171
0019FEE0 1
0019FEE4 2
0019FEE8
0019FF34 EBP

EIP 00401049

这三步操作可以理解为保存现场,保存上一阶段的位置信息。

LEA EDI,DWORD PTR SS:[EBP-40]

SS:[EBP-40]的地址编号到EDI

地址 描述
0019FE8C 0019FF34 ESP
0019FE90 00401220 ESI的值
0019FE94 002C3000 EBX的值
0019FE98 缓冲区,EDI的值
缓冲区
0019FED8 0019FF34 EBP
0019FEDC 00401171
0019FEE0 1
0019FEE4 2
0019FEE8
0019FF34 EBP

EDI: 0019FE98

EIP不变

EIP 0040104C

MOV ECX, 0x10

此部分解析以下命令,这些命令用于填充缓冲区,防止缓冲区溢出并清理内存中的垃圾。

1
2
3
MOV ECX,10
MOV EAX,CCCCCCCC
REP STOSD 
地址 描述
0019FE8C 0019FF34 ESP
0019FE90 00401220 ESI的值
0019FE94 002C3000 EBX的值
0019FE98 CCCCCCCC 缓冲区
CCCCCCCC 缓冲区
0019FED8 0019FF34 EBP,EDI的值
0019FEDC 00401171
0019FEE0 1
0019FEE4 2
0019FEE8
0019FF34 EBP

EIP 00401058

STOSD: 复制EAX存储的值到EDI指定的内存单元

REP: 重复执行命令 ECX次,注意:ECX的值是16进制的。

CCCCCCCC是断点,防止缓冲区溢出。

MOV EAX, DWORD PTR SS:[EBP+0x8]

此命令用于读取参数。

EAX: 1

命令执行完成后堆栈没有变化。

EIP 0040105B

ADD EAX, DWORD PTR SS:[EBP+0xC]

地址 描述
0019FE8C 0019FF34 ESP
0019FE90 00401220 ESI的值
0019FE94 002C3000 EBX的值
0019FE98 CCCCCCCC 缓冲区
CCCCCCCC 缓冲区
0019FED8 0019FF34 EBP,EDI的值
0019FEDC 00401171
0019FEE0 1
0019FEE4 2
0019FEE8
0019FF34 EBP

EAX:3

命令执行完成后堆栈没有变化。

EIP 0040105E

POP EDI/ESI/EBX

此命令用于恢复现场。

地址 描述
0019FE8C 0019FF34 恢复到EDI
0019FE90 00401220 恢复到ESI
0019FE94 002C3000 恢复到EBX
0019FE98 CCCCCCCC ESP,缓冲区
CCCCCCCC 缓冲区
0019FED8 0019FF34 EBP,EDI的值
0019FEDC 00401171
0019FEE0 1
0019FEE4 2
0019FEE8
0019FF34 EBP

EIP 00401061

MOV ESP, EBP

恢复堆栈

地址 描述
0019FE8C 0019FF34
0019FE90 00401220
0019FE94 002C3000
0019FE98 CCCCCCCC
CCCCCCCC
0019FED8 0019FF34 ESP, EBP
0019FEDC 00401171
0019FEE0 1
0019FEE4 2
0019FEE8
0019FF34 EBP

EIP 00401063

POP EBP

重新定位栈底

地址 描述
0019FE8C 0019FF34
0019FE90 00401220
0019FE94 002C3000
0019FE98 CCCCCCCC
CCCCCCCC
0019FED8 0019FF34 ESP
0019FEDC 00401171 ESP
0019FEE0 1
0019FEE4 2
0019FEE8
0019FF34 EBP

EIP 00401064

RET

相当于POP EIP

地址 描述
0019FE8C 0019FF34
0019FE90 00401220
0019FE94 002C3000
0019FE98 CCCCCCCC
CCCCCCCC
0019FED8 0019FF34
0019FEDC 00401171 ESP
0019FEE0 1 ESP
0019FEE4 2
0019FEE8
0019FF34 EBP

EIP: 0019FF34

EIP 00401171

堆栈平衡

程序的函数执行后,其栈顶指针与栈底指针应该保持一致。

上述程序中,函数返回后没有平衡堆栈,所以需要执行ADD ESP, 8

地址 描述
0019FE8C 0019FF34
0019FE90 00401220
0019FE94 002C3000
0019FE98 CCCCCCCC
CCCCCCCC
0019FED8 0019FF34
0019FEDC 00401171 ESP
0019FEE0 1
0019FEE4 2
0019FEE8 ESP
0019FF34 EBP

外平栈: 在函数外部对堆栈进行平衡。(谁调用谁平衡)

程序分析

通过对上述程序的分析,可以得知其行为:1+2

1
2
MOV EAX, DWORD PTR SS:[EBP+0x8]
ADD EAX, DWORD PTR SS:[EBP+0xC]

函数

概念

计算机的函数,是一个固定的一个程序段,或称其为一个子程序,它在可以实现固定运算功能的同时还带有一入口和一个出口,所谓的入口,就是函数所带的各个参数,我们可以通过这个入口,把函数的参数值代入子程序,供计算机处理,所谓出口,就是指函数的计算结果,也称为返回值,在计算机求得之后,由此口带回给调用它的程序。

汇编中的函数

提升堆栈,为函数执行提供空间。

1
2
3
PUSH EBP
MOV EBP, ESP
SUB ESP, 40

保留现场:函数在执行的时候会用到一些寄存器,但这些寄存器中的值很可能会被后面的程序用到,所以要先存储到内存中。

1
2
3
PUSH EBX
PUSH ESI
PUSH EDI

向分配的空间填充数据。

1
2
3
4
LEA EDI, DWORD PTR SS:[EBP-40]
MOV ECX, 10
MOV EAX, CCCCCCCC
REP STOSD

该函数的功能。

1
2
MOV EAX, DWORD PTR SS:[EBP+8]
ADD EAX, DWORD PTR SS:[EBP+C]

恢复现场:将之前保留的寄存器的值恢复。

1
2
3
POP EDI
POP ESI
POP EBX

降低堆栈。

1
MOV ESP, EBP

恢复栈底。

1
POP EBP

函数执行完毕,返回到调用处。

1
RET

函数的入口

1
2
3
PUSH 2
PUSH 1
CALL 0040100A

其中,第一行和第二行为函数的参数

也可以通过其他方式传入参数。

函数的出口

1
2
MOV EAX, DWORD PTR SS:[EBP+8]
ADD EAX, DWORD PTR SS:[EBP+C]

也可以通过其他方式返回参数。

堆栈的特点

Windows堆栈的特点

  • 先进后出
  • 向低地址扩展

Built with Hugo
主题 StackJimmy 设计