王丹, 陳嘉, 趙文兵, 林九川
(1.北京工業大學 信息學部,北京 100124; 2.公安部第三研究所 信息網絡安全公安部重點實驗室,上海 201204)
為對程序運行時行為進行監控和分析,通常是在運行時通過插樁、跟蹤調試等程序動態分析技術來完成。動態二進制插樁技術[1](dynamic binary instrument,DBI),是在不改變程序原有邏輯的基礎上,將一些探針插入到程序中,通過執行探針得到程序運行的特征數據,再分析這些特征數據完成對程序的分析[2-3]。DynamoRIO[4]、Valgrind[5]等是常用的動態二進制插樁工具,它們具有較完善的結構,但均是面向進程的,工作在用戶層,依靠動態插樁技術實現的,導致其難以實現對驅動、多進程、管道通信等的分析檢測,因此并不適合做與系統運行相關的內核分析。
跟蹤調試技術使用調試器來加載程序,通過跟蹤程序運行時調用的函數及執行的指令等來獲取相關信息。常用的跟蹤方法有兩種:一種是使用HOOK技術監視程序運行調用的函數并進行分析;二是以較長的時間代價單步跟蹤程序的執行過程并進行分析。但是,使用插樁技術會破壞程序運行現場和數據的完整性,也容易被惡意木馬反調試技術察覺和規避。
將程序置于虛擬機或虛擬機模擬器環境中運行以獲取其運行過程中的信息是另一種常用的程序運行時監控方法,且該方法不受多態、變形和加密及程序中的間接跳轉和間接調用指令的影響。目前常用的虛擬機模擬分析工具有TEMU[6]、DECAF(dynamic executable code analysis framework)等,它們都基于QEMU平臺。QEMU是一個通用的開源模擬器和虛擬機。作為虛擬機使用時,QEMU可以在不同體系結構的機器上運行同一個虛擬環境,安裝操作系統并運行程序,QEMU提供了多種接口供開發人員使用,采用動態翻譯技術,將虛擬環境中的目標程序翻譯成宿主機器語言,先對基本塊進行翻譯,然后再執行并加以緩存,后續可直接使用緩存的代碼,無需重復翻譯。TEMU是基于QEMU開發的全系統的動態二進制分析平臺,它定義了一組API,用于獲取和設置內存及CPU寄存器的值,并增加了語義提取模塊和污點分析模塊,為用戶開發相關插件提供了接口。DECAF是在相關研究人員改進TEMU不足的基礎上生成的一個新的二進制框架,具有高效、污點信息分析完整等特性。DECAF也為開發人員提供了許多回調接口,通過這些回調接口開發人員可以開發出用于分析Guest操作系統執行過程的強有力的插件。由于QEMU是面向系統的和基于事件驅動的,工作在系統層,能夠較為全面地對程序執行流程實施監控,避免插樁技術易被反調試的弊端。因此,本文基于虛擬機模擬技術的軟件行為監控系統,從系統視角獲取操作系統內核狀態和多個進程的信息并進行分析。設計并實現了基于QEMU并配置DECAF的動態監控平臺,被測程序在QEMU虛擬環境中運行,通過DECAF從外部監視整個模擬器的運行情況,獲取系統級信息。
圖1是總體的監控系統架構。首先在宿主機器上安裝QEMU并配置DECAF平臺,然后在全系統模擬器QEMU上安裝Windows XP操作系統,再在虛擬環境的操作系統中執行被監控對象(如圖1中所示的PE文件)。DECAF從外部監視整個模擬器的運行情況,獲取QEMU系統級語義信息。
如圖2所示,被測程序在QEMU虛擬環境中運行時,QEMU通過微指令生成器將多種不同結構的程序代碼,如x86上的Windows、x86上的Linux、MIPS上的Linux等,翻譯為統一的中間語言。然后,QEMU再根據宿主系統不同的結構,將中間語言翻譯為宿主操作系統可識別的機器碼,進而運行程序。這一系列操作對用戶來說都是透明的。與此同時,DECAF在QEMU翻譯的基礎之上,獲取用戶分析所需的相關信息,如當前進程名稱、程序計數器、當前系統環境等信息并進行處理。另外,通過事件處理機制,可處理用戶注冊的感興趣的事件。當DECAF檢測到用戶注冊的事件在模擬系統中發生時,會觸發DECAF調用用戶注冊的響應函數,獲取當前系統環境數據和被監控程序的信息并進行處理。

圖1 基于虛擬機的監控系統架構Fig.1 Monitoring framework based on virtual machine

圖2 平臺對照Fig.2 Platform contrast
基于虛擬機的動態二進制分析技術,首先會對程序進行動態二進制翻譯,然后再去執行翻譯的結果。這一功能主要依賴它的動態代碼生成器(TCG)。TCG采用動態的翻譯方式,主要負責分析并優化目標代碼,然后將其翻譯為主機代碼,遵循從目標代碼、到TCG代碼、再到主機可識別代碼這樣的流程。具體翻譯過程如下:首先,將每一條目標代碼指令切分為若干個單元操作,每個單元操作由一段簡單的C語言代碼實現,作為一個翻譯塊(TB)。TB是QEMU指令翻譯的基本單位,對應目標代碼的一條指令。在程序運行時,利用動態代碼生成器將以上單元組合操作,以函數形式展現。系統調用這個函數,就相當于執行了一條目標代碼的指令。在翻譯過程中會涉及很多事件,如塊開始執行/結束事件、內存讀寫、被修改的內存位置讀寫等。這些事件會在事件驅動中觸發函數調用。通過QEMU,目標代碼以翻譯塊為單位翻譯并生成中間代碼后放入翻譯緩存中,執行過程如圖3所示。
DECAF提供了簡單易用的事件驅動程序接口,當監測到被注冊的事件發生時,它會調用事先定義的相應的事件處理函數。利用這一接口,分析人員根據自己的需求選擇注冊事件,并在事件發生時,進行相應信息的提取和處理工作。因為要在事件發生時進行實時信息獲取,即注冊的事件在QEMU中發生后,會觸發所對應的回調函數,所以QEMU暫??蛻舨僮飨到y的運行,將DECAF的回調函數作為輔助函數插入到QEMU中,然后恢復QEMU的運行,這時回調函數就會被運行,如圖4所示。

圖3 翻譯過程Fig.3 Translation process

圖4 回調函數觸發過程Fig.4 Trigger process of callback function
當“翻譯塊開始/結束”,“讀取/寫入被污染的內存位置”這樣的事件發生時,相應的回調函數就會開始工作。DECAF通過接口將事件處理函數與事件相關聯。接收到事件的信號后,DECAF會在某個翻譯塊中插入一個輔助函數,使客戶操作系統暫停運行,將輔助函數中的指令兩次翻譯到翻譯塊中,并覆蓋原有指令,然后恢復客戶系統的運行。為這些事件注冊的回調函數就會利用這些數據開始分析處理工作。因為回調函數的觸發和客戶系統的執行是內聯的,所以當事件發生時,回調函數的觸發和客戶系統的執行也會同時發生。
// 開始翻譯塊
// 觸發DECAF_BLOCK_BEGIN回調
movi_i32 tmp21, $
movi_i32 tmp22, $DECAF_invoke_block_begin_callback
call tmp22, $0x0, $0, env, tmp21
// 初始化指令: orl %ebx, %eax
// 觸發DECAF_INSN_BEGIN回調
movi_i32 tmp23, $DECAF_invoke_insn_begin_callback
call tmp23, $0x0, $0, env
mov_i32 tmp11, ebx
mov_i32 tmp12, eax
or_i32 tmp13, tmp12, tmp11
// 觸發DECAF_INSN_END回調
movi_i32 tmp24, $DECAF_invoke_insn_end_callback
call tmp24, $0x0, $0, env
// 初始化指令: addl $0x01, %eax
// Insert DECAF_INSN_BEGIN callback
movi_i32 tmp25, $DECAF_invoke_insn_begin_callback
call tmp25, $0x0, $0, env
movi_i32 tmp14, $0x01
add_i32 tmp15, tmp14, tmp13
mov_i32 eax, tmp15
// 觸發 DECAF_INSN_END 回調
movi_i32 tmp26, $DECAF_invoke_insn_end_callback
call tmp26, $0x0, $0, env
// 翻譯塊結束
// 觸發 DECAF_BLOCK_END 回調
movi_i32 tmp27, $DECAF_invoke_block_end_callback
call tmp27, $0x0, $0, env
goto_tb $0x0
上面的代碼展示了輔助函數DECAF_invoke_insn_begin_callback 和 DECAF_invoke_insn_end_callback的使用,即在相應的事件發生時,這兩個函數會被插入到客戶指令的開頭和結尾。
這里需要說明:事件對應的回調函數調度機制的設計,即對于每一個事件,例如翻譯塊開始,只能插入一個輔助函數,而不能在一個事件發生時,同時調用多個函數對數據進行處理,且在輔助函數內,會遍歷為該事件注冊的所有回調函數,并且決定觸發哪個。該設計有兩個理由:1)各種插件和平臺自身對于同一個事件會注冊很多回調函數,重復調用這些輔助函數會對系統的性能產生負面影響。而上面設計的調度機制可以避免輔助函數的內聯重復調用這一問題。2)在全系統仿真模擬器中,插入到代碼流中的回調函數會在整個客戶操作系統環境中執行,例如,指令碼被插入到一個共享庫中,就會被所有使用這個庫的程序執行。所以需要調度機制來確保當前的執行環境是否對每一個注冊的回調函數都是正確的,之后才可以決定執行。
目前的基于軟件行為的可疑軟件的分析和監控可通過靜態分析或者動態學習,建立軟件的控制流行為模型來實現,如統調用模型和函數調用模型[7-9]??刂屏餍袨槎攘磕P鸵驯蛔C明可以有效地檢測對于控制數據的攻擊[10-11],如惡意代碼注入攻擊、返回庫函數攻擊等常見的攻擊類型。在此背景下,本文從控制流的角度出發,通過使用本文的監控框架對程序的可疑性進行分析判斷。以圖5為例,這是一個簡單的判斷輸入信息是否為數字的程序。當程序正常運行時,即用戶從終端輸入數字的情況下,將susData賦值給memData,但是當用戶輸入的信息不是數字時,即視為程序異常,將會彈出對話框并對用戶進行提示。
//判斷輸入是否為數字
1)if(susData < ‘0’ || susData > ‘9’)
2)MessageBox(NULL, TEXT(“WRONG”), TEXT(“NOT A NUMBER”), MB_OK);
3)else
4)memData=susData;
5)cout 《susData;

圖5 程序正常運行路徑Fig.5 Normal runtime path
正常的運行流程的執行順序應為1→3→4→5,但是當程序異常時,執行順序則為1→2→5,造成了程序的行為異常。這是由于在節點1的控制信息不同引發的。因此,可以通過監測程序的控制流信息,了解到程序是否在預期的軌跡上正常運行,并以此為依據,判斷程序的行為是否可疑。
在執行條件跳轉指令時,匯編語言通過判斷標志位寄存器的情況來判斷是否進行跳轉。如匯編語言的JE指令在執行的時候,系統會查詢標志寄存器中的ZF標志位的內容。如果ZF=1,符合跳轉條件,則程序計數器會跳轉到目標地址;如果ZF=0,則說明跳轉條件不成立,程序計數器將會指向緊接著的下一條指令地址,順序執行。通過獲取在每次跳轉時的標志位寄存器信息,加以處理整合,就可以得到程序運行過程中的控制流信息,并確定跳轉的目的地址。這里不考慮CALL指令和JMP指令這兩個跳轉指令,因為跳轉的目的地址在程序編寫時已經確定,不受控制流信息影響。
基于事件驅動機制,本文設計了回調函數來收集控制流信息。由于QEMU中每一個翻譯塊對應進程的一條指令,因此為了獲取條件跳轉指令,對代碼塊執行結束事件(VM_BLOCK_END_CB)進行注冊。在事件發生時,調用回調函數,該函數根據DECAF提供的用戶接口,對數據進行分析處理,完成控制流信息收集工作。
在回調函數中,需要獲取翻譯執行結束時的系統狀態、翻譯塊的信息、當前程序計數器及下一條指令的程序計數器值。DECAF提供了DECAF_Block_End_Params數據結構,且將對這些變量的賦值過程進行了封裝,可直接使用。
typedef struct _DECAF_Block_End_Params
{
CPUState* env; //CPU環境
TranslationBlock* tb; //翻譯塊
gva_t cur_pc; //當前PE值
gva_t next_pc; //下一個PC值
} DECAF_Block_End_Params;
本文首先通過當前的PC值獲取當前指令,然后通過操作碼判斷指令類型。對于指令JE/JZ (ZF=1),其操作碼為01111110??梢酝ㄟ^操作碼判斷當前指令是否為條件跳轉指令,如果是,繼續進行下一步處理。由于DECAF通過QEMU提供的接口獲取CPU狀態,并將CPU信息存儲在結構體CPUState中,所以本文將該結構體中的eflag的信息提取出來,并保存在記錄文件中。
在回調函數中,首先要初始化插件,然后獲取要檢測的程序名稱和保存結果的記錄文件名稱。根據事件驅動原理,當有新的程序被調用的時候,判斷是否為被測程序,如果是,則開始信息獲取工作,再根據指令的操作碼判斷當前指令是否為條件跳轉指令。如果否,則獲取虛擬機當前的操作系統狀態,并且保存在記錄文件中。然后,繼續按照此判斷和記錄原則監控和跟蹤程序的動態運行。當程序結束時,注銷翻譯塊結束事件發生時要調用的相關函數,最后清理插件資源。
本文選用虛擬機QEMU,可以直接使用如下命令進行QEMU安裝。
$ sudo apt-get install qemu sudo apt-get build-dep qemu
對于DECAF,需要安裝BFD庫和boost庫,命令如下:
$ sudo apt-get install binutils-dev
$ sudo apt-get install libboost-all-dev
在準備好庫后,開始進行配置和編譯工作。DECAF有三個基本的功能設置:TCG污點傳播、VMI和TCG IR日志。因本文只涉及到虛擬機自省技術(virtual machine instropection,VMI),所以只啟用這一功能。然后進行編譯,QEMU就可以運行了,指令如下:
$ sudo config make install
完成QEMU的安裝之后,就可以開始在其上安裝操作系統鏡像,創建所需使用的虛擬機。雖然QEMU本身已經幾乎和任何運行x86體系結構的客戶操作系統兼容,然而DECAF需要更多關于操作系統的信息,進行語義翻譯,提供更多諸如進程的操作系統抽象信息,所以從打開虛擬機開始,使用DECAF控制QEMU運行。
鏡像準備好之后,可以加載QCOW格式的鏡像到QEMU中,完成虛擬機的創建。接下來,通過終端啟動QEMU并運行虛擬機,QEMU窗口就會彈出,可以看到虛擬機啟動情況。
3.2.1 注冊關注事件
根據DECAF的事件驅動機制,用戶可選擇所關注的事件進行注冊,并根據這個事件的發生,獲取系統信息,進行相應的處理與分析。首先通過如下命令注冊新進程開始事件:handle_load_mainmodule=VMI_register_callback(VMI_CREATEPROC_CB,ProcessTrace_loadmainmodule_notify,&should_monitor);
同樣地,在被測程序關閉后,監控工作也應該自動結束,并且對注冊的時間關聯函數進行注銷,實現代碼如下:
handle_remov_process=VMI_register_callback(VMI_REMOVEPROC_CB,ProcessTrace_procexit,&should_monitor);
當新的進程開始運行這一事件發生后,所需要進行的操作如下。首先需要判斷新開始運行的這個進程是否為被測進程,這可以通過獲取QEMU當前系統環境信息實現。具體數據結構設計如下:
typedef struct _VMI_CreateProc_Params {
uint32_t pid; //新進程PID
uint32_t cr3; //新進程CR3
char *name; //新進程名稱
}VMI_CreateProc_Params;
將當前程序的名稱與被檢測的進程名稱進行對比,如calc.exe。判斷當前程序的名稱是否與用戶輸入的要監控的進程名稱一致。如果不一致,繼續等待下一個新進程被運行;如果一致,首先在終端輸出,告知用戶被監控程序已經開始。
程序運行后,系統會為程序分配一個進程PID,并根據當前程序運行情況,將被測程序的PID存入到被測程序的數據結構中。同樣,將CR3寄存器的內容進行保存。根據以上需求,被監控程序需要采用如下數據結構來保存相關信息。
struct monitored_proc {
char name[512]; //被測進程名稱
char configfile[512];//編譯文件
uint32_t cr3; //被測進程CR3
uint32_t pid; //被測進程PID
FILE *tracefile; //記錄文件地址
};
接下來,注冊事件發生時要調用的相關函數,DECAF_registerOptimizedBlockEndCallback,具體實現方法如下:
static void
ProcessTrace_loadmainmodule_notify(VMI_Callback_Params *pcp)
{ char *errorstring;
int i;
uint32_t pid=pcp->cp.pid; //獲取進程的id
char *name=pcp->cp.name; //獲取進程的名稱
if(strlen(mon_proc.name) > 0)
{ //檢查目標進程的名稱是否有效
if(strcmp(mon_proc.name, name)==0)
{ //創建的進程名稱與目標進程名稱一致
printf("%s is starting! ",mon_proc.name);
//輸出目標進程開始執行的信息
mon_proc.pid=pid; //設置目標進程的id
mon_proc.cr3=VMI_find_cr3_by_pid_c(pid);
//設置目標進程的cr3
/ / 進行開始執行, 注冊回調函數
if (!handle_block_end)
//注冊block end事件,開始對進程的控制流進行監控和收集
handle_block_end=
DECAF_registerOptimizedBlockEndCallback(do_block_end, NULL, INV_ADDR,INV_ADDR);
}
}
}
相應地,在被測程序關閉后,需要注銷已經注冊的事件。首先,在終端提示用戶被監控進程已關閉,監控任務結束后,關閉記錄文件;然后清空被監控程序的數據結構中對應的相應數據,最后利用DECAF提供的指令完成事件注銷。具體代碼如下:
int i=0;
uint32_t pid=pcp->rp.pid; //被刪除進程Pid
if(pid==mon_proc.pid) { //如果是被測進程
//輸出相關信息
printf("%s is closed. ", mon_proc.name);
printf("%d kernel calls found. ", kcount);
//關閉文件
fclose(mon_proc.tracefile);
mon_proc.tracefile=NULL;
if (handle_block_end) //如果有回調函數
DECAF_unregisterOptimizedBlockEndCallback(handle_block_end); //注銷
}
3.2.2 判斷獲取時機
確定被監測程序之后,可以開始控制流信息的獲取。當翻譯塊執行結束這一事件發生時,可以獲取到當前指令內容。首先通過當前系統的環境變量參數來判斷系統是否處于內核態,如果是內核態,則說明正在執行內核相關的系統調用指令,不需要進行分析處理,直接返回,等待下一個關注事件發生。 DECAF提供了一個回調函數聯合體,根據不同的事件,提供不同的參數。聯合體的數據結構如下:
typedef struct _DECAF_Callback_Params
{
DECAF_Handle cbhandle;
union{
DECAF_Block_Begin_Params bb;
DECAF_Block_End_Params be;
DECAF_Insn_Begin_Params ib;
DECAF_Insn_End_Params ie;
DECAF_Mem_Read_Params mr;
DECAF_Mem_Write_Params mw;
DECAF_EIP_Check_Params ec;
DECAF_Keystroke_Params ks;
DECAF_Nic_Rec_Params nr;
DECAF_Nic_Send_Params ns;
DECAF_Opcode_Range_Params op;
DECAF_Tlb_Exec_Params tx;
DECAF_Read_Taint_Mem rt;
DECAF_Write_Taint_Mem wt;
#ifdef CONFIG_TCG_LLVM
DECAF_Block_Trans_Params bt;
#endif /* CONFIG_TCG_LLVM */
};
} DECAF_Callback_Params;
在這部分,本文關注翻譯塊執行結束事件,即“DECAF_Block_End_Params”這一類型。這一類型中有四個變量:當前CPU狀態、翻譯塊指針、當前程序PC值和下一個PC值,數據結構如下:
typedef struct _DECAF_Block_End_Params
{
CPUState* env; //CPU狀態
TranslationBlock* tb; //翻譯塊
gva_t cur_pc; //當前PC
gva_t next_pc; //下一個PC
} DECAF_Block_End_Params;
通過傳入第一個變量env可以利用DECAF的判斷函數判斷當前系統是否處于內核狀態。若系統不處于內核態,則意味著當前指令屬于被測進程,通過當前PC值,獲取匯編指令對應的指令編碼。由于本文主要關注條件跳轉指令,通過其獲取控制流信息內容,而在Windows_x86系統中,編碼第一字節的內容為指令的操作碼,可以根據操作碼判斷當前指令是否為條件跳轉指令。
然后,判斷當前指令所屬的進程是否為監視進程??赏ㄟ^DECAF提供的宏,獲取當前CR3寄存器的值。因為每一個進程都有自己的CR3寄存器內容,所以可以根據這個值進行判斷。如果指令不屬于被監控程序,則直接返回,等待下一個翻譯塊執行事件的發生。如果是被監控進程,則繼續下面的相關信息的提取工作。
3.2.3 提取相關信息
確定當前指令是屬于被監控程序的一條跳轉指令后,開始獲取當前系統標志位寄存器狀態的工作。在x86系統中,有一個32位的標志寄存器。在初始化時,x86的標志寄存器狀態為00000002H,第1、3、5、15以及22~31位被系統預留,內容固定,不表示任何具體信息,程序的運行也不會以這些位的內容為依據。標志位寄存器的值不能被整體復制或修改,因為它們都是根據特定指令,由系統進行修改,例如cmp指令,執行后不保留運算結果,只對標志寄存器產生影響,然后通過其他相關指令訪問這些被影響的標志寄存器,來產生對整個程序的影響。但是,通過DECAF提供的接口,可以直接將標志寄存器的信息賦值給特定類型的變量,然后將其輸出到記錄文件中。
本文設計的獲取eflags的變量類型定義如下。因為DECAF支持多種體系結構和操作系統的虛擬機,所以根據不同的虛擬機類型,有一套對應機制。如果是32位系統,則將獲取eflags的變量類型定位為32位,對于64位的操作系統也進行相應的定義。
#if TARGET_LONG_SIZE==4
//如果目標代碼長4字節,按如下方式進行定義
//定義long型
typedef int32_t target_long
__attribute__((aligned(TARGET_LONG_ALIGNMENT)));
//定義無符號long型
typedef uint32_t target_ulong
__attribute__((aligned(TARGET_LONG_ALIGNMENT)));
//定義lx
#define TARGET_FMT_lx "%08x"
//定義ld
#define TARGET_FMT_ld "%d"
//定義lu
#define TARGET_FMT_lu "%u"
#elif TARGET_LONG_SIZE==8
//如果目標代碼長8字節,按如下方式進行定義
typedef int64_t target_long
__attribute__((aligned(TARGET_LONG_ALIGNMENT)));
typedef uint64_t target_ulong
__attribute__((aligned(TARGET_LONG_ALIGNMENT)));
#define TARGET_FMT_lx "%016" /*PRIx64*/
#define TARGET_FMT_ld "%" PRId64
#define TARGET_FMT_lu "%" PRIu64
#else
#error TARGET_LONG_SIZE undefined
#endif
通過以上過程得到了程序動態運行過程中的控制流信息。下面需要對功能進行封裝,完成與DECAF平臺接口的連接工作和用戶交互的實現。
用戶使用本項目所提供的功能時,需要在命令行輸入如下命令:
trace_process process_name trace_file_name
其中,包含兩個參數:進程名和記錄文件名稱。
在Linux中,通過定義命令配置文件,將實現功能的函數與命令綁定。具體來說,當用戶在終端輸入trace_process命令時,調用do_trace_process()函數。實現代碼如下:
{//命令名稱
.name=“trace_process”,
//命令類型
.args_type="proc_name:s,tracefile:F",
//命令處理函數
.mhandler.cmd=do_trace_process,
//記錄文件
.params=“process_name trace_file_name”,
//使用說明
.help="Trace by name of the process. The process must not have started yet. The trace is saved to the said file.",
}
然后,do_trace_process()函數從命令行提取參數,具體實現代碼如下:
//獲取進程名稱
const char *procname=qdict_get_str(qdict,
“proc_name”);
//獲取記錄文件路徑
const char *tracefile_path=qdict_get_str(qdict, “tracefile”);
存放被監測程序信息的結構體設計如下。
struct monitored_proc {
char name[512]; //進程名稱
char configfile[512]; //配置文件
uint32_t cr3; //CR3寄存器
uint32_t pid; //進程ID
FILE *tracefile; } //記錄文件
首先,命令的參數中,用戶輸入的被測程序的名字記錄到結構體對應的變量中;然后,根據用戶輸入的記錄文件路徑嘗試打開文件,如果路徑無效或者文件無法打開,則在終端給用戶提示,不進行后續工作。該處理可以增強程序的健壯性。如果文件可以成功打開,則將記錄文件路徑寫入結構體,然后等待被測程序運行,并通過終端告知用戶程序開始運行。
下面是Linux命令處理模塊的部分代碼。模塊的輸入信息為被測程序和記錄文件。
int i;
FILE *tracefile;
//新建進程如果是被測進程
if(strcmp(mon_proc.name, procname)==0) {
printf("Process %s already being traced. ", procname);
return;
}
//保存被測進程名稱
strncpy(mon_proc.name, procname, 512);
mon_proc.name[511]=' 主站蜘蛛池模板: 99精品伊人久久久大香线蕉| 成年免费在线观看| 亚洲第一区在线| 久久网欧美| 九九热精品在线视频| YW尤物AV无码国产在线观看| 国产精品无码久久久久AV| 无码高清专区| 亚洲欧美一区二区三区图片| 国产精品亚洲一区二区在线观看| 三级视频中文字幕| 亚洲一区免费看| 欧美成人看片一区二区三区| 一本大道AV人久久综合| 露脸国产精品自产在线播| 成人无码一区二区三区视频在线观看 | 日韩天堂视频| 高清免费毛片| 99久视频| 一级毛片在线免费视频| 免费欧美一级| 精品一区二区三区水蜜桃| 亚洲欧州色色免费AV| 国产精品男人的天堂| 婷婷在线网站| 日韩午夜伦| 欧美日韩激情| 国产女同自拍视频| 午夜无码一区二区三区| 日韩无码视频专区| 久久www视频| 国产91全国探花系列在线播放| 亚洲αv毛片| 香蕉蕉亚亚洲aav综合| 亚洲最大综合网| 欧美黄网站免费观看| 国产AV无码专区亚洲A∨毛片| 亚洲日韩每日更新| 波多野结衣在线一区二区| 国产福利一区视频| 亚洲资源站av无码网址| 国产香蕉在线| 狠狠躁天天躁夜夜躁婷婷| 91视频精品| 一级毛片在线直接观看| 国产一区成人| 在线无码av一区二区三区| 亚洲午夜天堂| 97久久精品人人做人人爽| 亚洲水蜜桃久久综合网站 | 亚洲色欲色欲www在线观看| 伊在人亚洲香蕉精品播放| 亚洲色中色| 国产麻豆精品手机在线观看| 免费一极毛片| 国产精品欧美亚洲韩国日本不卡| 欧美中日韩在线| 白丝美女办公室高潮喷水视频| 99re免费视频| 欧美日韩国产精品综合| 国产69精品久久久久妇女| 亚洲av日韩av制服丝袜| 尤物视频一区| 天堂岛国av无码免费无禁网站| 天天色天天综合网| 伊人欧美在线| 色综合中文| 国产在线小视频| 久久精品欧美一区二区| 国产亚洲高清在线精品99| 欧美精品不卡| 特级做a爰片毛片免费69| 国产精品xxx| 欧美精品黑人粗大| 3D动漫精品啪啪一区二区下载| 国产波多野结衣中文在线播放| 91精品网站| av一区二区人妻无码| 成人在线综合| 亚洲精品va| 久久频这里精品99香蕉久网址| 免费福利视频网站|