调试器的原理-详解ptrace函数及fork父子进程跟踪实例

本文探讨了Linux调试器的核心——ptrace函数,通过实例展示了如何利用ptrace进行程序跟踪,包括捕获输入和处理fork后的子进程。文中提到,可以自定义程序替代gdb,拦截特定程序的行为,例如SSH或FTP密码。通过ptrace(PTRACE_SETOPTIONS)设置跟踪选项,当程序fork时,父进程和子进程会暂停,等待跟踪程序的控制。文章提供了示例代码,演示了如何识别和跟踪fork产生的子进程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近仔细研究了一下linux调试程序的原理.gdb是linux下最为强大的调试工具,而strace可以拦截程序执行过程中的系统调用.他们的背后都隐藏了一个强悍的支持函数ptrace().调试程序过程中我们可以单步执行,逐步检查程序的输入输出,从而判断程序错误,当然我们也可以抛弃gdb,自己实现一个"外挂程序",拦截主程序中我们感兴趣的东西,比如ssh或ftp登录密码.

先看一个简单的程序:

#include<stdio.h>
int main(void){
	char buf[1024];
	gets(buf);
	puts(buf);
	return 0;
}

我们感兴趣的是他输入了什么,使用strace输出如下(部分):

fstat64(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77a9000
read(0, AAAAAAAAAAAA
"AAAAAAAAAAAA\n", 1024)         = 13
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77a8000
write(1, "AAAAAAAAAAAA\n", 13AAAAAAAAAAAA
)          = 13
exit_group(0)                           = ?
+++ exited with 0 +++

可以看到,在系统调用层面,程序使用了read函数实现了数据输入,所以"外挂"程序可以利用这一点,只针对read调用进行拦截:

/*
*该程序仅能在32位x86 linux中使用.64位系统需要修改struct user_regs_struct regs中寄存器格式.
*/
#include<stdio.h>
#include<sys/ptrace.h>
#include<unistd.h>
#include<sys/wait.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>
#include<sys/syscall.h>
#include<sys/user.h>
#include<strings.h>
void getdata(pid_t pid,long addr, char *str,int len){
	int i;
	long data;
	for(i=0;i<(len+sizeof(long)-1)/sizeof(long);i++){
		data=ptrace(PTRACE_PEEKDATA,pid,addr+i*sizeof(long),NULL);
		*(long *)(str+i*sizeof(long))=data;
	}
	*(str+len)='\0';
	printf("%s",str);
}
int main(int argc,char **argv){
	pid_t pid;
	int status,buf_len,i;
	struct user_regs_struct regs;
	char *buf;
	int insyscall=0;	
	
	if (argc<2){
		printf("Usage:./a.out prog <args>\n");
		return 1;
	}
	if ((pid=fork())==0){  //子进程运行被跟踪程序
		ptrace(PTRACE_TRACEME,0,NULL,NULL);
		status=execvp(argv[1],argv+1);
		if(status<0){
			printf("execvp %s error:%s\n",argv[1],strerror(errno));
			return -1;
		}
	}else if(pid>0){  //父进程拦截子进程所有系统调用
		while(1){
			wait(&stat
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值