继续

在《一》里,我把基本思路描写叙述了一遍,接下为我们先从注入開始入手。

注入


分类

我们平时所说的代码注入,主要静态和动态两种方式
  • 静态注入,针对是可运行文件,比方平时我们改动ELF,DEX文件等等,相关的辅助工具也非常多,比方IDA、JEB、ApkTool等等;
  • 动态注入,针对是进程,比方改动进程的寄存器、内存值等等;
动态跟静态最大的差别是,动态不须要修改源文件,但须要高权限(一般是root权限),并且所需的技术含量更高。

本质

动态注入技术,本质上就是一种调度技术。想想平时我们调试一个进程时,能够做哪些功能? 一般有下列几项:
  • 查看变量值
  • 改动变量值
  • 跟踪进程跳转
  • 查看进程调用堆栈
  • 等等
动态注入相比于普通的调试,最大的差别就是动态注入是一个”自己主动化调试并达到载入自己定义动态链接库“的过程。所谓自己主动化,事实上就是通过代码实现,在Linux上通过Ptrace就能够完毕上面全部功能,当然Ptrace功能是比較原始的,平时调试中的功能还须要非常多高层逻辑封装才干够实现。
在阅读以下章节之前,强烈建议阅读一下man文档,见这里

目的

一般而言,我们要对一个进程进行注入,主要有下面几方面目的:
  • 增强目标进程的功能;
  • 修复目标进程缺陷;
  • 劫持目标进程函数;
  • 窃取目标进程数据;
  • 篡改目标进程数据;


过程

如上图所看到的,进程A注入到进程B后,通过改动寄存器和内存,让进程B载入自己定义的动态库a,当a被载入后,a会尝试载入其它模块,比方载入dex文件等等,详细的注入步骤例如以下:
  • ATTATCH,指定目标进程,開始调试;
  • GETREGS,获取目标进程的寄存器,保存现场;
  • SETREGS,改动PC等相关寄存器,使其指向mmap;
  • POPETEXT,把so path写入mmap申请的地址空间;
  • SETRESG,改动PC等相关寄存器,使其指向dlopen;
  • SETREGS,恢复现场;
  • DETACH,解除调试,使其恢复;
上述是一个简化的过程,整个注入的代码,我已经上传到github,地址https://github.com/boyliang/Poison
当so被dlopen载入到目标进程后,我们须要让so中的逻辑被运行,比較复杂的做法是相同使用ptrace改动寄存器的办法,让目标进程调用dlsym找到我们函数的地址。而比較简单的做法有两种,例如以下
  • 使用gcc的预编译指令__attribute__ ((__constructor__)),作用是让so被载入后,函数被自己主动运行;
__attribute__ ((__constructor__))
void Main() {
LOGI(">>>>>>>>>>>>>I am in, I am a bad boy 1!!!!<<<<<<<<<<<<<<"); void* handle = dlopen("libinso.so", RTLD_NOW);
void (*setA_func)(int) = (void (*)(int))dlsym(handle, "setA"); if (setA_func) {
setA_func(999);
}
}
  • 使用c++全局对象初始化,其构造函数会被自己主动运行;
void Main();

static void* _main(void*){
Main();
return NULL;
} class EntryClass {
public: EntryClass() {
pthread_t tid;
pthread_create(&tid, NULL, _main, NULL);
pthread_detach(tid);
} } boy;

演示样例一

以下演示样例一个通过ptrace注入的演示样例,涉及到两部分代码,一部分是目标进程代码记作host,还有一部分是被我们注入的so代码记作libmyso.so

Host代码

包括三个源文件,各自是demo1.c,inso.h, inso.c
/*
* inso.h
*
* Created on: 2014年6月24日
* Author: boyliang
*/ __attribute__ ((visibility ("default"))) void setA(int i); __attribute__ ((visibility ("default"))) int getA();
/*
* inso.c
*
* Created on: 2014年6月24日
* Author: boyliang
*/ #include <stdio.h>
#include "inso.h" static int gA = 1; void setA(int i){
gA = i;
} int getA(){
return gA;
}
/*
* demo1.c
*
* Created on: 2014年6月24日
* Author: boyliang
*/ #include <stdio.h>
#include <unistd.h> #include "inso.h"
#include "log.h" int main(){ LOGI("DEMO1 start."); while(1){
LOGI("%d", getA());
setA(getA() + 1);
sleep(2);
} return 0;
}

libmyso.so代码

/*
* myso.c
*
* Created on: 2014年6月24日
* Author: boyliang
*/ #include <stdio.h>
#include <stddef.h>
#include <dlfcn.h>
#include <pthread.h>
#include <stddef.h> #include "log.h" __attribute__ ((__constructor__))
void Main() {
LOGI(">>>>>>>>>>>>>I am in, I am a bad boy 1!!!!<<<<<<<<<<<<<<"); void* handle = dlopen("libinso.so", RTLD_NOW);
void (*setA_func)(int) = (void (*)(int))dlsym(handle, "setA"); if (setA_func) {
setA_func(999);
}
}

调用

注入程序,我将其命名为poison,用法是poison <so_path> <target_pit>。以下是演示样例的输出显示:
I/TTT     (  594): DEMO1 start.
I/TTT ( 594): 1
I/TTT ( 594): 2
I/TTT ( 594): 3
I/TTT ( 594): 4
I/TTT ( 594): 5
I/TTT ( 594): 6
I/TTT ( 594): 7
I/TTT ( 594): >>>>>>>>>>>>>I am in, I am a bad boy 1!!!!<<<<<<<<<<<<<<
I/TTT ( 594): 999
I/TTT ( 594): 1000
I/TTT ( 594): 1001

当运行./poison /data/local/tmp/libmyso.so 594后,输出中立即出现了特定字符串,而且打印的数据一下子变成了999,证明我们注入成功了。

演示样例代码

上述演示样例所涉及到代码,我都放公布到github上了,大家假设想研究代码,能够到https://github.com/boyliang/injection_by_ptrace
《三》,我会再介绍一种Android上特有的注入技术,敬请期待。

进击的Android注入术《二》的更多相关文章

  1. 进击的Android注入术《一》

    写在前面 这个系列本来是在公司的一个分享.内容比較多,所以就把这个PPT又一次组织整理成博客,希望对大家学习有所帮助.我会先以一个"短信拦截"作为样例,抛出问题,并提出了一种基于& ...

  2. Android 注入详解

    Android下的注入的效果是类似于Windows下的dll注入,关于Windows下面的注入可以参考这篇文章Windows注入术.而Android一般处理器是arm架构,内核是基于linux,因此进 ...

  3. Spring 属性注入(二)BeanWrapper 结构

    Spring 属性注入(二)BeanWrapper 结构 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html) BeanWrap ...

  4. Android注入完全剖析

    0 前沿 本文主要分析了一份实现Android注入的代码的技术细节,但是并不涉及ptrace相关的知识,所以读者如果不了解ptrace的话,最好先学习下ptrace原理再来阅读本文.首先,感谢源代码的 ...

  5. Android仿微信二维码扫描

    转载:http://blog.csdn.net/xiaanming/article/details/10163203 了解二维码这个东西还是从微信中,当时微信推出二维码扫描功能,自己感觉挺新颖的,从一 ...

  6. Android Fragment使用(二) 嵌套Fragments (Nested Fragments) 的使用及常见错误

    嵌套Fragment的使用及常见错误 嵌套Fragments (Nested Fragments), 是在Fragment内部又添加Fragment. 使用时, 主要要依靠宿主Fragment的 ge ...

  7. Android反编译(二)之反编译XML资源文件

    Android反编译(二) 之反编译XML资源文件 [目录] 1.工具 2.反编译步骤 3.重新编译APK 4.实例 5.装X技巧 6.学习总结 1.工具 1).反编译工具  apktool http ...

  8. 小白日记44:kali渗透测试之Web渗透-SqlMap自动注入(二)-sqlmap参数详解REQUEST

    Sqlmap自动注入(二) Request ################################################### #inurl:.php?id= 1. 数据段:--d ...

  9. Android进阶笔记06:Android 实现扫描二维码实现网页登录

    一. 扫描二维码登录的实现机制: 详细流程图: (1)PC端打开网页(显示出二维码),这时候会保存对应的randnumber(比如:12345678). (2)Android客户端扫码登录,Andro ...

随机推荐

  1. 走向DBA[MSSQL篇] 面试官最喜欢的问题 ----索引+C#面试题客串

    原文:走向DBA[MSSQL篇] 面试官最喜欢的问题 ----索引+C#面试题客串 对大量数据进行查询时,可以应用到索引技术.索引是一种特殊类型的数据库对象,它保存着数据表中一列或者多列的排序结果,有 ...

  2. Meld Diff for windows 安装和配置

    Meld Diff for windows 安装和配置 假设你在ubuntu 正在开发中, meld diff 此工具你肯定不会感到陌生. 而且很容易使用. 在网上看 meld for Windows ...

  3. .NET单元测试艺术(3) - 使用桩对象接触依赖

    List 3.1 抽取一个设计文件系统的类,并调用它 [Test] public bool IsValidLogFileName(string fileName) { FileExtensionMan ...

  4. OpenGL缓冲区

    OpenGL缓冲区 颜色缓冲区 OpenGL时,先是在一个缓冲区中完毕渲染,然后再把渲染结果交换到屏幕上. 我们把这两个缓冲区称为前颜色缓冲区(屏幕)和后颜色缓冲区.在默认情况下,OpenGL命令是在 ...

  5. SharePoint 2013 禁用搜索服务

    原文:SharePoint 2013 禁用搜索服务 前言,在SharePoint2013中,对于硬件需求的提升,让我们虚机里安装总是一筹莫展,尤其开启了搜索服务以后,对于内存的消耗就更加严重,尤其对于 ...

  6. 如何在SSIS的脚本组件中访问变量

    原文:如何在SSIS的脚本组件中访问变量 这是一个小问题,我们在SSIS的设计中很多地方都会用到变量,我习惯性地将"变量"和"表达式"称为SSIS的灵魂,虽然不 ...

  7. Linux内核分析(五)----字符设备驱动实现

    原文:Linux内核分析(五)----字符设备驱动实现 Linux内核分析(五) 昨天我们对linux内核的子系统进行简单的认识,今天我们正式进入驱动的开发,我们今后的学习为了避免大家没有硬件的缺陷, ...

  8. php形式的内容被处理

    /** * 过滤HTML内容RETURN * * @param $string * @param bool $html * * @return array|string */ public stati ...

  9. Spring3.0学习笔记文档的官方网站(六)--3.4.1

    3.4 依靠 3.4.1 依赖注入     依赖注入两种方式:基于构造函数DI.基于setter方法DI. 3.4.1.1 基于构造函数DI     参数是引进一个对象的.和缺乏父母之前-子类关系: ...

  10. Android:ViewPager详细解释(异步网络负载图片,有图片缓存,)并与导航点

    android 应用.准则欢迎页面. 和图像旋转木马特征, 或者没有很多其他的内容显示在一个页面.以被划分成多个页面,在这一刻viewpager这是非常容易使用. 首先看下效果: 以下是一个样例.带异 ...