首页
社区
课程
招聘
[原创]Android Libinject X86平台EIP-2的分析
发表于: 2014-6-27 15:40 12510

[原创]Android Libinject X86平台EIP-2的分析

2014-6-27 15:40
12510
在看雪上看到古河大牛的android-LibInject,平台是arm版的。
想测试x86平台上的android-LibJect,搜索有人已经完成
http://blog.csdn.net/jinzhuojun/article/details/9900105

其中获取目标进程库函数地址的代码如下,特别的,x86平台的函数地址=实际函数地址+2。


这个+2的操作让人蛋疼,起初以为是ELF在X86平台上的特性。
在GDB中调试,发现函数地址并不需要+2。
调试发现,是因为如下的函数ptrace_call设置eip的时候需要把eip加2。


作如下测试,
设置错误的eip,Regs->eip=0,目标进程段错误,崩溃eip=-2;
设置错误的eip,regs->eip=10,目标进程段错误,崩溃eip=8

测试表明:X86版本的ptrace_call,确实需要eip=eip+2。
根据windows的经验,怎么也没明白为啥eip-2。
设置目标进程eip=funX,结果目标进程从funX-2开始执行,蛋疼。

测试GDB调试,设置目标进程的EIP,目标进程从EIP开始执行,蛋更疼了。
据说GDB也是用的ptrace接口,为啥GDP设置EIP就从EIP开始执行,而ptrace_call设置EIP却从EIP-2的地址开始执行。

请教原文作者,答复“可能是ABI的原因,有的平台并不需要”。
请教其它大牛,估计是被太多邮件淹没了。

在看雪上看到有文章说,需要在ptrace_attach之后先执行ptrace_syscall


测试表明,这篇文章说的没问题。但作者也没有为什么必须要先ptrace_syscall。
对比不添加ptrace_syscall和ptrace_syscall,ptrace_getreg获得EIP都是相同的,说明ptrace _attach返回时,目标进程的EIP都是相同的。那添加的ptrace_syscall又做了哪些额外的工作,导致执行结果不一样。

不明就里,如鲠在喉!一统搜索,没有结果!只有去看linux内核相关的书籍了。
在阅读完《linxu内核源码分析》的ptrace和signal章节后,找到了最终的原因。

EIP-2内幕
我的目标程序源码如下:


我的注入程序代码如下:


注入程序在ptrace_attach目标程序的时候,目标程序因为执行sleep(1)处于休眠状态。
此时EIP为系统调用的用户态返回地址,如下的0xb7fe2424。无论是sysenter方式还是int 0x80方式,返回EIP都是该地址。


Ptrace_attach首先向目标进程发送SIGSTOP信号,该信号把本来处于休眠的进程唤醒。然后进入等待目标进程状态发生改变。

目标进程被唤醒后经内核调度开始执行,开始执行其实是从原来的休眠处开始的,显然继续执行将会结束sleep系统调用,并且返回结果不是sleep满足,而是sleep被中断了。
目标进程准备退出sleep系统调用,在返回到用户态EIP之前,内核检测自身是否存在信号量。显然,赤裸裸的躺着注入程序发送的SIGSTOP信号。于是,转入执行SIGSTOP信号处理,该信号处理把进程状态为STOP,挂起自身,激活注入进程的wait调用。

注入进程wait调用返回,ptrace_getregs获取的EIP是确确实实的目标进程将来返回到用户态执行的EIP。

注入进程ptrace_setreg设置的EIP也确确实实是目标进程将来要返回到用户态执行的EIP。

注入进程ptrace_continue给目标进程发送信号SIGCON,信号发送本身将唤醒挂起的目标进程。

目标进程因为收到的SIGCON信号,恢复执行。此时进程的SIGSTOP信号即将处理完毕,系统检测该到信号来自系统调用,并且该信号处理不是由用户程序处理,这就意味着该信号导致了本系统调用失败,需要自动重新执行该系统调用。自动重新本系统调用的方法:恢复用户态寄存器EAX为系统调用号,用户态EIP=EIP-2。而EIP-2恰好就是int 80系统调用指令。

目标进程处理完信号后,开始执行系统调用返回到用户态。此时用户态的EIP由于-2的原因,不再是原来的pop ebp指令,而是int 80指令。因此返回到用户态后,自动重新执行本系统调用。

因此,EIP-2的本质原因,在于ptrace_attach的时候目标进程因系统调用进入了休眠,而attach发送的信号导致了目标进程调用中断返回,系统为了弥补中断返回的系统调用,在信号处理中将EIP-2来迫使中断的系统调用返回后自动重启本系统调用。

为何ptrace_attach+ptrace_syscall就没有EIP-2的问题?
在ptrace_attach后加入ptrace_syscall后不会导致eip-2,原因在于ptrace_syscall仅仅是设置目标进程的标志位,没有发送任何信号,也没有中断目标进程的任何系统调用。目标进程是主动在系统调用之前检查该标志位,主动挂起自己。这种条件下,注入进程设置目标进程eip,目标进程的系统调用自然是返回到设置的eip。

Ptrace_attach一定会有问题吗?
NO。attach时刻目标进程如果不是陷入系统调用,就不会触发自动重启系统调用导致的EIP-2。

ptrace_attach+ptrace_syscall一定安全吗?
NO。在ptrace_syscall+ptrace_setreg+ptrace_continue后,目标进程开始进行系统调用,如果系统调用是可中断的阻塞调用,在阻塞等待过程中如果因为接受到其它信号,导致系统调用中断返回,那么系统会因为自动重启系统调用而设置eip-2,并且系统期待的eip-2处的代码为int 80。显然,注入进程设置的eip为某个函数,而eip-2就是个不伦不类的东西。

注:最后两个问题,没有实际测试,只是推断;SIGCON信号对于目标进程只是简单的忽略。
不知道ARM平台存不存在因为自动重启系统调用而导致的EIP-2的问题。

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 3
支持
分享
最新回复 (8)
雪    币: 2323
活跃值: (4113)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
2
谢谢分享~~
2014-6-27 16:30
0
雪    币: 185
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
暂时看的不是太理解。周末慢慢消化
2014-6-27 16:55
0
雪    币: 138
活跃值: (460)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
LZ研究的比较透啊。
2014-6-27 17:34
0
雪    币: 822
活跃值: (380)
能力值: ( LV12,RANK:310 )
在线值:
发帖
回帖
粉丝
5
分析的很清楚,赞啊
2014-6-27 20:32
0
雪    币: 53
活跃值: (270)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
arm下重启系统调用,也有调整用户态pc位置,目前bionic中libc.so采用ARM方式编译,svc 0指令占用4Bytes,所以会-4
arch\arm\kernel\signal.c
static void do_signal(struct pt_regs *regs, int syscall)
{
......
        /*
         * If we were from a system call, check for system call restarting...
         */
        if (syscall) {
                continue_addr = regs->ARM_pc;
                restart_addr = continue_addr - (thumb_mode(regs) ? 2 : 4);

                retval = regs->ARM_r0;

                /*
                 * Prepare for system call restart.  We do this here so that a
                 * debugger will see the already changed PSW.
                 */
                switch (retval) {
                case -ERESTARTNOHAND:
                case -ERESTARTSYS:
                case -ERESTARTNOINTR:
                        regs->ARM_r0 = regs->ARM_ORIG_r0;
                        regs->ARM_pc = restart_addr;
                        break;
                case -ERESTART_RESTARTBLOCK:
                        regs->ARM_r0 = -EINTR;
                        break;
                }
        }

        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
        if (signr > 0) {
                // 用户未设置SA_RESTART sigaction,继续执行以-EINTR返回给调用者
                if (regs->ARM_pc == restart_addr) {
                        if (retval == -ERESTARTNOHAND
                            || (retval == -ERESTARTSYS
                                && !(ka.sa.sa_flags & SA_RESTART))) {
                                regs->ARM_r0 = -EINTR;
                                regs->ARM_pc = continue_addr;

                        }
                }

x86下,int 0x80指令2 Bytes:
arch\x86\kernel\signal.c
static void do_signal(struct pt_regs *regs)
{
......
       // x86下处理信号和arm下不同,先直接转到用户空间处理信号
        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
        if (signr > 0) {
                /* Whee! Actually deliver the signal.  */
                handle_signal(signr, &info, &ka, regs);
                return;
        }


       // 后判断系统调用结果,根据情况PC-2
        if (syscall_get_nr(current, regs) >= 0) {
                /* Restart the system call - no handlers present */
                switch (syscall_get_error(current, regs)) {

                case -ERESTARTNOHAND:
                case -ERESTARTSYS:
                case -ERESTARTNOINTR:
                        regs->ax = regs->orig_ax;
                        regs->ip -= 2;
                        break;

                case -ERESTART_RESTARTBLOCK:
                        regs->ax = NR_restart_syscall;
                        regs->ip -= 2;
                        break;

                }
        }
2014-6-30 17:36
0
雪    币: 125
活跃值: (35)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
多谢netsniffer的分享~~~
2014-7-1 12:08
0
雪    币: 208
活跃值: (40)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
arm下注入zygote和其子进程的时候也有这个问题,因为ptrace的注入点会在select那里,注入时修改pc,注入完成后恢复PC其实会影响到select的返回值,从而引起进程退出。
2014-7-2 16:31
0
雪    币: 1254
活跃值: (630)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
9
这个解决了吗?怎么解决的

搞定,参考6楼和数字公司实现。
2015-11-4 14:59
0
游客
登录 | 注册 方可回帖
返回
//