Skip to content

Commit

Permalink
Merge pull request #43 from tiann/master
Browse files Browse the repository at this point in the history
FEAT:支持提前生成配置,避免第一次打开的时候解析类导致黑屏。
  • Loading branch information
firesunCN authored Jan 2, 2019
2 parents 45cec3d + 09a5dd3 commit 1f3ccef
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,31 @@
import android.annotation.TargetApi;
import android.app.Application;
import android.app.FragmentManager;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceFragment;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;

import com.google.gson.Gson;

import java.lang.reflect.Method;

import dalvik.system.PathClassLoader;
import me.firesun.wechat.enhancement.util.HookParams;
import me.firesun.wechat.enhancement.util.SearchClasses;


public class SettingsActivity extends AppCompatActivity {
Expand Down Expand Up @@ -93,6 +101,61 @@ public boolean onPreferenceClick(Preference pref) {
return true;
}
});

Preference generate = findPreference("generate");
generate.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference pref) {
final Context context = getApplication();
if (context == null) {
return false;
}
final PackageManager packageManager = context.getPackageManager();
if (packageManager == null) {
return false;
}

final ProgressDialog dialog = new ProgressDialog(getActivity());
dialog.setCancelable(false);
dialog.setMessage(getResources().getString(R.string.generating));
dialog.show();

new Thread(new Runnable() {
@Override
public void run() {
boolean success = false;
try {
PackageInfo packageInfo = packageManager.getPackageInfo(HookParams.WECHAT_PACKAGE_NAME, 0);
String wechatApk = packageInfo.applicationInfo.sourceDir;
PathClassLoader wxClassLoader = new PathClassLoader(wechatApk, ClassLoader.getSystemClassLoader());
SearchClasses.generateConfig(wechatApk, wxClassLoader, packageInfo.versionName);

String config = new Gson().toJson(HookParams.getInstance());
SharedPreferences.Editor editor = context.getSharedPreferences(HookParams.WECHAT_ENHANCEMENT_CONFIG_NAME, Context.MODE_WORLD_READABLE).edit();
editor.clear();
editor.putString("params", config);
editor.commit();

success = true;

} catch (Throwable e) {
e.printStackTrace();
}

final String msg = getResources().getString(success ? R.string.generate_success : R.string.generate_failed);
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
dialog.dismiss();
Toast.makeText(getApplication(), msg, Toast.LENGTH_SHORT).show();
}
});
}
}, "generate-config").start();

return true;
}
});
}

private Application getApplication() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,55 @@
package me.firesun.wechat.enhancement.util;


import android.util.Log;

import net.dongliu.apk.parser.bean.DexClass;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import de.robv.android.xposed.XposedHelpers;

import static de.robv.android.xposed.XposedBridge.log;
import de.robv.android.xposed.XposedBridge;

public final class ReflectionUtil {

private static final Map classesCache = new HashMap();

private static boolean xposedExist;

static {
try {
Class.forName("de.robv.android.xposed.XposedBridge");
xposedExist = true;
} catch (ClassNotFoundException e) {
xposedExist = false;
}
}

public static void log(String msg) {
if (msg == null) {
return;
}

if (xposedExist) {
XposedBridge.log(msg);
} else {
Log.i("Xposed", "[WechatEnhancement] " + msg);
}
}

public static Method findMethodsByExactParameters(Class clazz, Class returnType, Class... parameterTypes) {
if (clazz == null) {
return null;
}

List<Method> list = Arrays.asList(XposedHelpers.findMethodsByExactParameters(clazz, returnType, (Class[]) Arrays.copyOf(parameterTypes, parameterTypes.length)));
// List<Method> list = Arrays.asList(XposedHelpers.findMethodsByExactParameters(clazz, returnType, (Class[]) Arrays.copyOf(parameterTypes, parameterTypes.length)));
List<Method> list = Arrays.asList(findMethodsByExactParametersInner(clazz, returnType, (Class[]) Arrays.copyOf(parameterTypes, parameterTypes.length)));
if (list.isEmpty())
return null;
else if (list.size() > 1) {
Expand Down Expand Up @@ -74,10 +99,79 @@ public static Classes findClassesFromPackage(ClassLoader loader, List<String> cl
return cs;
}

private static Map<String, Method> methodCache = new HashMap<>();

private static String getParametersString(Class<?>... clazzes) {
StringBuilder sb = new StringBuilder("(");
boolean first = true;
for (Class<?> clazz : clazzes) {
if (first)
first = false;
else
sb.append(",");

if (clazz != null)
sb.append(clazz.getCanonicalName());
else
sb.append("null");
}
sb.append(")");
return sb.toString();
}

public static Method findMethodExact(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
String fullMethodName = clazz.getName() + '#' + methodName + getParametersString(parameterTypes) + "#exact";

if (methodCache.containsKey(fullMethodName)) {
Method method = methodCache.get(fullMethodName);
if (method == null)
throw new NoSuchMethodError(fullMethodName);
return method;
}

try {
Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
method.setAccessible(true);
methodCache.put(fullMethodName, method);
return method;
} catch (NoSuchMethodException e) {
methodCache.put(fullMethodName, null);
throw new NoSuchMethodError(fullMethodName);
}
}

public static Method[] findMethodsByExactParametersInner(Class<?> clazz, Class<?> returnType, Class<?>... parameterTypes) {
List<Method> result = new LinkedList<>();
for (Method method : clazz.getDeclaredMethods()) {
if (returnType != null && returnType != method.getReturnType())
continue;

Class<?>[] methodParameterTypes = method.getParameterTypes();
if (parameterTypes.length != methodParameterTypes.length)
continue;

boolean match = true;
for (int i = 0; i < parameterTypes.length; i++) {
if (parameterTypes[i] != methodParameterTypes[i]) {
match = false;
break;
}
}

if (!match)
continue;

method.setAccessible(true);
result.add(method);
}
return result.toArray(new Method[result.size()]);
}

public static final Method findMethodExactIfExists(Class clazz, String methodName, Class... parameterTypes) {
Method method = null;
try {
method = XposedHelpers.findMethodExact(clazz, methodName, (Class[]) Arrays.copyOf(parameterTypes, parameterTypes.length));
// method = XposedHelpers.findMethodExact(clazz, methodName, (Class[]) Arrays.copyOf(parameterTypes, parameterTypes.length));
method = findMethodExact(clazz, methodName, (Class[]) Arrays.copyOf(parameterTypes, parameterTypes.length));
} catch (Error | Exception e) {
}
return method;
Expand All @@ -86,7 +180,7 @@ public static final Method findMethodExactIfExists(Class clazz, String methodNam
public static final Class findClassIfExists(String className, ClassLoader classLoader) {
Class c = null;
try {
c = XposedHelpers.findClass(className, classLoader);
c = Class.forName(className, false, classLoader);
} catch (Error | Exception e) {
}
return c;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,26 @@
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import me.firesun.wechat.enhancement.Main;

import static de.robv.android.xposed.XposedBridge.log;
import static me.firesun.wechat.enhancement.util.ReflectionUtil.log;

public class SearchClasses {
private static List<String> wxClasses = new ArrayList<>();
private static XSharedPreferences preferencesInstance = null;

public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam, String versionName) {
public static void init(Context context, XC_LoadPackage.LoadPackageParam lparam, String versionName) {

if (loadConfig(lpparam, versionName))
if (loadConfig(lparam, versionName))
return;

log("failed to load config, start finding...");

generateConfig(lparam.appInfo.sourceDir, lparam.classLoader, versionName);

saveConfig(context);
}

public static void generateConfig(String wechatApk, ClassLoader classLoader, String versionName) {

HookParams hp = HookParams.getInstance();
hp.versionName = versionName;
hp.versionCode = HookParams.VERSION_CODE;
Expand All @@ -49,8 +57,11 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam

ApkFile apkFile = null;
try {
apkFile = new ApkFile(lpparam.appInfo.sourceDir);
apkFile = new ApkFile(wechatApk);
DexClass[] dexClasses = apkFile.getDexClasses();

wxClasses.clear();

for (int i = 0; i < dexClasses.length; i++) {
wxClasses.add(ReflectionUtil.getClassName(dexClasses[i]));
}
Expand All @@ -66,14 +77,14 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam

//LuckMoney
try {
Class ReceiveUIParamNameClass = ReflectionUtil.findClassesFromPackage(lpparam.classLoader, wxClasses, "com.tencent.mm", 1)
Class ReceiveUIParamNameClass = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm", 1)
.filterByMethod(String.class, "getInfo")
.filterByMethod(int.class, "getType")
.filterByMethod(void.class, "reset")
.firstOrNull();
hp.ReceiveUIParamNameClassName = ReceiveUIParamNameClass.getName();

Class RequestCallerClass = ReflectionUtil.findClassesFromPackage(lpparam.classLoader, wxClasses, "com.tencent.mm", 1)
Class RequestCallerClass = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm", 1)
.filterByField("foreground", "boolean")
.filterByMethod(void.class, int.class, String.class, int.class, boolean.class)
.filterByMethod(void.class, "cancel", int.class)
Expand All @@ -85,7 +96,7 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam
void.class, RequestCallerClass, int.class)
.getName();

Class NetworkRequestClass = ReflectionUtil.findClassesFromPackage(lpparam.classLoader, wxClasses, "com.tencent.mm", 1)
Class NetworkRequestClass = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm", 1)
.filterByMethod(void.class, "unhold")
.filterByMethod(RequestCallerClass)
.firstOrNull();
Expand All @@ -95,7 +106,7 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam
RequestCallerClass)
.getName();

Class ReceiveLuckyMoneyRequestClass = ReflectionUtil.findClassesFromPackage(lpparam.classLoader, wxClasses, "com.tencent.mm.plugin.luckymoney", 1)
Class ReceiveLuckyMoneyRequestClass = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm.plugin.luckymoney", 1)
.filterByField("msgType", "int")
.filterByMethod(void.class, int.class, String.class, JSONObject.class)
.firstOrNull();
Expand All @@ -105,15 +116,15 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam
void.class, int.class, String.class, JSONObject.class)
.getName();

hp.LuckyMoneyRequestClassName = ReflectionUtil.findClassesFromPackage(lpparam.classLoader, wxClasses, "com.tencent.mm.plugin.luckymoney", 1)
hp.LuckyMoneyRequestClassName = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm.plugin.luckymoney", 1)
.filterByField("talker", "java.lang.String")
.filterByMethod(void.class, int.class, String.class, JSONObject.class)
.filterByMethod(int.class, "getType")
.filterByNoMethod(boolean.class)
.firstOrNull()
.getName();

hp.GetTransferRequestClassName = ReflectionUtil.findClassesFromPackage(lpparam.classLoader, wxClasses, "com.tencent.mm.plugin.remittance", 1)
hp.GetTransferRequestClassName = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm.plugin.remittance", 1)
.filterByField("java.lang.String")
.filterByNoField("int")

Expand All @@ -122,7 +133,7 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam
.firstOrNull()
.getName();

Class LuckyMoneyReceiveUIClass = XposedHelpers.findClass(hp.LuckyMoneyReceiveUIClassName, lpparam.classLoader);
Class LuckyMoneyReceiveUIClass = ReflectionUtil.findClassIfExists(hp.LuckyMoneyReceiveUIClassName, classLoader);
hp.ReceiveUIMethod = ReflectionUtil.findMethodsByExactParameters(LuckyMoneyReceiveUIClass,
boolean.class, int.class, int.class, String.class, ReceiveUIParamNameClass)
.getName();
Expand All @@ -134,7 +145,7 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam

//ADBlock
try {
Class XMLParserClass = ReflectionUtil.findClassesFromPackage(lpparam.classLoader, wxClasses, "com.tencent.mm.sdk.platformtools", 0)
Class XMLParserClass = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm.sdk.platformtools", 0)
.filterByMethod(Map.class, String.class, String.class)
.firstOrNull();
hp.XMLParserClassName = XMLParserClass.getName();
Expand All @@ -148,7 +159,7 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam

//AntiRevoke
try {
ReflectionUtil.Classes storageClasses = ReflectionUtil.findClassesFromPackage(lpparam.classLoader, wxClasses, "com.tencent.mm.storage", 0);
ReflectionUtil.Classes storageClasses = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm.storage", 0);
Class MsgInfoClass = storageClasses
.filterByMethod(boolean.class, "isSystem")
.firstOrNull();
Expand All @@ -175,12 +186,12 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam

//Photo Limits
try {
Class SelectConversationUIClass = XposedHelpers.findClass(hp.SelectConversationUIClassName, lpparam.classLoader);
Class SelectConversationUIClass = XposedHelpers.findClass(hp.SelectConversationUIClassName, classLoader);
hp.SelectConversationUICheckLimitMethod = ReflectionUtil.findMethodsByExactParameters(SelectConversationUIClass,
boolean.class, boolean.class)
.getName();

hp.ContactInfoClassName = ReflectionUtil.findClassesFromPackage(lpparam.classLoader, wxClasses, "com.tencent.mm.storage", 0)
hp.ContactInfoClassName = ReflectionUtil.findClassesFromPackage(classLoader, wxClasses, "com.tencent.mm.storage", 0)
.filterByMethod(String.class, "getCityCode")
.filterByMethod(String.class, "getCountryCode")
.firstOrNull()
Expand All @@ -189,8 +200,6 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam
} catch (Error | Exception e) {
log("Search Photo Limits Classes Failed!");
}

saveConfig(context);
}

private static int getVersionNum(String version) {
Expand Down
Loading

0 comments on commit 1f3ccef

Please sign in to comment.