Closed Hovn closed 4 years ago
Awesome find and bug report! Looks like the subscription id code never actually worked (I never had a dual SIM phone with Xposed so I never tested it). As for the subId = phoneId+1, we should just call the same API that dispatchIntent uses, which looks like SubscriptionManager.putPhoneIdAndSubIdExtra.
感谢指正。解决方法只需在hook dispatchIntent() 时原样执行原方法中的SubscriptionManager.putPhoneIdAndSubIdExtra()语句就可以了,无需关注内部具体的执行逻辑。 我检查了L~P的InboundSmsHandler.java代码,此方法应该完全通用。
通过反射取得 phoneId mPhone.getPhoneId()
public int getPhoneIdByReflection(XC_MethodHook.MethodHookParam param) {
XposedBridge.log("class name:" + param.thisObject.getClass().getName());
try {
Field field = null ;
Class<?> clazz = param.thisObject.getClass() ;
for(; clazz != Object.class ; clazz = clazz.getSuperclass()) {
try {
field = clazz.getDeclaredField("mPhone") ;//Tip: mPhone 可能在父类中
break;
} catch (Exception e) {
//do nothing
}
}
field.setAccessible(true);
Object mPhone = field.get(param.thisObject);
Method method = Class.forName("com.android.internal.telephony.Phone").getDeclaredMethod("getPhoneId");
int phone_id = (Integer) method.invoke(mPhone);
return phone_id ;
}catch (Exception e){
Xlog.e(e.getMessage());
}
return -1;
}
通过反射执行方法 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
int phoneId = getPhoneIdByReflection(param);
//SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
try{
//Class<SubscriptionManager> c = SubscriptionManager.class;
Class<?> c = Class.forName("android.telephony.SubscriptionManager");
Method method = c.getMethod("putPhoneIdAndSubIdExtra",Intent.class,int.class);
method.setAccessible(true);
method.invoke(null, intent,phoneId);
}catch (Exception e){
XposedBridge.log(e);
}
以上代码,在我设备(7.1.1)上进行测试,它正常工作,subid也是期望值。 另外我检查了以下Android代码,方法应该是通用的。希望能帮上忙。 http://androidxref.com/9.0.0_r3/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/InboundSmsHandler.java http://androidxref.com/8.1.0_r33/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/InboundSmsHandler.java http://androidxref.com/8.0.0_r4/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/InboundSmsHandler.java http://androidxref.com/7.1.2_r36/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/InboundSmsHandler.java http://androidxref.com/7.1.1_r6/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/InboundSmsHandler.java http://androidxref.com/7.0.0_r1/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/InboundSmsHandler.java http://androidxref.com/6.0.1_r10/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/InboundSmsHandler.java http://androidxref.com/6.0.0_r5/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/InboundSmsHandler.java http://androidxref.com/6.0.0_r1/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/InboundSmsHandler.java http://androidxref.com/5.1.1_r6/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/InboundSmsHandler.java http://androidxref.com/5.1.0_r1/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/InboundSmsHandler.java http://androidxref.com/5.0.0_r2/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/InboundSmsHandler.java
A lot of that code can be simplified by using the XposedHelper APIs which takes care of the reflection :-)
Object phone = XposedHelpers.getObjectField(param.thisObject, "mPhone");
int phoneId = XposedHelpers.callMethod(phone, "getPhoneId");
XposedHelpers.callStaticMethod(SubscriptionManager.class, "putPhoneIdAndSubIdExtra", intent, phoneId);
奈斯,对xposed api不那么熟,原来XposedHelper可以帮我们简化很多反射的代码,知识又增加了 ~ ps. 我重新测试了新代码段,它工作正常,subid的值正常。期待修复并关闭它。 :-)
作者你好: 一直很喜欢您这个项目,帮助我拦截了大量的垃圾短信。
问题描述: 1、双SIM卡手机,某条发送给SIM2的短信被NekoSMS拦截后,对该条短信进行恢复,在默认短信APP显示是由SIM1进行接收的。 2、检查NekoSMS的数据库,发现 sub_id 全是 1,猜该字段用于标识接收的SIM卡,修改该字段=2后进行恢复测试,短信APP即显示SIM2接收。
问题原因: 基于对项目的喜爱及学习的态度,尝试对问题进行定位。查看项目代码和涉及的Android代码,以及自行编译测试后,对问题原因描述如下:
NekoSMS对
InboundSmsHandler.java
的dispatchIntent()
方法用beforeHookedMethod()
进行了拦截。拦截的入参有个intent
,而subid
是由方法体中代码(如下)赋值到intent
中的,SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
故拦截的intent
未能包含正确的subid
(因为subid赋值还未执行),而根据intent
获得的message的subid
也就不正确。后续再通过反射(Integer)ReflectionUtils.invoke(sGetSubId, message);
去取的subid也就不正确。关键点: 1、dispatchIntent()方法执行前已被拦截( beforeHookedMethod()) 2、分析7.1.1源码发现subid是在dispatchIntent()执行后才有的 Android源码:http://androidxref.com/7.1.1_r6/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/InboundSmsHandler.java#1023
修复方法(仅测试了本人手机,供参考): beforeHookedMethod()的时候就要对intent或message设置正确的subid。
phoneId=param.thisObject.mPhone.getPhoneId();
//通过反射获取,mPhone可能在父类中subId=phoneId+1; //实测得出,具体关系未知。
intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
intent.putExtra(PhoneConstants.PHONE_KEY, phoneId);
或message.setSubId(subId);
最后: 才疏学浅,以上还请开发者检查确认~
If you are submitting a bug report and do not include the following info, your issue will be ignored!
Please paste your Xposed logs (Xposed Installer -> Logs -> Menu -> Save to SD card) below:
Thank you for helping us help you help us all.