⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ptrace.c

📁 linux内核的改写可以进行新的读写命令同时也可以在linux下体验编译内核的快感 这是我们os的一个project
💻 C
字号:
/* ptrace.c *//* By Ross Biro 1/23/92 *//* * Pentium III FXSR, SSE support *	Gareth Hughes <gareth@valinux.com>, May 2000 */#include <linux/kernel.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/errno.h>#include <linux/ptrace.h>#include <linux/user.h>#include <linux/security.h>#include <linux/audit.h>#include <linux/seccomp.h>#include <linux/signal.h>#include <asm/uaccess.h>#include <asm/pgtable.h>#include <asm/system.h>#include <asm/processor.h>#include <asm/i387.h>#include <asm/debugreg.h>#include <asm/ldt.h>#include <asm/desc.h>/* * does not yet catch signals sent when the child dies. * in exit.c or in signal.c. *//* determines which flags the user has access to. *//* 1 = access 0 = no access *//******************LKRR start 0372180****************/#define FLAG_MASK 0x00044dd5/***  EFLAG访问权限设定  ***//* set's the trap flag. */#define TRAP_FLAG 0x100/***  设置陷阱标志  ***//******************LKRR end 0372180****************//* * Offset of eflags on child stack.. */#define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs))/*  用于清除TF标志  */static inline struct pt_regs *get_child_regs(struct task_struct *task){	void *stack_top = (void *)task->thread.esp0;	return stack_top - sizeof(struct pt_regs);}/* * this routine will get a word off of the processes privileged stack.  * the offset is how far from the base addr as stored in the TSS.   * this routine assumes that all the privileged stacks are in our * data space. */   /******************LKRR start 0372180****************/static inline int get_stack_long(struct task_struct *task, int offset){	unsigned char *stack;	stack = (unsigned char *)task->thread.esp0;/*  获得ESP0寄存器值  */	stack += offset;/*  加偏移量  */	return (*((int *)stack));}/* * this routine will put a word on the processes privileged stack.  * the offset is how far from the base addr as stored in the TSS.   * this routine assumes that all the privileged stacks are in our * data space. */static inline int put_stack_long(struct task_struct *task, int offset,	unsigned long data){	unsigned char * stack;	stack = (unsigned char *) task->thread.esp0;/*  获得ESP0寄存器值  */	stack += offset;/*  加偏移量  */	*(unsigned long *) stack = data;	return 0;}/***读写所有i386用户寄存器使用ptrace的PTRACE_GETFPREGS和PTRACE_PUTFPREGS读写所有i387浮点寄存器。***/static int putreg(struct task_struct *child,	unsigned long regno, unsigned long value){	switch (regno >> 2) {//参数regno,表示寄存器的序号		case FS:			if (value && (value & 3) != 3)				return -EIO;			child->thread.fs = value;			return 0;		case GS:			if (value && (value & 3) != 3)				return -EIO;			child->thread.gs = value;			return 0;		case DS:		case ES:			if (value && (value & 3) != 3)				return -EIO;			value &= 0xffff;			break;		case SS:		case CS:			if ((value & 3) != 3)				return -EIO;			value &= 0xffff;			break;		case EFL:			value &= FLAG_MASK;//函数get_stack_long()和put_stack_long()为对子进程核心堆栈的操作			value |= get_stack_long(child, EFL_OFFSET) & ~FLAG_MASK;			break;	}	if (regno > GS*4)		regno -= 2*4;	put_stack_long(child, regno - sizeof(struct pt_regs), value);	return 0;}/***作用和putreg相仿,读写所有i386用户寄存器使用ptrace的PTRACE_GETFPREGS和PTRACE_PUTFPREGS读写所有i387浮点寄存器。***/static unsigned long getreg(struct task_struct *child,	unsigned long regno){	unsigned long retval = ~0UL;	switch (regno >> 2) {		case FS:			retval = child->thread.fs;			break;		case GS:			retval = child->thread.gs;			break;		case DS:		case ES:		case SS:		case CS:			retval = 0xffff;			/* fall through */		default:			if (regno > GS*4)				regno -= 2*4;			regno = regno - sizeof(struct pt_regs);//函数get_stack_long()和put_stack_long()为对子进程核心堆栈的操作			retval &= get_stack_long(child, regno);	}	return retval;}/******************LKRR end 0372180****************/#define LDT_SEGMENT 4static unsigned long convert_eip_to_linear(struct task_struct *child, struct pt_regs *regs){	unsigned long addr, seg;	addr = regs->eip;	seg = regs->xcs & 0xffff;	if (regs->eflags & VM_MASK) {		addr = (addr & 0xffff) + (seg << 4);		return addr;	}	/*	 * We'll assume that the code segments in the GDT	 * are all zero-based. That is largely true: the	 * TLS segments are used for data, and the PNPBIOS	 * and APM bios ones we just ignore here.	 */	if (seg & LDT_SEGMENT) {		u32 *desc;		unsigned long base;		down(&child->mm->context.sem);		desc = child->mm->context.ldt + (seg & ~7);		base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 0xff000000);		/* 16-bit code segment? */		if (!((desc[1] >> 22) & 1))			addr &= 0xffff;		addr += base;		up(&child->mm->context.sem);	}	return addr;}static inline int is_at_popf(struct task_struct *child, struct pt_regs *regs){	int i, copied;	unsigned char opcode[16];	unsigned long addr = convert_eip_to_linear(child, regs);//调用转换函数	copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0);	for (i = 0; i < copied; i++) {		switch (opcode[i]) {		/* popf */		case 0x9d:			return 1;		/* opcode and address size prefixes */		case 0x66: case 0x67:			continue;		/* irrelevant prefixes (segment overrides and repeats) */		case 0x26: case 0x2e:		case 0x36: case 0x3e:		case 0x64: case 0x65:		case 0xf0: case 0xf2: case 0xf3:			continue;		/*		 * pushf: NOTE! We should probably not let		 * the user see the TF bit being set. But		 * it's more pain than it's worth to avoid		 * it, and a debugger could emulate this		 * all in user space if it _really_ cares.		 */		case 0x9c:		default:			return 0;		}	}	return 0;}/******************LKRR start 0372180****************//***在处理器状态字(PSW)中设置Trace bit位,让子进程单步执行***/static void set_singlestep(struct task_struct *child){	struct pt_regs *regs = get_child_regs(child);//调用函数获取子函数标志	/*	 * Always set TIF_SINGLESTEP - this guarantees that 	 * we single-step system calls etc..  This will also	 * cause us to set TF when returning to user mode.	 */	set_tsk_thread_flag(child, TIF_SINGLESTEP);//设置标志函数	/*	 * If TF was already set, don't do anything else	 */	if (regs->eflags & TRAP_FLAG)		return;	/* Set TF on the kernel stack.. */	regs->eflags |= TRAP_FLAG;	/*	 * ..but if TF is changed by the instruction we will trace,	 * don't mark it as being "us" that set it, so that we	 * won't clear it by hand later.	 */	if (is_at_popf(child, regs))//进行判断,如果在栈顶需要进行pop操作,则返回		return;		child->ptrace |= PT_DTRACE;}static void clear_singlestep(struct task_struct *child)//用于清楚状态字的设置{	/* Always clear TIF_SINGLESTEP... */	clear_tsk_thread_flag(child, TIF_SINGLESTEP);	/* But touch TF only if it was set by us.. */	if (child->ptrace & PT_DTRACE) {		struct pt_regs *regs = get_child_regs(child);		regs->eflags &= ~TRAP_FLAG;		child->ptrace &= ~PT_DTRACE;	}}/******************LKRR end 0372180****************//* * Called by kernel/ptrace.c when detaching.. * * Make sure the single step bit is not set. */void ptrace_disable(struct task_struct *child){ 	clear_singlestep(child);}/* * Perform get_thread_area on behalf of the traced child. */static int/******************LKRR start 0372180****************//***此函数负责对线程空间的传递操作***/ptrace_get_thread_area(struct task_struct *child,		       int idx, struct user_desc __user *user_desc){	struct user_desc info;	struct desc_struct *desc;/* * Get the current Thread-Local Storage area: */#define GET_BASE(desc) ( \	(((desc)->a >> 16) & 0x0000ffff) | \	(((desc)->b << 16) & 0x00ff0000) | \	( (desc)->b        & 0xff000000)   )#define GET_LIMIT(desc) ( \	((desc)->a & 0x0ffff) | \	 ((desc)->b & 0xf0000) )#define GET_32BIT(desc)		(((desc)->b >> 22) & 1)#define GET_CONTENTS(desc)	(((desc)->b >> 10) & 3)#define GET_WRITABLE(desc)	(((desc)->b >>  9) & 1)#define GET_LIMIT_PAGES(desc)	(((desc)->b >> 23) & 1)#define GET_PRESENT(desc)	(((desc)->b >> 15) & 1)#define GET_USEABLE(desc)	(((desc)->b >> 20) & 1)	if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)		return -EINVAL;	desc = child->thread.tls_array + idx - GDT_ENTRY_TLS_MIN;	info.entry_number = idx;	info.base_addr = GET_BASE(desc);	info.limit = GET_LIMIT(desc);	info.seg_32bit = GET_32BIT(desc);	info.contents = GET_CONTENTS(desc);	info.read_exec_only = !GET_WRITABLE(desc);	info.limit_in_pages = GET_LIMIT_PAGES(desc);	info.seg_not_present = !GET_PRESENT(desc);	info.useable = GET_USEABLE(desc);	if (copy_to_user(user_desc, &info, sizeof(info)))		return -EFAULT;	return 0;}/* * Perform set_thread_area on behalf of the traced child. */static intptrace_set_thread_area(struct task_struct *child,		       int idx, struct user_desc __user *user_desc){	struct user_desc info;	struct desc_struct *desc;	if (copy_from_user(&info, user_desc, sizeof(info)))		return -EFAULT;	if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)		return -EINVAL;	desc = child->thread.tls_array + idx - GDT_ENTRY_TLS_MIN;	if (LDT_empty(&info)) {		desc->a = 0;		desc->b = 0;	} else {		desc->a = LDT_entry_a(&info);		desc->b = LDT_entry_b(&info);	}	return 0;}/***************LKRR end 0372180*************//***************LKRR end 0372180*************//***接下来,就进入ptrace最为关键的函数部分,其核心函数sys_ptrace函叔: 	sys_ptrace函数,完成ptrace系统调用的代码。 	为完成sys_ptrace功能所需调用的一些辅助 	函数 	寄存器读写函数和内存读写函数。 	信号处理函数中,对被调试进程的处

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -