標籤:
Use After Free
UAF 就是 Use After Free的縮寫,是一種比較常見的記憶體錯誤式利用。很多iOS的越獄都是利用的這種方法。
在此簡單的舉個例子說明UAF出現的情況
代碼說明一切
class Car { public: virtual void setValue(int value)=0; virtual int getValue()=0; protected: int mValue; }; class Electric_car: public Car { public: void setValue(int value){ mValue = value; } int getValue(){ mValue += 1; cout<<"This is Electric_car‘s getValue"<<endl; return mValue; } }; class Fuel_car : public Car { public: void setValue(int value){ mValue = value; } int getValue(){ cout<<"This is Fuel_car‘s getValue"<<endl; mValue += 100; return mValue; } }; void handleObject(Car* car) { car->setValue(0); cout<<car->getValue()<<endl; }
這個程式有三個類,其中Fuel_car和Electric_car都是繼承自Car。並且分別實現了Car類的虛函數。因此當程式調用handleObject這個函數的時候,無論出入的參數是Electric_car還是Fuel_car,handleObject函數都可以正常被調用。
接著我們來看一下主函數的情況
int main(void) { Electric_car *myElectric_car = new Electric_car(); printf("Electric_car=%p\n",myElectric_car); handleObject(myElectric_car); free(myElectric_car); Fuel_car *myFuel_car = new Fuel_car(); printf("Fuel_car=%p\n",myFuel_car); handleObject(c); }
- 我們先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錯誤
簡單看一下運行結果吧。
myElectric_car=0x15b23a76 This is Electric_car‘s getValue 1 myFuel_car=0x15b23a76 This is Fuel_car‘s getValue 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; }
(最近在嘗試在gitpage上寫文章,所以這篇文章也放到了自己的github上)
iOS的UAF錯誤到底是什麼錯誤