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的源码可以从Github(https://github.com/mwrlabs)上获取:
drozer: 包含了控制台与服务端代码;
drozer-agent: 包含了运行于Android设备的Agent代码;
jdiesel:反射和通信协议的核心jar工程;
mwr-tls:安全通信jar工程;
mwr-android: 移动端界面jar工程;
2. Drozer通信协议
Drozer和Agent之间的通信采用google protocol buffer协议,这种协议是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,很适合做数据存储或 RPC 数据交换格式。它可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 三种语言的 API。完整协议可以参见github(https://github.com/mwrlabs/mercury-common/blob/master/protobuf.proto)上的源码,该协议是两者协作的核心。
下面是对这个协议的简单介绍:
该协议中包含4种消息类型,其中包括SYSTEM_REQUEST、SYSTEM_RESPONSE、REFLECTION_REQUEST、REFLECTION_RESPONSE
enum MessageType {
SYSTEM_REQUEST= 1;
SYSTEM_RESPONSE= 2;
REFLECTION_REQUEST= 3;
REFLECTION_RESPONSE= 4;
}
}
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:主要包括响应的类型(绑定服务,设备列表,会话列表等)状态信息
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(对象引用ObjectReference(int32类型),方法对象method,和方法参数Argument),Invoke调用方法(同样包括对象引用ObjectReference(int32类型),方法对象method,和方法参数Argument),以及对Property的get与set,还有Delete(对象引用ObjectReference(int32类型))
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:主要是反射响应后的状态和参数,还有一些错误信息
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 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.Base(mwr\common\cli.py)。这个run()就在cli.Base这个类中实现,定位到cli.Base.run():
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():
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()
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 "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)
这里主要是实现Drozer与Agent建立Session,进入控制台,等待命令的输入并执行。
下面根据drozer console connect这条命令的流程重点分析SystemRequest、ReflectionRequest两类消息的执行过程:
SystemRequest消息执行过程
device = self.__get_device(arguments),这个方法获取与Drozer建立连接的设备。这里以这个分支详细分析SystemRequest消息的执行过程。定位到__get_device():
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。实现代码如下:
if self.__server == None:
#实例化ServerConnector类
self.__server = ServerConnector(arguments, self.__manage_trust)
return self.__server
ServerConnector这个类在drozer\connector\server_connector.py,核心代码是调用父类SocketTransport的__init__,从而获取与Agent的31415端口建立的socket。
#连接的主机与端口
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__():
def __init__(self, arguments, trust_callback=None):
Transport.__init__(self)
#socket实例化
self.__socket = socket.socket()
......
......
得到与agent建立连接的socket,接下来执行__getServerConnector(arguments).listDevices()定位到listDevices():
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主要是发送一个message给agent,并获取返回结果,定位到sendAndReceive:
#为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):
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():
#实例化SystemRequest类型的对象
builder = SystemRequestFactory(Message.SystemRequest.LIST_DEVICES)
return builder
到这里,SystemRequest消息在Drozer中执行完毕。接下来看Agent是如何接收这个SystemRequest.LIST-DEVICES这个请求,并如何处理的。
Agent端:
Agent首先会通过一个Receiver启动ServerService,这个ServerService就是与Drozer建立连接的服务。定位到Receiver:
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()这个方法。
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():
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.server是Server类的对象,这个Server类继承Link类,而Link类间接继承Thread,所以说,Server类是一个线程类。当执行this.server.start()时,这个线程就启动了。定位到Server类的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():
if(transport.isLive()) {
#实例化Connection对象
this.connection = new Connection(this,this.device_info, transport);
this.connection.start();
}
}
创建一个Connection实例,而后启动它。这个Connection也是间接继承Thread,也是一个线程类。定位到这个类的run(),而这个run()是继承来自它的父类AbstractConnection,真正负责接收Drozer的请求与处理相对应的请求就在这里实现的。具体代码如下:
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对象,是不是符合Drozer将message封装成Frame的过程?定位到receive():
try {
#将request转化为Frame类型
Frame f = this.transport.receive();
return f != null ?f.getPayload() : null;
}
再展开this.handleMessage(),代码如下:
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()代码如下:
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()
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():
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 "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__方法:
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的数据路径,当然这里就要用到消息反射了。定位到Modules的getContext():
#利用反射得到com.mwr.dz.Agent的实例
return self.klass('com.mwr.dz.Agent').getContext()
继续跟踪klass()
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方法:
#将反射请求发送到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的处理过程。最终执行过程如下:
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():
#利用反射得到类的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:
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():
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 "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()方法:
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():
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()方法:
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():
#实例化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():
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
- Android渗透工具之Drozer源码分析
- 利用drozer进行android渗透
- 利用drozer进行Android渗透测试
- 利用drozer进行Android渗透测试
- 利用drozer进行Android渗透测试 - AndroSecurity
- 利用drozer进行Android渗透测试
- Android测试渗透框架Drozer的安装与使用
- android安全框架工具drozer使用指南
- Drozer--Android APP安全评估工具
- 渗透工具之nmap
- 渗透工具之sqlmap
- 渗透工具之msf
- 渗透工具之mitmf
- 渗透工具之msf
- Android渗透测试工具
- Drozer二 亲测------测试android应用程序漏洞的安全评估工具---Drozer配置安装篇
- drozer工具的安装与使用:之二使用篇
- Drozer – Android APP安全评估工具小测
- 将ppt转换成word格式的简单方法分享
- AngularJs 服务区别小Demo
- xib里,scrollView的约束问题
- angular2 + nodejs+ express+ webpack+echart
- select、epoll模型概念
- Android渗透工具之Drozer源码分析
- IOS开发-从网络获取图片并显示
- JavaScript 表单的制作
- chrome自动填表会遮挡input中背景图的问题解决方法
- MyBatis入门
- IO复用\阻塞IO\非阻塞IO\同步IO\异步IO .
- Gitlab和SourceTree组合实现版本控制
- 传统电子地图与水经注下载的谷歌电子地图有何区别
- 沙盒在真机和模拟器上的缓存区别