首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++/CLI 安全編碼:緩衝區溢出風險與防禦實測

     編輯:關於C++

C++/CLI 支援 GC、泛型等現代特性,但混合模式下原生代碼仍面臨緩衝區溢出威脅。本文實測 Visual Studio 2005 混合組件在 /GS(緩衝區安全檢查)與 /clr 組合下的脆弱性。

案例一:主控台程式堆疊溢出

char buff[1028];
bool checkpassword() {
    char password[10];
    gets(password); // 危險:無邊界檢查
    return strcmp(password, "NCC-1701") == 0;
}
int main() {
    gets(buff); // 另一處溢出點
    if (!checkpassword()) { /* 記錄失敗 */ exit(-1); }
}

編譯選項 /GS- /clr 關閉保護。輸入超長密碼覆蓋返回位址至 0x00408130(shellcode),函數返回時跳轉執行任意代碼。/GS 啟用時會在堆疊陣列後插入 Cookie,檢測覆蓋並終止程式,但:

  • 僅保護堆疊陣列,不保護堆積/資料段緩衝區。
  • Cookie 可被暴力猜測或資訊洩漏繞過。
  • 拒絕服務攻擊(觸發 Cookie 檢查崩潰)仍可行。

案例二:GUI 程式資料段溢出繞過 /GS

Win32 應用程式中,全域緩衝區 lpszPassword[16] 緊鄰 userP、userNameLen、userPasswordLen。對話方塊 EM_GETLINE 訊息未限制長度,溢出覆蓋相鄰變數。攻擊者構造輸入:

  1. 覆蓋 userP 指向可控記憶體。
  2. 覆蓋 userNameLen 為目標返回位址。
  3. 第 124 行 userP->len = userNameLen 形成任意記憶體寫入,修改堆疊返回位址至 shellcode。

全程未觸動堆疊 Cookie(因溢出源在資料段),/GS 完全無效。

修正方案

*((WORD*)(&lpszPassword)) = (sizeof(lpszPassword)/sizeof(TCHAR)) - 1; // 設定最大長度
LRESULT ret = SendDlgItemMessage(hDlg, IDC_EDIT1, EM_GETLINE, 0, (LPARAM)lpszPassword);
lpszPassword[ret] = '\0'; // 手動加終結符

正確使用 EM_GETLINE 協定:首字設緩衝區大小,呼叫後依回傳長度加終結符。

結論

  1. /GS 非銀彈,僅緩解堆疊陣列溢出。
  2. 編譯無警告 ≠ 無漏洞(範例二編譯零警告)。
  3. 混模式專案必須審查所有原生代碼路徑,採用安全 CRT(gets_s、strcpy_s、StringCchCopy 等)。
  4. 長期策略:將安全關鍵邏輯遷移至托管代碼(C++/CLI 或 C#),享受型別安全與 GC 保護。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved