逆向工程核心原理
Last Update:
第一章
打补丁
对于修改书中的那个程度有两种办法
1.直接修改字符串缓冲区
2.其他位置生成新字符串并将该地址传递给消息函数
栈帧
使用EBP寄存器访问栈内局部变量、参数、函数返回地址等的手段。ESP寄存器承担着栈顶指针的作用,而EBP寄存器则负责行使栈帧指针的作用。程序运行时ESP的值随时改变,因此在调用函数时,先把基准点(函数起始位置)的ESP值保存到EBP,并维持在函数内部。这样无论ESP值如何变化,以EBP值为基准能够安全访问到相关函数的局部变量、参数、返回值等。其中EBP寄存器作为栈帧指针的作用。
在栈中保存函数返回地址是系统安全隐患之一,攻击者使用缓冲区溢出技术能把保存在栈内存的返回地址更改为其它地址。
举个简单的例子吧:
程序源码:
第一步:先让程序运行到main函数暂停,观察栈的初始状态:
当前ESP值为12FF44 ,EBP的值为12FF88
生成main函数的栈帧:
此时栈的状态变为:
这个时候main函数的栈帧就创建好了
接下来执行 long a=1 long b=2:
此时栈的状态变为:
再调用add()函数,对应汇编为:
因为add()函数有两个参数,所以调用前先把参数压住栈,注意入栈的顺序和参数顺序相反(函数参数的逆序存储)
此时栈内状态变为:
接下来进入add()函数内部,分析整个函数的调用过程
返回地址:执行call命令进入函数前,CPU会把函数的返回地址压住栈,用作函数执行完后的返回地址,当执行完call命令后,栈的状态为:
接下来开始执行add()函数,并形成add()函数的栈帧:
栈的状态变为:
add()函数内部有两个局部变量,并用两个形参为其赋初值,汇编如下:
此时栈的状态变为:
再就是执行add的运算了
先将x的值传给EAX,再将y的值与EAX相加并保存在EAX里。
函数执行完毕,开始删除add()的栈帧
再执行retn指令,存储在栈中的返回地址也出栈,此时栈完全恢复到调用add函数前的状态。所以,不管有多少函数嵌套调用,利用栈帧都可以很好的维护
现在,程序执行流重新返回到main()函数里
之后就没什么了,清除main函数的栈帧,程序结束
函数调用约定
cdecl
源代码:
1 |
|
动调发现:add函数1,2以逆序方式压入栈,之后使用add esp,8清理栈,这样的方式就是cdecl
好处:可以像c语言的printf函数一样,向被调用函数中传入多个参数,这种长度可变的参数在其他两种调用方式中很难实现
stdcall
栈的清理工作由add()函数的最后 RENT 8实现,含义为RENT+POP 8字节,及返回后使ESP增加到指定大小
像这样在被调用者add()函数内部清理栈的方式即为stdall方式。
好处:
fastcall
使用寄存器而非栈内存来传递参数