Android渗透工具之Drozer源码分析

来源:互联网 发布:怎么开启mysql服务 编辑:程序博客网 时间:2024/04/30 02:28


       最近时间比较充足,想找点事情来做做。再说Drozer这工具整天在手头用得着,只知其玄乎,又听大B哥说其架构是如何的NB。所以,就趁着这份热尽,体会了Drozer的神乎。确实挺神乎的,本人小菜一枚,求各位大神轻虐,在此放过了;如有想体会Drozer的神乎的朋友,在这抛砖引玉,不求感激,只求不坑了各位,哈哈、、、、

1.    Drozer简介

       Drozer是一个由MWR安全团队维护开源的软件,该软件可以说是针对Android平台的安全测试框架。安全人员可以通过Drozer自身提供的一些module完成一些基础的安全测试功能,同时也可以根据需求实现自己的module,甚至可以在利用Drozer提供的框架实现一些自动化审计功能。于目标设备上安装Agent,可以通过Agent接收PC端传来的指令或者代码并与Dalvik VM,其他app以及操作系统进行交互以达到某些安全审计功能。关于Drozer的源码可以从Githubhttps://github.com/mwrlabs)上获取:

drozer: 包含了控制台与服务端代码;

drozer-agent: 包含了运行于Android设备的Agent代码;

jdiesel:反射和通信协议的核心jar工程;

mwr-tls:安全通信jar工程;

mwr-android: 移动端界面jar工程;

2.    Drozer通信协议

       DrozerAgent之间的通信采用google protocol buffer协议,这种协议是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,很适合做数据存储或 RPC 数据交换格式。它可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++JavaPython 三种语言的 API。完整协议可以参见githubhttps://github.com/mwrlabs/mercury-common/blob/master/protobuf.proto)上的源码,该协议是两者协作的核心。

下面是对这个协议的简单介绍:

该协议中包含4种消息类型,其中包括SYSTEM_REQUESTSYSTEM_RESPONSEREFLECTION_REQUESTREFLECTION_RESPONSE

message Message {
         enum MessageType {
                   SYSTEM_REQUEST= 1;
                   SYSTEM_RESPONSE= 2;
                   REFLECTION_REQUEST= 3;
                   REFLECTION_RESPONSE= 4;
         }
   }

SystemRequest:包含设备信息,会话信息,连接控制

message SystemRequest {
                   enum RequestType {
                            PING= 1;
                            BIND_DEVICE= 2;
                            UNBIND_DEVICE= 3;
                            LIST_DEVICES= 4;
                            START_SESSION= 5;
                            STOP_SESSION= 6;
                            RESTART_SESSION= 7;
                            LIST_SESSIONS= 8;
                       }
                   required RequestType type = 1 [default = PING];
                   optional Device device = 5;
                   optional string session_id = 7;
                   optional string password = 8;
     }

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

message SystemResponse {
                   enum ResponseType {
                            PONG= 1;
                            BOUND= 2;
                            UNBOUND= 3;
                            DEVICE_LIST= 4;
                            SESSION_ID= 5;
                            SESSION_LIST= 6;
                   }

                   enum ResponseStatus {
                            SUCCESS= 1;
                            ERROR= 2;
                   }
                   required ResponseType type = 1;
                   required ResponseStatus status = 2;
                   repeated Device devices = 6;
                   optional string session_id = 7;
                   optional string error_message = 8;
                   repeated Session sessions = 9;
         }

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

message ReflectionRequest {
                   enum RequestType {
                            RESOLVE= 1;
                            CONSTRUCT= 2;
                            INVOKE= 3;
                            SET_PROPERTY= 4;
                            GET_PROPERTY= 5;
                            DELETE= 6;
                            DELETE_ALL= 7;
                   }

                   required string session_id = 1;
                   required RequestType type = 2;

                   message Resolve {
                            optional string classname = 1;
                   }

                   message Construct {
                            optional ObjectReference object = 1;
                            repeated Argument argument = 2;
                   }

                   message Invoke {
                            optional ObjectReference object = 1;
                            optional string method = 2;
                            repeated Argument argument = 3;
                   }

                   message SetProperty {
                            optional ObjectReference object = 1;
                            optional string property = 2;
                            optional Argument value = 3;
                   }

                   message GetProperty {
                            optional ObjectReference object = 1;
                            optional string property = 2;
                   }

                   message Delete {
                            optional ObjectReference object = 1;
                   }

                   optional Resolve resolve = 3;
                   optional Construct construct = 4;
                   optional Invoke invoke = 5;
                   optional SetProperty set_property = 6;
                   optional GetProperty get_property = 7;
                   optional Delete delete = 8;
         }

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

message ReflectionResponse {
                   enum ResponseStatus {
                            SUCCESS= 1;
                            ERROR= 2;
                            FATAL= 3;
                   }

                   required string session_id = 1;
                   required ResponseStatus status = 2;
                   optional Argument result = 3;
                   optional string errormessage = 8;
         }

3.    Drozer源码解析

        由于Drozer存在很多命令,在源码中会存在很多分支路径,本文不打算全部分析,主要侧重点在于我们常用的命令(连接Agent,运行模块)代码的分析,一般处理指令如下:

drozer console connect

run module_name argv

下面的内容就这两类命令的执行流程进行源码分析。

3.1 Drozer consoleconnect命令执行过程

     首先以drozer console connect为切入点。这条命令是Drozer端与Agent建立console会话。

Drozer端:

找到运行这条命令的入口点,入口点在drozer\cli\console.py

from mwr.common import logger
from drozer.console import Console
logger.setLevel(logging.DEBUG)
logger.addStreamHandler()

#实例化Console,并执行run(),这里取第3个及之后的参数,这里取的是connect

Console().run(sys.argv[2::])

在这个模块中,运行Console().run(sys.argv[2::])Console这个类在drozer\console\console.py,这个类继承cli.Basemwr\common\cli.py)。这个run()就在cli.Base这个类中实现,定位到cli.Base.run()

def run(self, argv=None):
        if argv == None:
            argv = []
        
        self.prepare_argument_parser(argv)
        # parse argv into arguments using the generated ArgumentParser
        #解析命令行参数

        arguments = self.parse_arguments(self._parser, argv)
       #根据命令行参数调用对应的方法
        try:

            self.__invokeCommand(arguments)
        except UsageError as e:
            self.__showUsage(e.message)
        except Exception as e:
            self.handle_error(e)

继续跟踪__invokeCommand():

def __invokeCommand(self, arguments):
   
        try:
            command = arguments.command

            if "do_" + command in dir(self):
                #调用do_xxx方法

                getattr(self, "do_" + command)(arguments)
            else:
                raise UsageError("unknown command: " + command)
        except IndexError:
            raise UsageError("incorrect usage")

run()最后调用__invokeCommand(),通过getattr()调用do_xxx(),由于传入的参数connect,这里执行Console类里的do_connect()

def do_connect(self, arguments):
        if arguments.password:
            with warnings.catch_warnings():
                warnings.simplefilter("ignore")

                password = getpass.getpass()
        else:
            password = None
        #获取与Drozer绑定的设备

        device = self.__get_device(arguments)
        #获取与Agent连接的socket
        server = self.__getServerConnector(arguments)
        #获取与Agent开始会话的响应
        response = server.startSession(device, password)
        
        if response.type == Message.SYSTEM_RESPONSE and\
            response.system_response.status == Message.SystemResponse.SUCCESS:
            session_id = response.system_response.session_id

            try:
                if(arguments.debug):
                    session = DebugSession(server, session_id, arguments)
                else:
                     #与Agent建立会话

                    session = Session(server, session_id, arguments)

                if len(arguments.file) > 0:
                    session.do_load(" ".join(arguments.file))
                    session.do_exit("")
                elif arguments.onecmd != None:
                    session.onecmd(arguments.onecmd)
                    session.do_exit("")
                else:
                    #进入控制台,等待命令输入并执行

                    session.cmdloop()
            except KeyboardInterrupt:
                print
                print "Caught SIGINT, terminating your session."
            finally:
                session.do_exit("")
                
            self.__getServerConnector(arguments).close()
        else:
            self.handle_error(RuntimeError(response.system_response.error_message), fatal=True)

这里主要是实现DrozerAgent建立Session,进入控制台,等待命令的输入并执行。

下面根据drozer console connect这条命令的流程重点分析SystemRequest、ReflectionRequest两类消息的执行过程:

SystemRequest消息执行过程

device = self.__get_device(arguments),这个方法获取与Drozer建立连接的设备。这里以这个分支详细分析SystemRequest消息的执行过程。定位到__get_device():

def __get_device(self, arguments):

        if arguments.device == None:
            #获取与Drozer建立连接的设备

            devices = self.__getServerConnector(arguments).listDevices().system_response.devices

            if len(devices) == 1:
                device = devices[0].id

                print "Selecting %s (%s %s %s)\n" % (devices[0].id, devices[0].manufacturer, devices[0].model, devices[0].software)

             ......
             ......
            return arguments.device

__getServerConnector()是为了得到与Agent建立连接的socket。实现代码如下:

def __getServerConnector(self, arguments):

        if self.__server == None:
            #实例化ServerConnector类

            self.__server = ServerConnector(arguments, self.__manage_trust)

        return self.__server

ServerConnector这个类在drozer\connector\server_connector.py,核心代码是调用父类SocketTransport__init__,从而获取与Agent31415端口建立的socket

class ServerConnector(SocketTransport):
    #连接的主机与端口

    DefaultHost = "127.0.0.1"
    DefaultPort = 31415

    
    def __init__(self, arguments, trust_callback=None):
        try:
             #调用SocketTransport.__init__,获取与Agent的31415端口建立的socket

            SocketTransport.__init__(self, arguments, trust_callback)
        ......
        ......

展开SocketTransport.__init__():

class SocketTransport(Transport):
    
    def __init__(self, arguments, trust_callback=None):
        Transport.__init__(self)
        #socket实例化

        self.__socket = socket.socket()
        
      ......
      ......

得到与agent建立连接的socket,接下来执行__getServerConnector(arguments).listDevices()定位到listDevices()

def listDevices(self):

        try:
            #向Agent发送LIST_DEVICES消息并接收响应

            return self.sendAndReceive(SystemRequestFactory.listDevices())
        except RuntimeError as e:
            if e.message == 'Received an empty response from the Agent. This normally means the remote service has crashed.':
                raise ConnectionError(e)
            else:
                raise

这个方法调用sendAndReceive(SystemRequestFactory.listDevices()),而sendAndReceive主要是发送一个messageagent,并获取返回结果,定位到sendAndReceive

def sendAndReceive(self, message):
         #为message加上一个id,然后将这个message封装为protocol buffer类型的Frame,最终发送给Agent

        message_id = self.send(message)

        while(True):
           #获取返回结果

            response = self.receive()

            if response == None:
                raise ConnectionError(RuntimeError('Received an empty response from the Agent.'))
            elif response.id == message_id:
                return response

展开send(message):

def send(self, message):
      
        try:
             #添加message id

            message_id = self.nextId()
            #封装为protocol buffer类对象
            frame = Frame.fromMessage(message.setId(message_id).build())
            #将消息发送给Agent
            self.__socket.sendall(str(frame))
    
            return message_id
      .....
      ......

我们再来看下此处message的细节。执行SystemRequestFactory.listDevices(),这个方法是为了获取与Drozer建立连接的Agent这样一个SystemRequest消息对象。定位到listDevices()

def listDevices(cls):
         #实例化SystemRequest类型的对象

        builder = SystemRequestFactory(Message.SystemRequest.LIST_DEVICES)

        return builder

到这里,SystemRequest消息在Drozer中执行完毕。接下来看Agent是如何接收这个SystemRequest.LIST-DEVICES这个请求,并如何处理的。

Agent端:

       Agent首先会通过一个Receiver启动ServerService,这个ServerService就是与Drozer建立连接的服务。定位到Receiver

public void onReceive(Context context, Intent intent) {
                   Intent start_service = new Intent();
                   start_service.putExtras(intent);         
                   if(intent.getCategories().contains("com.mwr.dz.START_EMBEDDED")){
                            start_service.addCategory("com.mwr.dz.START_EMBEDDED");

                            #Intent绑定ServerService

                            start_service.setComponent(new ComponentName("com.mwr.dz",
"com.mwr.dz.services.ServerService"));

                   }
                   else {
                            if(intent.getCategories().contains("com.mwr.dz.CREATE_ENDPOINT"))
                                     start_service.addCategory("com.mwr.dz.CREATE_ENDPOINT");
                            if(intent.getCategories().contains("com.mwr.dz.START_ENDPOINT"))
                                     start_service.addCategory("com.mwr.dz.START_ENDPOINT");                          
                            start_service.setComponent(new
ComponentName("com.mwr.dz", "com.mwr.dz.services.ClientService"));
                   }

                   #启动ServerService

                   context.startService(start_service);
         }

ServerService这个服务相对Drozer可以称为server端,主要负责监听Drozer的请求连接,并处理相关请求。

ServerService间接继承Service组件,onStartCommand()主要负责执行StartServer()这个方法。

public int onStartCommand(Intent intent, int flags, int startId){
                   int ret_val = super.onStartCommand(intent, flags, startId);
                   if(intent != null &&intent.getCategories() != null &&
intent.getCategories().contains("com.mwr.dz.START_EMBEDDED")) {
                            Agent.getInstance().setContext(this.getApplicationContext());


                            this.startServer();
                   }                 
                   return ret_val;
         }

定位到startServer()

public void startServer() {
                   if(this.server == null) {
                            (new ServerSettings()).load(this.server_parameters);                         
                            this.server_parameters.enabled= true;

                           #实例化Server对象,其中Server类间接继承Thread

                            this.server = new Server(this.server_parameters, Agent.getInstance().getDeviceInfo());

                            this.server.setLogger(this.server_parameters.getLogger());
                            this.server_parameters.getLogger().addOnLogMessageListener(this);

                            #启动Server这个实例化线程,执行run()

                            this.server.start();       
                    
                           Toast.makeText(this,String.format(Locale.ENGLISH, this.getString(R.string.embedded_server_started),this.server_parameters.getPort()), Toast.LENGTH_SHORT).show();
                   }
         }

代码中的this.serverServer类的对象,这个Server类继承Link类,而Link类间接继承Thread,所以说,Server类是一个线程类。当执行this.server.start()时,这个线程就启动了。定位到Server类的run()

public void run() {
                   this.running = true;                 
                   this.log(LogMessage.INFO,"Starting Server...");
                   while(this.running) {
                            try {
                                     if(this.connection== null) {               
                                               this.log(LogMessage.INFO,"Attempting to bind to port " +
((com.mwr.jdiesel.api.connectors.Server)this.parameters).getPort() +"...");

                                                #实例化ServerSocket对象

                                               this.server_socket= new
ServerSocketFactory().createSocket((com.mwr.jdiesel.api.connectors.Server)this.parameters);

                                              this.log(LogMessage.INFO,"Waiting for connections...");
                                               #接收Drozer的socket发送过来的请求

                                               Socket socket =this.server_socket.accept();
                                             
                                               if(socket!= null) {                                                                                                             
                                                        this.log(LogMessage.INFO,"Accepted connection...");                                             
                                                        this.log(LogMessage.INFO,"Starting drozer thread...");

                                                        #处理Drozer发过来的请求

                                                        this.createConnection(new SocketTransport(socket));
                                               }
                                     }

server_socket.accept()负责接收Drozer的请求。而createConnection(new SocketTransport(socket))负责处理这个请求。定位到createConnection()

protected void createConnection(Transport transport) {
                   if(transport.isLive()) {
                            #实例化Connection对象

                            this.connection = new Connection(this,this.device_info, transport);   
     
                            this.connection.start();
                   }
         }

创建一个Connection实例,而后启动它。这个Connection也是间接继承Thread,也是一个线程类。定位到这个类的run(),而这个run()是继承来自它的父类AbstractConnection,真正负责接收Drozer的请求与处理相对应的请求就在这里实现的。具体代码如下:

public void run() {
                   this.running = true;
                   this.started = true;
                   this.tryAndNotifyAll();                
                   this.last_message_at =System.currentTimeMillis();                
                   Message request = null;                 
                   if(!this.bindToServer(this.device_info))
                            this.stopConnection();                   
                   while(this.running) {

                             #获取Drozer发送过来的request

                            request = this.receive();  
                        
                            if(request != null){

                                     #处理request

                                     this.handleMessage(request);                          
                                     request =null;
                            }                        
                            this.checkForLiveness();                          
                            Thread.yield();
                   }

展开this.receive()这个函数,将请求转化为Frame对象,这里需要将request转化为Frame对象,是不是符合Drozermessage封装成Frame的过程?定位到receive()

protected Message receive() {
                   try {
                            #将request转化为Frame类型

                            Frame f = this.transport.receive();    
                     
                            return f != null ?f.getPayload() : null;
}   
          

再展开this.handleMessage(),代码如下:

private void handleMessage(Message message) {
                   try {
                            Message response = null;
                            switch(message.getType()){

                            case REFLECTION_REQUEST:
                                     response = this.handleReflectionRequest(message);
                                     break;

                            case REFLECTION_RESPONSE:
                                     response = this.handleReflectionResponse(message);
                                     break;

                            #匹配message类型,并做相应的处理

                            case SYSTEM_REQUEST:
                                     response = this.handleSystemRequest(message);

                                     break;

                            case SYSTEM_RESPONSE:
                                     response = this.handleSystemResponse(message);
                                     break;

                            default:
                                     throw new UnexpectedMessageException(message.getType());
                            }

                            #将处理后的结果返回给Drozer
                            if(response != null)

                                     this.send(response);
                   }

从这里可以看出,这里根据不同的消息类型进行处理。因为LIST_DEVICES属于SystemRequest,所以这个交给handleSystemRequest()处理。而handleSystemRequest()调用system_message_handler.handle()进行处理。而后将response返回给Drozer

展开system_message_handler.handle()system_message_handler属于SystemMessageHandler的实例。Handle()代码如下:

public Message handle(Message message) throws InvalidMessageException {
                   if(message.getType() != Message.MessageType.SYSTEM_REQUEST)
                            throw new InvalidMessageException(message);
                   if(!message.hasSystemRequest())
                            throw new InvalidMessageException(message);
                   switch(message.getSystemRequest().getType()){

                   #匹配具体的SystemRequest消息类型,并进行处理

                   case LIST_DEVICES:
                            return this.handleListDevices(message);

                   case LIST_SESSIONS:
                            return this.handleListSessions(message);                           
                   case PING:
                            return this.handlePing(message);                            
                   case START_SESSION:
                            return this.startSession(message);                           
                   case STOP_SESSION:
                            return this.stopSession(message);                          
                   default:
                            throw new InvalidMessageException(message);
                   }

到这里就看到LIST_DEVICES消息类型了。定位到handleListDevices()

protected Message handleListDevices(Message message) throws InvalidMessageException {
                   MessageFactory factory = new MessageFactory(SystemResponseFactory.deviceList(message).addDevice(
                                     this.device_info.getAndroidID(),
                                     this.device_info.getManufacturer(),
                                     this.device_info.getModel(),
                                     this.device_info.getSoftware()));                   
                   factory.inReplyTo(message);     
           
                   return factory.build();

         }

至此,整个获取与Drozer建立连接的设备就结束了。

接着往下走,下面重点分析

ReflectionRequest消息执行过程

现在我们重点分析建立会话过程,定位到Console.do_connect():

def do_connect(self, arguments):
        if arguments.password:
            with warnings.catch_warnings():
                warnings.simplefilter("ignore")

                password = getpass.getpass()
        else:
            password = None
        #获取与Drozer绑定的设备

        device = self.__get_device(arguments)
        #获取与Agent连接的socket
        server = self.__getServerConnector(arguments)        
        #获取与Agent开始会话的响应
        response = server.startSession(device, password)
        
        if response.type == Message.SYSTEM_RESPONSE and\
            response.system_response.status == Message.SystemResponse.SUCCESS:
            session_id = response.system_response.session_id

            try:
                if(arguments.debug):
                    session = DebugSession(server, session_id, arguments)
                else:                    
                     #与Agent建立会话

                    session = Session(server, session_id, arguments)

                if len(arguments.file) > 0:
                    session.do_load(" ".join(arguments.file))
                    session.do_exit("")
                elif arguments.onecmd != None:
                    session.onecmd(arguments.onecmd)
                    session.do_exit("")
                else:                   
                     #进入控制台,等待命令输入并执行

                    session.cmdloop()
            except KeyboardInterrupt:
                print
                print "Caught SIGINT, terminating your session."
            finally:
                session.do_exit("")
                
            self.__getServerConnector(arguments).close()
        else:
            self.handle_error(RuntimeError(response.system_response.error_message), fatal=True)

我们从这行入手session = Session(server, session_id, arguments),初始化session对象,建立与Agent联系的session

定位到Session类的__init__方法:

class Session(cmd.Cmd):

    def __init__(self, server, session_id, arguments):
        cmd.Cmd.__init__(self)
        self.__base = ""
        self.__has_context = None
        self.__module_pushed_completers = 0
        self.__permissions = None
        self.__server = server
        self.__session_id = session_id
        self.__onecmd = arguments.onecmd
        self.active = True
        self.aliases = { "l": "list", "ls": "list", "ll": "list" }
        self.intro = "drozer Console (v%s)" % meta.version
        self.history_file = os.path.sep.join([os.path.expanduser("~"), ".drozer_history"])
        #模块集

        self.modules = collection.ModuleCollection(loader.ModuleLoader())
        self.prompt = "dz> "
        #反射对象

        self.reflector = Reflector(self)
        if hasattr(arguments, 'no_color') and not arguments.no_color:
            self.stdout = ColouredStream(self.stdout)
            self.stderr = ColouredStream(self.stderr)
        else:
            self.stdout = DecolouredStream(self.stdout)
            self.stderr = DecolouredStream(self.stderr)

        #实例化Module对象m

        m = Module(self)

        if m.has_context():
            #如果Context不存在,获取com.mwr.dz.Agent的数据路径,得到的路径是/data/data/com.mwr.dz.Agent

            dataDir = str(m.getContext().getApplicationInfo().dataDir)
        else:
            dataDir = str(m.new("java.io.File", ".").getCanonicalPath().native())

        self.variables = {  'PATH': dataDir +'/bin:/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin',
                            'WD': dataDir }
        
        self.__load_variables()
        
        if arguments.onecmd == None:
            self.__print_banner()

如果Context不存在,获取com.mwr.dz.Agent的数据路径,当然这里就要用到消息反射了。定位到ModulesgetContext()

def getContext(self):
         #利用反射得到com.mwr.dz.Agent的实例

        return self.klass('com.mwr.dz.Agent').getContext()

继续跟踪klass()

def klass(self, class_name):

        if not Module.cached_klass(class_name):
             #存储反射引用到cache中

            Module.cache_klass(class_name, self.reflector.resolve(class_name))
        
        return Module.get_cached_klass(class_name)

继续执行会跳转到Reflector.resolve方法:

def resolve(self, class_name):
          #将反射请求发送到Agent

        response = self.sendAndReceive(ReflectionRequestFactory.resolve(class_name))

        if response is None:
            raise ReflectionException("expected a response to RESOLVE")
        elif response.reflection_response.status == Message.ReflectionResponse.SUCCESS:
            return ReflectedType.fromArgument(response.reflection_response.result, reflector=self)
        else:
            raise ReflectionException(response.reflection_response.errormessage)

到这里,我们又看到SendAndReceive(),接下来的执行过程可参考Drozer端的SystemRequest消息的执行过程。

Agent端:

Agent接收与处理ReflecionRequest类消息可参考上节讲的SystemReqeust。这里重点讲下ReflectionRequest的处理过程。最终执行过程如下:

public Message handle(Message message) throws InvalidMessageException {
                   if(message.getType() != Message.MessageType.REFLECTION_REQUEST)
                            throw new InvalidMessageException(message);
                   if(!message.hasReflectionRequest())
                            throw new InvalidMessageException(message);
                   try {
                            switch(message.getReflectionRequest().getType()){
                            case CONSTRUCT:
                                     if(!message.getReflectionRequest().hasConstruct())
                                              throw new InvalidMessageException(message);                                   
                                     return this.handleConstruct(message);                                   
                            case DELETE:
                                     if(!message.getReflectionRequest().hasDelete())
                                               throw new InvalidMessageException(message);                                    
                                     return this.handleDelete(message);                                    
                            case DELETE_ALL:
                                     return this.handleDeleteAll(message);                                   
                            case GET_PROPERTY:
                                     if(!message.getReflectionRequest().hasGetProperty())
                                               throw new InvalidMessageException(message);                                    
                                     return this.handleGetProperty(message);                                   
                            case INVOKE:
                                     if(!message.getReflectionRequest().hasInvoke())
                                               throw new InvalidMessageException(message);                                 
                                     return this.handleInvoke(message);

                            #执行resolve类的ReflectionRequest消息

                            case RESOLVE:
                                     if(!message.getReflectionRequest().hasResolve())
                                               throw new InvalidMessageException(message)  
                                  
                                     return this.handleResolve(message);

                            case SET_PROPERTY:
                                     if(!message.getReflectionRequest().hasSetProperty())
                                               throw new InvalidMessageException(message);
                                     return this.handleSetProperty(message);
                            default:
                                  throw new InvalidMessageException(message);
                            }
                   }

定位到handResolve():

protected Message handleResolve(Message message) throws InvalidMessageException {
                  #利用反射得到类的class

                  Class<?>klass =
Reflector.resolve(message.getReflectionRequest().getResolve().getClassname());

                   if(klass != null) {
                            int ref = this.session.object_store.put(klass);
                            return this.createResponse(message,   ReflectionResponseFactory.object(ref));
                  }
                   else {
                            return this.handleError(message, "cannot resolve " +
message.getReflectionRequest().getResolve().getClassname());
                   }
         }

定位到Reflector.resolve

public static Class<?> resolve(String className) {
                   try {
                            #反射得到类名的class

                            return Class.forName(className);
                   }
                   catch(ClassNotFoundException e) {
                            return null;
                   }
         }

至此,ReflectonRequest整个请求与处理过程完成了。

3.2 runmodule_name argvs命令执行过程

为了方便,这里以run app.package. AttackSurface packageName为例说明。

现在我们重点分析在console中执行命令的过程,定位到Console.do_connect():


def do_connect(self, arguments):
        if arguments.password:
            with warnings.catch_warnings():
                warnings.simplefilter("ignore")

                password = getpass.getpass()
        else:
            password = None
        #获取与Drozer绑定的设备

        device = self.__get_device(arguments)
        #获取与Agent连接的socket
        server = self.__getServerConnector(arguments)        
        #获取与Agent开始会话的响应
        response = server.startSession(device, password)
        
        if response.type == Message.SYSTEM_RESPONSE and\
            response.system_response.status == Message.SystemResponse.SUCCESS:
            session_id = response.system_response.session_id

            try:
                if(arguments.debug):
                    session = DebugSession(server, session_id, arguments)
                else:                    
                     #与Agent建立会话

                    session = Session(server, session_id, arguments)

                if len(arguments.file) > 0:
                    session.do_load(" ".join(arguments.file))
                    session.do_exit("")
                elif arguments.onecmd != None:
                    session.onecmd(arguments.onecmd)
                    session.do_exit("")
                else:                   
                     #进入控制台,等待命令输入并执行

                    session.cmdloop()
            except KeyboardInterrupt:
                print
                print "Caught SIGINT, terminating your session."
            finally:
                session.do_exit("")
                
            self.__getServerConnector(arguments).close()
        else:
            self.handle_error(RuntimeError(response.system_response.error_message), fatal=True)

此处从session.cmdloop()入手,定位到cmdloop()方法:

def cmdloop(self, intro=None):
        self.preloop()
        if self.use_rawinput and self.completekey:
            self.push_completer(self.complete, self.history_file)
        try:
            stop = None
            while not stop:
                if self.cmdqueue:
                    line = self.cmdqueue.pop(0)
                else:
                    if self.use_rawinput:
                        try:
                           #得到用户输入的命令

                            line = raw_input(self.prompt)
                        except EOFError:
                            line = 'EOF'
                    else:
                        self.stdout.write(self.prompt)
                        self.stdout.flush()
                        line = self.stdin.readline()
                        if not len(line):
                            line = 'EOF'
                        else:
                            line = line.rstrip('\r\n')
                            
                try:
                    line = self.precmd(line)
                     #解析输入的命令

                    stop = self.onecmd(line)
                    stop = self.postcmd(stop, line)
               .....
               .....

这里首先获取用户的输入命令,然后执行onecmd()对获取到的命令进行解析。定位到onecmd()

def onecmd(self, line):
        cmd, arg, line = self.parseline(line)
        if not line:
            return self.emptyline()
        if cmd is None:
            return self.default(line)
        self.lastcmd = line
        if line == 'EOF' :
            self.lastcmd = ''
        if cmd == '':
            return self.default(line)
        else:
            try:
                #获取console当中的命令,调用do_xxx

                func = getattr(self, 'do_' + cmd)
            except AttributeError:
                return self.default(line)

            return func(arg)

这里,根据输入的命令跳转到对应do_xxx的方法进行解析。

此处分析 run命令的执行过程,定位到Session.do_run()方法:

def do_run(self, args):     
        argv = shlex.split(args, comments=True)

        if len(argv) == 1 and (argv[0] == "-h" or argv[0] == "--help"):
            self.do_help("run")
            return

        if len(argv) > 0:
            try:
                 #解析run语句后面的第一个参数,这个参数决定调用哪个module,此处这个module指的是app.package. AttackSurface

                module = self.__module(argv[0])
                module.push_completer = self.__push_module_completer
                module.pop_completer = self.__pop_module_completer
                
                self.__module_pushed_completers = 0
            except KeyError as e:
                self.stderr.write("unknown module: %s\n" % str(e))
                return None

            try:
                 #调用module.run(),这里argv[1:]指的packageName

                module.run(argv[1:])
            except KeyboardInterrupt:
                self.stderr.write("\nCaught SIGINT. Interrupt again to terminate you session.\n")
            except Exception as e:
                self.handleException(e)
            
            while self.__module_pushed_completers > 0:
                self.__pop_module_completer()
        else:
            self.do_help("run")

因为所以的modules都继承Module,而module.run()这个run()是在Module中实现的,定位到Module.run():

 def run(self, args):
   
         #实例化parse对象

        parser = self.__prepare_parser()

        parser.description = self.usage.formatted_description()
        parser.usage = self.usage.formatted_usage(parser)

        if "-h" in args or "--help" in args:
            return parser.print_help()
        else:
             #获取命令行参数

            arguments = parser.parse_args(args)
            
            if hasattr(self, 'execute'):
                 #执行app.package. AttackSurface中的execute()

                result = self.execute(arguments)
            else:
                self.stderr.write("drozer doesn't know how to do that.\n")
                self.stderr.write("The %s module does not define an execute() method.\n\n" % self.fqmn())
                
                result = None
                
            self.clearObjectStore()

            return result

定位到app.package. AttackSurface.execute():

def execute(self, arguments):
        if arguments.package != None:

            package = self.packageManager().getPackageInfo(arguments.package, common.PackageManager.GET_ACTIVITIES | common.PackageManager.GET_RECEIVERS | common.PackageManager.GET_PROVIDERS | common.PackageManager.GET_SERVICES)
            application = package.applicationInfo

            activities = self.match_filter(package.activities, 'exported', True)
            receivers = self.match_filter(package.receivers, 'exported', True)
            providers = self.match_filter(package.providers, 'exported', True)
            services = self.match_filter(package.services, 'exported', True)
            
            self.stdout.write("Attack Surface:\n")
            self.stdout.write("  %d activities exported\n" % len(activities))
            self.stdout.write("  %d broadcast receivers exported\n" % len(receivers))
            self.stdout.write("  %d content providers exported\n" % len(providers))
            self.stdout.write("  %d services exported\n" % len(services))


            if (application.flags & application.FLAG_DEBUGGABLE) != 0:
                self.stdout.write("    is debuggable\n")

            if package.sharedUserId != None:
                self.stdout.write("    Shared UID (%s)\n" % package.sharedUserId)
        else:
            self.stdout.write("No package specified\n")

至此,在console当中run命令的执行分析过程就结束了。

4.    Drozer小结

      Drozer可以看成是C/S结构的工具。PC端是用Python写的,Agent端是用java写的。利用Google Protocol Buffer协议作为消息载体。很重要的一点就是利用反射,很大一部分工作都是由Agent代理完成,最后由PC端处理解析。后面还有就是命令的具体实现部分,后面会陆续更新。

5.    参考链接

 http://www.freebuf.com/articles/terminal/111863.html

 http://bbs.pediy.com/showthread.php?t=190561


0 0
原创粉丝点击