1. 导入 epic
dependencies {
compile 'me.weishu:epic:0.3.6'
}
2. 传入获取的 application
RevokeMsgHook.startHook(mInitialApplication); // 开始 HOOK 微信
3. 编写防撤回逻辑
public class RevokeMsgHook {
private static boolean disableRevoke = true;
private static Map<Long, Object> msgCacheMap = new HashMap<>();
private static Object storageInsertClazz;
public static void startHook(Application application) {
final ClassLoader classLoader = application.getClassLoader();
try {
Class clazz = classLoader.loadClass("com.tencent.wcdb.database.SQLiteDatabase");
DexposedBridge.findAndHookMethod(clazz, "updateWithOnConflict", String.class, ContentValues.class, String.class, String[].class, int.class,
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
if (param.args[0].equals("message")) {
ContentValues contentValues = ((ContentValues) param.args[1]);
//reload();
if (disableRevoke && contentValues.getAsInteger("type") == 10000 &&
!contentValues.getAsString("content").equals("你撤回了一条消息")) {
handleMessageRecall(contentValues);
param.setResult(1);
}
}
super.beforeHookedMethod(param);
}
});
} catch (Exception e) {
e.printStackTrace();
}
try {
Class avClass = classLoader.loadClass("com.tencent.mm.storage.av");
DexposedBridge.hookAllMethods(avClass, "b",
new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
storageInsertClazz = param.thisObject;
Object msg = param.args[0];
long msgId = XposedHelpers.getLongField(msg, "field_msgId");
msgCacheMap.put(msgId, msg);
super.afterHookedMethod(param);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
private static void handleMessageRecall(ContentValues contentValues) {
long msgId = contentValues.getAsLong("msgId");
Object msg = msgCacheMap.get(msgId);
long createTime = XposedHelpers.getLongField(msg, "field_createTime");
XposedHelpers.setIntField(msg, "field_type", contentValues.getAsInteger("type"));
XposedHelpers.setObjectField(msg, "field_content", contentValues.getAsString("content") + "(已被阻止)");
XposedHelpers.setLongField(msg, "field_createTime", createTime + 1L);
try {
av.b(storageInsertClazz, msg, false); // 使用反射
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void b(Object so, Object au, Object bo) {
try {
Method dMethod = so.getClass().getDeclaredMethod("b", au.getClass(), boolean.class);
if (dMethod != null) {
dMethod.setAccessible(true);
dMethod.invoke(so, au, bo);
}
} catch (Exception e) {
e.printStackTrace();
}
}
4. 逻辑分析
先 hook 掉 av.b 方法,保存接收到的 msg,在更改信息,保存到数据库,修改传入函数的参数
网友评论