[英]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.