android/java中短信pdu编码

最近在做毕设,用到了这个,搜了下网友有实现,我稍微修改了下把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);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值