A. android怎么实现hook
几天前,在看雪安卓版块的论坛上,看到有人发表了一份dalvik hook的实现代码,这里小弟果断献丑下,给提供一份dalvik hook的另外一种实现。
首先解释下dalvik虚拟机中的Method结构体,Method结构体声明在源码目录树下的dalvik/vm/oo/Object.h文件内,在dalvik的世界中,每一个java方法都有一个对应的Method对象,
dalvik虚拟机在执行java方法时,就会通过该方法的Method对象调用到方法的具体实现代码,Method结构体内有个成员,名位insns,该字段保存着java方法具体的实现代码。那么我今天提供的这个dalvik hook的实现原理就是通过修改Method对象中的insns字段的值来达到hook java的目的。
这里简短的用文字的形式描述下Hook的实现过程。
现在有一个返回字符串的函数原型声明为:
public String truth()
{
return "hello from truth";
}
另外声明一个方法为:
public String fake()
{
return "fake string";
}
之后,该类被加载后,分别获得truth和fake方法的Method对象,并将fake方法的实现代码赋值给truth的Method对象,之后,应用程序调用truth方法时,获得的字符串为"fake string"。
B. 如何Android hook https http
两种方式
1 静态织入,aspectJ算是比较成熟的aop方案了,原理是分析class,在要hook的方法前后加入你自己的执行函数。
2 动态注入,native hook。原理是在native中修改需要hook的java方法的修饰符,变为native方法—在native操作—执行原函数。自己懒得搞得话,阿里有Dexposed框架可用
C. Android Binder Hook的实现
Binder Hook可以Hook掉 当前App 用到的系统Service服务。
以LocationManager为例,在获取一个LocationManager时分为两步。第一,获取IBinder对象;第二:IBinder对象通过asInterface()转化为LocationMangerService对象。最后初始化LocationManager,application层用到的都是LocationManager。
Hook的大致原理是:ServiceManager在获取某个Binder时,如果本地有缓存的Binder,就不再跨进程请求Binder了。我们可以在缓存中加入自己的Binder,使得ServiceManager查询本地缓存时得到一个自定义的CustomBinder对象,不再跨进程向系统请求。并且ILocationManager.Stub.asInterface(CustomBinder)方法返回我们自定义的Service对象。
这里面有两个地方需要用到自定义的对象。由于我们只Hook其中一部分的功能,其他功能还需要保留,所以用动态代理的方式创建自定义的Binder和自定义的Service。
在理解后面的内容前你需要了解这些知识点:
Activity等类在获取系统Service时,都是调用getSystemService(serviceName)方法获取的。
Context 的 getSystemService() 方法调用了 SystemServiceRegistry 的 getSystemService() 方法。
SystemServiceRegistry 中有一个常量 SYSTEM_SERVICE_FETCHERS,这是一个Map。保存了ServiceName和对应的ServiceFetcher。ServicFetcher是用于创建具体Service的类。ServiceFetcher 的关键方法是 createService() 方法。
在 ServiceFetcher 的 createService() 方法中,调用了 ServiceManager.getService(name) 方法。以 LocationManager 对应的 ServiceFetcher 为例,它的createService()方法源码如下:
假如我们要修改 LocationManager 的 getLastKnownLocation() 方法(下文都是)。我们要做的就是让ServiceManager.getService("location")返回我们自定义的Binder。先看一下这个方法简化后的源码:
sCache是一个Map,缓存了已经向系统请求过的Binder。如果我们需要让这个方法返回我们我们自己的binder,只需要事先往sCache中put一个自定义的Binder就行了。
在put之前,需要先创建出一个自定义的Binder。这个Binder在被 ILocationManager.Stub.asInterface 处理后,可以返回一个自定义的 LocationManagerService。
先看一下Binder的 asInterface() 的实现:
如果把 queryLocalInterface()方法返回一个自定义的Service,使得走if语句内部,不走else,那就算是Hook成功了。
假设我们想让系统的LocationManager返回的位置信息全是在天安门(116.23, 39.54)。那我们需要使得 LocatitionManagerService 的 getLastLocation() 方法 返回的全是 (116.23, 39.54)。
由于我们不能直接拿到系统的这个Service对象,可以先用反射的方式拿到系统的LocationManagerService。然后拦截getLastLocation()方法。
原生的Binder对象在调用 queryLocalInterface() 方法时会返回原生的Service对象。我们希望返回3.1中的自定义Service。所以这里拦截 queryLocalInterface() 方法。
有了自定义的Binder后,将它注入到ServiceManger的sCache变量中就完成Hook了~
当onClick被调用的时候,Toast和Log都会显示天安门的坐标(116.23, 39.54)。证明Hook成功!
你甚至可以用Binder Hook的方式Hook掉 ActivityManager 。
D. 如何hook android framework
1.向目标进程注入代码(注入so,并调用该so里的一个函数)。首先调用ptrace函数,调试com.android.browser进程,在这里我们需要遍历该进程加载的libc.so,这里有我们需要的dlopen,dlsym等函数的地址,我们先中断com.android.phone,修改其寄存器...
E. android 怎么hook主入口
常用hook工具:
Xposed框架;
CydiaSubstrate框架;
ADBI/DDI框架。
这些工具使用流程:配置环境、安装本地服务、下载使用库。
Xposed框架:
handleLoadPackage获取包加载时的回调并拿到其对应的classLoader
findAndLoadHookMethod对指定类的方法进行hook
Cydiasubstrate框架的hook方法:
MS.hookClassLoad 拿到指定class载入时的通知
MS.hookMethod 使用一个Java方法去替换另一个Java方法
MS.moveUnderClassLoader 使用不同的ClassLoader重载对象
F. android插件化(四)Hook加载插件APK(ClassLoader方式)
前面插件化一和二说了下插桩式加载未安装的APK,主要是重写了getResource和getClassloader两个方法来实现的。以及每个组件要实现一个接口,通过接口注入上下文来达到它的生命周期。
那么插桩式和hook式的实现方式有什么不同呢?
插桩式是怎么加载到插件中的class文件呢,是通过将将APK转化成插件的Classloader,然后想要加载插件的class文件,我们的去拿这个插件的classloader去loadClass。所以是有一个中间者的。
hook式呢是将插件apk融入到了我们的宿主apk,那直接在里面就可以直接loadClass了,在不用这个插件的ClassLoader了,这样的话对于插件和宿主就没什么区别了,不像插桩式有一个中间者。
那么要实现hook式 就要知道android中一个class文件式怎样被加载到内存中去的。其实就是通过PathClassLoader来加载的。
那么我们先看下ClassLoader
任何一个java程序都是由一个或者多个class组成的,在程序运行时,需要将class文件加载到JVM中才可以使用,负责加载这些class文件的就是java的类加载机制。CLassLoader的作用就是加载class文件提供给程序运行时使用,每个Class对象内部都有一个ClassLoader来标示自己是有那个classLoade加载的。
Android app的所有的java文件都是通过PathClassLoader来加载的,那么它的父类是BaseDexClassLoader,还有一个兄弟类是DexClassLoader,那么他们有什么区别呢。
从上面可以看出这两个类的构造函数不同。(在26的源码中DexClassLoader中的optimizedDirectory也废弃了)
PathClassLoader:用于Android应用程序类加载器。可以加载指定的dex,以及jar、zip、apk中的classes.dex
DexClassLoader:加载指定的dex以及jar、zip、apk中的classes.dex。
可以看到创建ClassLoader的时候需要接收一个CLassLoader parent的参数,这个parent的目的就在于实现类加载的委托。
某个类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,一次递归,如果父加载器可以完成加载任务,那么就返回,只有当父加载器无法完成加载任务时,才自己去加载。
因此我们自己创建的ClassLoader:newPathClassLoader("/sdcard/xx.dex",getClassLoader()),并不仅仅只能加载我们的xx.dex中的class。
需要注意的是,findBootstrapClassOrNull 这个方法,当parent为null的时候,去这个BootCLassLoader进行加载,
但是在Android当中的实现:
所以new PathClassLoader("/sdcard/xx.dex",null),是不能加载Activity.class的。
上面分析了加载了一个class,是利用了双亲委托机制,那么要是都找不到那就开始调用自己的findCLass方法
在ClassLoader类中findClass:
任何ClassLoader的子类,都可以重写loadClass和findClass。如果你不想使用双亲委托,就重写loadClas修改实现,重写findClass则表示在双亲委托机制下,父ClassLoader都找不到class的情况下,定义自己去查找一个class。
而我们的PathClassLoader会自己负责加载Activity这样的类,利用双亲委托父类去加载activity,而我们的PathClassLoader没有重写findClass,是在它的父类里面。因此我们可以看看父类的findClass是如何实现的。
可以看到加载PathClassLoader加载class,转化为从DexPathList中加载class了,那么我们看看DexPathList中的findClass
那么从上面分析得到
到这里我们想要加载一个插件的apk ,其实最终加载的是一个dex文件(先说class文件,加载资源后面说),有没有办法吧这个dex文件给转化成一个 Element 对象,给放到 Elemeng数组 当中,这样直接就可以加载我们插件中的类了。
1、首先我们肯定是要得到插件APK的的中DexPathList对象中的dexElement数组
2、插件的dexElements数组我们拿到了,那么是不是要开始拿我们系统里面的 ,我们反射获取,和上面的一样。
3、上面我们获取到了系统和我们插件的dexElement数组,然后我们将这个数组合并到一个新的数组里面去,并且给注入到系统里面
至此,加载插件的一个流程基本就完成了。但是上面只是处理了class文件,没有处理资源。资源的话我们也是采用hook的方式去实现
在宿主的Application中hook这个方法,然后去重写getAsserts和getResources两个方法:
然后在插件的BaseActivity中继续重写getAssets和getResources两个方法
这样就可以完成hook式加载一个未安装的APK了。至此基本就完成了插桩式和Hook式插件化的基本实现。(后面几篇是优化)。
G. 一直不明白 hook 与 注入 有什么区别,关系
注入跟hook确实有密不可分的联系,我们通常都是把这两者放到一起来谈,导致很多人认为它们是一回事。
应用安全里面有一个概念叫完整性,指的是程序或数据不能被攻击者恶意篡改。根据篡改时刻的不同,我们有两类方式来破坏应用的完整性:静态和动态。
在安卓上,静态的篡改方式是反编译apk,修改或添加代码后重打包,用户只要安装了这个修改过的apk,运行时攻击者的代码就会被加载到进程空间。
动态的篡改方法就是hook。如果我要篡改代码,那么我要实现的就是在程序将要执行某段逻辑的时候控制它去执行我的代码,这个行为就叫hook。
一个运行时的程序表现形式是进程,代码跟数据都放在自己的进程里面。那么问题来了,操作系统隔离了进程,我的代码在我的进程里,别人的代码在别人的进程里,别人的进程是不能跳到我的进程来执行我的代码的,这怎么办呢,所以要先想办法把代码注入到别人的进程里。之前提到的重打包也算是一种静态的注入方法,动态的注入方法在安卓上与Linux的共享库注入是类似的,这种方法网上用的最多的应该是看雪的古河发布的libinject。另外还有Xposed,它采取了一种特殊的注入方法,是动静结合的。
H. hook是什么意思
HOOK技术是Windows消息处理机制的一个平台,应用程序可以在上面设置子程序以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。
钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。
Hook原理
Hook技术无论对安全软件还是恶意软件都是十分关键的一项技术,其本质就是劫持函数调用。
但是由于处于Linux用户态,每个进程都有自己独立的进程空间,所以必须先注入到所要Hook的进程空间,修改其内存中的进程代码,替换其过程表的符号地址。在Android中一般是通过ptrace函数附加进程,然后向远程进程注入so库,从而达到监控以及远程进程关键函数挂钩。