您可以通過從封裝器中派生編譯的程序來運行編譯後的程序,並使用Linux ptrace(2)工具攔截並檢查程序調用的所有系統調用。
以下示例代碼顯示了一個運行/ usr/bin/w命令的打包程序,打印由該命令調用的每個系統調用,並在嘗試調用write(2)系統調用時終止該命令。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <sys/reg.h>
#define BAD_SYSCALL __NR_write
int main(int argc, char *argv)
{
pid_t child;
int status, syscall_nr;
child = fork();
if (child == 0) {
/* In child. */
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execl("/usr/bin/w", NULL, NULL);
// not reached
}
/* In parent. */
while (1) {
wait(&status);
/* Abort loop if child has exited. */
if (WIFEXITED(status) || WIFSIGNALED(status))
break;
/* Obtain syscall number from the child's process context. */
syscall_nr = ptrace(PTRACE_PEEKUSER, child, 4 * ORIG_EAX, NULL);
printf("Child wants to execute system call %d: ", syscall_nr);
if (syscall_nr != BAD_SYSCALL) {
/* Allow system call. */
printf("allowed.\n");
ptrace(PTRACE_SYSCALL, child, NULL, NULL);
} else {
/* Terminate child. */
printf("not allowed. Terminating child.\n");
ptrace(PTRACE_KILL, child, NULL, NULL);
}
}
exit(EXIT_SUCCESS);
}
你可以使用ptrace的更強大的東西,如檢查和更改進程的地址空間(例如,獲得和修改傳遞給系統調用的參數)。
在這個Linux Journal Article及其follow-up可以找到一個很好的介紹。
這看起來很不容易。畢竟,幾乎所有可以想象的C程序都會合法地進行系統調用,如:分配內存,讀寫文件,使用標準輸入和標準輸出等。 – 2010-06-01 09:16:39
你認爲什麼樣的程序永遠不會進行系統調用?請發表一個例子。 – 2010-06-01 09:23:55
@高性能標記:嗯,我只是想阻止一些特定的系統調用,因爲它們是有限的,諸如fork(),open()等調用,... @Neil Butterworth:我的意思不是所有的系統調用,而是惡意的系統調用,例如execv()可以用來執行一個BASH腳本,將我的數據抹去在磁盤上。 – 2010-06-01 09:29:19