可变参数库函数的劫持

from:http://blog.donews.com/quickmouse/archive/2007/07/16/1187051.aspx


by quickmouse <quickmouse@263.net> 2007年7月16日

    已经有不少的文章提到过Linux系统库函数劫持的方法,最主要的是利用LD_PRELOAD环境变量进行预加载,将自己写的库函数编译成.so以后,将其列入LD_PRELOAD当中,于是程序就会使用我们自己所写的系统库函数。当然,这样做的目的往往是为了在调用系统功能的时候搞点小动作,最终还是要转到真正的库函数里去的。
    不过最近在完成一个函数库的劫持过程中,却碰到了一些意外——那就是碰到了我们可爱的可变参数库函数。所谓可变参数库函数,但凡打算看懂这篇文章的人都了解,我就不再仔细解释。最著名的可变参数库函数就是printf了。这回我碰到的是ioctl,也是一个底层常用的库函数,我只需要在ioctl进行某个操作时对它进行劫持。
    在我准备动手进行ioctl的劫持之前,我丝毫没有意识到可变参数函数对劫持技巧提出的要求。由于劫持操作之后还需要返回到原系统库函数,于是在传参的时候我发现需要对传入的参数进行解析,以便正确处理。可是ioctl这样牛x的函数完全依靠前面的固定参数来决定是否存在变参,以及它们的类型。这么说我不是要把所有的ioctl请求都解析一遍?(除非我疯了)。
    考虑传参的具体实现,是在上一级调用的时候按顺序由右到左依次把参数压入栈,也就是固定参数一定是在最靠近返回地址的位置,而远离它的有多少是参数是天知道的(god knows)。因此,想通过栈信息而不解析参数数值想直接得到参数个数,是行不通的 :-( 
    唯一可行的办法是在跳转到真正的(被劫持的)系统库函数时,保持上一级函数调用劫持函数时的栈信息,绕过变参解析的过程。具体的函数实现框架为:
int ioctl(int d, unsigned long int request, …)
{
        if(request != WE_WANT_HIJACK )
        {
        __asm__ __volatile__(
                "\n\
                mov 0xfffffffc(%%ebp), %%edi\n\
                mov 0xfffffff8(%%ebp), %%esi\n\
                mov 0xfffffff4(%%ebp), %%ebx\n\
                leave\n\
                jmp *%0\n\
                "
                 :
                 :"m"(real_ioctl));
        }
        else
        {
                // The hijack action code here
        }
}
    当遇到不是我们需要劫持的系统调用方式时,直接使用汇编代码恢复各寄存器的数值,跳转到真实的ioctl函数入口。否则,进入我们自己所写的劫持代码当中。由于我们只劫持了ioctl当中一种(或者几种)请求,这些请求所需要的参数个数、类型是很容易知道的,这就避免了解析所有ioctl请求的情况。
    需要注意的地方在如下这一段汇编代码里:
        __asm__ __volatile__(
                "\n\
                mov 0xfffffffc(%%ebp), %%edi\n\
                mov 0xfffffff8(%%ebp), %%esi\n\
                mov 0xfffffff4(%%ebp), %%ebx\n\
                leave\n\
                jmp *%0\n\
                "
                 :
                 :"m"(real_ioctl));
    汇编填写的内容并不是完全固定的,需要根据编译出来的库文件,用objdump反汇编以后,作出对应的修改,方法是找出进入这一段汇编代码之前寄存器改变的情况,对ebx,esi,edi等作为“被调用者保存”的寄存器进行恢复,而ebp,esp等基址、栈址在leave指令上恢复(需要esp指向正确)。最后在jmp的指令下直接跳转到真实的ioctl函数入口。real_ioctl可以通过dlsym(RTLD_NEXT, "ioctl")获得。
    当然,这一类的劫持并不是万能的,对于使用了setuid/setsid的应用程序,LD_PRELOAD变量并不会起作用。
    对于这样的情况,用什么方法再研究研究,呵呵,技术无止境嘛~~



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值