导航菜单

页面标题

页面副标题

万能钥匙 v1.1.23 - Phantom.java 源代码

正在查看: 万能钥匙 v1.1.23 应用的 Phantom.java JAVA 源代码文件

本页面展示 JAVA 反编译生成的源代码文件,支持语法高亮显示。 仅供安全研究与技术分析使用,严禁用于任何非法用途。请遵守相关法律法规。


package com.wifitutu.aab;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import com.google.android.inner_exoplayer2.metadata.id3.InternalFrame;
import com.google.gson.reflect.TypeToken;
import com.sdk.plus.data.manager.RalDataManager;
import com.wifitutu.aab.InterceptConfig;
import com.wifitutu.aab.Pine;
import com.wifitutu.aab.PineConfig;
import com.wifitutu.aab.callback.MethodHook;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

public class Phantom {
    protected static final String EXTRA_BYPASS = "phantom_bypass_market_check";
    private static int InterceptionType = 0;
    private static final long REPORT_INTERVAL = 1000;
    private static volatile Context appContext = null;
    private static Bundle extraBundle = null;
    private static volatile String lastFingerprint = "";
    private static volatile long lastReportTime;
    private static Context originalContext;
    private static Intent pendingIntent;
    private static final Object lock = new Object();
    private static final Map<String, Map<String, Boolean>> reportConfigCache = new ConcurrentHashMap();
    private static final Map<String, Boolean> defaultReportConfig = new HashMap<String, Boolean>() {
        {
            Boolean bool = Boolean.FALSE;
            put("stack", bool);
            put("no_block", bool);
        }
    };
    private static final Map<Uri, String> QUICKAPP_PKG_CACHE = new ConcurrentHashMap();

    public Phantom(Context context, PineConfig.ConfigProvider configProvider) {
        if (context == null) {
            throw new IllegalArgumentException("Context cannot be null");
        }
        synchronized (lock) {
            try {
                if (appContext == null) {
                    Context applicationContext = context.getApplicationContext();
                    if (applicationContext == null) {
                        throw new IllegalStateException("Cannot obtain Application Context");
                    }
                    appContext = applicationContext;
                    IntentHook();
                    configProvider.onInitialized(true);
                } else {
                    Log.w("Phantom", "SDK already initialized");
                    configProvider.onInitialized(false);
                }
            } catch (Throwable th) {
                throw th;
            }
        }
    }

    private static void IntentHook() {
        try {
            Class[] clsArr = {Activity.class, ContextWrapper.class, Class.forName("android.app.ContextImpl")};
            for (int i = 0; i < 3; i++) {
                hookMethod(clsArr[i], "startActivity", Intent.class, Bundle.class);
            }
        } catch (Exception e) {
            LogUtil.e("Hook初始化失败", e);
        }
    }

    private static String abbreviate(String str) {
        if (str == null) {
            return "null";
        }
        if (str.length() <= 15) {
            return str;
        }
        return str.substring(0, 12) + "...";
    }

    private static String abbreviate(String str, int i) {
        if (str.length() <= i) {
            return str;
        }
        return str.substring(0, i - 3) + "...";
    }

    private static HashMap<String, String> buildIntentInfo(Intent intent, boolean z, String str) {
        HashMap<String, String> hashMap = new HashMap<>();
        if (str != null) {
            hashMap.put("scene", str);
        }
        int i = InterceptionType;
        if (i == 1) {
            hashMap.put(RalDataManager.DB_TYPE, "appstore");
        } else if (i == 2) {
            hashMap.put(RalDataManager.DB_TYPE, "quickapp");
        } else if (i == 3) {
            hashMap.put(RalDataManager.DB_TYPE, "otherapp");
        }
        hashMap.put("intent_url", intent.toUri(4));
        if (z) {
            hashMap.put("stack", getStack());
        }
        return hashMap;
    }

    private static String buildMethodSignature(Method method) {
        StringBuilder sb = new StringBuilder();
        sb.append(method.getDeclaringClass().getSimpleName());
        sb.append("#");
        sb.append(method.getName());
        sb.append("(");
        Class<?>[] parameterTypes = method.getParameterTypes();
        for (int i = 0; i < parameterTypes.length; i++) {
            if (i > 0) {
                sb.append(", ");
            }
            sb.append(parameterTypes[i].getSimpleName());
        }
        sb.append(")");
        return sb.toString();
    }

    private static Intent createDialogIntent(Context context, HashMap<String, String> hashMap) {
        return new Intent(context, (Class<?>) DialogActivity.class).putExtra(DialogActivity.INTENT_MAP, hashMap).addFlags(343932928);
    }

    private static MethodHook createHook(final String str) {
        return new MethodHook() {
            @Override
            public void beforeCall(Pine.CallFrame callFrame) {
                String str2;
                Intent intentFromArgs = Phantom.getIntentFromArgs(callFrame.args);
                LogUtil.e("createHook  " + str + ":" + intentFromArgs + "|fullUri=" + intentFromArgs.toUri(4));
                if (intentFromArgs.getBooleanExtra(Phantom.EXTRA_BYPASS, false)) {
                    LogUtil.d("Phantom", "检测到绕过标记,不拦截");
                    return;
                }
                PineConfig.ConfigProvider configProvider = PineConfig.configProvider;
                if (configProvider == null) {
                    LogUtil.e("未初始化ConfigProvider");
                    return;
                }
                String uri = intentFromArgs.toUri(4);
                boolean isMarketIntent = Phantom.isMarketIntent(configProvider.getMarketPattern(), uri);
                boolean isQuickAppIntent = Phantom.isQuickAppIntent(configProvider.getQuickappPattern(), uri);
                boolean isOtherAppIntent = Phantom.isOtherAppIntent(configProvider.getAppPattern(), uri);
                if (isMarketIntent || isQuickAppIntent || isOtherAppIntent) {
                    if (isMarketIntent) {
                        int unused = Phantom.InterceptionType = 1;
                        str2 = "应用商店";
                    } else if (isQuickAppIntent) {
                        int unused2 = Phantom.InterceptionType = 2;
                        str2 = "快应用";
                    } else {
                        int unused3 = Phantom.InterceptionType = 3;
                        str2 = "其他应用";
                    }
                    LogUtil.d("拦截到" + str2 + "跳转: " + intentFromArgs);
                    Bundle bundle = Phantom.getBundle(callFrame.args);
                    StringBuilder sb = new StringBuilder();
                    sb.append("Hit-isApp:\nURI: ");
                    sb.append(intentFromArgs.toUri(4));
                    sb.append("\nFlags: 0x");
                    sb.append(Integer.toHexString(intentFromArgs.getFlags()));
                    sb.append("\nPackage: ");
                    sb.append(intentFromArgs.getPackage());
                    sb.append("\nComponent: ");
                    sb.append(intentFromArgs.getComponent());
                    sb.append("\nExtras: ");
                    sb.append(bundle != null ? bundle.toString() : "null");
                    LogUtil.d(sb.toString());
                    if (Phantom.InterceptionType == 3) {
                        Phantom.processRuleGroups(InterceptConfig.parse(configProvider.getOtherapp(), InterceptConfig.ConfigType.OTHER_APP_CONFIG), intentFromArgs, callFrame, configProvider);
                    } else {
                        Phantom.processRuleGroups(InterceptConfig.parse(configProvider.getConfig(), InterceptConfig.ConfigType.MAIN_CONFIG), intentFromArgs, callFrame, configProvider);
                    }
                }
            }
        };
    }

    private static String extractPackage(Intent intent) {
        if (intent == null) {
            return "";
        }
        String extractQuickAppPackage = extractQuickAppPackage(intent);
        if (!extractQuickAppPackage.isEmpty()) {
            return extractQuickAppPackage;
        }
        String extractPackageFromUri = extractPackageFromUri(intent);
        return !extractPackageFromUri.isEmpty() ? extractPackageFromUri : intent.getComponent() != null ? intent.getComponent().getPackageName() : intent.getPackage() != null ? intent.getPackage() : "";
    }

    private static String extractPackageFromUri(Intent intent) {
        Uri data;
        String queryParameter;
        return (intent == null || (data = intent.getData()) == null) ? "" : (!"market".equals(data.getScheme()) || (queryParameter = data.getQueryParameter("id")) == null) ? (!("https".equals(data.getScheme()) && "details".equals(data.getLastPathSegment())) && data.getQueryParameter("id") == null) ? "" : data.getQueryParameter("id") : queryParameter;
    }

    private static String extractQuickAppPackage(Intent intent) {
        Uri data = intent.getData();
        if (data == null) {
            return "";
        }
        Map<Uri, String> map = QUICKAPP_PKG_CACHE;
        String str = map.get(data);
        if (str != null) {
            return str;
        }
        List<String> pathSegments = data.getPathSegments();
        String str2 = pathSegments.size() > 0 ? pathSegments.get(0) : "";
        map.put(data, str2);
        return str2;
    }

    private static String generateLightweightFingerprint(Intent intent) {
        int i;
        String str = "0";
        String str2 = "";
        if (intent == null) {
            return "null|0";
        }
        try {
            if (intent.getDataString() != null) {
                str2 = intent.getDataString();
            }
        } catch (Exception e) {
            LogUtil.e("获取DataString异常", e);
        }
        try {
            ComponentName component = intent.getComponent();
            if (component != null) {
                str = String.valueOf(component.hashCode());
            }
        } catch (Exception e2) {
            LogUtil.e("获取Component异常", e2);
        }
        try {
            i = intent.getFlags();
        } catch (Exception e3) {
            LogUtil.e("获取Flags异常", e3);
            i = 0;
        }
        return str2.hashCode() + "|" + str + "|" + i;
    }

    public static Intent getAndClearPendingIntent() {
        Intent intent;
        synchronized (lock) {
            intent = pendingIntent;
            pendingIntent = null;
        }
        return intent;
    }

    public static Context getAppContext() {
        if (appContext == null) {
            synchronized (lock) {
                try {
                    if (appContext == null) {
                        throw new IllegalStateException("Must call initPhantom() first");
                    }
                } finally {
                }
            }
        }
        return appContext;
    }

    public static Context getAppContextSafe() {
        return appContext;
    }

    public static Bundle getBundle(Object[] objArr) {
        for (Object obj : objArr) {
            if (obj instanceof Bundle) {
                return (Bundle) obj;
            }
        }
        return null;
    }

    private static Context getContext(Pine.CallFrame callFrame) {
        Object obj = callFrame.thisObject;
        if (obj instanceof Context) {
            return (Context) obj;
        }
        for (Object obj2 : callFrame.args) {
            if (obj2 instanceof Context) {
                return (Context) obj2;
            }
        }
        return getAppContext();
    }

    public static synchronized Bundle getExtraBundle() {
        Bundle bundle;
        synchronized (Phantom.class) {
            bundle = extraBundle;
        }
        return bundle;
    }

    private static String getInputValue(String str, Intent intent) {
        String lowerCase = str.toLowerCase(Locale.US);
        lowerCase.getClass();
        switch (lowerCase) {
            case "sys_version":
                return String.valueOf(Build.VERSION.SDK_INT);
            case "package":
                return extractPackage(intent);
            case "model":
                String str2 = Build.MODEL;
                return str2 != null ? str2 : "";
            default:
                return "";
        }
    }

    private static String getInputValueApp(String str, Intent intent) {
        String lowerCase = str.toLowerCase(Locale.US);
        lowerCase.getClass();
        switch (lowerCase) {
            case "sys_version":
                return String.valueOf(Build.VERSION.SDK_INT);
            case "scheme":
                return intent.toUri(4);
            case "model":
                String str2 = Build.MODEL;
                return str2 != null ? str2 : "";
            default:
                return "";
        }
    }

    public static Intent getIntentFromArgs(Object[] objArr) {
        for (Object obj : objArr) {
            if (obj instanceof Intent) {
                return (Intent) obj;
            }
        }
        return null;
    }

    public static synchronized Context getOriginalContext() {
        Context context;
        synchronized (Phantom.class) {
            context = originalContext;
        }
        return context;
    }

    public static synchronized Intent getPendingIntent() {
        Intent intent;
        synchronized (Phantom.class) {
            intent = pendingIntent;
        }
        return intent;
    }

    private static String getStack() {
        StringBuilder sb = new StringBuilder();
        StackTraceElement[] stackTrace = new Throwable().getStackTrace();
        if (stackTrace != null) {
            int i = 0;
            for (StackTraceElement stackTraceElement : stackTrace) {
                String className = stackTraceElement.getClassName();
                if (!className.startsWith("java.") && !className.startsWith("android.") && !className.startsWith("sun.") && !className.startsWith("kotlin.") && !className.startsWith("com.wifitutu.aab")) {
                    sb.append(className);
                    sb.append(InternalFrame.ID);
                    sb.append(stackTraceElement.getFileName());
                    sb.append(InternalFrame.ID);
                    sb.append(stackTraceElement.getLineNumber());
                    sb.append(InternalFrame.ID);
                    sb.append(stackTraceElement.getMethodName());
                    sb.append("\n");
                    i++;
                    if (i >= 3) {
                        break;
                    }
                }
            }
        }
        if (sb.length() == 0) {
            sb.append("No relevant stack trace found.");
        }
        return sb.toString();
    }

    private static void handleAction(int i, Intent intent, Pine.CallFrame callFrame, boolean z, boolean z2) {
        if (i != 1) {
            if (i == 2) {
                LogUtil.w("handleAction 2: " + i);
                callFrame.setResult(null);
                PineConfig.configProvider.onInterception(buildIntentInfo(intent, z, "silent_block"));
                return;
            }
            if (i != 3) {
                LogUtil.w("未知动作类型: " + i);
                return;
            }
            LogUtil.w("handleAction 3: " + i);
            handleMarketJump(intent, callFrame, buildIntentInfo(intent, z, null));
            return;
        }
        LogUtil.d("handleAction=1:\nURI: " + intent.toUri(4) + "\nFlags: 0x" + Integer.toHexString(intent.getFlags()) + "\nPackage: " + intent.getPackage() + "\nComponent: " + intent.getComponent());
        if (z2) {
            String generateLightweightFingerprint = generateLightweightFingerprint(intent);
            long currentTimeMillis = System.currentTimeMillis();
            if (!Objects.equals(generateLightweightFingerprint, lastFingerprint) || currentTimeMillis - lastReportTime > 1000) {
                lastFingerprint = generateLightweightFingerprint;
                lastReportTime = currentTimeMillis;
                PineConfig.configProvider.onInterception(buildIntentInfo(intent, z, "no_block"));
            }
        }
    }

    private static void handleMarketJump(Intent intent, Pine.CallFrame callFrame, HashMap<String, String> hashMap) {
        setPendingInfo(new Intent(intent).setFlags(intent.getFlags()), getBundle(callFrame.args), getContext(callFrame));
        callFrame.args[0] = createDialogIntent(getContext(callFrame), hashMap);
    }

    private static void hookMethod(Class<?> cls, String str, Class<?>... clsArr) {
        try {
            Method declaredMethod = cls.getDeclaredMethod(str, clsArr);
            String buildMethodSignature = buildMethodSignature(declaredMethod);
            LogUtil.i(" 成功Hook方法: " + buildMethodSignature);
            Pine.hook(declaredMethod, createHook(buildMethodSignature));
        } catch (NoSuchMethodException e) {
            LogUtil.i(" Hook失败: " + e);
        }
    }

    public static boolean isMarketIntent(String str, String str2) {
        if (str != null && !str.isEmpty() && str2 != null) {
            try {
                return Pattern.compile(str).matcher(str2).find();
            } catch (PatternSyntaxException e) {
                LogUtil.e("应用商店正则格式错误: " + str, e);
            } catch (Exception e2) {
                LogUtil.e("应用商店检测异常", e2);
            }
        }
        return false;
    }

    public static boolean isOtherAppIntent(String str, String str2) {
        if (str != null && !str.isEmpty() && str2 != null) {
            try {
                return Pattern.compile(str).matcher(str2).find();
            } catch (PatternSyntaxException e) {
                LogUtil.e("跳转其他app正则格式错误: " + str, e);
            } catch (Exception e2) {
                LogUtil.e("跳转其他app检测异常", e2);
            }
        }
        return false;
    }

    public static boolean isQuickAppIntent(String str, String str2) {
        if (str != null && !str.isEmpty() && str2 != null) {
            try {
                return Pattern.compile(str).matcher(str2).find();
            } catch (PatternSyntaxException e) {
                LogUtil.e("快应用正则格式错误: " + str, e);
            } catch (Exception e2) {
                LogUtil.e("快应用检测异常", e2);
            }
        }
        return false;
    }

    private static boolean isQuickAppUri(Uri uri) {
        if (uri == null) {
            return false;
        }
        String scheme = uri.getScheme();
        return "hap".equalsIgnoreCase(scheme) || "quickapp".equalsIgnoreCase(scheme);
    }

    private static boolean isTargetSystemPackage(Intent intent) {
        return extractPackage(intent) != null;
    }

    private static boolean isValidThirdPartyScheme(String str) {
        return (str == null || str.length() < 3 || str.contains(".")) ? false : true;
    }

    private static boolean matchAllRules(List<InterceptConfig.Rule> list, Intent intent) {
        if (list == null || list.isEmpty()) {
            return false;
        }
        for (InterceptConfig.Rule rule : list) {
            if (!matchSingleRule(rule, intent)) {
                LogUtil.d("规则组匹配失败: " + rule.getType());
                return false;
            }
        }
        LogUtil.d("规则组全部匹配成功");
        return true;
    }

    private static boolean matchSingleRule(InterceptConfig.Rule rule, Intent intent) {
        if (rule == null || rule.getRule() == null || rule.getType() == null) {
            return false;
        }
        if (rule.getType().equals("dids")) {
            HashSet<String> didArr = rule.getDidArr();
            boolean z = didArr != null && didArr.contains(PineConfig.configProvider.getDid());
            LogUtil.d("规则检查 => dis is matched " + z);
            return z;
        }
        String inputValueApp = InterceptionType == 3 ? getInputValueApp(rule.getType(), intent) : getInputValue(rule.getType(), intent);
        String trim = rule.getRule().trim();
        try {
            LogUtil.d(String.format("规则检查 => 类型:%-8s 输入:%-15s 正则:%-20s", rule.getType(), abbreviate(inputValueApp), abbreviate(trim)));
            return Pattern.matches(trim, inputValueApp);
        } catch (Exception unused) {
            LogUtil.e("正则错误: " + trim);
            return false;
        }
    }

    private static Map<String, Boolean> parseReportConfig(String str) {
        if (str == null || str.isEmpty()) {
            return new HashMap(defaultReportConfig);
        }
        Map<String, Map<String, Boolean>> map = reportConfigCache;
        if (map.containsKey(str)) {
            LogUtil.d("命中report配置缓存");
            return new HashMap(map.get(str));
        }
        try {
            Map map2 = (Map) InterceptConfig.GSON_INSTANCE.fromJson(str, new TypeToken<Map<String, Boolean>>() {
            }.getType());
            HashMap hashMap = new HashMap(defaultReportConfig);
            if (map2 != null) {
                hashMap.putAll(map2);
            }
            map.put(str, new HashMap(hashMap));
            return hashMap;
        } catch (Exception e) {
            LogUtil.e("解析report配置失败", e);
            return new HashMap(defaultReportConfig);
        }
    }

    public static void processRuleGroups(List<InterceptConfig.RuleGroup> list, Intent intent, Pine.CallFrame callFrame, PineConfig.ConfigProvider configProvider) {
        if (list.isEmpty()) {
            LogUtil.w("无有效规则组");
            return;
        }
        Map<String, Boolean> parseReportConfig = parseReportConfig(configProvider.getReport());
        boolean booleanValue = parseReportConfig.get("no_block").booleanValue();
        boolean booleanValue2 = parseReportConfig.get("stack").booleanValue();
        for (InterceptConfig.RuleGroup ruleGroup : list) {
            if (matchAllRules(ruleGroup.getRules(), intent)) {
                handleAction(ruleGroup.getAction(), intent, callFrame, booleanValue2, booleanValue);
                return;
            }
        }
    }

    public static synchronized void setPendingInfo(Intent intent, Bundle bundle, Context context) {
        Intent intent2;
        synchronized (Phantom.class) {
            if (intent != null) {
                try {
                    intent2 = (Intent) intent.clone();
                } catch (Throwable th) {
                    throw th;
                }
            } else {
                intent2 = null;
            }
            pendingIntent = intent2;
            extraBundle = bundle != null ? new Bundle(bundle) : null;
            originalContext = context != null ? context.getApplicationContext() : null;
        }
    }
}