I need to make "Hello world" app for Xposed. I tried to change IMEI by Xposed. Some methods it hooked, some not. The question is how to hook them all?
I made test app that takes IMEI from TelephonyManager
and shows it:
telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
tv.setText(telephonyManager.getDeviceId());
Than I write method to replace the method:
private void replaceImei(final XC_LoadPackage.LoadPackageParam loadPackageParam,
final String className,
final String methodName)
{
try {
XC_MethodHook.Unhook u =
XposedHelpers.findAndHookMethod(
className,
loadPackageParam.classLoader,
methodName,
new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable {
XposedBridge.log("happy replaced " + methodHookParam.method.getName()
+ " at " + methodHookParam.method.getDeclaringClass().getName());
return "123456789012345";
}
}
);
if (u != null) {
XposedBridge.log("happy hooked " + u.getHookedMethod().getName() + " "
+ u.getHookedMethod().getDeclaringClass().getCanonicalName());
}
} catch (Exception e) {
XposedBridge.log("happy error " + e.getMessage());
e.printStackTrace();
}
}
And used it:
@Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
XposedBridge.log("happy loaded app: " + loadPackageParam.packageName);
replaceImei(loadPackageParam,
"android.telephony.TelephonyManager",
"getDeviceId");
}
It works!
But when I look at IMEI at the Settings
app, it is unchanged. Ok, I took APK of the Settings
app, extracted sources by apktool
and found the following:
.line 86
const-string v1, "imei"
invoke-interface {v0}, Lcom/android/internal/telephony/Phone;->getImei()Ljava/lang/String;
move-result-object v2
invoke-direct {p0, v1, v2}, Lcom/android/settings/deviceinfo/ImeiInformation;->setSummaryText(Ljava/lang/String;Ljava/lang/String;)V
So, it uses getImei()
method from the com.android.internal.telephony.Phone
interface. Because it's impossible to hook methods of interface, I found in sources all implementations of this interface:
replaceImei(loadPackageParam,
"com.android.internal.telephony.PhoneProxy",
"getImei");
replaceImei(loadPackageParam,
"com.android.internal.telephony.PhoneBase",
"getImei");
replaceImei(loadPackageParam,
"com.android.internal.telephony.gsm.GSMPhone",
"getImei");
replaceImei(loadPackageParam,
"com.android.internal.telephony.imsphone.ImsPhone",
"getImei");
replaceImei(loadPackageParam,
"com.android.internal.telephony.cdma.CDMAPhone",
"getImei");
Logs has record that getImea()
in PhoneProxy
in the Settings app was hooked (look at the sources above):
I/Xposed ( 6800): happy loaded app: com.android.settings
I/Xposed ( 6800): happy hooked getDeviceId android.telephony.TelephonyManager
I/Xposed ( 6800): happy hooked getImei com.android.internal.telephony.PhoneProxy
But nothing happens, IMEI in Settings was unchanged. Of course, I installed the app and rebooted the phone every iteration.
Ok, I tried to bruteforce this task: I found some other methods and hooked them also. But it doesn't help.
replaceImei(loadPackageParam,
"com.android.internal.telephony.gsm.GSMPhone",
"getPhoneId");
replaceImei(loadPackageParam,
"com.android.internal.telephony.imsphone.ImsPhone",
"getPhoneId");
replaceImei(loadPackageParam,
"com.android.internal.telephony.cdma.CDMAPhone",
"getPhoneId");
replaceImei(loadPackageParam,
"com.android.internal.telephony.PhoneSubInfoController",
"getDeviceId");
replaceImei(loadPackageParam,
"com.android.internal.telephony.PhoneSubInfoController",
"getImeiForSubscriber");
replaceImei(loadPackageParam,
"com.android.internal.telephony.PhoneSubInfoController",
"getDeviceIdForPhone");
replaceImei(loadPackageParam,
"com.android.internal.telephony.PhoneSubInfo",
"getDeviceId");
replaceImei(loadPackageParam,
"com.android.internal.telephony.PhoneSubInfo",
"getImei");
replaceImei(loadPackageParam,
"com.android.internal.telephony.PhoneSubInfoProxy",
"getImeiForSubscriber");
replaceImei(loadPackageParam,
"com.android.internal.telephony.PhoneSubInfoProxy",
"getImei");
replaceImei(loadPackageParam,
"com.android.internal.telephony.PhoneBase",
"getPhoneId");
Is there any ideas? What wrong? And what to do?
All experiments was on Nexus 4 with Android 5.1.1.
The full source from this question is here: https://gist.github.com/tseglevskiy/d100898468b286e1fff214778c9609b3
Update 1
Next part of the experiment. I found that it is possible to hook some methods on early stage of the Zygote by implementing the IXposedHookZygoteInit
interface. Ok, I did it:
private void replaceImeiInitZygote(final String className,
final String methodName)
{
try {
final Class<?> foundClass = XposedHelpers.findClass(className, null);
if (foundClass != null) {
XC_MethodHook.Unhook u = XposedHelpers.findAndHookMethod(foundClass, methodName,
new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable {
XposedBridge.log("happy replaced " + methodHookParam.method.getName()
+ " at " + methodHookParam.method.getDeclaringClass().getName());
return "123456789099999";
}
});
if (u != null) {
XposedBridge.log("happy hooked from initZygote " + u.getHookedMethod().getName() + " "
+ u.getHookedMethod().getDeclaringClass().getCanonicalName());
}
}
} catch (Exception e) {
XposedBridge.log("happy error " + e.getMessage());
e.printStackTrace();
}
}
And used it:
@Override
public void initZygote(StartupParam startupParam) throws Throwable {
replaceImeiInitZygote(
"android.telephony.TelephonyManager",
"getDeviceId");
replaceImeiInitZygote(
"com.android.internal.telephony.PhoneProxy",
"getImei");
replaceImeiInitZygote(
"com.android.internal.telephony.PhoneBase",
"getImei");
replaceImeiInitZygote(
"com.android.internal.telephony.gsm.GSMPhone",
"getImei");
replaceImeiInitZygote(
"com.android.internal.telephony.imsphone.ImsPhone",
"getImei");
replaceImeiInitZygote(
"com.android.internal.telephony.cdma.CDMAPhone",
"getImei");
}
By logs it hooks a few methods:
I/Xposed ( 198): happy hooked from initZygote getDeviceId android.telephony.TelephonyManager
I/Xposed ( 198): happy hooked from initZygote getImei com.android.internal.telephony.PhoneProxy
But id doesn't change IMEI in the Settings app also. What's wrong?
Well, you almost did it! You trying to hook getImei(), but actually it is never invoked by system. Use getDeviceId() instead, it returns the same data.
To change IMEI in settings try out this snippet, it works like a charm:
findAndHookMethod(
"com.android.internal.telephony.gsm.GSMPhone",
lpparam.classLoader,
"getDeviceId",
new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("NEW IMEI!!! com.android.internal.telephony.gsm.GSMPhone.getDeviceId()");
return "111111111111111";
}
}
);
By the way, you can hook these methods too:
com.android.internal.telephony.PhoneSubInfo.getDeviceId()
com.android.internal.telephony.gsm.GSMPhone.getDeviceId()
com.android.internal.telephony.cdma.CDMAPhone.getDeviceId()
com.android.internal.telephony.imsphone.ImsPhone.getDeviceId()
com.android.internal.telephony.sip.SipPhone.getDeviceId()
Cheers!