1

我需要为 Xposed 制作“Hello world”应用程序。我试图通过 Xposed 更改 IMEI。有些方法它迷上了,有些没有。问题是如何将它们全部钩住?

我制作了从 IMEI 中获取TelephonyManager并显示它的测试应用程序:

    telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
    tv.setText(telephonyManager.getDeviceId());

比我写方法来替换方法:

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();
    }
}

并使用它:

@Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {

    XposedBridge.log("happy loaded app: " + loadPackageParam.packageName);

    replaceImei(loadPackageParam,
            "android.telephony.TelephonyManager",
            "getDeviceId");
}

有用!

但是当我在应用程序中查看 IMEI 时Settings,它并没有改变。好的,我拿了Settings应用程序的 APK,提取了源代码apktool,发现以下内容:

.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

因此,它使用接口中getImei()的方法com.android.internal.telephony.Phone。因为不可能hook接口的方法,所以我在sources中找到了这个接口的所有实现:

    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");

日志记录了getImea()PhoneProxy设置应用程序中被钩住(查看上面的来源):

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

但是没有任何反应,设置中的 IMEI 没有改变。当然,我安装了应用程序并在每次迭代时都重新启动了手机。

好的,我尝试强制执行此任务:我找到了一些其他方法并将它们也钩住了。但这无济于事。

    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");

有什么想法吗?怎么了?怎么办?

所有实验均在装有 Android 5.1.1 的 Nexus 4 上进行。

这个问题的完整来源在这里:https ://gist.github.com/tseglevskiy/d100898468b286e1fff214778c9609b3

更新 1

实验的下一部分。IXposedHookZygoteInit我发现通过实现接口可以在Zygote的早期hook一些方法。好的,我做到了:

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();
    }
}

并使用它:

@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");

}

通过日志,它挂钩了一些方法:

I/Xposed  (  198): happy hooked from initZygote getDeviceId android.telephony.TelephonyManager
I/Xposed  (  198): happy hooked from initZygote getImei com.android.internal.telephony.PhoneProxy

但 id 也不会在“设置”应用中更改 IMEI。怎么了?

4

1 回答 1

1

好吧,你几乎做到了!您试图挂钩 getImei(),但实际上它从未被系统调用。请改用 getDeviceId(),它返回相同的数据。

要在设置中更改 IMEI,试试这个片段,它就像一个魅力:

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";
            }
        }
);

顺便说一句,您也可以挂钩这些方法:

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()

干杯!

于 2016-07-21T11:07:15.167 回答