/*
* 作者:蟑螂一号
* 原文链接:http://www.sanwho.com/133.html
* 转载请注明出处
*/

Android下so注入是基于ptrace系统调用,因此要想学会android下的so注入,首先需要了解ptrace的用法。

ptrace用法可以参考博客:http://blog.sina.com.cn/s/blog_4ac74e9a0100n7w1.html,也可以在ubuntu下输入man ptrace命令,查看具体描述。

android中进程系统调用劫持可参考博客:http://www.kanxue.com/bbs/showthread.php?t=180461,这是一个android简单的ptrace监控远程进程监控调用的例子。

Android系统是基于Linux系统,在linux系统中可以通过ptrace系统调用实现进程注入。ptrace注入过程大致过程如下:

(1)基于shellcode加载

[1]编写shellcode,shellcode是使用汇编语言写一段汇编程序,该程序实现so库的加载、so库函数查找以及执行库中的函数。

[2]通过远程进程pid,ATTACH到远程进程。

[3]获取远程进程寄存器值,并保存,以便注入完成后恢复进程原有状态。

[4]获取远程进程系统调用mmap、dlopen、dlsym调用地址。

[5]调用远程进程mmap分配一段存储空间,并在空间中写入shellcode、so库路径以及函数调用参数。

[6]执行远程进程shellcode代码。

[7]恢复远程进程寄存器。

[8]detach远程进程。

基于shellcode注入可看雪古河大哥写的libInject,网址:http://bbs.pediy.com/showthread.php?t=141355

其中,dlopen和dlsym是用于打开动态链接库中的函数,将动态链接库中的函数或类导入到本程序中。

dlopen函数定义:  void * dlopen( const char * pathname, int mode );  函数描述:  dlopen()函数以指定模式打开指定的动态链接库文件,并返回一个句柄给dlsym()的调用进程。使用dlclose()来卸载打开的库。dlsym函数原型是  void* dlsym(void* handle,const char* symbol)  该函数在<dlfcn.h>文件中。  handle是由dlopen打开动态链接库后返回的指针,symbol就是要求获取的函数的名称,函数返回值是void*,指向函数的地址,供调用使用。

(2)直接加载

[1]通过远程进程pid,ATTACH到远程进程。

[2]获取远程进程寄存器值,并保存,以便注入完成后恢复进程原有状态。

[3]获取远程进程系统调用mmap、dlopen、dlsym调用地址。

[4]调用远程进程mmap分配一段存储空间,并在空间中写入so库路径以及函数调用参数。

[5]执行远程进程dlopen,加载so库。

[6]执行远程进程dlsym,获取so库中需要执行的函数地址。

[7]执行远程进程中的函数。

[7]恢复远程进程寄存器。

[8]DETACH远程进程。

目前android so注入的版本基本上都是基于古河大哥的libInject修改而来。关于so注入的项目,还可以参考洗大师的一个开源项目,网址:https://code.google.com/p/libandroidinjector/downloads/list。洗大师注入需要修改elf文件。

提供一个方便测试so注入成功与否的小测试库,代码如下:

 1 #include <unstd.h> 2   3 #include <stdio.h> 4   5 #include <android/log.h> 6   7 #define LOG_TAG    "test" 8   9 __attribute__((constructor))   void   inject () {10  11 __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,"Hello,I am  injected."); 12 13 }

说明:若函数被设定为constructor属性,则该函数会在main()函数执行之前被自动的执行。因此,so注入测试中,只需注入以上代码编译的so库,无需调用注入so的相关函数,即可测试是否注入到远程进程。

补充说明——实现方式

转自:http://www.cnphp6.com/?post=27303

0x01 获取目标进程的pid,关联目标进程:

通过遍历查找/proc/pid/cmdline文件中是否含有目标进程名process_name,若有则进程名对应的进程号即为pid。接着,直接调用函数ptrace_attach(pid)即可完成关联。

0x02 获取并保存目标进程寄存器值:

直接调用ptrace(PTRACE_GETREGS, pid, NULL, &saved_regs),当然saved_regs要定义为全局变量。

0x03 获取目标进程的dlopen,dlsym函数的绝对地址:

大概思路是这样的:首先通过遍历/proc/pid/maps文件分别得到本进程中dlopen函数所在动态库的基地址local_module_base和目标进程dlopen函数所在动态库的基地址remote_module_base,接着获取本进程dlopen函数的绝对地址local_addr =(void*)dlopen。需要明白的是,不同进程中相同的动态库中的同一个函数的偏移地址一定是一样的,所以目标进程dlopen函数的绝对地址为:local_addr - local_module_base +remote_module_base。dlsym同理,不再详述。

0x04 获取并保存目标进程的堆栈,设置dlopen函数的相关参数,将要注入的SO的绝对路径压栈:

当我们的要执行的函数的某些参数需要压入堆栈的时候,就需要提前保存堆栈状态,调用ptrace_readdata(pid, (void *)regs.ARM_sp, (void *)sbuf, sizeof(sbuf)),其中sbuf为char数组,用来存放堆栈。调用ptrace_writedata(pid, (void *)regs.ARM_sp, (void *)so_path, strlen(so_path) + 1),其中so_path为SO的绝对路径。函数传参规则:前四个参数分别由寄存器r0、r1、r2、r3存放,超过四个参数则压入堆栈。

0x05 调用dlopen函数:

参数设置好后,设置ARM_pc = dlopen_addr,ARM_lr = 0。调用ptrace_setregs(pid, regs)写入修改后的寄存器值,调用ptrace_continue( pid )使目标进程继续运行。(注:dlopen_addr为0x03获取到的目标进程dlopen函数的绝对地址,ARM_lr = 0的目的在于当目标进程执行完dlopen函数,使目标进程发生异常,从而让本进程重新获得控制权)

0x06 调用dlsym函数,获取SO中要执行的函数地址:

实现方式与调用dlopen函数类似,不再详述。

0x07 调用要执行的函数:

实现方式与调用dlopen函数类似,不再详述。

0x08 恢复目标进程的堆栈,恢复目标进程寄存器值,解除关联,完成SO动态库注入:

调用ptrace_writedata(pid, (uint8_t *)saved_regs.ARM_sp, (uint8_t *)sbuf, sizeof(sbuf))恢复堆栈,调用ptrace_setregs(pid, &saved_regs)恢复寄存器值,调用ptrace_detach(pid)解除关联,完成SO动态库注入。

更多相关文章

  1. C语言函数以及函数的使用
  2. Android三角函数
  3. 进程博客纳入
  4. ISurfaceComposer接口有13个成员函数
  5. android 杀掉进程
  6. Android jni系统变量、函数、接口定义汇总
  7. Android 进程和线程模型
  8. 一个简单的Android进程管理器(初稿)
  9. Android进程管理简单介绍

随机推荐

  1. Android(安卓)Fragment的介绍与使用(案例
  2. Android NDK 笔记
  3. (OK) Android系统启动-SystemServer上篇
  4. Android Studio 更新时提示connection fa
  5. TextView 的设置现实的文字的长度?
  6. Unity Android(安卓)安装apk后显示两个ap
  7. AndroidStudio实现按钮按下时状态改变以
  8. Android上使用Google Map
  9. 从简单的android 登陆应用 ,学习布局,
  10. Android(安卓)ScrollView 中放入 ImageVi