频道栏目
首页 > 资讯 > 工具软件 > 正文

Android安全测试工具Drozer之手机端agent源码解析

16-08-18        来源:[db:作者]  
收藏   我要投稿

Drozer是MWR Labs开发的一款具有pc端(主要python编写)和移动端(agent代理)的开源Android渗透测试框架。可以自定义python脚本,与通过代理agent与Android虚拟机进行交互。本文主要解析移动端agent代码,为各位同学后续写自己的安全工具起到抛砖引玉的个作用。
Drozer的通信框架如下图所示,它有两张通信方式,具体请看Android AppInjection&&Drozer Use

首先从个github https://github.com/mwrlabs 下载drozer-agent、jdiesel、mwr-tls、mwr-android。
1、drozer-agent:移动端界面工程
2、jdiesel:反射和通信协议的核心jar工程
3、mwr-tls:安全通信jar工程
4、mwr-android: 移动端界面jar工程

0×01 pc与android端通信桥梁message
打开jdiesel->common中protobuf.proto文件,原来是ProtocolBuffers协议,是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,很适合做数据存储或 RPC 数据交换格式。它可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 三种语言的 API。
优点:体积小,解析速度快。
缺点:二进制的方式存储,抓包后几乎不可读,调试起来可能不方便。
1 required 不可以增加或删除的字段,必须初始化
2 optional 可选字段,可删除,可以不初始化
3 repeated 可重复字段, 对应到java文件里,生成的是List
代码中常常用到Build,生成具体的java类时,例如protobuf.java,同时会存在build方法。意思是对于转化后的数据,具有唯一性,build提供了便利的方法来初始化这些数据。protobuf详情
先看看protobuf.proto文件,其中主要的架构是这样。

消息类型除了id和消息类型(MessageType),就是消息体,是可有可无的分为四种:
SystemRequest
SystemRequest:包含设备信息,会话信息,连接控制

SystemResponse
SystemResponse::主要包括响应的类型(绑定服务,设备列表,会话列表等)状态信息。

ReflectionRequest
ReflectionRequest:java反射请求,主要有resolve(所反射的classname),Construct(对象引用ObjectReference(int32类型),方法对象method,和方法参数Argument),Invoke调用方法(同样包括对象引用ObjectReference(int32类型),方法对象method,和方法参数Argument),以及对Property的get与set,还有Delete(对象引用ObjectReference(int32类型))

ReflectionResponse
ReflectionResponse:主要是反射响应后的状态和参数,还有一些错误信息。

0×02 pc与android端通信方式
在jdiesel代码中com.mwr.jdiesel.api.transport包下四个文件


SecureTransport是加了ssl加密传输的,从Transport文件中可以看出,receive和send都是有Frame封装的数据格式,如下
public abstract class Transport {
   public abstract void close();
   protected abstract InputStream getInputStream() throws IOException;
   protected abstract OutputStream getOutputStream() throws IOException;
   public abstract boolean isLive();
   public Frame receive() throws APIVersionException, IOException,TransportDisconnectedException {
       if(this.getInputStream() != null)
            return Frame.readFrom(this.getInputStream());
       else
            throw newTransportDisconnectedException();
   }
   public void send(Frame frame) throws IOException {
       this.getOutputStream().write(frame.toByteArray());

   }
}
外部调用时只需new一个SocketTransport(socket)即可,再看看socket在哪儿传送过来的
在ServerSocketFactory类中有创建serversocket的方法
public class ServerSocketFactory {
   public ServerSocket createSocket(Server server) throwsCertificateException, IOException, KeyManagementException, KeyStoreException,UnrecoverableKeyException {
       if(server.isSSL())
            return this.createSSLSocket(server);
       else
            return new ServerSocket(server.getPort());
   }
   .
   .
   .
在Link包中,server.java代码中重载run方法中有accept()接受socket请求。
public class Server extends Link {
   @Override
   public void run() {
       this.running = true;
       this.log(LogMessage.INFO, "Starting Server...");
       while(this.running) {
            try {
                if(this.connection == null) {
                    this.parameters.setStatus(com.mwr.jdiesel.api.connectors.Server.Status.CONNECTING);
                    this.log(LogMessage.INFO, "Attempting tobind to port " + ((com.mwr.jdiesel.api.connectors.Server)this.parameters).getPort() + "...");
                    this.server_socket = new ServerSocketFactory().createSocket((com.mwr.jdiesel.api.connectors.Server)this.parameters);
                    this.log(LogMessage.INFO, "Waiting forconnections...");
                    Socket socket = this.server_socket.accept();
其中关于连接link的类关系图如下图所示。

在jdiesel代码中server.java的run方法中有循环接受客户端的 Socket socket=this.server_socket accept();.
在agent代码中找到一个Service(此服务为android四大组件的服务),在消息循环中有startServer()方法被调用,就有server线程的开启。该server正是import com.mwr.jdiesel.api.links.Server的Server
public class ServerService extends ConnectorService {
   public void startServer() {
       if(this.server == null) {
            (new ServerSettings()).load(this.server_parameters);
            this.server_parameters.enabled = true;
            this.server = new Server(this.server_parameters, Agent.getInstance().getDeviceInfo());
            this.server.setLogger(this.server_parameters.getLogger());
            this.server_parameters.getLogger().addOnLogMessageListener(this);
            this.server.start();
   @Override
   public void handleMessage(Message msg) {
       switch(msg.what) {    
            caseMSG_START_SERVER:
            try {
                this.startServer();
                Message message = Message.obtain(null,MSG_GET_SERVER_STATUS);
                message.setData(this.getStatus());
                msg.replyTo.send(message);
上面所讲的是console连接手机server的通信方式,是比较常用的通信方式。
还有一种通信方式是PC端开启一个Server,手机端Client连接PC服务,以上两张通信方式都离不开adb forword tcp:[localport] tcp:[remoteport]
在jdiesel代码中Client.java的run方法中有连接PC服务端的代码

 

Socket socket= new EndpointSocketFactory().createSocket(endpoint);
0×03 手机端反射框架解析
在jdiesel代码中最关键的反射代码为Reflector.java

这其中有Construct、Field、Method、NativeArgument、invoke、Property等
在Construct 中
   public static Object construct(Class klass, ReflectedType[] arguments) throws IllegalAccessException, InstantiationException,InvocationTargetException, NoSuchMethodException {
       Constructor constructor = null;
       if(arguments.length == 0)
            constructor = klass.getConstructor();
       else
            constructor =getConstructor(klass, arguments);
       if(constructor != null)
            return constructor.newInstance(getNativeArguments(arguments));
       else
            throw newNoSuchMethodException();
   }
   private static Constructor getConstructor(Class object, ReflectedType[] arguments) {
       for(Constructor constructor : object.getConstructors()) {
           if(hasCompatibleSignatures(constructor.getParameterTypes(),getNativeArguments(arguments)))
                return constructor;
       }
       return null;
   }
对引用实例化constructor.newInstance(getNativeArguments(arguments));
   private static Field getField(Object object, String property) throws NoSuchFieldException {
       if(object instanceof Class)
            return ((Class)object).getField(property);
       else
            return object.getClass().getField(property);
   }
getField用于返回一个指定名称的属性,但是这个属性必须是公有的,这个属性可以在父类中定义。如果是私有属性或者是保护属性,那么都会抛出异常提示找不到这个属性。getFields则是返回类型中的所有公有属性,所有的私有属性和保护属性都找不到。
   private static Method lookupMethod(Class klass, String method_name, ReflectedType[] arguments) throws NoSuchMethodException {
       for(Method method: klass.getMethods()) {
            if(method_name.equals(method.getName())) {
                if(hasCompatibleSignatures(method.getParameterTypes(),getNativeArguments(arguments)))
                    return method;
            }
       }
       throw new NoSuchMethodException(method_name + " for " + klass.toString());
   }
   private static Method getMethod(Object object, String method_name, ReflectedType[] arguments) throws NoSuchMethodException {
       if(object instanceof Class) {
            Method m = lookupMethod((Class)object, method_name, arguments);
            if(!Modifier.isStatic(m.getModifiers()))
                return null;
            else
                return m;
       }
       else
            return lookupMethod(object.getClass(), method_name, arguments);
   }
获取方法getMethod在类方法中获取特定方法名的方法。
getDeclaredField获得在这个类型的声明中定义的指定名称的属性,这个属性必须是在这个类型的声明中定义,但可以使私有和保护的。
   private static boolean isWrapperTypeOf(Class klass, Class primitive) {
       try {

 

            return !klass.isPrimitive() && klass.getDeclaredField("TYPE").get(null).equals(primitive);
       }
       catch(IllegalAccessException e) {
            return false;
       }
       catch(NoSuchFieldException e) {
            return false;
       }
方法调用
public static Object invoke(Object object, String method_name, ReflectedType[] arguments) throws IllegalAccessException, IllegalArgumentException,InvocationTargetException, NoSuchMethodException {
       if(arguments.length == 0)
            return getMethod(object, method_name, arguments).invoke(object, (Object[])null);
       else
            return getMethod(object, method_name, arguments).invoke(object,getNativeArguments(arguments));
   }
通过类名获取类
   public static Class resolve(String className) {
       try {
            return Class.forName(className);
       }
       catch(ClassNotFoundException e) {
            return null;
       }
   }
在反射类型如下


这些类型在protobuf.java中message中定义。
0×04 结论
本文分析源码的主要目的是做android安全测试工具,可以看出在drozer工具中的重要的模块为jdiesel。
Protobuf基于TCP之上的通信协议。
反射框架。在Android安全测试工具中,反射无疑是最关键的,不可或缺的。
相关TAG标签
上一篇:疑似美国安全局黑客团队遭攻破 针对中俄攻击工具被盗
下一篇:江苏驾校伪造学时 信息系统被黑客利用
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站