V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
kaolalicai
V2EX  ›  Android

Android 编译插桩

  •  
  •   kaolalicai · 2019-08-07 11:39:31 +08:00 · 7471 次点击
    这是一个创建于 1938 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景:这一次分享一下关于 android 编译插桩这个话题,在正常编写代码实现程序的逻辑外,还要使用一点点黑科技,拿起操作代码无所不能的武器。


    一、Android 常用的能动态改变代码逻辑的方法有两种

    1. Java hook (反射,动态代理)

    android 是基于 java,同时也就有了反射的概念,动态去加载代码,同时动态代理也可以实现,但比较难理解,网络上讲得也很多了,这里就不讲。

    2. 插桩(编译插桩,插件化插桩)

    如果是按照插桩时机,在编译时候的就是编译插桩,然而,有些时候需要在程序运行的时候动态加载一些东西。我理解的差异性是插桩的代码是跟原来程序是分开的,在一个特定的时机与原有程序合二为一。

    二、从 xposed 框架到编译插桩

    记得去年曾经分享过 xposed 框架的使用,那是在系统层面去 hook 住方法,不足之处是系统要先刷入框架包,优点是可以对该系统里面所有的 app 进行 hook

    是否可以对我们自己的应用进行代码的修改?比如上面提到的有 java hook,还有编译插桩:下面是比较流行的框架

    1. aspectJ (面向切面框架) 跟普通代码一样,理解容易

    2. Asm (操作字节码框架)需要使用 asm 字节码,相对复杂

    而插桩的应用场景:apm,无埋点

    三、比较一下 aspectJ 与 asm 分别插桩后的代码

    1. aspectJ

    2. asm

    通过上面两个图可以看出插桩后的代码还是有所区别,aspectJ 采用插入方法的方式,这种代码混淆的时候一定要注意,不然会出现找不到方法名。而 asm 采用直接把差异代码嵌入原有的方法里,显然执行起来更加高效。

    asm 实现的插桩

    1. 原代码

    2. 字节码

    3. asm 代码

    可以看出代码相对来说是比较复杂的,可能需要工具才能正确去编写 asm 代码,比如 idea 插件 bytecode outline

    asm 在编译打包的哪个步骤插桩呢

    如图所示:在编译成.class 文件后,执行 asm 步骤,对 class 文件进行处理。而后就把各种编译后的文件打包进 dex 文件的过程。

    demo-采用 asm 为某个方法插入代码

    一个简单的 demo,对一个方法进行 asm 插桩

    https://github.com/ydpzg/TestPlugin


    附录

    自定义 gradle plugin

    https://guides.gradle.org/writing-gradle-plugins/

    https://docs.gradle.org/current/userguide/custom_plugins.html

    Asm 字节码插件: Asm Bytecode Outline

    java 字节码: javac Apple.java javap -verbose Apple.class

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5505 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 07:17 · PVG 15:17 · LAX 23:17 · JFK 02:17
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.