這代碼看著就很危險
我能看到的就已經好幾個UB了
這代碼看著就很危險
我能看到的就已經好幾個UB了
这个,char *password这行对吗
多次聲明不是問題, 但是沒必要重複聲明
哦查了下原来在哪都可以声明函数,我一直习惯写在全局(或者说定义声明在同一个层级,你都定义在全局了)就以为不能这么搞
C不管的
我的敲代码能力堪比一根成年香蕉。。。
大佬可否指正一下![]()
GPT 6.1 Sol xHigh 簡單評價一下
其實你如果用C的標準庫 printf 和 scanf 本身就是漏洞百出的, 用好很困難
然後你再做 字符的 arithmetic calculation 就更容易錯, 這個地方都是天坑, 憑感覺就知道有錯誤
不過這些玩意兒… 初學者暫時不用管, 先能跑就行
– 分割線 –
主要問題是:輸入失敗後使用未初始化資料、整數溢位,以及缺乏字元與位移值的驗證。 以下區分可由目前 main() 觸發的問題,以及函式被其他程式呼叫時才會出現的風險。數值範例假設 ASCII 與 32 位元 int。
沒有檢查 scanf() 的回傳值:未初始化讀取,可能連帶造成記憶體越界
scanf("%99s %d", x, &y);
輸入 abc hello,或只有 abc 後就結束輸入時,只有 x 被成功賦值,y 仍未初始化;接著呼叫 password(x, y) 就會使用不確定的值。
若一開始就遇到 EOF,x、y 都未初始化。此時 x 沒有可靠的 '\0' 終止標記,迴圈可能越界讀取、修改堆疊記憶體,後面的 %s 輸出也可能越界讀取,造成崩潰或資訊洩漏。
至少必須在回傳值不等於 2 時停止處理;只把變數初始化,仍未解決接受無效輸入的問題。
%d 本身無法安全處理超出 int 範圍的輸入
例如:
abc 999999999999999999999999999999
依 C11/C17 的規則,若數值轉換結果無法由目標物件表示,行為未定義;不能假設 scanf() 一定會回傳失敗。因此,即使補上回傳值檢查,也還沒完整修好。 C 標準草案 N1570,§7.21.6.2¶10
應先以有長度限制的方式讀入文字,再使用 strtol(),檢查是否有數字、ERANGE、INT_MIN/INT_MAX 範圍,以及結尾是否有非法字元。
三處運算可能發生有號整數溢位
| 運算 | 觸發例子 | 問題 |
|---|---|---|
'z' - b |
a -2147483648 |
122 - INT_MIN 超出 int 範圍 |
a[i] - 'a' + b |
z 2147483647 |
25 + INT_MAX 溢位,之後才做 % 26 已經太晚 |
a[i] + b |
輸入位元組 0x80,位移 -2147483525,且 char 為有號 |
-128 + (-2147483525) 下溢 |
有號整數溢位屬於未定義行為,不能依賴它自然繞回。SEI CERT INT32-C
(int)a[i] 無法避免這些問題,也不會把負的 char 轉成正值。應在進行字元運算之前先縮小位移範圍:
b %= 26;
if (b < 0)
b += 26;
這段對 INT_MIN 也安全。
沒有驗證字元範圍,負位移也沒有正確循環
函式似乎預期處理小寫英文字母,實際上卻接受所有非空白位元組:
| 輸入 | 實際輸出 | 影響 |
|---|---|---|
a -1 |
反引號 ` |
沒有循環回 z |
Z 1 |
[ |
大寫字母被錯誤轉換 |
a -97 |
空字串 | a[0] 被寫成 '\0',printf() 提早結束輸出 |
a -70 |
ESC,位元組 0x1B |
輸出可能包含終端控制字元 |
中文/UTF-8 也會被逐位元組修改,破壞編碼。如果輸出進入終端或日誌,控制字元還可能干擾顯示或後續處理,實際影響取決於接收端。
另外,運算結果可能超出 char 可表示的範圍;對有號 char,C11/C17 規定這類轉換的結果或訊號由實作決定。N1570,§6.3.1.3
應明確決定:拒絕非小寫字元,或保留它們不變;接著只對合法字元做位移。
長度限制避免了直接寫爆,卻沒有完整驗證輸入
%99s 最多儲存 99 個字元,再補一個 '\0',所以與 char x[100] 的容量配合正確。
問題是超出的部分留在輸入串流中:
%d 失敗,觸發第 1 點。a,緊接著 1 2」,%d 會把緊接的 1 當成位移,真正的 2 留下。abc 1garbage 也會成功完成兩次賦值,非法尾巴被忽略。%s 無法讀取含空白的完整密碼;來自檔案或管線的內嵌 NUL,也可能造成讀入內容與處理內容不一致。若要求固定的輸入格式,就必須檢查整筆輸入、拒絕超長內容,並驗證分隔與剩餘字元。
password() 的記憶體安全依賴呼叫者保證
char *password(char *a, int b)
函式沒有容量或長度參數。呼叫者必須保證 a 指向有效、可寫,而且在物件邊界內有 '\0' 的緩衝區。
傳入 NULL、已釋放的指標、沒有終止字元的陣列,或需要修改的字串常值,都可能導致非法存取。對極大的合法字串,int i 還可能溢位。
這些不是目前 main() 成功讀入後必然存在的漏洞;若要把函式提供給其他程式使用,就應清楚訂定契約,或增加容量/長度參數、以 size_t 索引並限制存取範圍。
若用來保護真正的密碼,演算法不具安全性
對預期的小寫循環位移而言,這是凱撒密碼,只有 26 種位移,很容易還原,也不具備完整性保護。
登入密碼應交給成熟的密碼雜湊函式庫處理;需要還原的機密資料則應使用成熟的認證加密方案。
我已用 MemorySanitizer 重現錯誤輸入與 EOF 造成的未初始化讀取,並用 UndefinedBehaviorSanitizer 重現表中三處整數溢位。以上能確認程式存在未定義行為;能否進一步利用,仍取決於實際編譯與執行環境。
英语里学士和单身狗是一个词……
确实,但英语语境下bachelor有一种“aspiring to find a spouse”的意味在
如果一个人不想找男女朋友,一般直接说single(说bachelor也没错,但美国人会觉得你很奇怪)
這個在哲學初階課用來講equivocation的時候經常舉例子