前两天有人想让我做一个微信自动加好友的功能,今天就想试一试。 以微信6.6.7版本为例,手机root与Xposed框架安装本文不做讨论,如有需要查看论坛内其他帖子,本文只用于Xposed模块编写。
严重声明 本文的意图只有一个就是通过分析app学习更多的逆向技术,如果有人利用本文知识和技术进行非法操作进行牟利,带来的任何法律责任都将由操作者本人承担,和本文作者无任何关系,最终还是希望大家能够秉着学习的心态阅读此文。
经坛友提醒,使用文本存储手机号,在进行读取for循环搜索好友时,10个以上的时候就会产生操作过于频繁的提醒,而且这个提醒大概一个小时才能解除。 经过优化后,增加了线程的sleep时间,可实现自动循环查看好友信息,但在运行到25个左右时也会触发操作过于频繁的提醒。 并且如果加好友的功能也增加上的话,也会由于加好友频繁而被限制,所以最好是通过ContentProvider把大量手机号批量写入到手机通讯录数据库中,然后使用微信的添加通讯录好友的方式来添加好友,以下分析流程就仅做参考吧。
1.首先查看微信加好友的页面
使用 当前Activity 这个app来查看,是FTSAddFriendUI这个Activity。
2.使用jadx打开app,查找FTSAddFriendUI
3.寻找突破点
大体浏览后没有类似EditView的实例对象,但发现一个内部类FTSAddFriendUI$5
-1通过简单分析
确定这个内部类是搜索好友后的结果显示,成功的话就intent跳转,失败的话就显示该用户不存在等错误信息
-2直接查找它的使用
是CM方法使用到它了,分析可得这个方法的参数就是输入框的字符串,字符串不为空后进行查询,并显示一个正在查询的Dialog,有结果后回调OnCancelListener,并且触发内部类FTSAddFriendUI$5中的结果显示方法。
Hook CM方法,打印string参数,发现就是输入框的文本数据,确认CM方法就是要找的方法
-3xposed直接使用
final Class FTSAddFriendUIClass=loadPackageParam.classLoader.loadClass("com.tencent.mm.plugin.fts.ui.FTSAddFriendUI");
findAndHookMethod(FTSAddFriendUIClass,
"onCreate",Bundle.class,
new XC_MethodHook() {
@Override
protected void afterHookedMethod(final MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
XposedHelpers.callMethod(param.thisObject,"CM","微信号/QQ号/手机号");
}
},1000);
}
});
微信显示效果:
-4解决问题
结果可以看到只有dialog,dialog结束后并没有反应,但dialog能显示说明代码执行了,那就来看一下FTSAddFriendUI$5这个结果处理类里的方法有没有执行吧。
findAndHookMethod("com.tencent.mm.plugin.fts.ui.FTSAddFriendUI$5",loadPackageParam.classLoader,
"a",int .class, int .class,String.class,XposedHelpers.findClass("com.tencent.mm.ab.l",loadPackageParam.classLoader) ,
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
log("FTSAddFriendUI$5--0="+param.args[0]+"=1="+param.args[1]+
"=2="+param.args[2]);
}
});
打印结果如下:
2019-02-18 17:55:19.347 3872-3872/? I/Xposed: [17:55:19]: FTSAddFriendUI$5–0=0=1=0=2=Everything is OK
搜索结果处理的方法执行了,说明问题不在CM方法,而是在处理方法中因为某个问题而停止了。 那就来分析一下这个a方法里的哪段代码是有问题的吧。
a方法完整代码如下:
public final void mo2331a(int i, int i2, String str, C0879l c0879l) {
C1261g.m2963DF().mo8629b(106, (C0874e) this);
FTSAddFriendUI.this.aQA();
if (i == 0 && i2 == 0) {
FTSAddFriendUI.this.iJw = ((C9339f) c0879l).bcS();
if (FTSAddFriendUI.this.iJw.rHb > 0) {
if (FTSAddFriendUI.this.iJw.rHc.isEmpty()) {
C35785h.m67602a(FTSAddFriendUI.this, C8733g.search_contact_not_found, 0, true, null);
return;
}
Intent intent = new Intent();
intent.putExtra("add_more_friend_search_scene", 3);
if (FTSAddFriendUI.this.iJw.rHc.size() > 1) {
try {
intent.putExtra("result", FTSAddFriendUI.this.iJw.toByteArray());
C36379d.m70344b(FTSAddFriendUI.this.mController.tml, "subapp", ".ui.pluginapp.ContactSearchResultUI", intent);
return;
} catch (Throwable e) {
C3327x.printErrStackTrace("MicroMsg.FTS.FTSAddFriendUI", e, "", new Object[0]);
return;
}
}
((C33521h) C1261g.m2977l(C33521h.class)).mo24028a(intent, (biy) FTSAddFriendUI.this.iJw.rHc.getFirst(), FTSAddFriendUI.this.jvZ);
}
FTSAddFriendUI.this.jvX = 1;
FTSAddFriendUI.m48692g(FTSAddFriendUI.this);
} else {
switch (i2) {
case DownloadResult.CODE_CONNECTION_EXCEPTION /*-24*/:
C29477a eV = C29477a.m50825eV(str);
if (eV == null) {
FTSAddFriendUI.this.jvQ.setText(C8733g.no_contact_result);
break;
} else {
FTSAddFriendUI.this.jvQ.setText(eV.desc);
break;
}
case -4:
if (i != 4) {
FTSAddFriendUI.this.jvQ.setText(FTSAddFriendUI.this.getString(C8733g.search_contact_err_no_code));
break;
}
default:
FTSAddFriendUI.this.jvQ.setText(C8733g.no_contact_result);
break;
}
FTSAddFriendUI.this.jvX = -1;
FTSAddFriendUI.this.jvY = 1;
}
FTSAddFriendUI.m48693h(FTSAddFriendUI.this);
}
因为上面打印log时前两个参数都是0,所以精简后如下:
public final void mo2331a(int i, int i2, String str, C0879l c0879l) {
C1261g.m2963DF().mo8629b(106, (C0874e) this);
FTSAddFriendUI.this.aQA();
if (i == 0 && i2 == 0) {
FTSAddFriendUI.this.iJw = ((C9339f) c0879l).bcS();
if (FTSAddFriendUI.this.iJw.rHb > 0) {
if (FTSAddFriendUI.this.iJw.rHc.isEmpty()) {
C35785h.m67602a(FTSAddFriendUI.this, C8733g.search_contact_not_found, 0, true, null);
return;
}
Intent intent = new Intent();
intent.putExtra("add_more_friend_search_scene", 3);
if (FTSAddFriendUI.this.iJw.rHc.size() > 1) {
try {
intent.putExtra("result", FTSAddFriendUI.this.iJw.toByteArray());
C36379d.m70344b(FTSAddFriendUI.this.mController.tml, "subapp", ".ui.pluginapp.ContactSearchResultUI", intent);
return;
} catch (Throwable e) {
C3327x.printErrStackTrace("MicroMsg.FTS.FTSAddFriendUI", e, "", new Object[0]);
return;
}
}
((C33521h) C1261g.m2977l(C33521h.class)).mo24028a(intent, (biy) FTSAddFriendUI.this.iJw.rHc.getFirst(), FTSAddFriendUI.this.jvZ);
}
FTSAddFriendUI.this.jvX = 1;
FTSAddFriendUI.m48692g(FTSAddFriendUI.this);
}
FTSAddFriendUI.m48693h(FTSAddFriendUI.this);
}
前面代码分析后无问题,但 if (FTSAddFriendUI.this.iJw.rHb > 0) 判断时不知rHb的值,此处需要hook一下。
findAndHookMethod("com.tencent.mm.plugin.fts.ui.FTSAddFriendUI$5",loadPackageParam.classLoader,
"a",int .class, int .class,String.class,XposedHelpers.findClass("com.tencent.mm.ab.l",loadPackageParam.classLoader) ,
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
log("FTSAddFriendUI$5--0="+param.args[0]+"=1="+param.args[1]+
"=2="+param.args[2]+"=rHb="+XposedHelpers.findField(
XposedHelpers.findClass("com.tencent.mm.protocal.c.bja",loadPackageParam.classLoader),"rHb").
get(XposedHelpers.callMethod((param.args[3]),"bcS")));
}
打印得知rHb=0,所以不会走if语句内的代码,只有两个方法m48692g与m48693h有可能有问题,按顺序检查参数
最终发现是这两个方法中使用了FTSAddFriendUI的变量bWm,而在输入框使用addTextChangedListener进行绑定后,bWm存储了输入的字符串,所以如果直接调用CM方法的话,导致bWm变量为空,所以解决方法如下:
final Class FTSAddFriendUIClass=loadPackageParam.classLoader.loadClass("com.tencent.mm.plugin.fts.ui.FTSAddFriendUI");
findAndHookMethod(FTSAddFriendUIClass,"onCreate",Bundle.class,
new XC_MethodHook() {
@Override
protected void afterHookedMethod(final MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
XposedHelpers.setObjectField(param.thisObject,"bWm","微信号/QQ号/手机号");
XposedHelpers.callMethod(param.thisObject,"CM","微信号/QQ号/手机号");
}},1000);
}
});
显示如下:
当然如果输入数据搜索不到好友,结果处理方法的参数是 2019-02-18 17:58:34.082 3872-3872/? I/Xposed: [17:58:34]: FTSAddFriendUI$5–0=4=1=-4=2=User do not exist
以此可以实现用户是否存在的判断。