CS50 Week 4

重點回顧

16 進位

 

最常用來表示記憶體位址 (memory address)

 

0xFF

Pointer 指標

 

程式語言中的一類資料類型及其物件變數,用來表示或儲存一個記憶體位址,這個位址的直接指向(points to)存在該位址的物件的

 

Pointer 也能夠簡化許多資料結構(week 5)的實作,除了程式碼簡潔,特定 case 下效能也比直接複製或存取資料本身還要好。

 

有些程式語言將 pointer 實作成更抽象的 reference (參照) 資料型別,避免直接用指標

String 不是 C language 原生的 type

 

C 語言沒有獨立的字串型別,而 C 字串是以 char 或其他字元 (character) 為基礎型別的陣列

C 標準函式庫已經有 string.h 函式庫,在採作字串時應優先使用該函式庫,而非重造輪子

String 在 C 中不能直接比較

 

因為記憶體位置不同。  可以靠 strcmp()

 

 

用 ASCII 來判斷

不同程式語言設計不同

Malloc

 

 

變數建立後會配置記憶體空間,這類資源是配置在記憶體的堆疊區(Stack),生命週期侷限於函式執行期間,也就是函式執行過後,配置的空間就會自動清除。

 

這樣有什麼問題呢?

 

若要將函式執行結果傳回,不能直接傳回這類被自動配置空間的位址,因為函式執行過後,該空間就會釋出,函式呼叫者後續若透過位址取用這些資源,會發生不可預期的結果

Malloc

 

 

尤其程式跑起來,資源的運用更是複雜,因此在某些狀況下,需要開發者自行管理記憶體的配置,這些記憶體會被配置在堆積區(Heap),不會自動清除,開發者得在不使用資源時自行釋放記憶體。

Stack vs Heap

 

 

Stack Memory Space:系統自動化管理區塊

Stack中常見的存放資訊如下:區域變數(local variable)、函式參數 (function/method parameter)、函數的返回位址(function/method return address) 等資訊。因為程式在 compile 時就可以知道生命週期(一個 block)。因為可以預測,所以系統也會自動幫忙回收另外先進後出的特性也很適合 function call

 

這邊不是在指資料結構的 stack 與 heap,而是記憶體面向。

Heap Memory Space:由開發者自行控制與管理的區塊

例如 malloc 或是 new 一個物件出來

Stack Overflow vs Heap Overflow

 

 

Stack Overflow

一般是因為過多的函式呼叫(例如:遞迴太深)、或區域變數使用太多

Heap Overflow

檢查是否都有正確將heap space的資料回收,另外採行的動態配置是否合理,不要過渡濫用而new出無謂的空間

延伸知識

Garbage Collection

並不是所有程式語言都需要處理 malloc 再 free 的這種流程,例如 Java, Python 會自動檢查Heap中哪些資料已經沒有被使用,當確認資料已經沒有使用會自動將空間回收,如此工程師就專注撰寫程式即可。

 

看似方便不過在某些程式語言中 GC 卻是會亂的根源,例如 JavaScript

Security - Buffer Overflow

緩衝區溢位,除了 cs50 提到的概念,其實也是一種資安的攻擊手法,在一般使用 C 或 C++ 等程式在使用到固定大小的緩衝區進行資料存取時並不會自己進行緩衝區邊界的檢查,在一般正常使用情況,輸入值(Input data)會小於緩衝區的大小(Buffer size)

 

若程式設計者在設計讀取輸入值至緩衝區時也忽略了檢查輸入值長度時,攻擊者就可以透過輸入一筆較長的資料,以造成程式癱瘓或改變執行流程,通常會搭配 Shellcode 可以執行任意程式碼,而且同時擁有受害程式的權限

Shellcode

Shellcode 就是一堆十六進位的代碼組合而成,可以直接被 CPU 辨識執行,通常會透過 Buffer Overflow 改變程式執行流程到攻擊者存放在記憶體的 Shellcode,就可以為所欲為了,像是透過下面的程式碼以 xor 計算去改變 EBP 的值。

如何避免攻擊

  • 改使用較安全的函式(如 strncpy 來取代 strcpy)。
  • 加上輸入值與緩衝區長度檢查機制。
  • 改用較高階的程式語言,如 Java。
  • 使用工具檢查程式是否有安全性漏洞,像是 splint 等等。

Call Stack

呼叫堆疊最經常被用於存放子程式的返回位址。在呼叫任何子程式時,主程式都必須暫存子程式執行完畢後應該返回到的位址。因此,如果被呼叫的子程式還要呼叫其他的子程式,其自身的返回位址就必須存入呼叫堆疊,在其自身執行完畢後再行取回。

Call Stack

main

parentFunc

childrenFunc

So What If...

Stack Overflow !!!

 

https://stackoverflow.com/

Thanks 🙏 

Made with Slides.com