- 論壇徽章:
- 0
|
從網(wǎng)上看到有介紹截獲系統(tǒng)調(diào)用的文章,于是自己下載下來編譯執(zhí)行了一下。
但是發(fā)現(xiàn)這些例子都有缺點:像sys_execve(struct pt_regs regs)這樣的系統(tǒng)調(diào)用,
截獲后若要它仍然完成原有的功能需要調(diào)用do_execve()函數(shù),但是這個函數(shù)是內(nèi)核不導(dǎo)
出,很麻煩。另外,即算是截獲函數(shù)實現(xiàn)了它的功能,錯誤還是難免出現(xiàn)。
于是就想怎么樣截獲后又能不留痕跡地實現(xiàn)原有功能。一個好的想法是直接在截獲函數(shù)中
直接調(diào)用sys_execve().然而想到信號處理時如果中斷了系統(tǒng)調(diào)用則可以重新執(zhí)行,那么
能不能通過類似的方法執(zhí)行系統(tǒng)調(diào)用呢?一個想法:替換之前將要替換的系統(tǒng)調(diào)用保存在其他
中斷向量中,然后在替換函數(shù)中調(diào)整內(nèi)核堆棧,讓系統(tǒng)重新以另一個調(diào)用號調(diào)用保存的系統(tǒng)調(diào)用。
經(jīng)過近兩天的編碼調(diào)試,終于如愿以償。先說明一下關(guān)鍵之處,然后是代碼。
關(guān)鍵之處:
1.將原來的系統(tǒng)調(diào)用函數(shù)保存在向量__NR_save=17中,這里用17有兩個原因
1) 在文件syscall_table.S中,向量17的函數(shù)是sys_ni_syscall,這是一個沒有使用的
調(diào)用號。
.long sys_ni_syscall /* old break syscall holder */
2) 一開始我用 319,因為NR_syscalls=318
#define NR_syscalls 318
大于NR_syscalls的調(diào)用號自然沒人用,然而這樣做不行。因為在entry.S中
system_call:
...
cmpl $(nr_syscalls), %eax
jae syscall_badsys
. ...
若調(diào)用號大于NR_syscalls,根本不會執(zhí)行調(diào)用函數(shù)
2. 信號處理中重新執(zhí)行中斷的調(diào)用是這樣做的:
case -ERESTARTNOINTR:
regs->eax = regs->orig_eax;
regs->eip -= 2;
于是我就想這樣做
pr.eip-=2;
然而老是出錯,后來查看匯編后的代碼發(fā)現(xiàn),減2操作是在寄存器中實現(xiàn)的,內(nèi)核堆棧
根本沒有改變。于是改用匯編:
__asm__("sub $0x2,%0" : "=m" (pr.eip));
3. 將內(nèi)核堆棧中regs.eax改為__NR_save,然而這一步不能通過在函數(shù)中賦值改變
因為在entry.S中調(diào)用完函數(shù)后,內(nèi)核將寄存器eax值存入regs.eax中
system_call:
...
call *sys_call_table(,%eax,4)
movl %eax,EAX(%esp) # store the return value
. ...
我們知道寄存器eax存的是函數(shù)返回值,于是我將替換函數(shù)返回_NR_save,讓內(nèi)核自動
將其保存在regs.eax。
以下是代碼:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <asm/unistd.h>
#include <asm/ptrace.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xunil@bmy and hhj");
MODULE_DESCRIPTION("Different from others, this module automatically locate the entry of sys_call_table !");
unsigned long *sys_call_table=NULL;
//asmlinkage
int (*orig_exec)(struct pt_regs);
int __NR_save=17;
struct _idt
{
unsigned short offset_low,segment_sel;
unsigned char reserved,flags;
unsigned short offset_high;
};
unsigned long *getscTable(void)
{
unsigned char idtr[6],*shell,*sort;
struct _idt *idt;
unsigned long system_call,sct;
unsigned short offset_low,offset_high;
char *p;
int i;
/* get the interrupt descriptor table */
__asm__("sidt %0" : "=m" (idtr));
/* get the address of system_call */
idt=(struct _idt*)(*(unsigned long*)&idtr[2]+8*0x80);
offset_low = idt->offset_low;
offset_high = idt->offset_high;
system_call=(offset_high<<16)|offset_low;
shell=(char *)system_call;
sort="\xff\x14\x85";
/* get the address of sys_call_table */
for(i=0;i<(100-2);i++)
if(shell==sort[0]&&shell[i+1]==sort[1]&&shell[i+2]==sort[2])
{
printk("here ok!!\n");
break;
}
p=&shell;
p+=3;
sct=*(unsigned long*)p;
return (unsigned long*)(sct);
}
//asmlinkage
int hacked_exec(struct pt_regs pr){
__asm__("sub $0x2,%0" : "=m" (pr.eip));
// pr.eax=__NR_save;
printk("PID %d called sys_execve !\n",current->pid);
return __NR_save;
}
static int __init find_init(void){
sys_call_table = getscTable();
printk("here 1\n");
orig_exec=(int(*)(struct pt_regs))(sys_call_table[__NR_execve]);
printk("here 2,%d\n",__NR_save);
sys_call_table[__NR_execve]=(long)hacked_exec;
sys_call_table[__NR_save]=(long)orig_exec;
return 0;
}
static void __exit find_cleanup(void){
sys_call_table[__NR_execve]=(unsigned long)orig_exec;
}
module_init(find_init);
module_exit(find_cleanup);
有空到我的博客瞧瞧哦 hhj.cublog.cn
[ 本帖最后由 hauto 于 2007-6-18 15:27 編輯 ] |
|