【C語言】第七課 字符串與危險函數??

C語言中的字符串處理既是基礎,也是安全漏洞的重災區。理解C風格字符串的底層原理及其危險函數的運作方式,對于編寫安全代碼和進行逆向工程分析至關重要。

🧩 C風格字符串的本質

C風格字符串本質上是以空字符'\0'(ASCII值為0)結尾的字符數組。這個終止符是字符串的“生命線”,它告訴字符串處理函數字符串在哪里結束。

  • 內存中的表示:字符串 "Hello" 在內存中實際存儲為 {'H', 'e', 'l', 'l', 'o', '\0'}
  • 長度與容量:字符串的長度strlen() 返回的值(不包含'\0'),而容量是字符數組實際占用的總字節數。長度不能超過容量減一(必須為'\0'留出空間)。
  • 聲明方式
    char str1[] = "Hello"; // 編譯器自動計算大小,包含'\0'
    char str2[6] = {'H', 'e', 'l', 'l', 'o', '\0'}; // 手動指定大小并初始化
    char str3[10]; // 未初始化,后續需要手動添加'\0'
    

?? 危險的字符串操作函數

C標準庫提供了一系列字符串操作函數,但它們大多不檢查目標緩沖區的邊界,這是導致緩沖區溢出的根源。

以下是幾個常見的高危函數及其安全注意事項:

函數用途危險原因安全替代建議
strcpy(dest, src)將源字符串復制到目標緩沖區src長度 > dest容量,導致溢出strncpy(dest, src, dest_size-1) 并手動添加 dest[dest_size-1] = '\0'
strcat(dest, src)將源字符串追加到目標字符串末尾若合并后總長度 > dest容量,導致溢出strncat(dest, src, dest_size - strlen(dest) - 1)
sprintf(dest, format, ...)格式化輸出到字符串若生成的字符串長度 > dest容量,導致溢出snprintf(dest, dest_size, format, ...)
gets(dest)從標準輸入讀取一行到dest極度危險! 無法限制讀取長度,必然溢出絕對不要使用!fgets(dest, size, stdin) 代替
scanf("%s", dest)讀取字符串若輸入過長,導致溢出始終指定寬度:scanf("%19s", dest) // 假設dest大小為20

安全函數的注意事項

  • strncpy不會自動添加終止符:如果源字符串長度超過或等于指定的最大復制長度,strncpy 不會 在目標末尾添加 '\0'你必須手動添加以確保字符串正確終止。
    char dest[10];
    strncpy(dest, "ThisIsAVeryLongString", sizeof(dest) - 1); // 只復制前9個字符
    dest[sizeof(dest) - 1] = '\0'; // 手動添加終止符,這是關鍵!
    
  • strncat 相對安全:它會自動在追加的字符串末尾添加 '\0',但你必須確保目標緩沖區有足夠的剩余空間(包括終止符)。

💥 緩沖區溢出漏洞詳解(以棧溢出為例)

緩沖區溢出是當數據寫入緩沖區時,超出了緩沖區的邊界,覆蓋了相鄰內存區域的行為。棧溢出是其中最常見且最危險的一種。

漏洞代碼示例
#include <stdio.h>
#include <string.h>void vulnerable_function(const char* input) {char buffer[16]; // 在棧上分配一個16字節的緩沖區strcpy(buffer, input); // 🚨 危險!無邊界檢查的復制printf("Buffer: %s\n", buffer);
}int main() {char large_input[256] = "This string is definitely longer than sixteen bytes...";vulnerable_function(large_input);return 0;
}
溢出過程與逆向分析

在逆向工程中,理解函數調用時的棧幀布局至關重要。當調用 vulnerable_function 時,棧幀通常如下布局(簡化示意,具體取決于編譯器和架構):

內存地址(高)棧幀內容說明
ebp + 8參數 input傳遞給函數的參數
ebp + 4返回地址 (Return Address)這是攻擊者的主要目標!
ebp保存的上一幀ebp (Saved EBP)
ebp - 4局部變量 buffer[12-15]
ebp - 8局部變量 buffer[8-11]
ebp - 12局部變量 buffer[4-7]
ebp - 16局部變量 buffer[0-3]
  1. 正常操作:如果輸入的字符串長度小于16字節(包括結尾的'\0'),strcpy 會正常復制,不會破壞棧上的其他數據。
  2. 發生溢出:當輸入遠長于16字節時,strcpy 會持續復制,超出 buffer 的邊界。
  3. 覆蓋關鍵數據
    • 首先會覆蓋保存的EBPebp指向的位置)。
    • 繼續覆蓋返回地址ebp + 4指向的位置)。攻擊者可以精心構造輸入數據,使這個返回地址指向他們注入的惡意代碼(通常也在棧上)或現有的特殊函數
  4. 劫持程序流程:當 vulnerable_function 執行完畢,準備返回時,CPU會從棧上取出那個已被覆蓋的返回地址,并跳轉到該地址執行。程序的控制流就此被劫持
在調試器(GDB)中觀察溢出
  1. 編譯代碼:使用調試信息編譯(gcc -g -o program program.c)。
  2. 啟動GDBgdb ./program
  3. 設置斷點:在 vulnerable_functionstrcpy 之后設置斷點。
    (gdb) break vulnerable_function
    (gdb) break *(vulnerable_function+某偏移量) # 在strcpy之后設置斷點
    
  4. 運行并傳遞超長參數
    (gdb) run $(python -c "print 'A'*256)") # 使用一串'A'作為輸入
    
  5. 觀察棧內存
    • strcpy之前,使用 x/20xw $esp 查看棧內存(正常)。
    • strcpy之后,再次使用 x/20xw $esp,你會看到返回地址和被保存的EBP已被字符’A’(ASCII碼0x41)覆蓋
    (gdb) x/8xw $ebp # 查看ebp附近的內存
    0xffffd00c: 0x41414141 0x41414141 0x41414141 0x41414141 # 覆蓋的EBP和返回地址
    0xffffd01c: 0x41414141 0x41414141 0x41414141 0x41414141
    
  6. 繼續執行:當函數返回時(stepicontinue),程序會嘗試跳轉到地址 0x41414141(即"AAAA")去執行,這顯然是一個非法地址,會導致段錯誤(Segmentation fault)。在真實的攻擊中,這個地址會被替換為精心計算的、指向惡意代碼的有效地址。

🛡? 如何防范緩沖區溢出

  1. 使用安全函數:優先使用帶 n 版本的函數(如 strncpy, strncat, snprintf)并正確使用它們(特別是為strncpy手動添加終止符)。
  2. 動態內存管理:如果可能,使用malloc根據字符串實際長度動態分配足夠的內存,但記得最后要free
  3. 現代編譯器和操作系統保護機制
    • 棧保護器(Stack Canaries):編譯器(如GCC的-fstack-protector)會在棧上的返回地址前插入一個隨機值(canary)。函數返回前檢查該值是否被修改,若被修改則終止程序。
    • 數據執行保護(DEP/NX):將數據所在的內存頁(如棧)標記為不可執行,即使攻擊者注入了代碼,也無法運行。
    • 地址空間布局隨機化(ASLR):隨機化進程內存布局(棧、堆、庫的地址),使得攻擊者難以預測惡意代碼的準確地址。
  4. 靜態代碼分析工具:使用工具掃描代碼,自動識別潛在的緩沖區溢出風險。
  5. 代碼審計:養成良好的編程習慣,始終對外部輸入保持懷疑,并手動檢查所有緩沖區操作的邊界。

💎 總結

理解C風格字符串和危險函數是C編程和逆向分析的基石。'\0'終止符是生命線,緩沖區邊界是高壓線。通過調試器親眼目睹棧溢出如何覆蓋返回地址,是理解整個漏洞機理最直觀的方式。在開發中,務必摒棄危險的函數,采用安全替代方案,并利用現代系統的保護機制,從根本上減少漏洞的產生。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/98124.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/98124.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/98124.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Mac安裝hadoop

1.在terminal中檢查是否安裝brew命令 brew --version 如果沒有安裝&#xff0c;在terminal中執行命令&#xff0c;安裝brew /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 安裝完成后&#xff0c;再重新打…

多語言編碼Agent解決方案(4)-Eclipse插件實現

Eclipse插件實現&#xff1a;支持多語言的編碼Agent集成 本部分包含Eclipse插件的完整實現&#xff0c;包括多語言支持、命令注冊、API調用和UI集成。插件使用Java開發&#xff0c;基于Eclipse Plugin Development Environment (PDE)。 1. Eclipse插件目錄結構 eclipse-plugin/…

風險規則引擎-RPA 作為自動化依賴業務決策流程的強大工具

機器人流程自動化&#xff08;RPA&#xff09;聽起來好像跟機器人統治世界似的&#xff0c;但其實不是那么回事。RPA 就是一套能在電腦上運行的程序&#xff0c;能快速、高效地自動完成日常重復的工作。RPA 讓你能夠設置一些軟件“機器人”來執行特定的任務。RPA 的一個大好處就…

漏洞無效化學習

一、基礎概念與原理1. 核心定義漏洞無效化&#xff08;Vulnerability Mitigation&#xff09;&#xff1a;并非直接修補漏洞本身&#xff0c;而是通過技術手段降低漏洞被成功利用的概率。其目標是讓攻擊者即使發現漏洞也無法達成攻擊目的。 關鍵思路&#xff1a;通過訪問控制、…

「Vue 項目中實現智能時間選擇:帶業務規則的級聯選擇器」

#創作靈感公司業務需要&#xff0c;某個時間節點前可以選擇到月&#xff0c;某個時間節點后只能選擇季度vue2 Vant2javascriptimport { Cascader, Field, Form, Popup, Button } from vant; import vant/lib/index.css;export default {name: CascaderPage,components: {VanCa…

day1———Qt———應用程序界面設置

1&#xff0c;定義一個Mystring類代替string的功能#include <iostream> #include <string.h>using namespace std; class Mystring {friend ostream &operator<<(ostream &cout,const Mystring &s);friend istream &operator>>(istrea…

apache實現LAMP+apache(URL重定向)

1.apache實現LAMPLAMP是指一組通常一起使用來運行動態網站的自由軟件名稱首字母的縮寫a.L是指Linux操作系統b,.A是指Apache&#xff0c;用來提供Web服務c.M指MySQL&#xff0c;用來提供數據庫服務d.P指PHP&#xff0c;是動態網站的一種開發語言1.1php運行方式說明php是腳本語言…

SAConv可切換空洞卷積

SAConv可切換空洞卷積 帶來的改進機制時可切換的空洞卷積 是一種創新型卷積網絡 專門為增強物體檢測和分割任務&#xff0c;中特征提取去設計 SAC核心時相同的輸入兒子應用到不同空洞率去進行卷積&#xff0c;設計特別開關函數融合這些不同卷積的成果 該方法可讓網絡更靈活的適…

基于Matlab的霧霾天氣和夜間車牌識別系統

在復雜天氣和低光照環境下&#xff0c;車牌識別系統的準確率和穩定性顯著下降&#xff0c;嚴重影響交通管理與智能監控的可靠性。本文針對霧霾天氣和夜間環境下車牌圖像特征模糊、對比度低、噪聲干擾嚴重的問題&#xff0c;提出了一種融合圖像增強與模板匹配的車牌識別方法。系…

華為云/本地化部署K8S-查看容器日志

華為云日志查看 目前工作的大部分情況下&#xff0c;通過華為云LTS云日志服務就可以滿足日常需求。 不過上線時過來支援的開發老哥更習慣于從容器里查看日志&#xff0c;也一并記錄下以備不時之需。 1.登錄服務節點服務器 點擊左側三個橫線&#xff0c;選擇 應用服務-云容器引擎…

【MySQL 死鎖:從 “業務卡頓“ 到 “根因定位“ 的實戰指南】

MySQL 死鎖&#xff1a;從 “業務卡頓” 到 “根因定位” 的實戰指南 后端開發必看&#xff1a;MySQL死鎖排查與預防全攻略線上系統突然報出Deadlock found when trying to get lock; try restarting transaction&#xff0c;用戶操作卡頓甚至超時&#xff0c;排查時卻對著一堆…

從虛擬化基石到云原生架構的降維打擊:用dd/mkfs玩轉namespace隔離,解鎖Docker/K8S資源密碼,看透物理機到云服務器的進化之路

本篇摘要 本文圍繞虛擬化與容器化技術展開&#xff0c;涵蓋架構演進、Docker/K8S優勢與挑戰、namespace隔離實操&#xff08;如主機名/PID隔離&#xff09;、磁盤操作&#xff08;dd/mkfs/df/mount&#xff09;等&#xff0c;對比虛擬機與容器差異&#xff0c;闡明技術原理與架…

自動化測試的概念

文章目錄自動化測試能夠取代人工測試嗎&#xff1f;回歸測試自動化分類自動化測試金字塔為啥單元測試的性價比這么高呢&#xff1f;那為啥UI自動化測試的性價比沒有組件測試的高呢&#xff1f;web自動化測試舉例引入自動化測試的準備工作自動化測試的簡單示例自動化測試能夠取代…

OSPF故障排查實戰:如何通過一條命令精準定位網絡掩碼不匹配問題

掌握display ospf error命令的解讀技巧&#xff0c;快速解決OSPF鄰接關系建立失敗難題。一、問題背景與場景引入 在網絡運維工作中&#xff0c;OSPF&#xff08;開放最短路徑優先&#xff09;協議作為主流的內部網關協議&#xff0c;其穩定運行至關重要。然而&#xff0c;在實際…

Redis----如何引入分布式鎖

一、概述首先引入分布式鎖指的是應用程序引入&#xff0c;不是Redis本身引入&#xff0c;Redis作為中間件可以作為分布式鎖的一個典型實現方案&#xff0c;同時也有一些其他的實現方案。分布式鎖指的是一個/組程序&#xff0c;使用Redis實現的話就是通過添加一個特殊的Key-Valu…

prometheus-2.42.0.linux-amd64.tar.gz 安裝配置展示

一、prometheus 1.1解壓文件 # tar -xzvf prometheus-2.42.0.linux-amd64.tar.gz -C ~/apps/ prometheus-2.42.0.linux-amd64/ prometheus-2.42.0.linux-amd64/NOTICE prometheus-2.42.0.linux-amd64/consoles/ prometheus-2.42.0.linux-amd64/consoles/index.html.example p…

Linux 標準輸入 標準輸出 標準錯誤

目錄一. 簡介二. 常見用法2.1 輸出重定向2.2 錯誤重定向2.3 同時重定向標準輸出 錯誤2.4 輸入重定向2.5 特殊設備三. 這樣設計的好處3.1 區分正常信息和錯誤信息3.2 方便調用方腳本處理3.3 與管道結合時更清晰四. 案例4.1 if判斷4.2 ls查詢一. 簡介 ?在 Linux/Unix 中&#…

零基礎新手小白快速了解掌握服務集群與自動化運維(二)Linux Journalctl命令、Journalctl日志持久化存儲

Linux提供了一個強大的日志系統&#xff0c;它可以跟蹤和記錄系統的各種活動。在這個系統中&#xff0c;journalctl是一個非常重要的工具&#xff0c;用于查詢和操作由systemd進程管理的日志。 本文將深入探討journalctl命令&#xff0c;介紹其基本使用、高級選項及示例等內容…

【學習】【js】棧數據結構

棧 棧是一種遵從后進先出&#xff08;LIFO&#xff09;原則的有序集合。新添加或待刪除的元素都保存在棧的同一端&#xff0c;稱作棧頂&#xff0c;另一端就叫棧底。在棧里&#xff0c;新元素都靠近棧頂&#xff0c;舊元素都接近棧底。 基于數組的棧 時間復雜度O(n),占用較多的…

【Linux】基本指令 · 下

alias 指令起別名為什么 ls -l 指令等價于 ll 指令呢&#xff1f;指令就是可執行程序&#xff0c;和我們自己寫的代碼編譯好的程序&#xff0c;沒有本質區別&#xff01; 指令在系統的某一個位置存在&#xff01; 執行指令前&#xff0c;現在系統中查找對應的指令指令在根目錄下…