Use After Free
UAF 就是 Use After Free的缩写,是一种比较常见的内存错误式利用。很多iOS的越狱都是利用的这种方法。
在此简单的举个例子说明UAF出现的情况
代码说明一切
1 class Car 2 { 3 public: 4 virtual void setValue(int value)=0; 5 virtual int getValue()=0; 6 7 protected: 8 int mValue; 9 }; 10 11 class Electric_car: public Car 12 { 13 public: 14 void setValue(int value){ 15 mValue = value; 16 } 17 18 int getValue(){ 19 mValue += 1; 20 cout<<"This is Electric_car's getValue"<<endl; 21 return mValue; 22 } 23 }; 24 25 class Fuel_car : public Car 26 { 27 public: 28 void setValue(int value){ 29 mValue = value; 30 } 31 int getValue(){ 32 cout<<"This is Fuel_car's getValue"<<endl; 33 mValue += 100; 34 return mValue; 35 } 36 }; 37 38 void handleObject(Car* car) 39 { 40 car->setValue(0); 41 cout<<car->getValue()<<endl; 42 }
这个程序有三个类,其中Fuel_car和Electric_car都是继承自Car。并且分别实现了Car类的虚函数。因此当程序调用handleObject这个函数的时候,无论出入的参数是Electric_car还是Fuel_car,handleObject函数都可以正常被调用。
接着我们来看一下主函数的情况
1 int main(void) { 2 Electric_car *myElectric_car = new Electric_car(); 3 printf("Electric_car=%p ",myElectric_car); 4 5 handleObject(myElectric_car); 6 7 free(myElectric_car); 8 9 Fuel_car *myFuel_car = new Fuel_car(); 10 printf("Fuel_car=%p ",myFuel_car); 11 12 handleObject(c); 13 }
- 我们先new一个Electric_car,然后再调用handleObject来打印它的value值。最后释放掉这个Electric_car。
- 接着,我们new一个Fuel_car,然后调用handleObject来打印Electric_car(请注意是Electric_car,不是Fuel_car)
按照以上的步骤调用了相关函数之后会发生什么情况呢,正常情况下会出现内存泄漏的报错。但是上面主函数只是free掉了myElectric_car,并且没有把指针也置为NULL。这个时候如果有另一个对象(比如上面的Fuel_car)刚好被分配到了myElectric_car的指针地址里面。handleObject就会对这个对象进行处理并且不会出现错误。这就是典型的UAF错误
简单看一下运行结果吧。
1 myElectric_car=0x15b23a76 2 This is Electric_car's getValue 3 1 4 myFuel_car=0x15b23a76 5 This is Fuel_car's getValue 6 100
可以看到Electric_car对象在内存中的地址为0x15b23a76,然后Electric_car就被free掉了。随后,程序又创建了另一个对象myFuel_car。因为堆的特性,系统会把刚刚free掉的内存再分配给myFuel_car。因此myFuel_car在内存中的地址也是0x15b23a76。所以当程序调用handleObject(myElectric_car)的时候,本应该期待调用Electric_car's getValue()函数却调用了Fuel_car's getValue()函数,这就造成一个UAF错误。
总结
以上就是对UAF错误发生原因的介绍,对应方法一般为释放内存之后还要记得把指针也释放掉。 提一个有意思的话题,在iOS9.0中,有人就用这个UAF错误实现了越狱。主要漏洞发生的函数是IOHIDResourceUserClient。 你能找出问题吗(同学们这是一道送分题啊)
//---------------------------------------------------------------------------- // IOHIDResourceDeviceUserClient::terminateDevice //---------------------------------------------------------------------------- IOReturn IOHIDResourceDeviceUserClient::terminateDevice() { if (_device) { _device->terminate(); } OSSafeRelease(_device); return kIOReturnSuccess; }