[英]How to find the “exit” of a C program
該測試是在32-bit x86
Linux上進行的。
因此,基本上,我試圖通過在匯編代碼中插入檢測指令來記錄已執行的基本塊的信息。
我的策略是這樣的:在globl數組中寫入已執行的基本塊的索引,並在數組已滿(16M)時將其從內存刷新到磁盤。
這是我的問題。 當檢測的二進制文件執行結束時,即使它沒有達到16M邊界,我也需要將數組刷新到磁盤。 但是,我只是不知道在哪里可以找到assembly
程序的出口。
我嘗試了這個:
grep exit
從目標匯編程序grep exit
,並在call exit
指令之前刷新內存。 但是根據一些調試經驗,目標C程序(例如md5sum
二進制文件)在完成執行后不會調用exit
。
在main
功能末尾刷新內存。 但是,在匯編代碼中,我只是不知道main
函數的確切結尾在哪里。 我可以采取保守的方法,例如,查找所有ret
指令,但是在我看來,並非所有main
功能都以ret
指令結尾。
所以這是我的問題,如何識別assembly code
的確切執行端,並在其中插入一些檢測指令? 掛鈎一些庫代碼對我來說很好。 我了解使用不同的輸入,二進制可以在不同的位置退出,所以我想我需要一些保守的估計。 我清楚嗎? 謝謝!
我相信您通常無法做到這一點。 首先,如果main
正在返回某些代碼,則它是一個退出代碼(如果main
沒有顯式return
則最新的C標准要求編譯器添加隱式 return 0;
)。 然后,一個函數可以將exit
地址存儲在某些數據中(例如,全局函數, struct
的字段等),而其他一些函數可以通過函數指針來間接調用它。 實際上,程序可以使用dlopen
加載某些插件,並使用dlsym
作為"exit"
名稱,或者只是在插件內部調用exit
,等等。。。AFAIU完全解決了該問題(從動態意義上尋找實際的exit
調用)可以證明等同於停止問題 。 另請參見賴斯定理 。
在不要求詳盡無遺的方法的情況下,我會提出其他建議(假設您對使用C或C ++等編碼的程序感興趣,...您可以使用其源代碼)。 您可以使用MELT自定義GCC編譯器,以更改在GCC中處理的基本塊,以調用某些檢測函數。 它不是很簡單,但是是可行的...當然,您需要使用這種定制的GCC重新編譯一些C代碼以對其進行檢測。
(免責聲明,我是MELT的主要作者;請隨時與我聯系以獲取更多信息...)
順便說一句,您了解atexit(3)嗎? 它可能對您的刷新問題有幫助...,並且您還可以使用LD_PRELOAD
技巧(有關動態鏈接器的信息 ,請參閱ld-linux(8) )。
每次都應該起作用的方法是創建一個共享內存部分,用於在其中存儲數據。
您還創建了一個子進程,該進程正在等待調試的進程完成。
待調試的進程完成后,子進程將使用共享內存中的數據來完成寫操作。
這應該適用於所有形式的退出,過程中斷(例如Ctrl + C,關閉終端窗口等),或者即使該過程已使用“ kill”殺死。
但是根據一些調試經驗,目標C程序(例如md5sum二進制文件)在完成執行后不會調用exit。
讓我們看一下i686
GNU / Linux系統上的md5sum
二進制文件:
在反匯編中( objdump -d /usr/bin/md5sum
),我們有:
Disassembly of section .text:
08048f50 <.text>:
8048f50: 55 push %ebp
8048f51: 89 e5 mov %esp,%ebp
8048f53: 57 push %edi
8048f54: 56 push %esi
8048f55: 53 push %ebx
8048f56: 83 e4 f0 and $0xfffffff0,%esp
8048f59: 81 ec c0 00 00 00 sub $0xc0,%esp
8048f5f: 8b 7d 0c mov 0xc(%ebp),%edi
[ ... ]
8049e8f: 68 b0 d6 04 08 push $0x804d6b0
8049e94: 68 40 d6 04 08 push $0x804d640
8049e99: 51 push %ecx
8049e9a: 56 push %esi
8049e9b: 68 50 8f 04 08 push $0x8048f50
8049ea0: e8 4b ef ff ff call 8048df0 <__libc_start_main@plt>
8049ea5: f4 hlt
這是所有啟動樣板代碼。 實際程序的main
調用在__libc_start_main
調用內調用。 如果程序從那里返回,那么,看,有一條hlt
指令。 那是你的目標。 查找該hlt
指令並將其作為程序的結尾。
您可以嘗試以下方法:
int main()
bool keepGoing = true;
{
while(keepGoing) {
string x;
cin >> x;
if(x == "stop") {
keepGoing = false;
}
}
}
即使它是原始的……我可能也砍掉了代碼,但這只是一個概念。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.