obj-m :=hack_open.o
EXTRA_CFLAGS := -Dsymname=sys_call_table
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
make -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
rm -rf .*.cmd *.mod.c *.o *.ko .tmp* *.symvers
Sep 24 19:06:49 localhost kernel: intercept: function:get_sys_call_table-L220: sys_call_table at 0xc11f14e0, call dispatch at 0xcebeceaa
Sep 24 19:06:49 localhost kernel: intercept: function:intercept_init-L276: sys call table address c11f14e0
Sep 24 19:06:50 localhost kernel: intercept: function:new_open-L234: hello
Sep 24 19:07:00 localhost last message repeated 460 times
# system call handler stub
ENTRY(system_call)
RING0_INT_FRAME # can't unwind into user space anyway
pushl %eax # save orig_eax
CFI_ADJUST_CFA_OFFSET 4
SAVE_ALL
GET_THREAD_INFO(%ebp)
testl $TF_MASK,EFLAGS(%esp)
jz no_singlestep
orl $_TIF_SINGLESTEP,TI_flags(%ebp)
no_singlestep:
# system call tracing in operation / emulation
/* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
jnz syscall_trace_entry
cmpl $(nr_syscalls), %eax
jae syscall_badsys
syscall_call:
call *sys_call_table(,%eax,4)
movl %eax,EAX(%esp) # store the return value
000000d0 <system_call>:
d0: 50 push %eax
d1: fc cld
d2: 06 push %es
d3: 1e push %ds
d4: 50 push %eax
d5: 55 push %ebp
d6: 57 push %edi
d7: 56 push %esi
d8: 52 push %edx
d9: 51 push %ecx
da: 53 push %ebx
db: ba 7b 00 00 00 mov $0x7b,%edx
e0: 8e da movl %edx,%ds
e2: 8e c2 movl %edx,%es
e4: bd 00 f0 ff ff mov $0xfffff000,%ebp
e9: 21 e5 and %esp,%ebp
eb: f7 44 24 30 00 01 00 testl $0x100,0x30(%esp)
f2: 00
f3: 74 04 je f9 <no_singlestep>
f5: 83 4d 08 10 orl $0x10,0x8(%ebp)
000000f9 <no_singlestep>:
f9: 66 f7 45 08 c1 01 testw $0x1c1,0x8(%ebp)
ff: 0f 85 bf 00 00 00 jne 1c4 <syscall_trace_entry>
105: 3d 3e 01 00 00 cmp $0x13e,%eax
10a: 0f 83 27 01 00 00 jae 237 <syscall_badsys>
00000110 <syscall_call>:
110: ff 14 85 00 00 00 00 call *0x0(,%eax,4)
117: 89 44 24 18 mov %eax,0x18(%esp)
unsigned long get_syscall_table_x86_64(void) { #define OFFSET_SYSCALL 256 unsigned long syscall_entry; char sc_asm[OFFSET_SYSCALL]; char *p; #ifndef CONFIG_XEN syscall_entry = get_syscall_from_hw(ARCH_X86_64); #else if (!is_running_on_xen()) syscall_entry = get_syscall_from_hw(ARCH_X86_64); else if ((is_initial_xendomain())) syscall_entry = get_syscall_from_xen(ARCH_X86_64); else syscall_entry = get_syscall_from_kallsyms(ARCH_X86_64); #endif if (unlikely(syscall_entry == 0)) { printk("[%s] Could not find system_call entry\n", __FUNCTION__); return -ENOSYS; } memcpy(sc_asm, (void*)syscall_entry, OFFSET_SYSCALL); p = (char *)memmem(sc_asm, OFFSET_SYSCALL, "\xff\x14\xc5", 3); if (unlikely(!p)) { printk("[%s] Could not to find system calls table\n", __FUNCTION__); return -ENOSYS; } return *(unsigned long*)(p + 3); #undef OFFSET_SYSCALL } |
unsigned long get_syscall_from_hw(arch_t arch) { unsigned long syscall_entry = 0; struct idtr idtr; struct idt idt; switch(arch) { case ARCH_X86_64: rdmsrl(MSR_LSTAR, syscall_entry); break; case ARCH_X86: asm("sidt %0" :"=m"(idtr) ); memcpy(&idt, (char *) idtr.base + 16 * 0x80, sizeof(idt)); syscall_entry = (((unsigned long)idt.offset_high ) << 32) | (((idt.offset_middle << 16) | idt.offset_low) & 0x00000000ffffffff ); break; } return syscall_entry; } |
unsigned long get_syscall_from_xen(arch_t arch) { unsigned long syscall_entry = 0; xen_domctl_t dmctl; vcpu_guest_context_t ctxt; dmctl.cmd = XEN_DOMCTL_getvcpucontext; dmctl.domain = 0; dmctl.interface_version = XEN_DOMCTL_INTERFACE_VERSION; dmctl.u.vcpucontext.vcpu = 0; dmctl.u.vcpucontext.ctxt.p = &ctxt; if (unlikely(HYPERVISOR_domctl(&dmctl) != 0)) { printk("[%s] hypercall failed\n", __FUNCTION__); return 0; } switch(arch) { case ARCH_X86_64: syscall_entry = ctxt.syscall_callback_eip; break; case ARCH_X86: syscall_entry = ctxt.trap_ctxt[0x80].address; break; } return syscall_entry; } |
unsigned long get_syscall_from_kallsyms(arch_t arch) { unsigned long syscall_entry; struct nameidata nd; const char *path_str = "/proc/kallsyms"; const char *symbol_str; struct vfsmount *old_mnt; struct dentry *old_dentry; int err = 0; void *p; struct seq_file *m; struct kallsym_iter *iter; struct file *kallsyms_file; loff_t index = 0; void *old_buf; switch(arch) { case ARCH_X86_64: symbol_str = "system_call"; break; case ARCH_X86: symbol_str = "ia32_syscall"; break; default: return 0; } old_mnt = current->fs->rootmnt; old_dentry = current->fs->root; nd.mnt = mntget(current->fs->rootmnt); nd.dentry = dget(current->fs->root); nd.last_type = LAST_ROOT; nd.flags = LOOKUP_FOLLOW | LOOKUP_NOALT; nd.depth = 0; if ((err = path_walk(path_str, &nd)) == 0) { kallsyms_file = dentry_open(nd.dentry, nd.mnt, O_RDWR); if (kallsyms_file == NULL) { printk("[%s] can not open kallsyms file\n", __FUNCTION__); syscall_entry = -EIO; goto out; } m = kallsyms_file->private_data; m->version = kallsyms_file->f_version; mutex_lock(&m->lock); old_buf = m->buf; m->buf = kmalloc(m->size = KSYM_SYMBOL_LEN, GFP_KERNEL); iter = m->private; while (1) { p = m->op->start(m, &index); err = PTR_ERR(p); if (!p || IS_ERR(p)) { syscall_entry = err; break; } m->count = 0; m->op->show(m, p); if (!strncmp(m->buf + sizeof("%s+%#lx/%#lx [%s]") + 1, symbol_str, strlen(symbol_str))) { m->buf[2 * sizeof(void *)] = 0; sscanf(m->buf, "%lx", &syscall_entry); break; } m->op->stop(m, p); index++; } m->op->stop(m, p); m->count = 0; m->size = 0; kfree(m->buf); m->buf = old_buf; mutex_unlock(&m->lock); filp_close(kallsyms_file, NULL); } else { printk("[%s] path_walk failed %d\n", __FUNCTION__, err); } out: dput(old_dentry); mntput(old_mnt); return syscall_entry; } |
typedef enum { ARCH_X86 = 0, ARCH_X86_64, } arch_t; |
.macro LOAD_SYSCALL_ARGS movq 8(%rsp), %r11 movq 16(%rsp), %r10 movq 24(%rsp), %r9 movq 32(%rsp), %r8 movq 56(%rsp), %rdx movq 64(%rsp), %rsi movq 72(%rsp), %rdi movq %r10, %rcx .endm |
GOD 兄, 我来提下意见:
你的第一贴和第二贴似乎没啥关系啊. 第一贴用的是KPROBE. 它是内核已经做好的监测内核运行行为的工具. 可以监视任何内核函数. 第二贴讲的是传统的改SYSTEM CALL TABLE的方法. 而KPROBE用的不是这种方法. 关于KPROBE的解释可以看下面2个帖子:
p[1] = (offset & 0x000000ff); p[2] = (offset & 0x0000ff00) >> 8; p[3] = (offset & 0x00ff0000) >> 16; p[4] = (offset & 0xff000000) >> 24; |
看到你写的关于inline hook的文章,
原帖由 vupiggy 于 2009-12-8 09:40 发表
看到你写的关于inline hook的文章, 忘了是米国哪个大学若干年前(32位时代)某门课的一份作业是劫持 page fault 处理就用的是同一思路. 那个老师给的参考代码和你文章里出现的一段代码一样, 我认为有问题, 至少 ...
原帖由 vupiggy 于 2009-12-8 09:40 发表
看到你写的关于inline hook的文章, 忘了是米国哪个大学若干年前(32位时代)某门课的一份作业是劫持 page fault 处理就用的是同一思路. 那个老师给的参考代码和你文章里出现的一段代码一样, 我认为有问题, 至少 ...
至于怎么inline hook, 方法也很多 , 加jmp或push, ret指令就ok,
WP Write Protect (bit 16 of CR0) — When set, inhibits supervisor-level procedures
from writing into read-only pages; when clear, allows supervisor-level
procedures to write into read-only pages (regardless of the U/S bit setting;
see Section 4.1.3 and Section 4.6). This flag facilitates implementation of the
copy-on-write method of creating a new process (forking) used by operating
systems such as UNIX.
原帖由 Godbach 于 2010-1-19 11:26 发表
修改了1楼中的一个小错误,CR0的WP bit是bit16,而不是bit20. 该位置位的时候是只读模式,清0之后有写权限。
参见intel的手册:
原帖由 W.Z.T 于 2010-1-19 12:51 发表
楼主的那个代码是从abl*版主那借鉴过来的, 原始的代码就有问题。 我也贴一个自己写的宏:
#define CLEAR_CR0 asm ("pushl %eax\n\t" \
"m ...
/* * Certain special system calls that need to save a complete full stack frame. */ |
ENTRY(stub_execve) CFI_STARTPROC popq %r11 CFI_ADJUST_CFA_OFFSET -8 CFI_REGISTER rip, r11 SAVE_REST FIXUP_TOP_OF_STACK %r11 movq %rsp, %rcx call sys_execve RESTORE_TOP_OF_STACK %r11 movq %rax,RAX(%rsp) RESTORE_REST jmp int_ret_from_sys_call CFI_ENDPROC END(stub_execve) |
.macro PTREGSCALL label,func,arg .globl \label \label: leaq \func(%rip),%rax leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */ jmp ptregscall_common END(\label) .endm ... PTREGSCALL stub_clone, sys_clone, %r8 ... ENTRY(ptregscall_common) popq %r11 CFI_ADJUST_CFA_OFFSET -8 CFI_REGISTER rip, r11 SAVE_REST movq %r11, %r15 CFI_REGISTER rip, r15 FIXUP_TOP_OF_STACK %r11 call *%rax RESTORE_TOP_OF_STACK %r11 movq %r15, %r11 CFI_REGISTER rip, r11 RESTORE_REST pushq %r11 CFI_ADJUST_CFA_OFFSET 8 CFI_REL_OFFSET rip, 0 ret CFI_ENDPROC END(ptregscall_common) |
原帖由 vupiggy 于 2010-1-21 01:42 发表
个人认为武断地清除和设置 cr0 的权限位也不合理,更合理的是,保存原来的 cr0,干完坏事之后再恢复回去。
多嘴说点题内话,用 kprobe 这类``官方''提供的方法来插入自己的逻辑很不美,受制于人。要做到真正 ...
个人认为武断地清除和设置 cr0 的权限位也不合理,更合理的是,保存原来的 cr0,干完坏事之后再恢复回去。
#ifdef __i386__
/* this struct defines the way the registers are stored on the
stack during a system call. */
#ifndef __KERNEL__
struct pt_regs {
long ebx;
long ecx;
long edx;
long esi;
long edi;
long ebp;
long eax;
int xds;
int xes;
int xfs;
int xgs;
long orig_eax;
long eip;
int xcs;
long eflags;
long esp;
int xss;
};
#else /* __KERNEL__ */
struct pt_regs {
unsigned long bx;
unsigned long cx;
unsigned long dx;
unsigned long si;
unsigned long di;
unsigned long bp;
unsigned long ax;
unsigned long ds;
unsigned long es;
unsigned long fs;
unsigned long gs;
unsigned long orig_ax;
unsigned long ip;
unsigned long cs;
unsigned long flags;
unsigned long sp;
unsigned long ss;
};
#endif /* __KERNEL__ */
Fedora Core 4-2014-05-23-11-51-40.png (14.11 KB, 下载次数: 43)
欢迎光临 Chinaunix (http://bbs.chinaunix.net/) | Powered by Discuz! X3.2 |