2017-05-22 22 views
-1

所以我一直在爲這個練習而努力。我必須得到由我選擇的任何給定的Linux命令(I.E.ls或cd)所做的系統調用,將它們列在.txt文件中,並在它們旁邊列出其唯一的ID。獲取系統調用ID並將它們存儲在.txt文件中(LINUX)

到目前爲止,這裏就是我的了:

strace -o filename.txt ls 

這時候在Linux shell中執行給了我包含ls命令的所有系統調用「FILENAME.TXT」文件。現在,在我的C腳本:

#include <stdio.h> 
#include <stdlib.h> 

int main(){ 
    system("strace -o filename.txt ls"); 
    return 0; 
} 

這應該做一樣的前面的代碼,但它沒有返回我什麼,雖然成功地代碼編譯。我將如何去解決這個問題,然後獲得ID?我使用的是「stdlib」庫,因爲在我的研究中,我發現它與系統調用ID有一些關係,但沒有找到任何關於如何獲得它們的指示。基本上我必須讀取我創建的文件,並讓它給每個系統調用它的ID。

+0

從你自己的程序執行shell命令有什麼意義?如果你被要求在c中這樣做,你應該看看[man ptrace](http://man7.org/linux/man-pages/man2/ptrace.2.html) –

+0

1)C不是一種腳本語言。 2)@FelixPalmen是對的:它沒有任何意義。 – Olaf

回答

0

這個練習顯然是設計成可以通過使用ptrace()工具來解決的,因爲strace實用程序沒有打印系統調用號的選項(據我所知)。

從技術上講,你可以使用像

printf '#include <sys/syscall.h>\n' | gcc -dD -E - | awk '$1 == "#define" { m[$2] = $3 } END { for (name in m) if (name ~ /^SYS_/) { v = name; while (v in m) v = m[v]; sub(/^SYS_/, "", name); printf "%s %s\n", v, name } }' 

產生了一些syscall-number syscall-name線,用於映射系統調用的名稱回系統調用號,但是這將是愚蠢的,而且容易出錯。愚蠢的是,因爲能夠使用ptrace()比使用strace實用程序給你更多的控制權,並且使用上面的「聰明黑客」只是意味着你避免學習如何做到這一點,在我看來,這在定義上是自欺欺人的,因此非常愚蠢;並且容易出錯,因爲絕對不能保證安裝的標題與正在運行的體系結構相匹配。在多體系結構中這尤其成問題,您可以使用-m32-m64編譯器選項在32位和64位體系結構之間切換。它們通常具有完全不同的系統調用號碼。

從本質上講,你的程序:

  1. fork()一個子進程。

    在子過程:

    1. 通過調用ptrace(PTRACE_TRACEME, (pid_t)0, (void *)0, (void *)0)

    2. 可選致電prctl(PR_SET_DUMPABLE, 1L)

    3. 製作父進程示蹤劑啓用ptracing,設置跟蹤選項。例如,致電ptrace(PTRACE_SETOPTIONS, getpid(), PTRACE_O_TRACECLONE | PTRACE_O_TRACEEXEC | PTRACE_O_TRACEEXIT | PTRACE_O_TRACEFORK),以便至少捕獲clone(),fork()和exec()系列調用系列。

      如果您沒有設置PTRACE_O_TRACEEXEC選項,您應該使用例如,停止子進程。 raise(SIGSTOP);,以便父進程可以開始追蹤這個孩子。

    4. 執行要使用例如跟蹤的命令。 execv()。特別是,如果第一個命令行參數是要運行的命令,可以選擇後跟其選項,則可以使用execvp(argv[1], argv + 1);

      如果您設置了上面的PTRACE_O_TRACEEXEC選項,那麼內核會在執行新的二進制文件之前自動暫停子進程。

      如果exec失敗,子進程應該退出。我喜歡用exit(127);,返回退出狀態127

  2. 在父進程,使用waitpid(childpid, &status, WUNTRACED | WCONTINUED在循環,抓子進程中的事件。

    第一個事件應該是初始暫停,即WIFSTOPPED(status)爲真。 (如果沒有,否則出事了。)

  3. 有三個三種不同的原因waitpid(childpid, &status, WUNTRACED | WCONTINUED)可能返回:

    • 當孩子退出(WIFEXITED(status)將是真實的)。 這應該明顯地結束跟蹤,並且也有父跟蹤程序進程退出。

    • 當孩子恢復執行(WIFCONTINUED(status)將成立)。

      您不能認爲PTRACE_SYSCALL,PTRACE_SYSEMU,PTRACE_CONT等命令實際上已導致子進程繼續,直到父進程獲取此信號。換句話說,你不能只將ptrace()命令發送給子進程,並期望它們以有序的方式發生! ptrace()工具是異步的,並且該調用將立即返回;你需要waitpid()WIFCONTINUED(status)類型的事件來知道子進程注意到該命令。

    • 當內核由於子進程即將執行系統調用而停止子進程(使用SIGTRAP)時。每當子進程被停止,因爲它是即將執行系統調用(在父,WIFSTOPPED(status)將是真實的。)

  4. ,你需要使用ptrace(PTRACE_GETREGS, childpid, (void *)0, &regs)以獲得子進程的CPU寄存器狀態系統調用執行點。

    regs的類型爲struct user,定義於<sys/user.h>。對於Intel/AMD架構,regs.regs.eax(32位)或regs.regs.rax(64位),包含在<sys/syscall.h>定義的系統調用號(SYS_foo

    然後,您需要調用ptrace(PTRACE_SYSCALL, childpid, (void *)0, (void *)0)告訴內核來執行系統調用和waitpid()再次等待WIFCONTINUED(status)事件通知,它做到了。

    waitpid()WIFSTOPPED(status)類型的事件發生時,系統調用就完成了。如果你願意,你可以使用PTRACE_GETREGS再次檢查regs.regs.eaxregs.regs.rax,這包含系統調用返回值;在Intel/AMD上,如果發生錯誤,它將是一個負的錯誤值(即-EACCES-EINVAL或類似的。)

    你需要調用ptrace(PTRACE_SYSCALL, childpid, (void *)0, (void *)0)來告訴內核繼續運行子進程,直到下一次系統調用。

有上線展示上面的一些細節相當多的例子,雖然大部分是我親自看到的都是在錯誤檢查不嚴漂亮,偶爾省略檢查WIFCONTINUED(status)waitpid()事件。我甚至寫了一個答案,詳細說明如何在StackOverflow上停止並繼續單獨的線程。由於該技術可以用作非常強大的自定義調試工具,因此我建議您嘗試學習該設施,以便在工作中利用它,而不是複製粘貼一些現有代碼以獲得通過評分。

相關問題