最近在做毕设,用到了这个,搜了下网友有实现,我稍微修改了下把android库去掉了,纯java库
import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Calendar; /** * Created by ashqal on 15-1-16. */ public class PduEncoder { public static Object[] createFakeSms( String sender, String body) { byte[] pdu = null; byte[] scBytes = networkPortionToCalledPartyBCD("0000000000"); //短信中心号码,调用networkPortionToCalledPartyBCD转换为BCD二进制码格式. byte[] senderBytes = networkPortionToCalledPartyBCD(sender); //伪造的发信号码. int lsmcs = scBytes.length; //短信中心的号码长度。 try { ByteArrayOutputStream bo = new ByteArrayOutputStream(); bo.write(lsmcs); bo.write(scBytes); //以上两项是SCA bo.write(0x04); //PDU TYPE bo.write((byte) sender.length()); //所伪造发件号码的长度。 bo.write(senderBytes); //以上两项是OA bo.write(0x00); //PID try { byte[] bodybytes = EncodeUCS2(body,null); //用EncodeUCS2函数将短信内容编码为UCS2,短信的长度在函数中已经计算并加入body的头部. bo.write(0x08); // 0x08代表UCS-2编码格式 //Log.e("编码结果",getBCDString()); bo.write(str2Bcd(getBCDString())); //以BCD格式写入当前时间 bo.write(bodybytes); //写入短信内容 } catch (Exception e) { } pdu = bo.toByteArray(); //最后把结果转换成byte } catch (IOException e) { } return new Object[] { pdu }; } /** * 取当前日期并转换为BCD格式 * 输出String共14位,每两位为一时间单位,每个时间单位均为位数倒置,最后两位是offset: * 年+月+日+时+分+秒+offset * 只适用于offset取值23的情况 * @return */ private static String getBCDString(){ String BCDDate=""; String YEAR,MONTH,DAY,HOUR,MINUTE,SECOND; Calendar now = Calendar.getInstance(); YEAR=String.valueOf(now.get(Calendar.YEAR)); MONTH=String.valueOf(now.get(Calendar.MONTH)+1); //Calendar的月份是从0开始的,即0代表1月份,故此处要加1. DAY=String.valueOf(now.get(Calendar.DAY_OF_MONTH)); HOUR=String.valueOf(now.get(Calendar.HOUR_OF_DAY)); MINUTE=String.valueOf(now.get(Calendar.MINUTE)); SECOND=String.valueOf(now.get(Calendar.SECOND)); BCDDate=FmtBCDDate(YEAR.substring(2))+FmtBCDDate(MONTH)+FmtBCDDate(DAY)+ FmtBCDDate(HOUR)+FmtBCDDate(MINUTE)+FmtBCDDate(SECOND)+"23"; //offset为23 return BCDDate; } /** * 日期格式化函数,一位数后面加零变两位数,两位数则颠倒位数 * @param s * @return */ private static String FmtBCDDate(String s){ if(ReverseInt(Integer.parseInt(s)).equals("0")) { return "00"; } else { if(ReverseInt(Integer.parseInt(s)).length()==1) return ReverseInt(Integer.parseInt(s))+"0"; else return ReverseInt(Integer.parseInt(s)); } } /** * 整数位数颠倒函数 ,输出String. * @param i * @return */ private static String ReverseInt(int i){ StringBuffer bs = new StringBuffer(String.valueOf(i)); return bs.reverse().toString(); } /** * String转BCD编码函数,来自网络. * @param asc * @return */ private static byte[] str2Bcd(String asc) { int len = asc.length(); int mod = len % 2; if (mod != 0) { asc = "0" + asc; len = asc.length(); } byte abt[] = new byte[len]; if (len >= 2) { len = len / 2; } byte bbt[] = new byte[len]; abt = asc.getBytes(); int j, k; for (int p = 0; p < asc.length()/2; p++) { if ( (abt[2 * p] >= '0') && (abt[2 * p] <= '9')) { j = abt[2 * p] - '0'; } else if ( (abt[2 * p] >= 'a') && (abt[2 * p] <= 'z')) { j = abt[2 * p] - 'a' + 0x0a; } else { j = abt[2 * p] - 'A' + 0x0a; } if ( (abt[2 * p + 1] >= '0') && (abt[2 * p + 1] <= '9')) { k = abt[2 * p + 1] - '0'; } else if ( (abt[2 * p + 1] >= 'a') && (abt[2 * p + 1] <= 'z')) { k = abt[2 * p + 1] - 'a' + 0x0a; }else { k = abt[2 * p + 1] - 'A' + 0x0a; } int a = (j << 4) + k; byte b = (byte) a; bbt[p] = b; } return bbt; } /** * 以UCS-2格式编码String,用于发送汉字,使用此格式编码最多可发送70个字。 * @param message * @param header * @return * @throws java.io.UnsupportedEncodingException */ private static byte[] EncodeUCS2(String message, byte[] header) throws UnsupportedEncodingException { byte[] userData, textPart; textPart = message.getBytes("UTF-16BE"); if (header != null) { 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; } /** * Note: calls extractNetworkPortion(), so do not use for * SIM EF[ADN] style records * * Returns null if network portion is empty. */ private static byte[] networkPortionToCalledPartyBCD(String s) { String networkPortion = extractNetworkPortion(s); return numberToCalledPartyBCDHelper(networkPortion, false); } /** Extracts the network address portion and canonicalizes * (filters out separators.) * Network address portion is everything up to DTMF control digit * separators (pause or wait), but without non-dialable characters. * * Please note that the GSM wild character is allowed in the result. * This must be resolved before dialing. * * Returns null if phoneNumber == null */ public static String extractNetworkPortion(String phoneNumber) { if (phoneNumber == null) { return null; } int len = phoneNumber.length(); StringBuilder ret = new StringBuilder(len); for (int i = 0; i < len; i++) { char c = phoneNumber.charAt(i); // Character.digit() supports ASCII and Unicode digits (fullwidth, Arabic-Indic, etc.) int digit = Character.digit(c, 10); if (digit != -1) { ret.append(digit); } else if (c == '+') { // Allow '+' as first character or after CLIR MMI prefix String prefix = ret.toString(); if (prefix.length() == 0 || prefix.equals(CLIR_ON) || prefix.equals(CLIR_OFF)) { ret.append(c); } } else if (isDialable(c)) { ret.append(c); } else if (isStartsPostDial (c)) { break; } } return ret.toString(); } private static byte[] numberToCalledPartyBCDHelper(String number, boolean includeLength) { int numberLenReal = number.length(); int numberLenEffective = numberLenReal; boolean hasPlus = number.indexOf('+') != -1; if (hasPlus) numberLenEffective--; if (numberLenEffective == 0) return null; int resultLen = (numberLenEffective + 1) / 2; // Encoded numbers require only 4 bits each. int extraBytes = 1; // Prepended TOA byte. if (includeLength) extraBytes++; // Optional prepended length byte. resultLen += extraBytes; byte[] result = new byte[resultLen]; int digitCount = 0; for (int i = 0; i < numberLenReal; i++) { char c = number.charAt(i); if (c == '+') continue; int shift = ((digitCount & 0x01) == 1) ? 4 : 0; result[extraBytes + (digitCount >> 1)] |= (byte)((charToBCD(c) & 0x0F) << shift); digitCount++; } // 1-fill any trailing odd nibble/quartet. if ((digitCount & 0x01) == 1) result[extraBytes + (digitCount >> 1)] |= 0xF0; int offset = 0; if (includeLength) result[offset++] = (byte)(resultLen - 1); result[offset] = (byte)(hasPlus ? TOA_International : TOA_Unknown); return result; } /** True if c is ISO-LATIN characters 0-9, *, # , +, WILD */ public final static boolean isDialable(char c) { return (c >= '0' && c <= '9') || c == '*' || c == '#' || c == '+' || c == WILD; } /** This any anything to the right of this char is part of the * post-dial string (eg this is PAUSE or WAIT) */ public final static boolean isStartsPostDial (char c) { return c == PAUSE || c == WAIT; } private static int charToBCD(char c) { if (c >= '0' && c <= '9') { return c - '0'; } else if (c == '*') { return 0xa; } else if (c == '#') { return 0xb; } else if (c == PAUSE) { return 0xc; } else if (c == WILD) { return 0xd; } else { throw new RuntimeException ("invalid char for BCD " + c); } } /* * Special characters * * (See "What is a phone number?" doc) * 'p' --- GSM pause character, same as comma * 'n' --- GSM wild character * 'w' --- GSM wait character */ public static final char PAUSE = ','; public static final char WAIT = ';'; public static final char WILD = 'N'; /* * Calling Line Identification Restriction (CLIR) */ private static final String CLIR_ON = "*31#"; private static final String CLIR_OFF = "#31#"; /* * TOA = TON + NPI * See TS 24.008 section 10.5.4.7 for details. * These are the only really useful TOA values */ public static final int TOA_International = 0x91; public static final int TOA_Unknown = 0x81; }
构造好给intent发送就好了
Intent smsIntent = new Intent(); smsIntent.setAction("android.provider.Telephony.SMS_RECEIVED"); smsIntent.putExtra("pdus", PduEncoder.createFakeSms("1688", msg.obj.toString())); context.sendOrderedBroadcast(smsIntent, null); //或者 Intent smsIntent2 = new Intent(); smsIntent2.setAction("android.intent.action.DATA_SMS_RECEIVED"); smsIntent2.putExtra("pdus", PduEncoder.createFakeSms("1688", msg.obj.toString())); smsIntent2.setData(Uri.parse("sms:")); context.sendOrderedBroadcast(smsIntent2, null);