Android4.4 往短信收件箱中插入自定义短信(伪造短信)
这段时间稍微有点空闲,把前一段学习Android做过的一些小项目整理整理。虽然没有什么工程量很大的项目,但是对于一个新手,解决这些问题还是花了一段时间。感觉还是非常有记录的意义呢~~~么么哒*—*
今天要说明的这个项目,是要在Android手机里伪造一条短信,也就是在短信箱中插入一条自定义的短信,看上去就像自己的手机里收到了新的信息,但其实这并不是一条通过通信运营商的网络发过来的信息,这是一条假的信息。
在Android4.4之前的版本,往短信箱插入信息很方便,所以这个对用户来说很有威胁的漏洞,在Android4.4得到了修复。Android4.4中只有手机默认的消息App才能处理和短信相关的操作,而手机默认的消息App一般就是手机里自带的官方App,当然用户可以在设置里面,手动地将自己信任的消息App设置为默认App,总的来说,短信的操作控制权掌握到用户自己的手中。
那如何自己实现一个处理消息的App呢?可以参考这篇文章。让你的短信应用迎接Android 4.4(KitKat)。这篇文章是根据Google给出的官方文档翻译下来的。里面对消息App的必须的实现细节已经做了详细的说明。
下面是我自己用到的时候具体的代码:
MainActivity.java
package tina.messagebox; import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.provider.Telephony;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.text.method.MovementMethod;
import android.text.method.ScrollingMovementMethod;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast; import java.text.SimpleDateFormat;
import java.util.Date; public class MainActivity extends ActionBarActivity {
private String defaultSmsPkg;
private String mySmsPkg;
private TextView mMessageView=null;
private EditText mPhoneNumber=null;
private EditText mMsg=null; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); mPhoneNumber=(EditText)findViewById(R.id.editText);
mMsg=(EditText)findViewById(R.id.editText2);
mMessageView=(TextView)findViewById(R.id.textView3);
mMessageView.setMovementMethod(ScrollingMovementMethod.getInstance()); //设置滚动
defaultSmsPkg= Telephony.Sms.getDefaultSmsPackage(this);
mySmsPkg= this.getPackageName(); if(!defaultSmsPkg.equals(mySmsPkg)){
// 如果这个App不是默认的Sms App,则修改成默认的SMS APP
// 因为从Android 4.4开始,只有默认的SMS APP才能对SMS数据库进行处理
Intent intent=new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME,mySmsPkg);
startActivity(intent);
} Button button=(Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mySmsPkg.equals(Telephony.Sms.getDefaultSmsPackage(MainActivity.this))){
if(mPhoneNumber.getText().toString().isEmpty()){
Toast.makeText(MainActivity.this,"Phone number cannot be empty!",Toast.LENGTH_LONG).show();
return;
}
if(mMsg.getText().toString().isEmpty()){
Toast.makeText(MainActivity.this,"Message cannot be empty!",Toast.LENGTH_LONG).show();
return;
}
System.out.println("My App is default SMS App.");
// 对短信数据库进行处理
ContentResolver resolver=getContentResolver(); ContentValues values=new ContentValues();
values.put(Telephony.Sms.ADDRESS,mPhoneNumber.getText().toString());
values.put(Telephony.Sms.DATE, System.currentTimeMillis());
long dateSent=System.currentTimeMillis()-5000;
values.put(Telephony.Sms.DATE_SENT,dateSent);
values.put(Telephony.Sms.READ,false);
values.put(Telephony.Sms.SEEN,false);
values.put(Telephony.Sms.STATUS, Telephony.Sms.STATUS_COMPLETE);
values.put(Telephony.Sms.BODY, mMsg.getText().toString());
values.put(Telephony.Sms.TYPE, Telephony.Sms.MESSAGE_TYPE_INBOX); Uri uri=resolver.insert(Telephony.Sms.CONTENT_URI,values);
if(uri!=null){
long uriId= ContentUris.parseId(uri);
System.out.println("uriId "+uriId);
} Toast.makeText(MainActivity.this, "Insert a short Message.",
Toast.LENGTH_LONG).show(); // 对短信数据库处理结束后,恢复原来的默认SMS APP
Intent intent=new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME,defaultSmsPkg);
startActivity(intent);
System.out.println("Recover default SMS App"); // 打印出收件箱里的最新5条短信
Cursor cursor=getContentResolver().query(Telephony.Sms.CONTENT_URI,null,null,null,null);
String msg="";
while ((cursor.moveToNext()) &&
(cursor.getPosition()<5)){
int dateColumn=cursor.getColumnIndex("date");
int phoneColumn=cursor.getColumnIndex("address");
int smsColumn=cursor.getColumnIndex("body"); System.out.println("count "+cursor.getCount()+" position "+cursor.getPosition());
// 把从短信中获取的时间戳换成一定格式的时间
SimpleDateFormat sfd=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date date=new Date(Long.parseLong(cursor.getString(dateColumn)));
String time=sfd.format(date);
msg=msg+time+" "+cursor.getString(phoneColumn)+":"+cursor.getString(smsColumn)+"\n";
mMessageView.setText(msg);
} }
else{
Toast.makeText(MainActivity.this,"Sorry,the App is not default Sms App.",
Toast.LENGTH_LONG).show();
}
}
});
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId(); //noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
} return super.onOptionsItemSelected(item);
}
}
以上是具体的动作实现,要完成一个默认的消息App,还需要具备接收SMS和MMS的能力以及发送SMS的能力,所以还需要MmsReceiver/SmsReceiver/SmsSendService,具体到今天要实现的功能而言,这几个能力都不用具体实现,所以Receiver和Service并不用对具体的action进行相应。
MmsReceiver.java
package tina.messagebox; import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent; /**
* Created by Tina on 2015/8/11.
*/
public class MmsReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) { }
}
SmsReceiver.java
package tina.messagebox; import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent; /**
* Created by Tina on 2015/8/11.
*/
public class SmsReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) { }
}
SmsSendService.java
package tina.messagebox; import android.app.Service;
import android.content.Intent;
import android.os.IBinder; public class SmsSendService extends Service {
public SmsSendService() {
} @Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return null;
}
}
最后,要在AndroidManifest.xml中对Receiver和Service进行注册,并声明消息相关的权限。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="tina.messagebox" > <!-- Adding -->
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" /> <!-- End Adding -->
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> <!-- Adding -->
<action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SENDTO" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="sms" />
<data android:scheme="smsto" />
<data android:scheme="mms" />
<data android:scheme="mmsto" />
<!-- End Adding --> </intent-filter>
</activity> <!-- Adding -->
<!-- BroadcastReceiver that listens for incoming SMS messages -->
<receiver
android:name=".SmsReceiver"
android:permission="android.permission.BROADCAST_SMS" >
<intent-filter>
<action android:name="android.provider.Telephony.SMS_DELIVER" />
</intent-filter>
</receiver> <!-- BroadcastReceiver that listens for incoming MMS messages -->
<receiver
android:name=".MmsReceiver"
android:permission="android.permission.BROADCAST_WAP_PUSH" >
<intent-filter>
<action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" /> <data android:mimeType="application/vnd.wap.mms-message" />
</intent-filter>
</receiver> <!-- Service that delivers messages from the phone "quick response" -->
<service
android:name=".SmsSendService"
android:exported="true"
android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE" >
<intent-filter>
<action android:name="android.intent.action.RESPOND_VIA_MESSAGE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="sms" />
<data android:scheme="smsto" />
<data android:scheme="mms" />
<data android:scheme="mmsto" />
</intent-filter>
</service>
<!-- End Adding -->
</application> </manifest>
这两个Receiver和Service缺了任何一个,App都无法成为一个默认的消息App。
下面,是今天实现的App的运行效果。第一次打开App,会检测该App是否是默认消息App,如果不是,则弹出对话框让用户决定是否将其设置为默认App,如果用户同意,则可以输入手机号码和短信内容,按一下Insert,手机短信箱里就会多了一条短信,插入成功后会再弹出一个对话框,询问用户是否恢复手机自带的短信App为默认,用户选择Yes,那么回到Message中,就可以看到一条未读短信啦。当然,万一一不小心,在后面这个对话框里选择了NO,那么为了能够正常地处理短信,还是到手机的“设置”里面,把原来的App设为默认吧。
Android4.4 往短信收件箱中插入自定义短信(伪造短信)的更多相关文章
- android 访问SMS短信收件箱
访问 SMS收件箱是另一个常见的需求.首先,需要将读取 SMS 的权限 <uses-permission android:name="android.permission.READ ...
- 【排障】Outlook Express 2G收件箱大小限制
Outlook Express 2G收件箱大小限制 文:铁乐猫 ----------------------------- Outlook Express(以下简称OE)客户端收件箱大于或接近2G时, ...
- JavaMail读取收件箱退信邮件/分析邮件附件获取Message_Id
需求描述:公司最近有个项目邮件通知功能,但是客户上传的邮件地址并不一定存在,以及其他的各种问题.所有希望发送通知后有个回执,及时发现地址存在问题的邮箱. 需求分析:经过分析JavaMail可以读取收件 ...
- 通什翡翠商城大站协议邮件群发系统日发20-30万封不打码不换ip不需发件箱100%进收件箱
用一种新的技术思维去群发邮件一种不用换IP,不需要任何发件箱的邮件群发方式一种不需要验证码,不需要**代码变量的邮件群发方式即使需要验证码也能全自动识别验证码的超级智能软件教你最核心的邮件群发思维和软 ...
- 懒人邮件群发日发50-100万封不打码不换IP不需发件箱大站协议系统营销软件100%进收件箱
用一种新的技术思维去群发邮件 一种不用换IP,不需要任何发件箱的邮件群发方式 一种不需要验证码,不需要**代码变量的邮件群发方式 即使需要验证码也能全自动识别验证码的超级智能软件 教你最核心的邮件群发 ...
- [C#]exchange发送,收件箱操作类
最近项目中需要用到exchange的操作,就参照msdn弄了一个简单的操作类.目前先实现了,发送邮件和拉取收件箱的功能,其他的以后在慢慢的添加. using Microsoft.Exchange.We ...
- SendMail发送回执及读取收件箱
一.SendMail发送有回执提示 1.邮件发送配置 Properties props = new Properties(); String smtp = "smtp.qq.com" ...
- AKKA Inbox收件箱
起因 得到ActorRef就可以给actor发送消息,但无法接收多回复,也不知道actor是否停止 Inbox收件箱出现就是解决这两个问题 示例 package akka.demo.actor imp ...
- Win10 收件箱添加QQ邮箱(2019年5月19日)
Emmm弄的时候没截图,就语言描述吧,非常简单. 登录到网页端QQ邮箱.点我登录 登录之后,界面上端的Logo右边有个"设置"(字有点小).点它 邮箱设置下面有一堆标签,点击&qu ...
随机推荐
- 【Alpha版本】冲刺-Day3
队伍:606notconnected 会议时间:11月11日 会议总结 张斯巍(433) 今天安排:个人信息界面设计 完成度:100% 明天计划:个人信息界面设计 遇到的问题:ps掌握的还不够熟练,导 ...
- HD1269迷宫城堡(有向图 && 划分连通块)
迷宫城堡 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- web前端环境搭建
第一部分:浏览器 浏览器推荐chrome浏览器.FireFox浏览器. 1. chrome浏览器因为集成了Google Developer Tools(谷歌开发者工具),因此大受欢迎. 下载地址:ht ...
- photoshop切图介绍
第一部分:界面设置 1.点击“文件-新建”(或者ctrl+n)打开一个新建对话框.名称可随意填写.“预设”设置为自定,“宽度”一般选择1920,“单位”选为像素.“高度”可选择为2000,“单位”选为 ...
- JavaScript中的变量及数据类型
转自:http://blog.csdn.net/mygis2005/article/details/7375419 JavaScript是一种弱类型的语言,变量名.操作符和方法名都区分大小写. 1.变 ...
- ef to sqlite 实际开发问题终极解决方法
版本问题 vs安装问题 x64/x86 发布问题 针对开发中遇到的问题,通过一下方法解决: 1.sqlite下载地址http://system.data.sqlite.org/index.html/d ...
- OpenGL瓶颈
在优化Erya3D引擎的过程中,遇到的瓶颈: 1. 字符串操作,避免逐个字符的比较,使用哈希码比较2. 贴图操作:切换绑定贴图.更改贴图参数3. 切换绑定GLSL程序4. Draw Call:http ...
- Swiper基本上使用
导入三个文件 jquery-1.11.1.min.js,swiper.min.js,swiper.min.css 攻略教程 http://www.swiper.com.cn/api/function/ ...
- 单点登录(SSO)系统的总结
前些天一位其他开发部门的同事找到我们了解一些关于SSO单点登录的事,他们要做单点登录,同时也需要和我们这边的系统做集成,要我帮忙做一单点登录,了解关于单点登录的解决方案和资料,虽然做单点登录已经很久了 ...
- vnc服务器配置实例
系统环境为CentOS.RHEL. 临时需要远程连接,参考:http://www.centoscn.com/CentOS/Intermediate/2013/0917/1641.html 一.安装.启 ...