在计算机的内存中,既包含了程序运行的所有代码指令,又包含了程序运行的输入输出等各种数据,并没有一种强制的机制将指令和数据区分。因为对于计算机来说它们都是一样的0和1,大部分时候都是靠程序按照既定的“规则”去解释理解内存中的这些0和1。而一旦这些“规则”理解错误,事情就变得糟糕起来。
具体到我们现代CPU和OS,不管是x86/x64处理器,还是处理器,均采用了寄存器+堆栈式的设计,而这个堆栈中,既包含了程序运行各个函数栈帧中的变量数据等信息,还保存了函数调用产生的返回地址。
所谓栈溢出攻击,则是通过一些手段输入到栈中的缓冲区中,冲破缓冲区原有的界限,将存储返回地址的位置覆盖为一个数值,使其指向攻击者提前布置的恶意代码位置,劫持了程序的执行流程。
防御手段:现代操作系统针对栈溢出攻击已经有非常成熟的应对方案,像Linux平台的Stack Canary,dows平台的GS机制等等,程序员需要做的就是充分利用这些机制。
重点关注:C/C++工程师
整数溢出攻击和栈溢出攻击一样,整数溢出攻击也是属于溢出类攻击,不一样的是溢出的目标不是栈中的缓冲区,而是一个整数。
我们知道,计算机数值以补码的方式表示和存储。在表示一个有符号数时,最高位是用来表示这是一个正数(0)还是一个负数(1),比如对于一个16位的short变量而言,+1和-1的表示 *** 如下:
+1: 0000 0000 0000 0001-1: 1111 1111 1111 1111一个16位的short变量表示的范围是-32768~32767,现在思考一个问题,假如一个short变量的值现在是32767:
32767: 0111 1111 1111 1111如果现在对其执行+1操作,将变成:
1000 0000 0000 0000而这正是-32768的补码形式!
试想一下,如果这个变量名字叫length作为strcpy参数,或是叫index作为数组的下标,整数的溢出将导致可怕的后果,轻则进程崩溃,服务宕机,重则远程代码执行,拿下控制权。
重点关注:所有程序员
空指针攻击空指针一般出现在指针没有初始化,或者使用new进行对象创建/内存分配时失败了,而粗心的程序员并没有检查指针是否为空而进行访问导致的攻击。
大多数情况下,这将导致内存地址访问异常,程序会崩溃退出,造成拒绝服务的现象
而在一些特殊的情况下,部分操作系统允许分配内存起始地址为0的内存页面,而攻击者如果提前在该页面准备好攻击代码,则可能出现执行恶意代码的风险。
释放后使用攻击释放后使用Use After Free意为访问一个已经释放后的内存块。较多的出现在针对浏览器的JaScript引擎的攻击中。
正常情况下,一个释放后的对象我们是没法再访问的,但如果程序员粗心大意,在delete对象后,没有即时对指针设置为NULL,在后续又继续使用该指针访问对象(比如通过对象的虚函数表指针调用虚函数),将出现内存访问异常。
在上面的场景中,如果攻击者在delete对象后,马上又new一个同样内存大小的对象,在现代操作系统的堆内存管理算法中,会有很大概率将这个新的对象放置于刚刚被delete的对象的位置处。这个时候还通过原来对象的指针去访问,将出现鸠占鹊巢,出现可怕的后果。
养成好的编程习惯,对象delete后,指针及时置空。
重点关注:C/C++工程师
HOOK