原文:http://blog.csdn.net/u011068702/article/details/53208825

附:Android Hook 全面入侵监听器

第一步、先爆项目demo照片,代码不多,不要怕

 

第二步、应该知道Java反射相关知识

如果不知道或者忘记的小伙伴请猛搓这里,Android插件化开发基础之Java反射机制研究 http://blog.csdn.net/u011068702/article/details/49863931


第三步、应该知道Java静态代理知识

如果不知道或者忘记的小伙伴请猛搓这里,Android插件化开发基础之静态代理模式 http://blog.csdn.net/u011068702/article/details/51765578
 

第四部、应该知道Java动态代理知识

如果不知道或者忘记的小伙伴请猛搓这里,Android插件化开发基础之Java动态代理(proxy)机制的简单例子  http://blog.csdn.net/u011068702/article/details/53185210
上面只有代码的解释,如果不是很清楚的小伙伴可以再去到网上搜一搜相关知识。
 

第五步、应该知道Android里面的ActivityThread类和Instrumentation类

 如果不知道或者忘记的小伙伴请猛搓这里,Android插件化开发之AMS与应用程序(客户端ActivityThread、Instrumentation、Activity)通信模型分析 http://blog.csdn.net/u011068702/article/details/53207039
希望认真看,知道ActivityThread和Instrumentation是干嘛的,方便下面分析。

第六步、理解hook,并且分析源码

如果我们自己创建代理对象,然后把原始对象替换为我们的代理对象,那么就可以在这个代理对象为所欲为了;修改参数,替换返回值,我们称之为Hook。
接下来我们来实现Hook掉startActivity这个方法,当每次调用这个方法的时候来做我们需要做的事情,我这里之打印了一些信息,读者可以更具自己的需求来修改,
我们的目的是拦截startActivity方法,有点类是spring 里面AOP的思想。
 

1、hook一般在哪里hook?

首先分析我们需要hook哪些对象,也就是说我们要hook的地方,什么样的对象比较好Hook呢?一般是容易找到和不容易改变的对象,这思路就来了,不改变一般在我们类的里面单例对象是唯一对象,静态变量我们一般加上final static 修饰,有了final就不会改变,不变模式里面比如String类,里面就很多final,我们更加这些找到hook的地方。
 

2、我们hook startActivity,分析startActivity到底是怎么实现的

我们每次Context.startActivity,由于Context的实现实际上是ContextImpl来实现的,;我们看ConetxtImpl类的startActivity方法:

 
  1. @Override
  2. public void startActivity(Intent intent, Bundle options) {
  3. warnIfCallingFromSystemProcess();
  4. if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
  5. throw new AndroidRuntimeException(
  6. "Calling startActivity() from outside of an Activity "
  7. + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
  8. + " Is this really what you want?");
  9. }
  10. mMainThread.getInstrumentation().execStartActivity(
  11. getOuterContext(), mMainThread.getApplicationThread(), null,
  12. (Activity)null, intent, -1, options);
  13. }

我们可以看到startActivity方法最后还是通过Instrumentation对象来执行execStartActivity来实现的,如果你认真看了《Android插件化开发之AMS与应用程序(客户端ActivityThread、Instrumentation、Activity)通信模型分析 》上面这篇博客,我们知道ActivityThread就是主线程,也就是我们常说的UI线程,可以去更新UI,一个进程只有一个主线程,我们可以在这里hook.
我们需要Hook掉我们的主线程对象,把主线程对象里面的mInstrumentation给替换成我们修改过的代理对象;要替换主线程对象里面的字段

1)首先我们得拿到主线程对象的引用,如何获取呢?ActivityThread类里面有一个静态方法currentActivityThread可以帮助我们拿到这个对象类;但是ActivityThread是一个隐藏类,我们需要用反射去获取,代码如下:

  1. // 先获取到当前的ActivityThread对象
  2. Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
  3. Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
  4. currentActivityThreadMethod.setAccessible(true);
  5. Object currentActivityThread = currentActivityThreadMethod.invoke(null);

2)拿到这个currentActivityThread之后,我们需要修改它的mInstrumentation这个字段为我们的代理对象,我们先实现这个代理对象,由于JDK动态代理只支持接口,而这个Instrumentation是一个类,我们可以手动写静态代理类,覆盖掉原始的方法,代码如下

  1. package com.example.hookstartactivity;
  2. import java.lang.reflect.Method;
  3. import android.app.Activity;
  4. import android.app.Instrumentation;
  5. import android.app.Instrumentation.ActivityResult;
  6. import android.content.Context;
  7. import android.content.Intent;
  8. import android.os.Bundle;
  9. import android.os.IBinder;
  10. import android.util.Log;
  11. public class InstrumentationProxy extends Instrumentation {
  12. public static final String TAG = "InstrumentationProxy";
  13. public static final String EXEC_START_ACTIVITY = "execStartActivity";
  14. // ActivityThread里面原始的Instrumentation对象,这里千万不能写成mInstrumentation,这样写
  15. //抛出异常,已亲测试,所以这个地方就要注意了
  16. public Instrumentation oldInstrumentation;
  17. //通过构造函数来传递对象
  18. public InstrumentationProxy(Instrumentation mInstrumentation) {
  19. oldInstrumentation = mInstrumentation;
  20. }
  21. //这个方法是由于原始方法里面的Instrumentation有execStartActivity方法来定的
  22. public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,
  23. Intent intent, int requestCode, Bundle options) {
  24. Log.d(TAG, "\n打印调用startActivity相关参数: \n" + "who = [" + who + "], " +
  25. "\ncontextThread = [" + contextThread + "], \ntoken = [" + token + "], " +
  26. "\ntarget = [" + target + "], \nintent = [" + intent +
  27. "], \nrequestCode = [" + requestCode + "], \noptions = [" + options + "]");
  28. Log.i(TAG, "------------hook  success------------->");
  29. Log.i(TAG, "这里可以做你在打开StartActivity方法之前的事情");
  30. Log.i(TAG, "------------hook  success------------->");
  31. Log.i(TAG, "");
  32. //由于这个方法是隐藏的,所以需要反射来调用,先找到这方法
  33. try {
  34. Method execStartActivity = Instrumentation.class.getDeclaredMethod(
  35. EXEC_START_ACTIVITY,
  36. Context.class, IBinder.class, IBinder.class, Activity.class,
  37. Intent.class, int.class, Bundle.class);
  38. execStartActivity.setAccessible(true);
  39. return (ActivityResult) execStartActivity.invoke(oldInstrumentation, who,
  40. contextThread, token, target, intent, requestCode, options);
  41. } catch (Exception e) {
  42. //如果你在这个类的成员变量Instrumentation的实例写错mInstrument,代码讲会执行到这里来
  43. throw new RuntimeException("if Instrumentation paramerter is mInstrumentation, hook will fail");
  44. }
  45. }
  46. }

3)然后用代理对象替换,代码如下

  1. package com.example.hookstartactivity;
  2. import java.lang.reflect.Field;
  3. import java.lang.reflect.Method;
  4. import android.app.Application;
  5. import android.app.Instrumentation;
  6. import android.util.Log;
  7. public class MyApplication extends Application {
  8. public static final String TAG = "MyApplication";
  9. public static final String ACTIVIT_THREAD = "android.app.ActivityThread";
  10. public static final String CURRENT_ACTIVITY_THREAD = "currentActivityThread";
  11. public static final String INSTRUMENTATION = "mInstrumentation";
  12. @Override
  13. public void onCreate() {
  14. try {
  15. //这个方法一般是写在Application的oncreate函数里面,如果你写在activity里面的oncrate函数里面就已经晚了
  16. attachContext();
  17. } catch (Exception e) {
  18. e.printStackTrace();
  19. }
  20. }
  21. public static void attachContext() throws Exception{
  22. //获取当前的ActivityThread对象
  23. Class<?> activityThreadClass = Class.forName(ACTIVIT_THREAD);
  24. Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod(CURRENT_ACTIVITY_THREAD);
  25. currentActivityThreadMethod.setAccessible(true);
  26. Object currentActivityThread = currentActivityThreadMethod.invoke(null);
  27. //拿到在ActivityThread类里面的原始mInstrumentation对象
  28. Field mInstrumentationField = activityThreadClass.getDeclaredField(INSTRUMENTATION);
  29. mInstrumentationField.setAccessible(true);
  30. Instrumentation mInstrumentation = (Instrumentation) mInstrumentationField.get(currentActivityThread);
  31. //构建我们的代理对象
  32. Instrumentation evilInstrumentation = new InstrumentationProxy(mInstrumentation);
  33. //通过反射,换掉字段,注意,这里是反射的代码,不是Instrumentation里面的方法
  34. mInstrumentationField.set(currentActivityThread, evilInstrumentation);
  35. //做个标记,方便后面查看
  36. Log.i(TAG, "has go in MyApplication attachContext method");
  37. }
  38. }

要注意这个替换要在Application里面的oncreate方法里面去执行,如果到Activity方法里面去执行的话就晚了,程序不会报错,但是hook不到。

然后我是在主页面写了一个按钮,点击来触发startActivity的。
MainActivity.java 文件如下

  1. package com.example.hookstartactivity;
  2. import android.content.Intent;
  3. import android.os.Bundle;
  4. import android.support.v7.app.ActionBarActivity;
  5. import android.util.Log;
  6. import android.view.Menu;
  7. import android.view.MenuItem;
  8. import android.view.View;
  9. import android.view.View.OnClickListener;
  10. import android.widget.TextView;
  11. public class MainActivity extends ActionBarActivity {
  12. public static final String TAG  =  "MainActivity";
  13. public TextView tv;
  14. @Override
  15. protected void onCreate(Bundle savedInstanceState) {
  16. super.onCreate(savedInstanceState);
  17. setContentView(R.layout.activity_main);
  18. tv = (TextView)findViewById(R.id.start);
  19. tv.setOnClickListener(new OnClickListener(){
  20. @Override
  21. public void onClick(View v) {
  22. try {
  23. Intent intent = new Intent(MainActivity.this, SecondActivity.class);
  24. Bundle bundle = new Bundle();
  25. Log.i(TAG, "-------------------------------->");
  26. Log.i(TAG, "startActivity before");
  27. Log.i(TAG, "-------------------------------->");
  28. startActivity(intent, bundle);
  29. Log.i(TAG, "-------------------------------->");
  30. Log.i(TAG, "startActivity after");
  31. Log.i(TAG, "-------------------------------->");
  32. } catch (Exception e) {
  33. e.printStackTrace();
  34. }
  35. }
  36. } );
  37. }
  38. }

跳转到的Second.java文件如下

  1. package com.example.hookstartactivity;
  2. import android.os.Bundle;
  3. import android.support.v7.app.ActionBarActivity;
  4. public class SecondActivity extends ActionBarActivity{
  5. @Override
  6. protected void onCreate(Bundle savedInstanceState) {
  7. super.onCreate(savedInstanceState);
  8. setContentView(R.layout.activity_second);
  9. }
  10. }

第七步、运行代码

启动项目在ubuntu终端打印的日志图片如下:
 
 
然后我点击图标调用startActivity方法后ubuntu终端打印的日志图片如下:
 
日志上面看到,hook success了
看到ubuntu终端日志打印,前面显示了类,方便通过日志找bug,我用的是pidcat,下载pidcat 
然后在ubuntu上面运行 
  1. pidcat.py 包名
就可以非常方便看的日志找bug了。
 

第八步、总结

  通过这篇日志,希望打击可以更好的理解hook、java反射、静态代理、动态代理、ActivityThread、Instrumentation
  最后附上源码下载地址,需要的小伙伴请猛搓这里 HookStartActivityDemo
 

Android Hook技术的更多相关文章

  1. Android so注入(inject)和Hook技术学习(三)——Got表hook之导出表hook

    前文介绍了导入表hook,现在来说下导出表的hook.导出表的hook的流程如下.1.获取动态库基值 void* get_module_base(pid_t pid, const char* modu ...

  2. Android Native Hook技术(二)

    Hook技术应用 已经介绍了安卓 Native hook 原理,这里介绍 hook 技术的应用,及 Cyida Substrate 框架. 分析某APP,发现其POST请求数据经过加密,我们希望还原其 ...

  3. Android Native Hook技术(一)

    原理分析 ADBI是一个著名的安卓平台hook框架,基于 动态库注入 与 inline hook 技术实现.该框架主要由2个模块构成:1)hijack负责将so注入到目标进程空间,2)libbase是 ...

  4. Hook技术

    hook钩子: 使用技术手段在运行时动态的将额外代码依附现进程,从而实现替换现有处理逻辑或插入额外功能的目的. 它的技术实现要点有两个: 1)如何注入代码(如何将额外代码依附于现有代码中). 2)如何 ...

  5. Android官方技术文档翻译——新构建系统概述

    本文译自Android官方技术文档<New Build System>,原文地址:http://tools.android.com/tech-docs/new-build-system. ...

  6. Android Hook框架adbi源码浅析(一)

    adbi(The Android Dynamic Binary Instrumentation Toolkit)是一个Android平台通用hook框架,基于动态库注入与inline hook技术实现 ...

  7. 20145307陈俊达_安卓逆向分析_Xposed的hook技术研究

    20145307陈俊达_安卓逆向分析_Xposed的hook技术研究 引言 其实这份我早就想写了,xposed这个东西我在安卓SDK 4.4.4的时候就在玩了,root后安装架构,起初是为了实现一些屌 ...

  8. Android Hook神器:XPosed入门与登陆劫持演示

    前段时间写了一篇关于Cydia Substrate广告注入的文章,大家都直呼过瘾.但是,真正了解这一方面的同学应该知道,其实还有一个比Cydia Substrate更出名的工具:XPosed. 不是因 ...

  9. android hook 框架 ADBI 如何实现so函数挂钩

    上一篇 android 5 HOOK 技术研究之 ADBI 项目 02 分析了hijack.c, 这个文件编译为一个可执行程序 hijack, 该程序实现了向目标进程注入一个动态库的功能.这一篇继续研 ...

随机推荐

  1. python学习笔记1:python入门

    关于版本的选择 按照网上的说法,如果python是为了在工作中使用,选择2.7版本的.这里我选择2.7.9版本的来进行学习: Python是什么? 是一种高级的计算机程序设计语言.应用范围比较广,go ...

  2. HTTPS和HTTP的区别

    (转自:http://www.php100.com/html/it/biancheng/2015/0209/8582.html) 总的来说,http效率更高,https安全性更高. 首先谈谈什么是HT ...

  3. 人工智能AI-机器视觉CV-数据挖掘DM-机器学习ML-神经网络-[资料集合贴]

    说明:这个贴用于收集笔者能力范围内收集收藏并认为有用的资料,方便各方参考,免去到处找寻之苦,提升信息的交叉引用价值.仅供参考,不作为必然的推荐倾向.如涉及版权等问题请相关人员联系笔者,谢谢. |博客| ...

  4. linux下安装 oracle 11g

    oracle 11g安装 一.环境准备 划分区 / 15000M /tmp 4096M /boot 100M Swap 4096M /u01 剩余空间 2.更改主机名,ip地址 3.安装软件包 那么l ...

  5. [Top-Down Approach] Chatper 3 Notes

    这里留下空白,提醒自己,第一章第二章尚待整理回顾. 此处缺了3.6/3.7两节拥塞控制的内容

  6. python学习3

    这部分学习python函数的写法: 在写python函数之前,首先看一下python中已经写好的函数,就像C中的<math>中的那些函数一样的东西有哪些:网址为https://docs.p ...

  7. Spring之BeanFactory及Bean生命周期

    1.spring通过BeanFactory灵活配置.管理bean,Spring对管理的bean没有任何特别的要求,完全支持对POJO的管理: 2.BeanFactory有个ApplicationCon ...

  8. 代码管理工具 --- git的学习笔记二《git的工作原理》

    通过几个问题来学习代码管理工具之git 一.git是什么?为什么要用它?使用它的好处?它与svn的区别,在Mac上,比较好用的git图形界面客户端有 git 是分布式的代码管理工具,使用它是因为,它便 ...

  9. Oracle 判断某個字段的值是不是数字

    转:https://my.oschina.net/bairrfhoinn/blog/207835 摘要: 壹共有三种方法,分别是使用 to_number().regexp_like() 和 trans ...

  10. 检索 COM 类工厂中 CLSID 为 {000209FF-0000-0000-C000-000000000046} 的组件时失败,原因是出现以下错误: 80070005

    检索 COM 类工厂中 CLSID 为 {000209FF-0000-0000-C000-000000000046} 的组件时失败,原因是出现以下错误: 80070005 在CSDN上总是有网友问这个 ...