Skip to content

Commit

Permalink
fix: 钱迹自动适配
Browse files Browse the repository at this point in the history
  • Loading branch information
ankio committed Aug 20, 2022
1 parent 581f1f3 commit 35dcc59
Show file tree
Hide file tree
Showing 11 changed files with 323 additions and 174 deletions.
3 changes: 3 additions & 0 deletions app/src/main/java/cn/dreamn/qianji_auto/app/QianJi.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ public void run() {
public void asyncDataBefore(Context context, int type) {
if (AppStatus.isXposed()) {
Log.i("自动记账同步", "同步开始");

RootUtils.exec(new String[]{"am force-stop com.mutangtech.qianji"});
//杀死其他应用
// Tool.stopApp(context,"com.mutangtech.qianji");
Expand Down Expand Up @@ -214,12 +215,14 @@ public void handleMessage(@NonNull Message msg) {
}

private void doRei(Context context, Bundle extData) {
RootUtils.exec(new String[]{"am force-stop com.mutangtech.qianji"});
Intent intent = new Intent("net.ankio.auto.QIANJI_REI");
intent.putExtras(extData);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
}

private void doYear(Context context, Bundle extData) {
RootUtils.exec(new String[]{"am force-stop com.mutangtech.qianji"});
Intent intent = new Intent("net.ankio.auto.QIANJI_Year");
intent.putExtras(extData);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/java/cn/dreamn/qianji_auto/core/hook/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -315,5 +315,12 @@ public void send(Bundle bundle, String identify) {
public void setContext(Context context) {
mContext = context;
}

public void restart() {
final Intent intent = getContext().getPackageManager().getLaunchIntentForPackage(getPackageName());
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
getContext().startActivity(intent);
android.os.Process.killProcess(android.os.Process.myPid());
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public void initLoadPackage(String pkg) {

}

public abstract void hookLoadPackage();
public abstract void hookLoadPackage() throws ClassNotFoundException;

@Override
public void onLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,54 +17,262 @@

package cn.dreamn.qianji_auto.core.hook.hooks.qianji;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

import cn.dreamn.qianji_auto.core.hook.core.hookBase;
import cn.dreamn.qianji_auto.core.hook.hooks.qianji.hooks.AutoError;
import cn.dreamn.qianji_auto.core.hook.hooks.qianji.hooks.DataBase;
import cn.dreamn.qianji_auto.core.hook.hooks.qianji.hooks.LeftSide;
import cn.dreamn.qianji_auto.core.hook.hooks.qianji.hooks.Lock;
import cn.dreamn.qianji_auto.core.hook.hooks.qianji.hooks.Reimbursement;
import cn.dreamn.qianji_auto.core.hook.hooks.qianji.hooks.Timeout;
import dalvik.system.DexFile;
import dalvik.system.PathClassLoader;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;

public class Qianji extends hookBase {
static final hookBase self = new Qianji();
public static hookBase getInstance() {
return self;
}





private Handler mHandler;
private Thread mUiThread;

final void attach(){
mHandler = new Handler();
mUiThread = Thread.currentThread();
}

public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}


interface RunBody {
void run(Class<?> clz) throws IllegalAccessException, InstantiationException, InvocationTargetException;
}
private void scan(Context ctx,ClassLoader loader,RunBody runnable) {
try {
// utils.log("Class-dump-dex:"+ctx.getPackageResourcePath());
DexFile dex = new DexFile(ctx.getPackageResourcePath());
Enumeration<String> entries = dex.entries();
while (entries.hasMoreElements()) {
String strClazz = entries.nextElement();
if (!strClazz.startsWith("android.")
&& !strClazz.startsWith("androidx.")
&& !strClazz.startsWith("com.android.")
&& !strClazz.startsWith(".system")
&& !strClazz.contains(".system")
&& !strClazz.startsWith("java.")
&& !strClazz.startsWith("com.alipay.sdk")
&& !strClazz.contains("com.google")
&& !strClazz.contains("xposed")){
// utils.log("Class-dump:"+strClazz);
try{
Class<?> entryClass =loader.loadClass(strClazz);
runnable.run(entryClass);
}catch (Exception e){
// e.printStackTrace();
}
}

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

}
//查找需要hook的class
private JSONObject findAllHookClass() throws ClassNotFoundException {
String key = "version_"+(utils.getVerName()+utils.getVerCode()).hashCode();
String data = utils.readData(key);
if(!Objects.equals(data, "")){
try{
return JSONObject.parseObject(data);
}catch (Exception e){
e.printStackTrace();
}
}

Toast.makeText(utils.getContext(),"钱迹版本:"+utils.getVerName()+"("+utils.getVerCode()+")未适配,尝试适配!",Toast.LENGTH_LONG).show();
utils.log("钱迹版本:"+utils.getVerName()+"("+utils.getVerCode()+")未适配,尝试适配!");
attach();
new Thread(){
@Override
public void run() {
//新的线程适配
JSONObject jsonObject = new JSONObject();
// 查找timeout
scan(utils.getContext(),utils.getClassLoader(), clz -> {
//遍历每一个class
if(clz.getName().equals("com.mutangtech.qianji.bill.auto.AddBillIntentAct")) {
Method[] m = clz.getDeclaredMethods();
// 打印获取到的所有的类方法的信息
Log.e("XPosed", Arrays.toString(m));
for (Method method : m) {

//私有
Class<?>[] parameterTypes = method.getParameterTypes();

Log.e("Xposed---method", method.toString());

if (parameterTypes.length == 2 && parameterTypes[1].getName().equals("com.mutangtech.qianji.data.model.AutoTaskLog") && parameterTypes[0].getName().equals("java.lang.String")) {
//找到AutoError
JSONArray jsonArray = new JSONArray();
jsonArray.add("com.mutangtech.qianji.bill.auto.AddBillIntentAct");
jsonArray.add(method.getName());
jsonObject.put("autoError", jsonArray);
// Log.e("Xposed-Find1",jsonObject.toString());

} else if (parameterTypes.length == 1 && parameterTypes[0].getName().equals("int") && method.getReturnType().getName().equals("boolean")) {
Log.e("Xposed-find","查找到对应的方法");
runOnUiThread(new Runnable() {
@Override
public void run() {
// Looper.prepare();
Object obj = null;
try {
obj = clz.newInstance();
method.setAccessible(true);
Boolean result = (Boolean) method.invoke(obj, 2);
if (Boolean.TRUE.equals(result)) {
JSONArray jsonArray = new JSONArray();
jsonArray.add("com.mutangtech.qianji.bill.auto.AddBillIntentAct");
jsonArray.add(method.getName());
jsonObject.put("baoxiaoTest", jsonArray);
// Log.e("Xposed-Find2", jsonObject.toString());
}
} catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
e.printStackTrace();
}


}
});


}
}
}else{
Method[] methods = clz.getMethods();
int flagIsVip = 0;
String[] vipMethods = new String[]{"getInstance","isVip","isVipExpired","checkVIP"};
for (Method m:methods) {
String mName = m.getName();
Class<?>[] parameterTypes = m.getParameterTypes();
if("timeoutApp".equals(m.getName())&&parameterTypes.length==2&&parameterTypes[0].getName().equals("java.lang.String")&&parameterTypes[1].getSimpleName().equals("long")){
//找到timeout类
JSONArray jsonArray = new JSONArray();
jsonArray.add(clz.getName());
jsonArray.add(m.getName());
jsonObject.put("timeout", jsonArray);
// Log.e("Xposed-Find3", jsonObject.toString());

}else{
if(Arrays.asList(vipMethods).contains(mName)){
flagIsVip++;
}
}
}

if(flagIsVip==vipMethods.length){
//找到User
JSONArray jsonArray = new JSONArray();
jsonArray.add(clz.getName());
jsonArray.add("isVip");
jsonObject.put("user", jsonArray);
// Log.e("Xposed-Find4",jsonObject.toString());
}
}

});

runOnUiThread(() -> {
if(jsonObject.containsKey("user")&&jsonObject.containsKey("timeout")&&jsonObject.containsKey("baoxiaoTest")&&jsonObject.containsKey("autoError")){
Toast.makeText(utils.getContext(),"钱迹版本:"+utils.getVerName()+"("+utils.getVerCode()+")适配成功!",Toast.LENGTH_LONG).show();
utils.log("钱迹版本:"+utils.getVerName()+"("+utils.getVerCode()+")适配成功!");
utils.writeData(key,jsonObject.toString());
try {
Thread.sleep(2000);
utils.restart();
} catch (InterruptedException e) {
e.printStackTrace();
}

}else{
Toast.makeText(utils.getContext(),"钱迹版本:"+utils.getVerName()+"("+utils.getVerCode()+")适配失败!",Toast.LENGTH_LONG).show();
utils.log("钱迹版本:"+utils.getVerName()+"("+utils.getVerCode()+")适配失败!");
Log.e("Xposed",jsonObject.toJSONString());
}
});
}
}.start();

return null;

}
@Override
public void hookLoadPackage() {
public void hookLoadPackage() throws ClassNotFoundException {

try {
DataBase.init(utils);
LeftSide.init(utils);
} catch (Throwable e) {
utils.log("钱迹 DataBase HookError " + e.toString());
utils.log("钱迹 LeftSide HookError " + e.toString());
}

JSONObject jsonObject = findAllHookClass();
if(jsonObject==null)return;
try {
Timeout.init(utils);
DataBase.init(utils,jsonObject.getJSONArray("user"));
} catch (Throwable e) {
utils.log("钱迹 Timeout HookError " + e.toString());
utils.log("钱迹 DataBase HookError " + e.toString());
}
try {
AutoError.init(utils);
Timeout.init(utils,jsonObject.getJSONArray("timeout"));
} catch (Throwable e) {
utils.log("钱迹 AutoError HookError " + e.toString());
utils.log("钱迹 Timeout HookError " + e.toString());
}
try {
LeftSide.init(utils);
AutoError.init(utils,jsonObject.getJSONArray("autoError"));
} catch (Throwable e) {
utils.log("钱迹 LeftSide HookError " + e.toString());
utils.log("钱迹 AutoError HookError " + e.toString());
}


try {
Reimbursement.init(utils);
Reimbursement.init(utils,jsonObject.getJSONArray("baoxiaoTest"));
} catch (Throwable e) {
utils.log("钱迹 Reimbursement HookError " + e.toString());
}
try {
Lock.init(utils);
} catch (Throwable e) {
utils.log("钱迹 Lock HookError " + e.toString());
}


}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import android.content.Intent;
import android.widget.Toast;

import com.alibaba.fastjson.JSONArray;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
Expand All @@ -16,7 +18,7 @@
import de.robv.android.xposed.XposedHelpers;

public class AutoError {
public static void init(Utils utils) throws ClassNotFoundException {
public static void init(Utils utils, JSONArray jsonArray) throws ClassNotFoundException {
ClassLoader mAppClassLoader = utils.getClassLoader();
Class<?> AutoTaskLog = mAppClassLoader.loadClass("com.mutangtech.qianji.data.model.AutoTaskLog");
Class<?> WebViewActivity = mAppClassLoader.loadClass("com.mutangtech.qianji.ui.webview.WebViewActivity");
Expand Down Expand Up @@ -53,21 +55,15 @@ protected void beforeHookedMethod(MethodHookParam param) throws ClassNotFoundExc
}
};

HashMap<String, String> clazz = new HashMap<>();
clazz.put("com.mutangtech.qianji.bill.auto.AddBillIntentAct", "a");
clazz.put("com.mutangtech.qianji.bill.auto.AddBillIntentAct", "t0"); // 钱迹3.2.1.4版本

for (Map.Entry entry : clazz.entrySet()) {
String cls = (String) entry.getKey();
String method = (String) entry.getValue();
String cls =jsonArray.getString(0);
String method = jsonArray.getString(1);

try {
utils.log("钱迹 AutoError.init Hook<" + cls + "." + method + "> ");
XposedHelpers.findAndHookMethod(cls, mAppClassLoader, method, String.class, AutoTaskLog, methodHook);
break;
} catch (Exception e) {
utils.log("钱迹 AutoError.init Hook <" + cls + "." + method + "> HookError " + e);
}
try {
utils.log("钱迹 AutoError.init Hook<" + cls + "." + method + "> ");
XposedHelpers.findAndHookMethod(cls, mAppClassLoader, method, String.class, AutoTaskLog, methodHook);
} catch (Exception e) {
utils.log("钱迹 AutoError.init Hook <" + cls + "." + method + "> HookError " + e);
}
}

Expand Down
Loading

0 comments on commit 35dcc59

Please sign in to comment.