目录(?)[-]

  1. 继续
  2. 注入
    1. 分类
    2. 本质
    3. 目的
    4. 过程
    5. 示例一
      1. Host代码
      2. libmysoso代码
      3. 调用
  3. 示例代码

继续

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

注入

分类

我们平时所说的代码注入,主要静态和动态两种方式
  • 静态注入,针对是可执行文件,比如平时我们修改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被加载后,函数被自动执行;
[cpp] view plain copy
  1. __attribute__ ((__constructor__))
  2. void Main() {
  3. LOGI(">>>>>>>>>>>>>I am in, I am a bad boy 1!!!!<<<<<<<<<<<<<<");
  4. void* handle = dlopen("libinso.so", RTLD_NOW);
  5. void (*setA_func)(int) = (void (*)(int))dlsym(handle, "setA");
  6. if (setA_func) {
  7. setA_func(999);
  8. }
  9. }
  • 使用c++全局对象初始化,其构造函数会被自动执行;
[cpp] view plain copy
  1. void Main();
  2. static void* _main(void*){
  3. Main();
  4. return NULL;
  5. }
  6. class EntryClass {
  7. public:
  8. EntryClass() {
  9. pthread_t tid;
  10. pthread_create(&tid, NULL, _main, NULL);
  11. pthread_detach(tid);
  12. }
  13. } boy;

示例一

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

Host代码

包含三个源文件,分别是demo1.c,inso.h, inso.c
[cpp] view plain copy
  1. /*
  2. * inso.h
  3. *
  4. *  Created on: 2014年6月24日
  5. *      Author: boyliang
  6. */
  7. __attribute__ ((visibility ("default"))) void setA(int i);
  8. __attribute__ ((visibility ("default"))) int getA();
[cpp] view plain copy
  1. /*
  2. * inso.c
  3. *
  4. *  Created on: 2014年6月24日
  5. *      Author: boyliang
  6. */
  7. #include <stdio.h>
  8. #include "inso.h"
  9. static int gA = 1;
  10. void setA(int i){
  11. gA = i;
  12. }
  13. int getA(){
  14. return gA;
  15. }
[cpp] view plain copy
  1. /*
  2. * demo1.c
  3. *
  4. *  Created on: 2014年6月24日
  5. *      Author: boyliang
  6. */
  7. #include <stdio.h>
  8. #include <unistd.h>
  9. #include "inso.h"
  10. #include "log.h"
  11. int main(){
  12. LOGI("DEMO1 start.");
  13. while(1){
  14. LOGI("%d", getA());
  15. setA(getA() + 1);
  16. sleep(2);
  17. }
  18. return 0;
  19. }

libmyso.so代码

[cpp] view plain copy
  1. /*
  2. * myso.c
  3. *
  4. *  Created on: 2014年6月24日
  5. *      Author: boyliang
  6. */
  7. #include <stdio.h>
  8. #include <stddef.h>
  9. #include <dlfcn.h>
  10. #include <pthread.h>
  11. #include <stddef.h>
  12. #include  "log.h"
  13. __attribute__ ((__constructor__))
  14. void Main() {
  15. LOGI(">>>>>>>>>>>>>I am in, I am a bad boy 1!!!!<<<<<<<<<<<<<<");
  16. void* handle = dlopen("libinso.so", RTLD_NOW);
  17. void (*setA_func)(int) = (void (*)(int))dlsym(handle, "setA");
  18. if (setA_func) {
  19. setA_func(999);
  20. }
  21. }

调用

注入程序,我将其命名为poison,使用方法是poison <so_path> <target_pit>。下面是示例的输出显示:
[plain] view plain copy
  1. I/TTT     (  594): DEMO1 start.
  2. I/TTT     (  594): 1
  3. I/TTT     (  594): 2
  4. I/TTT     (  594): 3
  5. I/TTT     (  594): 4
  6. I/TTT     (  594): 5
  7. I/TTT     (  594): 6
  8. I/TTT     (  594): 7
  9. I/TTT     (  594): >>>>>>>>>>>>>I am in, I am a bad boy 1!!!!<<<<<<<<<<<<<<
  10. I/TTT     (  594): 999
  11. I/TTT     (  594): 1000
  12. I/TTT     (  594): 1001

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

示例代码

上述示例所涉及到代码,我都放发布到github上了,大家如果想研究代码,可以到https://github.com/boyliang/injection_by_ptrace

在《三》,我会再介绍一种Android上特有的注入技术,敬请期待。

原文地址: http://blog.csdn.net/l173864930/article/details/38456313

进击的Android Hook 注入术《二》相关推荐

  1. 进击的Android Hook 注入术《四》

    目录(?)[-] 继续 注入之后 示例三 输出 最后 继续 在前<一>.<二>.<三>里已经把注入的技术介绍完了,这章开始说注入之后需要做的事情.如果对注入技术已经 ...

  2. 进击的Android Hook 注入术《三》

    目录(?)[-] 继续 Component Injection 原理 示例二 comdemohost comdemoinject 绕过ClassLoader双亲委托 输出 最后 继续 在<二&g ...

  3. 进击的Android Hook 注入术《一》

    目录(?)[-] 写在前面 短信拦截 场景 问题 解决方案 问题来了 基本思路 写在前面 这个系列本来是在公司的一个分享,内容比较多,所以就把这个PPT重新组织整理成博客,希望对大家学习有所帮助.我会 ...

  4. 进击的Android Hook 注入术《五》

    版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] 继续 BinderProxy 原理 获取AMS引用 获取JavaBBinder 替换mObject对象 示例四 最后 继续 在A ...

  5. xposed hook java_[原创]Android Hook 系列教程(一) Xposed Hook 原理分析

    章节内容 一. Android Hook 系列教程(一) Xposed Hook 原理分析 二. Android Hook 系列教程(二) 自己写APK实现Hook Java层函数 三. Androi ...

  6. 【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 远程调用 目标进程中 libc.so 动态库中的 mmap 函数 二 | 准备参数 | 远程调用 mmap 函数 )

    文章目录 一.准备 mmap 函数的参数 二.mmap 函数远程调用 一.准备 mmap 函数的参数 上一篇博客 [Android 逆向]Android 进程注入工具开发 ( 注入代码分析 | 远程调 ...

  7. linux qt getpid,[QTA] Android 动态注入原理分析

    一.前言 Android 的 UI 自动化测试可以通过注入式和非注入式分别实现,通过注入式可以更加方便地与应用进行交互.QTA 团队提供的 Android UI 自动化测试框架QT4A, 是通过动态注 ...

  8. Frida Android hook

    From:https://eternalsakura13.com/2020/07/04/frida/ 目录 1.r0ysue 大佬 2.Frida 环境 2.1 pyenv 2.2 frida 安装 ...

  9. android hook 第三方app_基于 VirtualApp 结合 whale hook框架实现hook第三方应用

    要点 1. whale hook framework 使用示例: 2. 参考项目:VirtualHook: 3. 按照 VirtualHook 修改 VirtualApp: 4. 编写 hook pl ...

最新文章

  1. Qt中线程的生命期问题
  2. #react-native BUG#
  3. kali-linux nat模式下无法联网问题
  4. 卷积在计算机中实现+pool作用+数据预处理目的+特征归一化+理解BN+感受野理解与计算+梯度回传+NMS/soft NMS
  5. truncate python是删除文件内容吗_在Python中操作文件之truncate()方法的使用教程
  6. C# 用Attribute实现AOP事务
  7. HDU多校联合赛(1007 Magical Forest)模拟题
  8. 同一台主机部署两个比特币钱包以及rpc服务的摘要
  9. “精钢云”落地:鞍钢携手金山云推动中国制造
  10. 一次百万长连接压测 Nginx OOM 的问题排查分析
  11. Android 编程下的计时器
  12. Windows下nmap命令及Zenmap工具的使用方法
  13. pgadmin3连接mysql_postgresql – PgAdmin III – 密码为空时如何连接数据库?
  14. QT学习笔记(一)——QT基础
  15. 平衡二叉树的调整整理
  16. 使用excel校验身份证号码是否正确
  17. 零基础微信小程序开发学习笔记(1.初识目录结构)
  18. UVA 1449 Dominating Patterns(AC自动机)
  19. 双目 机器视觉-- 测距
  20. 2019 年度程序员薪酬报告:40 岁以后普遍遭遇收入天花板

热门文章

  1. C++ unique and erase问题处理
  2. 用服务器控件在后台调用前台客户端JS方法
  3. css hack方法,css hack怎么应用
  4. 【Python】字符转换为 ASCII 码
  5. 【C++】构建栈 进栈和出栈
  6. 目标检测,目标识别的SAR数据集构建和标注
  7. 952计算机网络是那本书,952计算机网络复习参考提纲.doc
  8. python flask安装_python flask安装和命令详解
  9. Go进阶(6): uuid生成及其作用
  10. 线性判别分析LDA的数学原理(二)