您的位置:首页 > 移动开发 > Android开发

Android操作系统MMS保护方案

2015-06-03 12:45 411 查看
最近在做Android短信保护的一些东西,技术实现是用xposed框架.

下面先来一些原理性的介绍,算是概念的普及.

短信:Short Message Service,简称SMS,是用户通过手机或其他电信终端直接发送或接收的文字或数字信息,用户每次能接收和发送短信的字符数,是160个英文或数字字符,或者70个中文字符。在Android操作系统上,信息应用程序的名称为MMS,它既能处理短信SMS(Short Message Service),也能处理彩信(Multimedia Message Service)。它是除电话程序外,另一个非常重要的手机系统核心应用程序,因为对于手机来讲,最重要的二个功能就是电话功能和信息功能。与功能手机时代的信息应用一样,Android的Mms也具有通用的信息程序所具有的功能,比如创建信息,收发信息,转发信息,以及对于信息的管理,还有就是对于信息的一些配置。在功能手机时代,信息是以文件夹的方式来组织和管理,如收信箱、发信箱、草稿箱,已发信息、短信、彩信等。信息以时间、主题等方式来排序,再把所有的信息罗列在相应的文件夹中。而在智能手机时代,引入了对话(Thread)的概念,即把二个联系人之间的信息交互看成一个系列对话,二人之间的所有信息都列在对话之中。在每个对话中,又以时间为序来管理具体的信息,以不同的着色来区分发出去的信息和收到的信息,在信息的旁边还可以显示联系人的信息,如头像,点击头像还可以有其他的快捷操作(比如拨号)。MMS管理一系列对话列表,抛弃了传统的通过各种文件夹来管理的方式。所以,对于MMS来讲核心概念是对话,而非信息或文件夹。

与MMS相关的概念

在Android操作系统中,与MMS相关的概念如下:

Thread对话

用户与某个联系人或某几个联系人之间的一系列信息交互。在Mms中,用Thread Id来标识和管理对话,Thread Id也即在数据库表threads中的_id。

Conversation

Thread对话的抽象出来数据结构,每一个Conversation有一个唯一的Thread Id,用来管理Thread对话。能够从数据库中查询,删除一个对话中的消息,也负责对一组对话的管理,比如查询所有的对话,删除所有的对话等。

ConversationList

负责显示和编辑所有的对话,以列表形式显示所有的Thread,每一项代表一个Thread,通常也会显示这个Thread的状态,如有无草稿,信息发送/接收是否成功等。

Message

消息,泛指短信SMS和彩信MMS。Message的数据结构是MessageItem,它是一个纯数据结构,里面存储着关于一个信息的所有数据,还有MessageListitem,它是一个View,专门用于在消息列表中显示一个信息,里面的数据都是从MessageItem获取。它们统一都被ComposeMessageActivity,MessageListAdapter和MessageListView来管理。

WorkingMessage

当前消息。它是专门用于代表当前正在创建和编辑的信息的数据结构,无论是短信还是彩信,在创建和编辑的时候都放在一个WorkingMessage对象里面,这个对象也负责信息的发送和存储为草稿。

Slideshow

彩信的幻灯片形式的展示。MMS就是以幻灯片形式存在的,创建的时候是对一张张幻灯片的编辑,收到的彩信或编辑完后,就可以一张张地放映浏览幻灯片。

Recipient

接收人,这里是指信息的接收者,要么是一个陌生的电话号码,要么是一个陌生的电子邮件地址(彩信时),要么就是手机联系人数据库中的联系人。

在上面的几个概念中,对于Slideshow需要注意的是,以幻灯片方式显示彩信仅是应用程序层的处理方式,不同的信息应用程序会以不同的方式处理彩信,而在系统中,实际的彩信数据是以标准的Pdu方式进行发送和接收,应用程序在发送前把幻灯片转化成为Pdu,并在接收后把Pdu转化成为自己可识别的幻灯片。

与MMS相关的类

对于Android操作系统中,关于短信应用程序,从软件的功能角度来讲,Mms分为对话列表,消息列表,短信编辑,彩信编辑,短信显示,彩信显示和配置。从实现的角度来看,它分为GUI展示层,发送/接收,彩信解析,彩信附件,信息数据等,这些分类对应着源码中的各种包。在Android操作系统中,与MMS相关的源码放在com.android.mms包中。下面主要介绍在com.android.mms包中与短信有关的类和包的功能。

对于com.android.mms.ui包,主要负责系统直接与用户交互,用于GUI的显示,如展示对话列表,消息列表,消息编辑页,彩信附件编辑,彩信展示,播放幻灯片等。

对于com.android.mms.data包,主要用于操作当前正在编辑的信息的相关数据,比如联系人列表,当前对话,当前消息等。该包中的类都是在编辑信息的时候使用,短信产生的最源头的类也在这个包中。

部分类的功能介绍如下:

- WorkingMessage.java

用来管理当前正在编辑的消息,它从创建,草稿到发送完成后一直存在,只要打开了编辑信息的页面就会创建一个WorkingMessage,直到退出编辑页面.

- Conversation.java

用来管理对话Threads,通常用来管理当前的对话,也就是进入的对话和正在进行操作的对话,它也用来管理对话列表,比如查询对话列表.

- Contact.java

用来代表一个联系人的信息,和管理联系人,加载联系人信息,其中还有相应的Cache信息.

- ContactList.java

Contact的List列表,继承自ArrayList,用来管理一个Contact列表,或管理多个Contact.

- RecipientIdCache.java

用于保存所用到的Contact的Id和地址(电话)。每次WorkingMessage会更新这个Cache,然后ContactList会优先从这个Cache中查询联络人.

在上面的几个类中,需要重点关注的类是orkingMessage,该类中封装了代表短信内容的属性和相关的处理方法,可以认为是framework层上最原始的短信产生的源头

对于包com.android.mms.dom,是解析彩信内容的工具包;对于包com.android.mms.drm,是用于处理DRM媒体文件的工具包;对于com.android.mms.layout包,包含了短信布局方式的布局元素;对于com.android.mms.model包,定义了彩信支持的附件数据结构和附件的组织方式;对于com.android.mms.util包,包含了整个MMS共享的工具类。

对于com.android.mms.transaction包,是有关MMS最底层的一个包,用户不可见,主要是负责发送信息和接收信息,用于发送信息的最后处理和接收信息的最初处理。从物理层次上来讲,并不是真正的发送和接收信息,而是由Android系统Framework层来负责接收和发送信息。在系统的接收端部分类的功能介绍如下:

- MmsMessageSender.java

继承自MessageSender,用于发送彩信。它并不是做发送的事情,而是做一些错误检查和前期准备工作,然后启动TransactionService来做发送相关的事情。

- MessageSender.java

为了发送信息而封装的一个接口,它里面只有一个方法sendMessage(),UI层只需要调用实现了这个接口的类即可发送信息。

- SmsMessageSender.java

发送短信的封装,继承自MessageSender,它会启动SmsReceiverService来发送短信

- SmsSingleRecipientSender.java

继承自SmsMessageSender,它针对一个收信人,调用Frameworks层的接口发送信息,对于Mms应用来说,这是发送短信的最后一站,对就是说对于应用来说,它会把短信发送出去。

- Transaction.java

各种Transaction的基类,定义了两个方法,getPdu()和sendPdu(),从MMSC取彩信数据,和向MMSC发送数据。

在上面的类中,需要重点关注的是SmsSingleRecipientSender和SmsMessageSender,SmsSingleRecipientSender是短信发送的最后一站,对于Android系统的应用来说,可以会利用该类来实现短信的发送,因此要想在Server端进行拦截,应该考虑hook该类本身或者与该类有关的类

发送端的拦截

以发送端的拦截实现为例,进行详细地说明实现的方案。经过上面的分析,可以知道,在发送时的client端,需要重点关注的类是com.android.mms.data包中的类WorkingMessage,该类用来管理当前正在编辑的消息,它从创建,草稿到发送完成后一直存在,只要打开了编辑信息的页面就会创建一个WorkingMessage,直到退出编辑页面。该类中封装了代表短信内容的属性和相关的处理方法,可以认为是framework层上最原始的短信产生的源头。

在Android系统的client端,该类定义了一个标识短信内容的属性变量如下:

……
// Text of the message.
   private CharSequence mText;
……


通过调用send方法来实现短信的发送,send方法的实现如下:

public void send(final String recipientsInUI) {
       long origThreadId = mConversation.getThreadId();
……
       // Get ready to write to disk.
       prepareForSave(true /* notify */);

       // We need the recipient list for both SMS and MMS.
       final Conversation conv = mConversation;
       String msgTxt = mText.toString();
……
           // Make local copies of the bits we need for sending a message,
           // because we will be doing it off of the main thread, which will
           // immediately continue on to resetting some of this state.
           final Uri mmsUri = mMessageUri;
           final PduPersister persister = PduPersister.getPduPersister(mActivity);

           final SlideshowModel slideshow = mSlideshow;
           final CharSequence subject = mSubject;
           final boolean textOnly = mAttachmentType == TEXT;
……
 // Do the dirty work of sending the message off of the main UI thread.
           new Thread(new Runnable() {
               @Override
               public void run() {
                   final SendReq sendReq = makeSendReq(conv, subject);

   // Make sure the text in slide 0 is no longer holding onto a reference to
   // the text in the message text box.
                   slideshow.prepareForSend();
                   sendMmsWorker(conv, mmsUri, persister, slideshow, sendReq, textOnly);

                   updateSendStats(conv);
               }
           }, "WorkingMessage.send MMS").start();
       } else {
           // Same rules apply as above.
           final String msgText = mText.toString();
           new Thread(new Runnable() {
               @Override
               public void run() {
                   preSendSmsWorker(conv, msgText, recipientsInUI);

                   updateSendStats(conv);
               }
           }, "WorkingMessage.send SMS").start();
       }

       // update the Recipient cache with the new to address, if it's different
       RecipientIdCache.updateNumbers(conv.getThreadId(), conv.getRecipients());

       // Mark the message as discarded because it is "off the market" after being sent.
       mDiscarded = true;
   }


因此从短信产生的源头进行拦截的时候,可以考虑拦截WorkingMessage的send方法,然后获取到其mText属性变量的内容,通过对该内容进行加密处理来实现保护。其中对于mText属性变量的获取,可以调用XposedHelpers的findField方法来实现,获取后将获取的内容整合成字节流的形式,通过对字节流的每一位的加密处理来实现对敏感MMS信息的保护。

在发送时的server端,需要重点关注的是SmsSingleRecipientSender和SmsMessageSender,其中,SmsSingleRecipientSender是短信发送的最后一站,对于Android系统的应用来说,会利用该类来实现短信的发送,因此要想在Server端进行拦截,应该考虑hook住该类本身或者与该类有关的类。经过分析Android系统中SmsSingleRecipientSender的源码,发现该类继承自SmsMessageSender,再进一步分析,发现SmsMessageSender类中定义了标识短信内容的属性变量mMessageText,其声明如下:

……
protected final String mMessageText;
……


该类通过调用sendMessage方法来实现在server端的发送,该方法的具体实现如下:

public boolean sendMessage(long token) throws MmsException {
        // In order to send the message one by one, instead of sending now, the message will split,
        // and be put into the queue along with each destinations
        return queueMessage(token);
    }


同样,用Xposed框架拦截住该函数的SmsMessageSender的sendMessage方法,利用反射机制获取server端的标识短信内容的属性变量,针对client端的加密算法,实施解密处理,就可以实现发送端的保护。可以知道,在没有获取信赖的前提下,任何在发送端具有攻击性的拦截所获取的都是密文
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: