- 論壇徽章:
- 0
|
從網(wǎng)上看到有介紹截獲系統(tǒng)調(diào)用的文章,于是自己下載下來(lái)編譯執(zhí)行了一下。
但是發(fā)現(xiàn)這些例子都有缺點(diǎn):像sys_execve(struct pt_regs regs)這樣的系統(tǒng)調(diào)用,
截獲后若要它仍然完成原有的功能需要調(diào)用do_execve()函數(shù),但是這個(gè)函數(shù)是內(nèi)核不導(dǎo)
出,很麻煩。另外,即算是截獲函數(shù)實(shí)現(xiàn)了它的功能,錯(cuò)誤還是難免出現(xiàn)。
于是就想怎么樣截獲后又能不留痕跡地實(shí)現(xiàn)原有功能。一個(gè)好的想法是直接在截獲函數(shù)中
直接調(diào)用sys_execve().然而想到信號(hào)處理時(shí)如果中斷了系統(tǒng)調(diào)用則可以重新執(zhí)行,那么
能不能通過(guò)類似的方法執(zhí)行系統(tǒng)調(diào)用呢?一個(gè)想法:替換之前將要替換的系統(tǒng)調(diào)用保存在其他
中斷向量中,然后在替換函數(shù)中調(diào)整內(nèi)核堆棧,讓系統(tǒng)重新以另一個(gè)調(diào)用號(hào)調(diào)用保存的系統(tǒng)調(diào)用。
經(jīng)過(guò)近兩天的編碼調(diào)試,終于如愿以償。先說(shuō)明一下關(guān)鍵之處,然后是代碼。
關(guān)鍵之處:
1.將原來(lái)的系統(tǒng)調(diào)用函數(shù)保存在向量__NR_save=17中,這里用17有兩個(gè)原因
1) 在文件syscall_table.S中,向量17的函數(shù)是sys_ni_syscall,這是一個(gè)沒有使用的
調(diào)用號(hào)。
.long sys_ni_syscall /* old break syscall holder */
2) 一開始我用 319,因?yàn)镹R_syscalls=318
#define NR_syscalls 318
大于NR_syscalls的調(diào)用號(hào)自然沒人用,然而這樣做不行。因?yàn)樵趀ntry.S中
system_call:
...
cmpl $(nr_syscalls), %eax
jae syscall_badsys
. ...
若調(diào)用號(hào)大于NR_syscalls,根本不會(huì)執(zhí)行調(diào)用函數(shù)
2. 信號(hào)處理中重新執(zhí)行中斷的調(diào)用是這樣做的:
case -ERESTARTNOINTR:
regs->eax = regs->orig_eax;
regs->eip -= 2;
于是我就想這樣做
pr.eip-=2;
然而老是出錯(cuò),后來(lái)查看匯編后的代碼發(fā)現(xiàn),減2操作是在寄存器中實(shí)現(xiàn)的,內(nèi)核堆棧
根本沒有改變。于是改用匯編:
__asm__("sub $0x2,%0" : "=m" (pr.eip));
3. 將內(nèi)核堆棧中regs.eax改為__NR_save,然而這一步不能通過(guò)在函數(shù)中賦值改變
因?yàn)樵趀ntry.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)核自動(dòng)
將其保存在regs.eax。
以下是代碼:
#include
#include
#include
#include
#include
#include
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_highpid);
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);
本文來(lái)自ChinaUnix博客,如果查看原文請(qǐng)點(diǎn):http://blog.chinaunix.net/u1/36646/showart_319467.html |
|