Skip to content

makeloveandroid/apphook

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

前介

我不知道大伙有没有这么一个烦恼,随着项目越来越庞大。从代码海中去定位一块实现逻辑,犹如大海捞针。

解决思路

通过 Xposed 拦截一些核心的关键方法,然后将收集的信息下发,我们就可以快速的定位代码啦!

看看成品吧

源码

源码在这里,来个素质3连

demo.gif

如何使用呢?

  1. 激活Xposed插件
  2. 选择需要分析的应用(最好直选中1个)
  3. 打开mac程序
  4. 输入指令 adb forward tcp:8000 localabstract:app_hook

源码分析

入口

Core.kt 负责 xposed 的入口,主要用途来初始化&拦截。

/**
 * 应用级hook
 */
fun appHook(application: Application) {
    val context = application.applicationContext
    val app = application
    val classLoader = application.classLoader
    Utils.init(app)
    SharedPreferencesUtils.init(context)
    CallActionManager.init()
    WebSocketManager.onOpen(context)
    LocationHookUtils.startHook(classLoader)
//        DexHelper.loadDex(context)
    InitManager.init(app)
    HookManager.register()
    HookManager.hookAll(classLoader)
    log("hook完成!!")
}

虚拟定位

主要封装在 LocationHookUtils 中。

拦截Activity创建等事件

封装在 ActivityAction 中。

Vclass ActivityAction : BaseAction<Activity, ActivityOnCreateData>() {
    override fun hook(classLoader: ClassLoader) {
        MethodHook
            .Builder()
            .setClass(Activity::class.java)
            .methodName("onCreate")
            .parameterTypes(Bundle::class.java)
            .afterHookedMethod {
                val activity = it.thisObject as Activity
                send(parsingData(activity))
            }
            .build()
            .execute()
    }
    .....
}

View事件拦截

  1. 点击事件 ViewClickEventAction 中,主要hook所有View的 performClick 方法,然后反射获取View的 mOnClickListener 输出对应View的点击监听对象。
  2. 长按事件 ViewLongClickEventAction 中,主要hook所有View的 performLongClickInternal 方法,然后反射获取View的 mOnLongClickListener 输出对应View的点击监听对象。

Fragment创建拦截

FragmentCreateAction 拦截所有 Fragment 的生命周期。

class FragmentCreateAction : BaseAction<Any, FragmentData>() {
    override fun hook(classLoader: ClassLoader) {
        // 区分Fragment
        val xFragment = ReflectUtils.findClass(classLoader, "androidx.fragment.app.Fragment")
        if (xFragment != null) {
            hookFragment("androidx.fragment.app.Fragment", xFragment)
        }
        val fragment = ReflectUtils.findClass(classLoader, "android.app.Fragment")
        if (fragment != null) {
            hookFragment("android.app.Fragment", fragment)
        }

        val v4fragment = ReflectUtils.findClass(classLoader, "android.support.v4.app.Fragment")
        if (v4fragment != null) {
            hookFragment("android.app.Fragment", v4fragment)
        }
    }
}

startActivity方法拦截

StartActivityAction 中拦截 InstrumentationexecStartActivity 方法。

class StartActivityAction : BaseAction<Intent, StartActivityOnCreateData>() {
    override fun hook(classLoader: ClassLoader) {
        MethodHook
            .Builder()
            .setClass(Instrumentation::class.java)
            .methodName("execStartActivity")
            .isHookAll(true)
            .afterHookedMethod {
                log("activity启动:${it.args.size}")
                if (it.args.size == 7) {
                    val context = it.args[0] as Context
                    val intent = it.args[4] as Intent
                    val data = parsingData(intent)
                    data.startContext = context.javaClass.name
                    data.stack = Log.getStackTraceString(Throwable())
                    send(data)
                }
            }
            .build()
            .execute()
    }
}

数据通讯

WebSocketManager 拦截应用启动后,移动端创建 WebSocket 服务。

object WebSocketManager : SimpleEndpoint, CoroutineScope by GlobalScope {
    private lateinit var mServer: LocalSocketServer
    private lateinit var context: Context

    val conns = mutableListOf<SimpleSession>()

    fun onOpen(context: Context) {
        this.context = context
        try {
            log("启动!!")
            mServer = LocalSocketServer(
                "app_hook", "app_hook",
                LazySocketHandler(ForwardSocketHandlerFactory(context, this))
            )
            GlobalScope.launch(Dispatchers.IO) {
                try {
                    mServer.run()
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
        } catch (e: Exception) {
            log("出错:${e.message}")
        }
    }
    .....
}

在通过 adb forward 命令,将移动端的端口隐射到客户端。这样就能移动端&客户端通讯啦!

桌面程序

桌面程序我就用 Flutter 写啦!

总结

好啦!可以快乐的分析APP啦!详细代码大伙自己看吧!