xposed-frameworkxposed

Xposed doesn't hook the method


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?


Solution

  • 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!