一、概述
在上个帖子http://bbs.pediy.com/showthread.php?t=191649中介绍了so加解密实现的基本思路和有源码自加解密实现。仅仅实现有源码的方式,肯定不是我们想要的。下面介绍一种无源码的加解密实现和简单的Native method hook思路。
二、无源码加解密实现
在上个简单粗暴的so加解密帖子中,介绍了基于section和特定目标函数(或数据区)加解密实现思路。加密步骤中,我们并不需要被加密so文件的源码,而需要源码原因是:解密的时机放在了so文件被linker加载执行.init_array中的代码过程中,实现so加载时的自解密。把解密代码插到.init_array中,自然需要源码。其实,只要在函数被执行前进行解密,都是可以的。由于所有被加载的so处于同一进程中,故可以将解密函数放在另一个so执行,即实现无源码解密。
将解密函数放在另一个so中,只需保证解密函数在被加密函数执行前执行即可。和其他so一样,解密so的加载也放在类的初始化static{}中。我们可以在解密so加载过程中执行解密函数,就能保证被加密函数执行前解密。执行时机可以选在linker执行.init_array时,也可以选在OnLoad函数中。当然,解密so一定要放在被解密so后加载。否则,搜索进程空间找不到被解密的so。
加密方法可以随意选择上个帖子中的一种,解密只需将原来的解密函数单独放在一个so文件即可。相信读者已经明白,这里就不啰嗦,见附件源码shelldemo。
三、Nativemethod Hook 简单实现
1. 解包添加hook.so实现
很容易知道,native 方法并不像so中的其他函数被直接被调用。而是通过注册并被间接调用的。在so加载和卸载过程中,Onload 和 Unload函数会被调用,类似于驱动的加载和卸载。Onload函数主要功能是调用RegisterMethod注册native函数;而Unload则相反。那么如果增加一个so文件,在Onload中调用UnregisterMethod函数,将当前绑定的函数注销,再调用RegisterMethod注册我们自己的函数,即实现简单的hook功能。相信读者已经懂得如何做,这里就不给出源码了。
这里存在着一个问题,UnregisterMethod会将clazz所有的函数都注销掉(Un-register all native methodsassociated with the class)。当一个类存在多个native函数时,这种方法显然是不可取的。我们不可能实现原so中的所有函数,且也达不到hook的某一或某些函数的目的。
我们知道,同一个native方法是可以被多次注册的。既然可以被多次注册,那么struct Methodinsns 字段绑定的是最后一次注册的函数。Hook的思路很简单了:调用RegisterMethod,替换原来的某一或某些native方法。相信读者已经懂得如何做,这里就不给出源码了。
2. 进程注入实现
既然可以hook native方法,绕过一些简单注册什么的,还是可以的,读者可以自行试试。但美中不足的是,现很多apk作了自校验,直接添加hook.so到原包中,添加