相信每个人的微信通信录里都存在一些 「 僵尸粉 」 ,他们默默地躺在联系人列表中,你以为对方还是朋友,那就真是太年轻、太天真的;实际上,对方早就把从好友列表中删了,那如何来筛选出这群人呢?


本篇文章的目的是自动化操作微信 App,通过 「 模拟给好友转账 」 来筛选出所有的僵尸粉,并一键删除它们。

准 备 工 作

在开始编写脚本之前,需要做好如下准备工作

  • 一部 Root 后的 Android 手机或者模拟器,如果没有 Root 的设备,推荐使用网易 MuMu 模拟器
  • Android 开发环境、Android Studio
  • sqlcipher 图形化工具
  • 自动化工具:Python 虚拟环境下安装 pocoui
'''
更多Python学习资料以及源码教程资料,可以在群1136201545免费获取
'''

编 写 脚 本

第 1 步,我们需要破解微信 App 的数据库。

//微信 App 的目录
public static final String WX_ROOT_PATH = "/data/data/com.tencent.mm/";/*** 执行linux指令** @param paramString
*/
public static void execRootCmd(String paramString)
{try{Process localProcess = Runtime.getRuntime().exec("su");Object localObject = localProcess.getOutputStream();DataOutputStream localDataOutputStream = new DataOutputStream((OutputStream) localObject);String str = String.valueOf(paramString);localObject = str + "
";localDataOutputStream.writeBytes((String) localObject);localDataOutputStream.flush();localDataOutputStream.writeBytes("exit
");localDataOutputStream.flush();localProcess.waitFor();localObject = localProcess.exitValue();} catch (Exception localException){localException.printStackTrace();}
}//获取权限
RootUtils.execRootCmd("chmod 777 -R " + WX_ROOT_PATH);

然后,获取微信数据库的密码。

微信数据库的密码是由设备的 imei 和微信的 uid 进过 md5 算法生成的。

/*** 根据imei和uin生成的md5码,获取数据库的密码(去前七位的小写字母)** @param imei* @param uin* @return*/
public static String getDbPassword(String imei, String uin)
{if (TextUtils.isEmpty(imei) || TextUtils.isEmpty(uin)){Log.d("xag", "初始化数据库密码失败:imei或uid为空");return "密码错误";}String md5 = MD5Utils.md5(imei + uin);assert md5 != null;return md5.substring(0, 7).toLowerCase();
}

接着,就可以使用 SQLCipher 依赖库来对微信数据库进行查询,我们需要为项目添加如下依赖,方便操作数据库。

//我们需要对项目增加依赖
implementation 'net.zetetic:android-database-sqlcipher:3.5.4@aar'

利用上面得到的密码打开加密数据库,然后查询「rcontact」表获取微信通讯录内所有的好友的微信号、昵称、用户名等数据。

/*** 连接数据库* <p>* 常用库介绍:【rcontact】联系人表,【message】聊天消息表** @param dbFile*/
private void openWxDb(File dbFile, String db_pwd)
{//所有联系人List<Contact> contacts = new ArrayList<>();SQLiteDatabase.loadLibs(this);SQLiteDatabaseHook hook = new SQLiteDatabaseHook(){public void preKey(SQLiteDatabase database){}public void postKey(SQLiteDatabase database){atabase.rawExecSQL("PRAGMA cipher_migrate;"); //兼容2.0的数据库}};try{//打开数据库连接SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbFile, db_pwd, null, hook);//查询所有联系人//过滤掉本人、群聊、公众号、服务号等一些联系人//verifyFlag != 0:公众号、服务号//注意黑名单用户,我-设置-隐私-通讯录黑名单Cursor c1 = db.rawQuery("select * from rcontact where verifyFlag =0 and type not in (2,4,8,9,33,35,256,258,512,2051,32768,32770,32776,33024,65536,65792,98304) and username not like "%@app" and username not like "%@qqim" and username not like "%@chatroom" and encryptUsername!=""",null);while (c1.moveToNext()){String userName = c1.getString(c1.getColumnIndex("username"));String alias = c1.getString(c1.getColumnIndex("alias"));String nickName = c1.getString(c1.getColumnIndex("nickname"));int type = c1.getInt(c1.getColumnIndex("type"));contacts.add(new Contact(userName, alias, nickName));}Log.d("xag", "微信通讯录中,联系人数目:" + contacts.size() + "个");for (int i = 0; i < contacts.size(); i++){Log.d("xag", contacts.get(i).getNickName());}c1.close();db.close();} catch (Exception e){Log.e("xag", "读取数据库信息失败" + e.toString());Toast.makeText(this, "读取微信通信录失败!", Toast.LENGTH_SHORT).show();}Toast.makeText(this, "读取微信通信录成功!", Toast.LENGTH_SHORT).show();
}

需要注意的是,数据库中 rcontact 表的数据比较杂乱,除了正常的好友数据,黑名单好友、已删除好友、公众号、微信群等数据也包含在内,需要我们通过 type 和 verifyFlag 字段进行筛选。

为了便于 Python 操作,最后将查询的好友数据写入到 csv 文件中。

/**** 写入数据到csv中* @param output_path* @param contacts*/
public static void writeCsvFile(String output_path, List<Contact> contacts)
{try{File file = new File(output_path);//删除之前保存的文件if (file.exists()){file.delete();}BufferedWriter bw = new BufferedWriter(new FileWriter(file, true));// 添加头部名称bw.write("userName" + "," + "alias" + "," + "nickName");bw.newLine();for (int i = 0; i < contacts.size(); i++){bw.write(contacts.get(i).getUserName() + "," + contacts.get(i).getAlias() + "," + contacts.get(i).getNickName());bw.newLine();}bw.close();} catch (IOException e){e.printStackTrace();}
}

第 2 步,我们需要模拟给好友转账,来判断这个好友关系是否正常。

首先,我们需要初始化 Airtest,然后利用 adb 把第 1 步生成的数据从手机里导出到本地。

def __init_airtest(self):"""初始化Airtest:return:"""device_1 = Android('822QEDTL225T7')# device_1 = Android('emulator-5554')connect_device("android:///")self.poco = AndroidUiautomationPoco(device_1, screenshot_each_action=False)auto_setup(__file__)def export_wx_db_from_phone(target_path):"""从手机中导出通信录数据:param target_path::return:"""# 微信通信录数据wx_db_source_path = "/data/data/com.xingag.crack_wx/wx_data.csv"# 导出到本地os.popen('adb pull %s %s' % (wx_db_source_path, target_path))

然后就是一系列自动化操作。

打开微信,遍历好友列表,拿到每一个好友的微信号去搜索好友,跳转到好友的聊天界面。

def __to_friend_chat_page(self, weixin_id):"""点击到一个好友的聊天界面:param weixin_id::param weixin_name::return:"""# 1、点击搜索element_search = self.__wait_for_element_exists(self.id_search)element_search.click()print('点击搜索')# 2、搜索框element_search_input = self.__wait_for_element_exists(self.id_search_input)element_search_input.set_text(weixin_id)# 3、搜索列表element_search_result_list = self.__wait_for_element_exists(self.id_search_result_list)# 3.1 是否存在对应的联系人,如果存在就在第一个子View布局下# 注意:可能出现最常用的聊天列表,这里需要进行判断index_tips = 0for index, element_search_result in enumerate(element_search_result_list.children()):# 联系人的Tips# if element_search_result_list.children()[0].offspring(self.id_contact_tips).exists():if element_search_result.offspring(text=self.text_contact_tips).exists():index_tips = indexbreak# 4、点击第一个联系人进入聊天界面element_search_result_list.children()[index_tips + 1].click()

接着尝试着给对方转账,如果好友关系正常,就会跳出一个支付页面让输入密码。

def __judge_is_friend(self, weixin_id, weixin_name):"""判断是不是微信好友:param weixin_id: 微信号:return:"""# 尝试给好友转账,设置一个小额度,以防止刷脸直接支付了# 如果对方是你的好友,接下来会让你输入密码,关掉页面就行了# 如果对方不是你的好友,会提示不是你的好友,不能继续操作了# 5、点击好友界面的+按钮self.poco(self.id_chat_more_button).click()# 6、点击转账按钮self.poco(self.id_chat_more_container).offspring(text=self.text_chat_transfer_account_text).click()# 7、输入金额self.poco(self.id_transfer_account_input).set_text(self.money)# 8、点击转账按钮self.poco(self.id_transfer_account_container).offspring(text=self.text_chat_transfer_account_text).click()

如果是僵尸粉,应用会弹出一个警告对话框,提示你不是收款方好友,没法完成转账的操作。

通过警告对话框是否存在,就可以判断好友关系是否正常。 非正常的好友关系,包含:僵尸粉、对方账号异常等。

# 10.弹出警告对话框
# 弹出好友关系不正常
if element_transfer_account_result_button:# 提示内容ransfer_account_result_tips = self.poco(self.id_transfer_account_result_tips).get_text()if self.text_friend_no_tips in transfer_account_result_tips:print('注意!%s已经把你拉黑了!!!' % weixin_name)self.friend_black_list.append({'id': weixin_id,'nickName': weixin_name})write_to_file(self.path_black_list, 'id:%s,nickName:%s' % (weixin_id, weixin_name))elif self.text_friend_limit_tips in transfer_account_result_tips:print('%s账号收到限制!!!' % weixin_name)write_to_file(self.path_account_limit, 'id:%s,nickName:%s' % (weixin_id, weixin_name))elif self.text_friend_is_norm in transfer_account_result_tips:print('%s好友关系不正常!!!' % weixin_name)write_to_file(self.path_relationship_unnormal, 'id:%s,nickName:%s' % (weixin_id, weixin_name))# 点击确认按钮element_transfer_account_result_button.click()# 返回到主页面self.__back_to_home()else:# 包含正常好友关系和对方账号限制的情况print('好友关系正常')self.__back_to_home()

最后,模拟点击手机的返回键,一直回退到微信主界面。

def __back_to_home(self):"""回退到主界面:return:"""print('准备回退到主界面')home_tips = ['微信', '通讯录', '发现', '我']while True:keyevent('BACK')is_home = False# 判断是否到达首页if self.poco(text=home_tips[0]).exists() and self.poco(text=home_tips[1]).exists() and self.poco(text=home_tips[2]).exists() and self.poco(text=home_tips[3]).exists():is_home = Trueif is_home:print('已经回到微信首页~')break

循环上面的操作,就可以判断出哪些是僵尸粉,哪些好友的账号被限制,哪些是正常的好友关系。

第 3 步,删除上面获取到的僵尸粉列表。

拿到上面的僵尸粉数据列表,就可以利用上面的方式进行一系列自动化UI 操作,删除掉这些好友。

'''
更多Python学习资料以及源码教程资料,可以在群1136201545免费获取
'''
def del_friend_black(self, weixin_id):"""删除黑名单好友:return:"""# 到好友聊天界面self.__to_friend_chat_page(weixin_id)# 点击聊天界面右上角,进入到好友的详细信息界面self.poco(self.id_person_msg_button).click()# 点击好友头像self.poco(self.id_person_head_url).click()# 点击个人名片的右上角,弹出好友操作菜单self.poco(self.id_person_manage_menu).click()# 查找删除操作栏# 注意:对于目前主流的手机,都需要滑动到最底部才能出现【删除】这一操作栏self.poco.swipe([0.5, 0.9], [0.5, 0.3], duration=0.2)# 点击删除,弹出删除对话框self.poco(self.id_person_del, text=self.text_person_del).click()# 确定删除好友【确定删除】# 界面会直接回到主界面self.poco(self.id_person_del_sure, text=self.text_person_del).click()

有人偷偷删了你的微信?别慌!Python 帮你揪出来相关推荐

  1. 谁偷偷删了你的微信?别慌!Python 把 TA 揪出来

    1 目 标 场 景 不知道你有没有经历过,想联系一位很长时间没有联系的朋友,发现对方很早以前已经把你删除了,而你还一无所知. 相信每个人的微信通信录里都存在一些「僵尸粉」,他们默默地躺在联系人列表中, ...

  2. 谁偷偷删了你的微信?别慌!Python 帮你都揪出来了!

    1 目 标 场 景 不知道你有没有经历过,想联系一位很长时间没有联系的朋友,发现对方很早以前已经把你删除了,而你还一无所知. Python资源共享群:484031800 相信每个人的微信通信录里都存在 ...

  3. 谁偷偷删了你的微信?别慌啊,Python全都帮你都揪出来

    导语: 哈喽,哈喽~小编不知道你有没有经历过,想联系一位很长时间没有联系的朋友,发现对方很早以前已经把你删除了,而你还一无所知.反正小编经历过! 每个人的微信通信录里都存在一些「僵尸粉」,他们默默地躺 ...

  4. 谁偷偷删了你的微信?别慌!Python 帮你都揪出来了

    点击上方"码农突围",马上关注 这里是码农充电第一站,回复"666",获取一份专属大礼包 真爱,请设置"星标"或点个"在看&quo ...

  5. python微信库有哪些_谁偷偷删了你的微信?别慌!一篇Python学习教程帮你都揪出来...

    contacts) { try { File file = new File(output_path); //删除之前保存的文件 if (file.exists()) { file.delete(); ...

  6. 谁偷偷删了你的微信?别慌!Python 揪出来

    不知道你有没有经历过,想联系一位很长时间没有联系的朋友,发现对方很早以前已经把你删除了,而你还一无所知. 相信每个人的微信通信录里都存在一些「僵尸粉」,他们默默地躺在联系人列表中,你以为对方还是朋友, ...

  7. 谁偷偷删了你的微信?别慌!Python 帮你揪出来

    不知道你有没有经历过,想联系一位很长时间没有联系的朋友,发现对方很早以前已经把你删除了,而你还一无所知. 相信每个人的微信通信录里都存在一些 「 僵尸粉 」 ,他们默默地躺在联系人列表中,你以为对方还 ...

  8. 谁偷偷删了你的微信?别慌!Python帮你都揪出来了

    作者 | 星安果 来源 | AirPython(ID:AirPython) 01 目标场景 不知道你有没有经历过,想联系一位很长时间没有联系的朋友,发现对方很早以前已经把你删除了,而你还一无所知. 相 ...

  9. @所有人,官网下载的微信小程序开发工具安装后黑屏咋办?

    @所有人,官网下载的微信小程序开发工具安装后黑屏咋办? 一直这样,重复安装也是这样 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页.如果你想学习如何使 ...

最新文章

  1. C# ListView添加DragDrop
  2. 虚幻gameframe_【虚幻4】从0开始的Galgame开发框架(2)--MainManager
  3. criterion java_Java Criterion類代碼示例
  4. linux游戏脚本,ubuntu 新手一键配置脚本
  5. Unity,WebGL, 页面JS调用Unity方法
  6. mysql换成oracle_mysql数据库迁移至Oracle数据库
  7. jquery饼状图插件的指引线_JQuery图表插件Highcharts示例教程
  8. 从零开始实现ASP.NET Core MVC的插件式开发(二) - 如何创建项目模板
  9. Windows Embedded CE 6.0开发初体验(七)编译和调试平台
  10. Kubernetes集群(概念篇)
  11. centos8.4 nginx 问题
  12. 神经网络-神经元模型、Hebb学习
  13. mantis修改mysql端口_Mantis配置指南
  14. 一个功能简洁,使用简易的微信机器人
  15. 电脑计算机D盘红格式化不了,电脑D盘无法格式化提示Windows无法格式该驱动器的解决办法...
  16. 禁止触摸屏触控板手指缩放,需要这样处理
  17. 程序复杂性度量方法-McCabe
  18. RuntimeError: Attempting to deserialize object on CUDA device 3 but torch.cuda.device_count() is 1.
  19. 计算机插上u盘就无法点亮,为什么电脑插着U盘就无法正常开机
  20. java+分割+汉字和英文_Java分割中英文,并且中文不能分割一半?

热门文章

  1. Linux:页表中PGD、PUD、PMD、TLB等概念介绍
  2. php mipsl,MIPS系列笔记-交叉编译MIPS架构ASLA
  3. LM1117MPX-2.5参数
  4. PT2050(TWS 蓝牙耳机二合一触摸 IC)
  5. Fabric、FISCO BCOS、以太坊对比
  6. JAVA 18道基础循环练习题,带你了解循环是如何实现的(带答案)
  7. 浮动QQ在线客服,MSN在线代码|QQ在…
  8. 高等教育出版社计算机网络技术局域网课件,计算机网络术基础(第3版)高等教育出版社.ppt...
  9. 信贷风控一:风控产品流程
  10. 量化投资里的风险收益分析与可视化:empyrical和pyfolio实战,与backtrader整合