<kbd id="9plqc"><label id="9plqc"></label></kbd>

        <th id="9plqc"></th>
        1. <center id="9plqc"><video id="9plqc"></video></center>
          <sub id="9plqc"><form id="9plqc"><pre id="9plqc"></pre></form></sub>
          <nav id="9plqc"><form id="9plqc"><legend id="9plqc"></legend></form></nav>
          c語言中fgets()和read()的區(qū)別以及pwn題目中需要設(shè)置setbuf的原理。 您所在的位置:網(wǎng)站首頁 屬虎和屬蛇的能婚配嗎女孩名字 c語言中fgets()和read()的區(qū)別以及pwn題目中需要設(shè)置setbuf的原理。

          c語言中fgets()和read()的區(qū)別以及pwn題目中需要設(shè)置setbuf的原理。

          2023-11-01 20:00| 來源: 網(wǎng)絡(luò)整理| 查看: 265

          fgets是一個c語言函數(shù), read 是一個系統(tǒng)調(diào)用(實際上也是libc里面的一個c語言函數(shù),只不過封裝了一個系統(tǒng)調(diào)用) 。fgets 讀取的數(shù)據(jù)來自stdin的緩沖區(qū)(由read負責讀入stdin緩沖區(qū))再寫入用戶指定的緩沖區(qū), read則是直接讀取數(shù)據(jù)存到用戶指定的緩沖區(qū)(不經(jīng)過stdin緩沖區(qū))read不會 fgets 通過文件指針讀文件, read 使用文件描述符讀文件fgets 遇到回車就停止讀取 而read遇到回車、空格、\x00都不管,它會一直讀取你讓他讀取的字節(jié)數(shù)。fgets把數(shù)據(jù)拷貝到用戶指定的緩沖之后會加一個\x00,read不會加。 以上原理的依據(jù)在哪,以調(diào)試記錄為證:

          這個是調(diào)用fgets時候所經(jīng)歷的函數(shù)backtrace以及系統(tǒng)調(diào)用的參數(shù):

          在這里插入圖片描述 在這里插入圖片描述 可以看到系統(tǒng)調(diào)用read讀入的buffer是IO_2_1_stdin的緩沖區(qū),從libc的fgets()到read經(jīng)歷了不少函數(shù)幀,而且我們可以嘗試不停往管道里寫入不包含換行符字符串,會發(fā)現(xiàn),我們每到read阻塞的時候,每寫一次,read函數(shù)就會返回,但是接著又會繼續(xù)調(diào)用繼續(xù)阻塞,所以說,一次fgets()可能會調(diào)用多次read。

          這個是調(diào)用read時候所經(jīng)歷的函數(shù)backtrace以及系統(tǒng)調(diào)用的參數(shù): 在這里插入圖片描述 可以看到系統(tǒng)調(diào)用read讀入的buffer是用戶空間指定的buffer,且read()函數(shù)僅僅為libc里面的sys_read系統(tǒng)調(diào)用的封裝。 順帶一提 getchar()也是調(diào)用的read函數(shù),調(diào)試如下:

          在這里插入圖片描述 而我們在終端上發(fā)送ctrl+c的中斷信號后,這個信號稱為SIGINT也被read()讀入,之后程序就會斷在下一個位置:

          在這里插入圖片描述 可以對比上圖的0x40009112bc 我們在終端上發(fā)送ctrl+D的EOF信號(windows上是ctrl+z)后,也被getchar()讀入,但區(qū)別是之后但getchar()函數(shù)就不再起作用了,因為getchar讀的數(shù)據(jù)是從文件指針里讀,而文件指針指向EOF之后就不再前進了,這也是為什么我們這個程序輸入ctrl+D之后會一直返回亂碼的原因:

          #include void main() { int c; while (1) { c = getchar(); // Get one character from the input putchar(c); // Put the character to the output } }

          但以下代碼就沒關(guān)系,因為read讀入的數(shù)據(jù)繞過了文件指針,直接讀入:

          #include void main() { int c; while (1) { read(0,&c,1); // Get one character from the input write(1,&c,1); // Put the character to the output } }

          至于為什么以上兩個程序在使用方向鍵的時候會^[[C請參考這篇: https://www.zhihu.com/question/21518507 如果要讓終端不要回車才發(fā)送數(shù)據(jù)可以設(shè)置 結(jié)構(gòu)體termios的數(shù)據(jù)成員c_lflag的ICANON flag。 看這里gnu官方 關(guān)于pwtools發(fā)送EOF參考這篇:

          https://github.com/Gallopsled/pwntools/issues/985

          假如我們考慮這個命令:

          command1 | command2

          以上命令中包含了兩個緩沖區(qū)標準輸入緩沖(stdin buffer)、管道緩沖(pip buffer) 在這里插入圖片描述

          而如果在還沒讀取完需要的字節(jié)數(shù)(nbytes)前就已經(jīng)空了,那么read將分類討論:

          在讀取一個空管道的情況下: 此時如果沒有進程在往這個管道里寫東西(也就是把這個管道關(guān)閉了),read()就不報錯,返回0,因為空管道的大小是0.此時有進程在往這個管道里寫東西而且之前設(shè)置了O_NONBLOCK 標志, read() 就會報錯,并返回-1此時有進程在往這個管道里寫東西而且之前沒設(shè)置O_NONBLOCK 標志,或者是這個標志(flag)被清除了, 調(diào)用read的那個線程就會被read阻塞,直到有新數(shù)據(jù)寫過來或者管道關(guān)閉(也就是沒有任何一個進程往管道里寫東西)。 在被中斷的情況下:

          read被中斷的時候沒有還沒有來得及讀取任何數(shù)據(jù),會報錯,返回-1 read被中斷的時候已經(jīng)讀取了一些數(shù)據(jù),會返回讀取的字節(jié)數(shù)量大小。

          在讀取其他大小不為空的管道(PIPE)、有名管道(FIFO)、文件、終端的時候。 文件大小比nbytes小,返回文件大小終端一行的數(shù)據(jù)比nbytes小也就是按了回車,返回這一行數(shù)據(jù)的大小管道(FIFO或者PIPE)能夠 即時(immediately) 提供的數(shù)據(jù)小于nbytes,返回能夠即時提供的數(shù)據(jù)的大小。

          根據(jù)以上規(guī)則,我們可以推斷出,在read等待輸入的時候,輸入的地方打開了類似管道的數(shù)據(jù)流,此時線程會被阻塞,而一旦接收到數(shù)據(jù),read就無論后續(xù)是否有數(shù)據(jù)發(fā)送過來,立即把當前的數(shù)據(jù)讀取并返回,所以我們在設(shè)置緩沖區(qū)的時候,不能設(shè)置的過小,不然會導致read讀取的數(shù)據(jù)不全。當然,通過setbuf(0)把緩沖區(qū)設(shè)置為0,也就是關(guān)閉緩沖區(qū)也能解決這個問題。

          還有一個問題就是搭建pwn題的時候有時候無法立即回顯,這是因為我們搭建pwn環(huán)境的時候連接程序輸出用的是管道而不是像直接啟動程序的時候那樣用的是終端,對于終端,程序的輸出會直接回顯,而對于管道或者硬盤那樣的文件系統(tǒng),程序會設(shè)置緩沖區(qū),知道緩沖區(qū)滿了才回顯,如我上次寫的這篇文章: https://blog.csdn.net/fjh1997/article/details/105046180

          事實上,還有一個緩沖區(qū),他存在在我們的命令行中,那就是終端層(tty或pty)的緩沖區(qū),這個緩沖區(qū)就是我們還沒有輸入回車之前輸入的數(shù)字,一旦按了回車,這個緩沖區(qū)就會清空,然后把數(shù)據(jù)發(fā)送給我們的程序。 根據(jù)模式的不同分為“Cooked"和”raw“模式,”Cooked“模式不會輸入類似于 CtrlD, CtrlS, CtrlU, Backspace這樣的字符,一旦檢測到這類字符,就會把他們處理掉,而“raw”模式就不會處理這些字符,一旦檢測到,就會原封不動的發(fā)送過去。可以關(guān)于tty的行歸程看這篇文章:-

          https://blog.csdn.net/dog250/article/details/78818612 源碼在這里有:https://github.com/torvalds/linux/blob/master/drivers/tty/pty.c 在這里插入圖片描述

          詳見:

          https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.htmlhttp://www.pixelbeat.org/programming/stdio_buffering/https://unix.stackexchange.com/questions/21752/what-s-the-difference-between-a-raw-and-a-cooked-device-driverhttps://stackoverflow.com/questions/31856286/getchar-loops-over-eof-when-stdin-provided-through-a-pipe?rq=1


          【本文地址】

          公司簡介

          聯(lián)系我們

          今日新聞

          推薦新聞

          專題文章
            CopyRight 2018-2019 實驗室設(shè)備網(wǎng) 版權(quán)所有
            黄色免费网站在线看,韩国精品在线观看,韩国美女一区二区,99国产热 丰顺县| 大英县| 增城市| 沁水县| 铜鼓县| 灌云县| 长治市| 伊春市| 德令哈市| 康保县| 田东县| 永吉县| 自贡市| 大名县| 九江市| 石泉县| 锡林郭勒盟| 新宁县| 安乡县| 安陆市| 彰化市| 成安县| 若羌县| 汉沽区| 耿马| 隆林| 贡山| 辽宁省| 富川| 永顺县| 廉江市| 上虞市| 京山县| 乌兰察布市| 云龙县| 五莲县| 杭锦旗| 梁平县| 磴口县| 长葛市| 三原县| http://444 http://444 http://444 http://444 http://444 http://444