hook语法

一、什么是 Hook 技术
  Hook 技术又叫做钩子函数,在系统没有调用该函数之前,钩子程序就先捕获该消息,钩子函数先得到控制权,这时钩子函数既可以加工处理(改变)该函数的执行行为,还可以强制结束消息的传递。简单来说,就是把系统的程序拉出来变成我们自己执行代码片段。
  要实现钩子函数,有两个步骤:
  1. 利用系统内部提供的接口,通过实现该接口,然后注入进系统(特定场景下使用)
  2.动态代理(使用所有场景)

二、Hook 技术实现的步骤
  Hook 技术实现的步骤也分为两步
  1.找到 hook 点(Java 层),该 hook 点必须满足以下的条件:需要 hook 的方法,所属的对象必须是静态的,因为我们是通过反射来获取对象的,我们获取的是系统的对象,所以不能够 new 一个新的对象,必须用系统创建的那个对象,所以只有静态的才能保证和系统的对象一致。
  2.将 hook 方法放到系统之外执行(放入我们自己的逻辑)

三、使用 hook 技术实现免注册式跳转
解释一下上面的步骤,我们有一个 MainActivity,四个按钮,前三个是打开不同的 Activity,最后一个是退出登录,这三个 Activity 其中界面2是不需要登录的,界面3和界面4都是需要登录才能看到的。
  那么既然要在打开 Activity 之前就判断是否登录了,而且要使用 hook 技术,那么我们下看一下 startActivity 的源码,因为我们知道我们需要 hook 的就是 startActivity 方法。

找 Hook 点
解释一下上面的源码,ActivityManager.getService()方法调用的是 IActivityManagerSingleton.get()方法,而这个IActivityManagerSingleton是 Singleton(android.util),所以 IActivityManagerSingleton.get()就是调用了 Singleton 里面的 get 方法,进到 Singleton 类,发现 get() 方法里面会通过 create() 抽象方法方法给 mInstance 属性赋值,回到刚才的地方,我们发现,create() 方法返回了一个 IAcivityManager 对象。最终结果:其实最终是 IActivityManager 调用了 startActivity() 方法。
  所以我们真正想 hook 的点是 IActivityManager 对象,那么如何拿到这个静态对象呢?其实聪明的帅哥和美女肯定都发现了,这个 IActivityManagerSingleton 其实就是一个静态的,而且我们拿到该系统对象后就获取到该对象的 mInstance 属性,即 IActivityManager,那么我们就把 IActivityManagerSingleton 当做一个伪 hook 点。
  hook 点已经找到了,第一步已经完成,接下来就该第二步了,那么如何将系统执行的 startActivity() 拉到系统外执行,给其添加一些自己的逻辑呢?这里我们使用动态代理来实现。
  这里大概说一下项目,肯定有五个 Activity,一个 MainActivity 是用来展示四个按钮的,一个 LoginActivity,还有其他三个是测试的展示页面,其实还有一个 ProxyActivity,并且,在清单文件中,我们除了 MainActivity 是启动页,ProxyActivity 进行了注册,其他的 Activity 都没有在清单文件中注册,没错,你没有看错,就是没有注册,那运行会崩溃吗?空口无凭,我们先看一下代码,然后看运行结果。

四 移动存储代码示例
func init() {
// Register Service
server.RegisterService(
// Service
NewService(), 第一执行
// StartHook
frameworkServer.WithServiceStartHook(func(provider frameworkServer.ServiceProvider) error {
// CheckErrors
err := common.CheckErrors(
第四执行
initProvider(provider),
initOrmAndRegisterTables(),
initStorage(),
)
if err != nil {
return err
}
// run after init
run() 第五执行
return nil
}),
)
initFlags()
第二执行
registerModels() *** 第三执行
}

五 defer 表示对紧跟其后的 xxx() 函数延迟到 defer 语句所在的当前函数返回时()再进行调用。
移动存储示例代码
func main() {
defer da.Init()() *** 双括号表示 会第一执行da.Init()。然后把da.Init()看作一个函数T,T()最后第五执行

    crossApi.RegisterAllService()    *** 第二执行

    if err := da.RunServer(); err != nil {         *** 第四执行
        panic("run service error:" + err.Error())
    }
}

package main
import "fmt"
var g = 100

package main

import "fmt"

var g = 100

func f() (r int) {
    r = g
    defer func() {
        r = 200
    }()

    fmt.Printf("f: r = %d\n", r)

    r = 0
    return r
}

func main() {
    i := f()
    fmt.Printf("main: i = %d, g = %d\n", i, g)
}

f: r =100
main: i =200, g =100

准确的说,defer 函数的执行既不是在 return 之后也不是在 return 之前,而是一条go语言的 return 语句包含了对 defer 函数的调用,即 return 会被翻译成如下几条伪指令。go 语言的 return 会被编译器翻译成多条指令,其中包括保存返回值,调用defer注册的函数以及实现函数返回。