一、简介
Drozer是MWR Labs开发的一款开源Android渗透测试框架。它能够通过自身实现的协议,与Android虚拟机进行交互。良好的框架,也使得我们能够根据自身的需求,进行定制化的拓展模块开发,打造更为强大的Drozer。
二、Drozer的基本架构
从本质上来看,Drozer是一个C/S架构的程序。安装在PC端的Drozer处理用户的各种操作,并将这些操作按照一定的格式进行封装,发送到手机端。手机端的Agent收到请求后,对请求进行解包,然后执行请求,并将结果返回到Drozer端。
三、Drozer与Agent的交互
Drozer使用了google的protobuf作为序列化数据交换的格式。在 https://github.com/mwrlabs/mercury-common/blob/master/protobuf.proto ,我们可以看到Drozer的消息格式,其中部分如下:
Message描述了,Drozer与Agent交互中的消息的完整格式,也是protobuf对消息进行序列化和反序列化的依据。
如图可见,消息的类型有SYSTEM_REQUEST、SYSTEM_RESPONSE、REFLECTION_REQUEST、REFLECTION_RESPONSE等四种。本文关注第三种,REFLECTION_REQUEST,即反射请求消息。
我们知道,Drozer是可以进行模块扩展的。而Drozer的模块扩展也分为两类,一类是python模块,运行于PC端;另一类是dex模块,在运行时会由Drozer端经protobuf协议传送到android端运行。这里面存在一个通过python调用android模块的机制。Drozer采用的方法是:由控制端(Drozer)发送指定格式的请求到Agent。Agent对请求进行解析,使用反射机制,对dex模块进行调用。这也是Android端的程序被命名为Agent的原因。通过python调用dex模块的请求的类型即为REFLECTION_REQUEST。
对于和一个特定设备的连接会话,Drozer使用一个具有唯一session_id的Session来标识。Drozer端和Agent端都会维护一个session的集合SessionCollection,其中包含了所有的已连接设备。Session的结构如下:
其中session_id唯一标识一个session,也使得我们可以向多个受控设备发送消息。device是设备相关信息,而console则是与session关联的控制台。
Drozer端的所有消息都经过一个叫做Drozer的类来处理,这个类通过其中的frameReceived函数来将所有的消息分发到指定的handler或forwarder。该类位于drozerp.py中。
如下图,Drozer的消息是封装在Frame中的,Frame中的payload便是没有经过序列化的Message。
不管是本地发送,还是远程接收的消息,都是以Frame形式封装,然后统一进入Drozer类进行分发处理。
发送REFLECTION_REQUEST的代码位于reflection_request_forwarder.py中的handle方法,该方法的主要功能是检查参数和异常处理,最终会调用session中的write方法将序列化的消息写入指定的session中。而消息的构造位于ReflectionRequestFactory类中,该类用于根据特定的调用类型,构造指定的消息。消息的类型有:
很明显,从名称就可以看出这些请求类型的意义。它们囊括了一个对象生命周期中的各种主要操作。通过这些操作,我们可以控制一个对象。实际上,这些方法在ReflectionRequestFactory中都有一个对应的方法,这便是工厂类的作用。
Drozer反射机制的核心在于其ReflectedType机制。Drozer将要反射调用的对象分为array,binary,object,primitive,string,null等类型,这些类均由继承自ReflectedType的类来单独表示。ReflectedType中实现了根据不同类型,将不同的反射请求分发到指定的反射类中。这些继承自ReflectedType的反射类,在其内部使用“映射”的方式,实现了将远程的各种对象映射到本地的方法,在这些类中实现了该对象所支持的操作,使得我们在使用反射操作远程对象时,就像操作本地对象一样。
而在Agent端,每一个session都有一个由SparseArray实现的对象池。它用来存储远程反射调用在本地生成的对象。
每一个session中都设置了ReflectionMessageHandler,当接收到REFLECTION_REQUEST时,该消息会被分发到ReflectionMessageHandler进行处理。而ReflectionMessageHandler实际上是一个对对象池进行操作的工具类:
根据接收到消息的具体类型,执行不同的操作,并返回结果。值得一提的是,这里的对象池到drozer端的映射对于ARRAY和OBJECT类型是一一对应的,对于Agent端的对象,都有一个唯一的object reference被“映射”到drozer端,以保证能够操作正确的对象。而对于PRIMITIVE(内置)类型等简单类型,则是直接通过反射进行操作。
四、总结
实际上,Drozer使用的是一种简单的代理对象的思想。使用protobuf作为通信协议,将对象映射到远程,由代理实际控制对象。在drozer端的控制接口的抽象,使我们能够像操作本地对象一样操作远程对象。
五、实例
下面我们来单步跟踪一个命令的执行过程,了解一下反射调用的机制。
run app.package.info –a (package name)命令为列出一个指定包的基本信息。
键入命令后,程序会对命令行进行解析。如下:
当命令被成功解析后,程序便会根据我们需要的功能将指令派发到特定的模块之中。然后调用模块的execute方法。
执行时,经过一系列的参数检查等过程,就来到了消息构造的过程。在此处,我们的程序调用到resolve方法。
实际上,该请求由工厂方法处理并生成。
该调用的反射类型为对象类型,
最终到达本命令的功能执行处,
消息发送前,会由Frame进行封装:
执行成功后,会再次发送反射请求,销毁对象。
值得注意的是,一个简单命令的执行,通常会有多次的反射调用,对象的生成、方法调用、获取(设置)属性、销毁对象等一系列的过程,都会生成反射调用,这个过程实际上与本地对象的生命周期相一致。
*本文作者:猎豹科学院(企业账号),转载须注明来自FreeBuf黑客与极客(FreeBuf.COM)