概述

Hook,英文直译是”钩子“的意思。在程序中将其理解为”劫持“可能会更好理解,我们可以通过hook技术来劫持某个对象,从而控制它与其他对象的交互。

Hook技术分类

  1. 根据Hook的API语言划分,分为Hook Java和Hook Native。
  2. Hook Java主要通过反射和代理来实现,用于在SDK开发环境中修改Java代码。
  3. Hook Native则应用于在NDK开发环境和系统开发中修改Native代码。
  4. 根据Hook的进程划分,分为应用程序进程Hook和全局Hook。
  5. 应用程序进程Hook只能Hook当前所在的应用程序进程。
  6. 应用程序进程是Zygote进程fork出来的,如果对Zygote进行Hook,就可以实现Hook系统所有的应用程序进程,这就是全局Hook。
  7. 根据Hook的实现方式划分,分为如下两种:
  8. 通过反射和代理实现,只能Hook当前的应用程序进程。
  9. 通过Hook框架实现,比如Xposed,可以实现全局Hook,但是需要root。

Hook原理

创建一个代理对象,然后把原始对象替换为我们的代理对象,这样就可以在这个代理对象为所欲为,修改参数或替换返回值。

正常的调用和返回:

v2-6c9e80dfa7109b81040d77b1a6dbbd38_b.jpg

Hook的调用和返回:

v2-eb2ce92fc69e96b32fcf51f006205652_b.jpg

Hook的过程

Step1. 寻找Hook点,原则是静态变量或者单例对象,尽量Hook public的对象和方法,非public不保证每个版本都一样,需要适配。
Step2. 选择合适的代理方式,如果是接口可以用动态代理;如果是类可以用静态代理
Step3. 偷梁换柱——用代理对象替换原始对象。

Hook Activity的startActivity

寻找Hook点

Activity的startActivity方法的调用链:

// android/app/Activity.java// Step1
@Override
public void startActivity(Intent intent) {this.startActivity(intent, null);
}// Step2
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {if (options != null) {startActivityForResult(intent, -1, options);} else {startActivityForResult(intent, -1);}
}// Step3
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) {if (mParent == null) {options = transferSpringboardActivityOptions(options);// Hook点Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options);if (ar != null) {mMainThread.sendActivityResult(mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData());}if (requestCode >= 0) {mStartedActivity = true;}cancelInputsAndStartExitTransition(options);} else {if (options != null) {mParent.startActivityFromChild(this, intent, requestCode, options);} else {mParent.startActivityFromChild(this, intent, requestCode);}}
}

Hook点分析

当调用Activity的startActivity方法时,最后会调用mInstrumentation的execStartActivity方法来完成Activity的开启,而mInstrumentation是Activity的成员变量,所以是一个很好的Hook点,用代理Instrumentation来替代原始的Instrumentation完成Hook。

Hook代码

代理类:InstrumentationProxy.java

/*** 1. InstrumentationProxy继承Instrumentation* 2. InstrumentationProxy持有Instrumentation实例的引用* 3. 实现execStartActivity方法,并在内部通过反射调用Instrumentation的execStartActivity方法*/
public class InstrumentationProxy extends Instrumentation {private static final String TAG = "InstrumentationProxy";private Instrumentation的 mInstrumentation;public InstrumentationProxy(Instrumentation instrumentation) {mInstrumentation = instrumentation;}public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {Log.i(TAG, "Hook成功" + "--who:" + who);try {Method execStartActivityMethod = Instrumentation.class.getDeclaredMethod("execStartActivity",Context.class, IBinder.class, IBinder.class, Activity.class,Intent.class, int.class, Bundle.class);return (ActivityResult) execStartActivityMethod.invoke(mInstrumentation, who, contextThread, token, target,intent, requestCode, options);} catch (Exception e) {throw new RuntimeException(e);}}
}

用InstrumentationProxy来替换Instrumentation:

public class HookHelper {public static void hookActivityInstrumentation(Activity activity) {try {// 得到Activity的mInstrumentation字段Field field = Activity.class.getDeclaredField("mInstrumentation");field.setAccessible(true);// 得到Activity中的Instrumentation对象Instrumentation instrumentation = (Instrumentation) field.get(activity);// 创建InstrumentationProxy对象来代理Instrumentation对象InstrumentationProxy instrumentationProxy = new InstrumentationProxy(instrumentation);// 用代理去替换Activity中的Instrumentation对象field.set(activity, instrumentationProxy);} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}
}

执行Hook:

public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// HookHookHelper.hookActivityInstrumentation(this);Intent intent = new Intent(this, DetailActivity.class);startActivity(intent);}
}

运行结果:

I/InstrumentationProxy: Hook成功--who:com.github.xch168.hooktest.MainActivity@bd3e1b1

Hook Context的startActivity

Context的实现类为ContextImpl。

寻找Hook点

ContextImpl中startActivity的调用链:

// Step1
@Override
public void startActivity(Intent intent) {warnIfCallingFromSystemProcess();startActivity(intent, null);
}// Step2
@Override
public void startActivity(Intent intent, Bundle options) {warnIfCallingFromSystemProcess();final int targetSdkVersion = getApplicationInfo().targetSdkVersion;if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0&& (targetSdkVersion < Build.VERSION_CODES.N|| targetSdkVersion >= Build.VERSION_CODES.P)&& (options == null|| ActivityOptions.fromBundle(options).getLaunchTaskId() == -1)) {throw new AndroidRuntimeException("Calling startActivity() from outside of an Activity "+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."+ " Is this really what you want?");}// Hook点mMainThread.getInstrumentation().execStartActivity(getOuterContext(), mMainThread.getApplicationThread(), null, (Activity) null, intent, -1, options);
}

Hook点分析:

  • 调用ActivityThread的getInstrumentation方法获取Instrumentation。
  • ActivityThread是主线程的管理类,Instrumentation是ActivityThread的成员变量,一个进程只有一个ActivityThread。
  • 选择Instrumentation作为Hook点,通过代理类进行替换。

Hook代码

public class HookHelper {public static void hookContextInstrumentation() {try {// 获取ActivityThread类Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");// 获取ActivityThread类中的静态变量sCurrentActivityThreadField currentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread");currentActivityThreadField.setAccessible(true);// 获取sCurrentActivityThread字段的值,即ActivityThread的对象Object currentActivityThread = currentActivityThreadField.get(null);// 获取ActivityThread的mInstrumentation字段Field mInstrumentationField = activityThreadClass.getDeclaredField("mInstrumentation");mInstrumentationField.setAccessible(true);// 获取mInstrumentation对象Instrumentation instrumentation = (Instrumentation) mInstrumentationField.get(currentActivityThread);// 创建Instrumentation的代理对象InstrumentationProxy instrumentationProxy = new InstrumentationProxy(instrumentation);// 用InstrumentationProxy替换ActivityThread中的InstrumentationmInstrumentationField.set(currentActivityThread, instrumentationProxy);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}
}

执行Hook

public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// HookHookHelper.hookContextInstrumentation();Intent intent = new Intent(this, DetailActivity.class);getApplicationContext().startActivity(intent);}
}

运行结果:

I/InstrumentationProxy: Hook成功--who:android.app.Application@7e13696

参考链接

  1. Android插件化原理解析——Hook机制之动态代理
  2. Android Hook 机制之简单实战
  3. Android Hook Activity 的几种姿势
  4. 理解 Android Hook 技术以及简单实战
  5. 《Android进阶解密》

android hook截取其他程序的按钮事件_Hook技术相关推荐

  1. 160个CrackMe之108 mfc程序 寻找按钮事件,代码还原(上)

    ·前言  虽然网上已经有帖子写160个CrackMe,我个人还是以正向的思路来逆向一部分的crackme,还有一些 代码还原的小技巧,挑选出这160个CrackMe中由c,c++,汇编编写的程序来来写 ...

  2. 小程序监听android返回键,如何监听小程序返回按钮事件?

    写在前面 为了能及时的将自己踩到的前端坑(包括ionic,angular,react,ReactNative,小程序,APICloud)分享给大家,以后会逐渐将文章转移到微信公众号:前端e家(fron ...

  3. 转用特征码秒杀各程序语言按钮事件

    作者:小童 工具:OllyDbg.Delphi程序一个.易语言程序一个.MFC程序一个 -------------------------------------------------------- ...

  4. 用特征码秒杀各程序语言按钮事件

    作者:小童 工具:OllyDbg.Delphi程序一个.易语言程序一个.MFC程序一个 -------------------------------------------------------- ...

  5. 如何监听小程序返回按钮事件?

    2020-06-09更新 //--------------------------2020-06-09更新-------------------开始-------------------------- ...

  6. Android 开发笔记(一) 按钮事件调用Activity

    UI创建按钮及事件 Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button);mEmailSignInB ...

  7. .Net 转战 Android 4.4 日常笔记(4)--按钮事件和国际化

    原文:.Net 转战 Android 4.4 日常笔记(4)--按钮事件和国际化 我们知道资源被注册到R.java我们通过R.java就可以读取到界面中的组件.跟我们.net一样,通过ID来读取组件 ...

  8. Android按钮事件的4种写法

    经过前两篇blog的铺垫,我们今天热身一下,做个简单的例子. 目录结构还是引用上篇blog的截图. 具体实现代码: public class MainActivity extends Activity ...

  9. android 6.0 权限程序崩溃,扫二维码崩溃与按键事件

    1.权限 解决困扰我两天的问题,项目调用一些.so文件,demo,和老版本的在华为 6.0系统运行正常,但是我的项目在6.0以下的手机上运行正常,在6.0系统上程序直接崩溃,6.0系统自然想到了权限问 ...

最新文章

  1. oracle去掉blob的黑边,oracle Blob处理
  2. Lyft估值目标近200亿美元 有望成今年来美国最大IPO
  3. 手机广告投放(phone advertising)唯一标识
  4. “我工作八年,换了四家小公司,今后的职业生涯该怎么走?”
  5. [Redis6]常用数据类型_String字符串
  6. CUDA out of memory. Tried to allocate 14763.13 GiB (GPU 3; 10.73 GiB total capacity; 165.28 MiB alre
  7. python mysql异常处理_python-处理PyMySql异常-最佳做法
  8. 深度学习优化方法总结比较(SGD,Adagrad,Adadelta,Adam,Adamax,Nadam)
  9. 集算器(仓库版)发布,黑科技获得用户好评
  10. 如果同时需要两张表,但其中一个表中没有另一个表中的字段,该如何正确使用
  11. 【新征程】1、考研路漫漫
  12. .NET中对于日文输入法的控制
  13. NNDL 实验六 卷积神经网络(4) ResNet18实现MINIST
  14. Linux的开源操作系统
  15. HttpClient请求https类型的网站接口碰到ssl证书不受信任问题处理
  16. jzoj2555 雾雨魔理沙
  17. 颜色迁移之四——模糊聚类(FCM)算法
  18. 工件SSMwar exploded 部署工件时出错。请参阅服务器日志了解详细信息
  19. intellij 打开两个窗口
  20. 真实生活的记录:我三年的外企生涯(1)出处:天涯虚拟社区

热门文章

  1. Leet Code OJ 4. Median of Two Sorted Arrays [Difficulty: Hard]
  2. Effective Java之避免创建不必要的对象(五)
  3. poj 2492 A Bug's Life
  4. 【最简便解法】1086 就不告诉你 (15分)_13行代码AC
  5. C语言满分代码:L1-059 敲笨钟 (20分)
  6. 16行代码AC——紫书| 例题7-3 Fractions Again?! (UVA - 10976)_时间复杂度O(n)
  7. 举例说明事务隔离级别
  8. Spring中BeanPostProcessor 执行过程
  9. (*长期更新)软考网络工程师学习笔记——Section 8 传输层
  10. Python程序开发——第五章 函数