原文: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. Java接口响应超时监控

    为什么要监控 服务化接口是提供服务的,接口正确性.稳定性是最最重要的,在保证正确的同时需要尽量提高接口响应时间. 有的团队会有专门的工具来对系统响应时间.吞吐量做监控,但如果团队没有这种"待 ...

  2. ASP.NET MVC搭建项目后台UI框架—1、后台主框架

    目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...

  3. spider RPC框架的需求来源与特性介绍(一)

    spider RPC 特性介绍 spider RPC 性能测试 spider RPC 入门指南 spider RPC 配置文件参考 spider RPC 开发指南 spider RPC 安全性 spi ...

  4. WCF实现事件通知相关应用技巧介绍

    WCF实现事件通知是一个比较容易掌握的知识点,不过在实现的过程中,我们还是需要注意一些事项,以保证功能的完善性. WCF中有一些方法的应用对于初学者来说还是比较容易应用.只要熟练的联系这些方法操作,一 ...

  5. Atittit.研发公司的组织架构与部门架构总结

    Atittit.研发公司的组织架构与部门架构总结 1. archi组织架构与 部门规划2 1.1. 最高五大组织机构2 1.2. 宗教事务部2 1.3. 制度与重大会议委员会2 1.4. 纠纷处理部: ...

  6. 解析URL 获取某一个参数值

    /** * 解析URL 获取某一个参数值 * * @param name 需要获取的字段 * @param webaddress URL * * @return 返回的参数对应的 value */ - ...

  7. IO流的登录与注册

    import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.File;import java.io.FileR ...

  8. 原创 C++之常量(一)

    1概述 一个C++程序就是一系列数据与操作的集合.当一个C++程序开始运行的时候,与该程序相关的数据就会被加载到内存中.当数据与内存发生关联的时候,这些数据就会具有如下的特性: 数据在内存中的地址.这 ...

  9. 突然想到一个问题:有关 cqrs 分离

    大部分的系统,都是查询多,c少,那为什么我们不把q放在内存里面,而c直接操作数据库呢? 就如enode,c在内存,而q在数据库,当然q也很容易扩展到内存缓存上.二个enode案例demo,都可以让c的 ...

  10. shell脚本实现算术运算且输入的不能为非数字的值

    #!/bin/bash c= ] do echo "请输入第一个数" read a echo "请输入第二个数" read b ]* ]] && ...