首页
社区
课程
招聘
[求助]Android RIL发送短信
发表于: 2015-8-9 22:50 8829

[求助]Android RIL发送短信

2015-8-9 22:50
8829
大家好,最近在做关于RIL短信发送的项目,遇到一些难点,希望大家帮忙解决一下难题。
首先以单条手机短信的发送为例,流程如下:
-> SmsManager.getDefault().sendTextMessage()
-> 经过IBinder接口到IccSmsInterfaceManagerProxy
-> 具体实现在IccSmsInterfaceManager执行方法为sendtext()
-> 再经过SMSDispatcher.java,辗转到RIL.java的sendSMS(GSM短信)和sendCdmaSms(CDMA短信)两个方法负责最后的加工。
-> 最后由RIL的native层通过LOCAL_SOCKET发送出去。

而查看RIL.JAVA的源码SOCKET_NAME_RIL = "rild",所以我的方法就是,通过反射模仿短信BINDER服务端部分的信息加工过程,最后建立一个LOCAL_SOCKET连接,将信息发送出去。

首先经过测试,我可以通过LocalSocket连接到rild。所以我可以开始利用反射来模仿短信数据的打包过程,我尽量用的都是原来的消息结构体如:RILRequest。

最终短信还是没能发送出去,我的机器是双卡双待的,代码如下:

执行sendsms(mContext);发送短信

static class RILSender extends Handler implements Runnable {
		public RILSender(Looper looper) {
			super(looper);
		}

		// ***** Runnable implementation
		@Override
		public void run() {
			// setup if needed
		}

		// ***** Handler implementation
		@Override
		public void handleMessage(Message msg) {
			SysLog.logW(TAG, "[+]RILSender MSG = "+msg.what);
		}
	}
public static boolean sendsms(Context context) {
		String destAddr = "13078950351";
		String text = "短信内容";
		PendingIntent sentIntent = null;
		PendingIntent deliveryIntent = null;

		// SmsManager smsm = SmsManager.getDefault();
		String scAddr = "";// 获取服务中心号码
		SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddr, destAddr,
				text, (deliveryIntent != null));
		HashMap<String, Object> map = new HashMap<String, Object>();
		map.put("smsc", pdus.encodedScAddress);
		map.put("pdu", pdus.encodedMessage);

		byte smsc[] = (byte[]) map.get("smsc");
		byte pdu[] = (byte[]) map.get("pdu");

		// 获取话机类型gsm或者cdma
		TelephonyManager tm = new TelephonyManager(context);
		tm.getPhoneType();
		TelephonyManager telMag = (TelephonyManager) context
				.getSystemService(Context.TELEPHONY_SERVICE);
		Class<TelephonyManager> c = TelephonyManager.class;
		Method mthEndCall = null;
		int phoneType = 0;
		try {
			mthEndCall = c.getDeclaredMethod("getPhoneType", (Class[]) null);
			mthEndCall.setAccessible(true);
			phoneType = Integer.parseInt(String.valueOf(mthEndCall.invoke(
					telMag, (Object[]) null)));
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
			SysLog.logW(TAG, "[+]PHONE_TYPE_GSM");
			// String str_smsc = IccUtils.bytesToHexString(smsc);
			// String str_pdu = IccUtils.bytesToHexString(pdu);
			String str_smsc = null;
			String str_pdu = null;
			HRef href = new HRef();
			if (!href.setClass("com.android.internal.telephony.uicc.IccUtils")) {
				return false;
			}
			try {
				Object obj_smsc = href.invokeMethod("bytesToHexString", smsc);
				Object obj_pdu = href.invokeMethod("bytesToHexString", pdu);
				str_smsc = String.valueOf(obj_smsc);
				str_pdu = String.valueOf(obj_pdu);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return false;
			}

			Message msg = mSender.obtainMessage(
					RILConstants.RIL_REQUEST_SEND_SMS, new Object());
			sendGsmSms(str_smsc, str_pdu, msg);
		} else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
			SysLog.logW(TAG, "[+]PHONE_TYPE_CDMA");
			Message msg = mSender.obtainMessage(
					RILConstants.RIL_REQUEST_CDMA_SEND_SMS, new Object());

			sendCdmaSms(pdu, msg);
		}
		return true;
	}

	private static boolean sendGsmSms(String smscPDU, String pdu, Message result) {
		HRef href = new HRef();
		if (!href.setClass("com.android.internal.telephony.RILRequest")) {
			SysLog.logW(TAG,
					"[+]cannot find com.android.internal.telephony.RILRequest");
			return false;
		}
		Object rr = null;
		try {
			rr = href.invokeMethod("obtain", RILConstants.RIL_REQUEST_SEND_SMS,
					result);
			Object mParcel = href.getObject(rr, "mParcel");
			href.invokeMethod(mParcel, "writeInt", true, 2);
			href.invokeMethod(mParcel, "writeString", true, smscPDU);
			href.invokeMethod(mParcel, "writeString", true, pdu);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// RILRequest rr = RILRequest.obtain(RILConstants.RIL_REQUEST_SEND_SMS,
		// result);
		// rr.mParcel.writeInt(2);
		// rr.mParcel.writeString(smscPDU);
		// rr.mParcel.writeString(pdu);

		return send(rr);
	}

	private static boolean sendCdmaSms(byte[] pdu, Message result) {
		int address_nbr_of_digits;
		int subaddr_nbr_of_digits;
		int bearerDataLength;
		ByteArrayInputStream bais = new ByteArrayInputStream(pdu);
		DataInputStream dis = new DataInputStream(bais);

		HRef href = new HRef();
		if (!href.setClass("com.android.internal.telephony.RILRequest")) {
			return false;
		}
		Object rr = null;

		try {
			rr = href.invokeMethod("obtain",
					RILConstants.RIL_REQUEST_CDMA_SEND_SMS, result);
			Object mParcel = href.getObject(rr, "mParcel");
			// teleServiceId
			href.invokeMethod(mParcel, "writeInt", true, dis.readInt());
			// servicePresent
			href.invokeMethod(mParcel, "writeByte", true, (byte) dis.readInt());
			// serviceCategory
			href.invokeMethod(mParcel, "writeInt", true, dis.readInt());
			// address_digit_mode
			href.invokeMethod(mParcel, "writeInt", true, dis.read());
			// address_nbr_mode
			href.invokeMethod(mParcel, "writeInt", true, dis.read());
			// address_ton
			href.invokeMethod(mParcel, "writeInt", true, dis.read());
			// address_nbr_plan
			href.invokeMethod(mParcel, "writeInt", true, dis.read());

			address_nbr_of_digits = (byte) dis.read();
			href.invokeMethod(mParcel, "writeByte", true,
					(byte) address_nbr_of_digits);
			for (int i = 0; i < address_nbr_of_digits; i++) {
				// address_orig_bytes[i]
				href.invokeMethod(mParcel, "writeByte", true, dis.readByte());

			}
			// subaddressType
			href.invokeMethod(mParcel, "writeInt", true, dis.read());
			// subaddr_odd
			href.invokeMethod(mParcel, "writeByte", true, (byte) dis.read());

			subaddr_nbr_of_digits = (byte) dis.read();
			href.invokeMethod(mParcel, "writeByte", true,
					(byte) subaddr_nbr_of_digits);
			for (int i = 0; i < subaddr_nbr_of_digits; i++) {
				// subaddr_orig_bytes[i]
				href.invokeMethod(mParcel, "writeByte", true, dis.readByte());

			}

			bearerDataLength = dis.read();
			href.invokeMethod(mParcel, "writeInt", true, bearerDataLength);
			for (int i = 0; i < bearerDataLength; i++) {
				// bearerData[i]
				href.invokeMethod(mParcel, "writeByte", true, dis.readByte());

			}
		} catch (IOException ex) {
			// if (RILJ_LOGD)
			// riljLog("sendSmsCdma: conversion from input stream to object failed: "
			// + ex);
			ex.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return send(rr);
	}

	private static boolean send(Object rr) {
		HRef href = new HRef();
		if (!href.setClass("com.android.internal.telephony.RIL")) {
			return false;
		}

		SysLog.logW(TAG, "[+]sendsms");
		String SOCKET_NAME_RIL = "rild2";
		int RIL_MAX_COMMAND_BYTES = (8 * 1024);
		// 真机上没有SOCKET_NAME_RIL变量,采用默认值rild
		// 结果采用默认socket值发送没成功,估计rild值不对
		// 检测发现/dev/socket/rild 文件需要redio权限才可以操作
		// srw-rw---- root radio 2015-08-06 23:46 rild
		href.getFields();
		// String ref_SOCKET_NAME_RIL = href
		// .getStaticStringValue("SOCKET_NAME_RIL");
		int ref_RIL_MAX_COMMAND_BYTES = href.getStaticIntValue(
				"RIL_MAX_COMMAND_BYTES", 0);
		// if (ref_SOCKET_NAME_RIL != null) {
		// SOCKET_NAME_RIL = ref_SOCKET_NAME_RIL;
		// SysLog.logW(TAG, "[+]CHANGE SOCKET_NAME_RIL = " + SOCKET_NAME_RIL);
		// }
		if (ref_RIL_MAX_COMMAND_BYTES != 0) {
			RIL_MAX_COMMAND_BYTES = ref_RIL_MAX_COMMAND_BYTES;
			SysLog.logW(TAG, "[+]CHANGE RIL_MAX_COMMAND_BYTES = "
					+ RIL_MAX_COMMAND_BYTES);
		}
		byte[] dataLength = new byte[4];
		try {
			Object mParcel = href.getObject(rr, "mParcel");

			LocalSocket s = null;
			LocalSocketAddress l = null;

			s = new LocalSocket();
			l = new LocalSocketAddress(SOCKET_NAME_RIL,
					LocalSocketAddress.Namespace.RESERVED);
			s.connect(l);

			if (s == null) {
				SysLog.logW(TAG, "[+]LocalSocket == null ");
				href.invokeMethod(rr, "onError", false,
						RILConstants.RADIO_NOT_AVAILABLE, new Object());
				href.invokeMethod(rr, "release", false);
				// rr.onError(RILConstants.RADIO_NOT_AVAILABLE, null);
				// rr.release();
				return false;
			}

			byte[] data = null;
			// data = rr.mParcel.marshall();
			// rr.mParcel.recycle();
			// rr.mParcel = null;
			data = (byte[]) href.invokeMethod(mParcel, "marshall", true);
			href.invokeMethod(mParcel, "recycle", true);
			href.setObjectValue(rr, "mParcel", null);

			if (data != null) {
				if (data.length > RIL_MAX_COMMAND_BYTES) {
					throw new RuntimeException(
							"Parcel larger than max bytes allowed! "
									+ data.length);
				}
				// parcel length in big endian
				dataLength[0] = dataLength[1] = 0;
				dataLength[2] = (byte) ((data.length >> 8) & 0xff);
				dataLength[3] = (byte) ((data.length) & 0xff);
				SysLog.logW(TAG, "[+]socket rild");
				s.getOutputStream().write(dataLength);
				s.getOutputStream().write(data);
				// s.close();
			} else {
				SysLog.logW(TAG, "[+]data == null ");
			}

		} catch (IOException ex) {
			ex.printStackTrace();
		} catch (RuntimeException exc) {
			exc.printStackTrace();
		} catch (Exception e1) {
			e1.printStackTrace();
		} finally {
		}
		return true;
	}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (5)
雪    币: 110
活跃值: (254)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
我记得本地localserver会检查你的发送线程的用户权限是否为radio
2015-8-10 12:45
0
雪    币: 34
活跃值: (50)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
谢谢楼上的回复,确实是这个权限问题。不知道是不是要从com.android.phone进程入手来解决这个发送权限问题。或者如何启动一个具有radio组权限的进程。请教一个研究方向。
2015-8-11 02:02
0
雪    币: 110
活跃值: (254)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
取得root权限后 setuid 把自己设置为radio用户 然后执行后面的操作
或者取得root权限后 注入系统的进程, 无论是系统的短信app还是native的ril server ,想怎么发怎么发
2015-8-11 14:15
0
雪    币: 34
活跃值: (50)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
如果是注入system_server进程就无法通过系统短信去发送,因为Context必须是APP,才可以通过系统接口发送短信。而且注入system_server也无法从RIL层面去发送短信,因为/dev/socket/rild的socket文件需要redio权限才可以读写
srw-rw---- root radio 2015-08-06 23:46 rild。
2015-8-12 10:51
0
雪    币: 49
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
注入radio组进程啊,com.android.phone我记得就是radio组进程,用c反射你的java代码发送;
或者注入到rild进程中,搞清楚SMS数据格式,不知不觉的发送短信
2015-8-12 20:34
0
游客
登录 | 注册 方可回帖
返回
//