本帖最后由 hjw45611 于 2019-3-14 15:23 编辑
严重声明
本文的意图只有一个就是通过分析app学习更多的逆向技术,如果有人利用本文知识和技术进行非法操作进行牟利,带来的任何法律责任都将由操作者本人承担,和本文作者无任何关系,最终还是希望大家能够秉着学习的心态阅读此文。
前两天有人想让我做一个微信自动加好友的功能,今天就想试一试。
以微信6.6.7版本为例,手机root与Xposed框架安装本文不做讨论,如有需要查看论坛内其他帖子,本文只用于Xposed模块编写。
经坛友提醒,使用文本存储手机号,在进行读取for循环添加时,10个以上的时候就会产生操作过于频繁的提醒,而且这个提醒大概一个小时才能解除。
经过优化后,增加了线程的sleep时间,可实现自动循环查看好友信息,但在运行到25个左右时也会触发操作过于频繁的提醒。
并且如果加好友的功能也增加上的话,也会由于加好友频繁而被限制,所以最好是通过ContentProvider把大量手机号批量写入到手机通讯录数据库中,然后使用微信的添加通讯录好友的方式来添加好友,但有网友反应可用,也有网友反应加的多了收不到验证信息,我也并未实验, 以下分析流程就仅做参考吧。
至今(2019-03-14)微信自动加好友的分析已经完成,主要分三步:
1.查找好友(本文)
2.自动点击添加好友按钮进入验证页面
https://www.52pojie.cn/thread-886190-1-1.html
3.自动发送验证信息
https://www.52pojie.cn/thread-897346-1-1.html
希望喜欢Xposed的朋友能交流学习,从中获益。
1.首先查看微信加好友的页面
是FTSAddFriendUI这个Activity。
2.使用jadx打开app,查找FTSAddFriendUI
3.寻找突破点
大体浏览后没有类似EditView的实例对象,但发现一个内部类FTSAddFriendUI$5
-1通过简单分析,确定这个内部类是搜索好友后的结果显示
成功的话就intent跳转,失败的话就显示该用户不存在等错误信息
-2直接查找它的使用
是CM方法使用到它了,分析可得这个方法的参数就是输入框的字符串,字符串不为空后进行查询,并显示一个正在查询的Dialog,有结果后回调OnCancelListener,并且触发内部类FTSAddFriendUI$5中的结果显示方法。
Hook CM方法,打印string参数,发现就是输入框的文本数据,确认CM方法就是要找的方法
-3xposed直接使用
[Java] 纯文本查看 复制代码 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这个结果处理类里的方法有没有执行吧。
[Java] 纯文本查看 复制代码 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方法完整代码如下,
[Java] 纯文本查看 复制代码 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,所以精简后如下
[Java] 纯文本查看 复制代码 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一下。
[Java] 纯文本查看 复制代码 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变量为空,所以解决方法如下:
[Java] 纯文本查看 复制代码 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
|