誰偷偷刪了你的微信?別慌!Python 幫你都揪出來了

2020-12-15 SegmentFault思否

目標場景

不知道你有沒有經歷過,想聯繫一位很長時間沒有聯繫的朋友,發現對方很早以前已經把你刪除了,而你還一無所知。

相信每個人的微信通信錄裡都存在一些「殭屍粉」,他們默默地躺在聯繫人列表中,你以為對方還是朋友,那就真是太年輕、太天真的;實際上,對方早就把從好友列表中刪了,那如何來篩選出這群人呢?

網上的很大量檢測殭屍粉的工具,檢測的時候會給微信通信錄內的每一個好友發送一條檢測信息,嚴重「打擾」到對方;另外一部分軟體在檢測的時候,會植入一些代碼病毒,暗箱操作顯得很不安全。

本篇文章的目的是自動化操作微信 App,通過「模擬給好友轉帳」來篩選出所有的殭屍粉,並一鍵刪除它們。

準備工作

在開始編寫腳本之前,需要做好如下準備工作

一部 Root 後的 Android 手機或者模擬器,如果沒有 Root 的設備,推薦使用網易 MuMu 模擬器Android 開發環境、Android Studiosqlcipher 圖形化工具自動化工具:Python 虛擬環境下安裝 pocoui

編寫腳本

整個操作分為 3 步驟,分別是破解微信資料庫篩選出通信錄中的好友、模擬給好友轉帳得到殭屍粉數據、刪除所有殭屍粉。

第 1 步,我們需要破解微信 App 的資料庫。

ps:這裡只是簡單的說一下破解流程,想一鍵破解微信通信錄數據,可以跳過這一步,直接使用文末提供的 APK。

首先,我們使用 Android Studio 新建一個項目,在項目初始化的時候,授予應用管理員權限以及修改微信目錄的讀寫權限。

//微信 App 的目錄public static final String WX_ROOT_PATH = "/data/data/com.tencent.mm/";/** * 執行linux指令 * * @param paramString*/public staticvoid 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 + "\n"; localDataOutputStream.writeBytes((String) localObject); localDataOutputStream.flush(); localDataOutputStream.writeBytes("exit\n"); 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 */publicstatic 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 */privatevoidopenWxDb(File dbFile, String db_pwd){//所有聯繫人 List<Contact> contacts = new ArrayList<>(); SQLiteDatabase.loadLibs(this); SQLiteDatabaseHook hook = new SQLiteDatabaseHook() {publicvoidpreKey(SQLiteDatabase database){ }publicvoidpostKey(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 */publicstaticvoidwriteCsvFile(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__)defexport_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()ifself.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 = ['微信', '通訊錄', '發現', '我']whileTrue: 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 操作,刪除掉這些好友。

defdel_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()

結果結論

編譯 Android 項目或者直接運行 APK 就能將微信通信錄的好友數據保存到項目文件目錄下。

然後運行 Python 程序會遍歷通訊錄好友數據,自動化去操作微信 App,接著將所有的殭屍粉寫入到本地文件中,最後可以選擇將這些殭屍粉全部刪除掉。

相關焦點

  • 微信裡,這樣「麻煩」你的男人,往往都在偷偷的愛著你,你別不懂
    微信上,這樣「麻煩」你的男人,往往都在偷偷的愛著你,你別不懂。身邊會有幾個男性友人,所以我們幾個女孩子只要感情出現問題了,都會問他們一下,想要知道在這種情況下,你們男人是怎麼想的。跟他們經常討論到,這件事上,你們男人會怎麼做,那件事情上,你們男人會怎麼做。也不負眾望,每一次,我們詢問了以後,他們都能給出一些很好的答案。
  • 誰在偷偷喜歡你,微信「拍一拍」告訴你,真的
    01微信推出的新功能「拍一拍」你用過了嗎?第一次是對誰使用的呢?而現在這樣你一拍,我一拍,看似不經意的動作,其實是在表達自己內心的感受,即使對方不回應,也可以假裝只是不小心點了「拍一拍,」以此來隱藏自己的真實心意。誰在偷偷喜歡你,微信「拍一拍」告訴你答案!
  • 「你微信的異性都留著吧,別刪了」
    這一次她逼著男朋友刪掉微信裡所有的異性,不然就分手。聽起來挺無理取鬧的,畢竟生活不能全圍著愛情轉,換我我也不樂意。但她以前不是這樣的,我們認識很多年了,在我印象裡她一直是個很懂事的女孩子。甚至前幾段戀愛連男朋友的手機都沒碰過。
  • 刪了你的人,再也別加回來
    驚訝之餘,兩個人還噓寒問暖了一番,之後就體面的互刪了好友。事後,朋友和我說起,也是一臉興奮。然而生活中我們經常遇到的情況是:微信裡總會有這麼一個人,上一次的對話已經記不起在何時,連對話框都被壓在了消息的最低端,終於鼓起勇氣打破僵局,卻只收到一句「對方開啟好友驗證」。
  • 為什麼說分手後誰先刪微信誰輸?~婚戀課堂!第一百四十七期!
    但還有一個說法是分手後誰先刪微信誰輸,越早刪微信的人,說明ta心裡越在意,才會做出刪微信的舉動,下面就來為大家解釋為什麼說為什麼說分手後誰先刪微信誰輸。不管是男生還是女生,一般來說那種分手後總先刪除對方的人,這種心理比較多見。
  • 高盛Data崗位百萬年薪,python真的可以幫你實現,用數據幫你解讀
    高盛集團在很多國家都有子公司,他是一個世界頂級的投資公司,擁有跟金融風暴正面對持的能力和資本。能夠在高盛集團工資的人都是金融行業的精英。前幾年被高盛集團以3萬實習工資來實習的實習生基本上都是北大清華等一流學校的學生,如果你能夠在高盛集團工資,那年薪百萬是一個基礎標準,在高盛工作人員眼裡,只有月薪百萬才是最符合他們的工資。
  • 微信上,男人要是不顧慮你感受,這樣回覆你,就刪了吧,別再聯繫
    微信上,男人要是不顧慮你感受,這樣回覆你,就刪了吧,別再聯繫01一個真正愛你的男人會在微信上和你說著甜言蜜語,他們恨不得每天都和你在一起,反而如果有一天冷淡了你,他們都會覺得很難過。一個男人愛你的程度取決於你說每句話時他的反應,我們應該清楚地判斷他是否真心的喜歡你,如果不是請早點放手,下面就和小編一起來看看那些在微信上說過的話,如果她這樣回你那就儘早刪除了吧。
  • 愛而不得的人是刪還是留?看完這兩故事,事實比你想像的還要扎心
    愛而不得的人是刪還是留?看完這兩故事,事實比你想像的還要扎心。01 刪掉還會想念我的好朋友,一位在北京讀書的成都姑娘,和前任和平分手了。前男友提分手時,就在微信上說了句:「感覺不喜歡了,咱們暫時分開吧!姑娘回復了一個「嗯」,之後是一夜哭泣。
  • 痘痘、色素沉澱、腰間盤突出...別慌,專家門診幫你安排好了!
    痘痘、色素沉澱、腰間盤突出......別慌,專家門診幫你安排好了! 編輯:路景斕來源:芷江新視野↓可能你還想看
  • 為什麼分手後男生不刪你微信?原因只有三點!
    好朋友小偉之前分手的時候,前任叫他把她微信刪了,兩個人你叫我刪,我叫你刪,到最後誰都不刪,就留著彼此的微信,不聯繫,不打擾,只是還關注著彼此的動態。後來,小偉想了很久,想清楚之後,主動跟前任說想複合,不行就重新追求她。現在兩個人已經準備結婚了。
  • 微信刪除的聊天記錄怎麼恢復?老闆:我有灰鴿子,刪也沒用!
    最近有同事使壞,在我電腦刪除微信聊天記錄,很想知道微信聊天記錄怎麼恢復。手機和電腦不同步,拿不出客戶聊天數據,沒有證據,被叫到辦公室聊了聊近期的工作。結果老闆讓我別灰心,讓我好好幹。然後直接找管理員恢復了我的聊天記錄,這操作絕了。
  • 小虎否認自己刪MLXG微信:他還欠我錢呢,不要了嗎?
    最近一段時間,因為LPL的新規定,各大戰隊的職業選手都齊聚峽谷之巔上分。可正所謂「打得好不如排得好」,找個強力的大腿當隊友是非常重要的事情,可如果你興衝衝的去找你前隊友雙排結果卻發現他把你微信刪了,你心態會不會爆炸?
  • 女孩刪你微信說明什麼?知道這些原因,讓妹子捨不得拉黑你
    2、朋友圈太亂這裡不是指你不能交異性朋友,而是指你不能交太多狐朋狗友,尤其尤其的一點是不要交女生不喜歡的朋友,其實你要是正好和女生不喜歡的那個女生關係好,也沒什麼關係,但請你千萬別發到朋友圈好嗎?你這是想刺激誰呢?
  • 2020年,應屆生別慌,求職秘籍來幫你
    2020年太難了,這是常聽到的詞語,在這裡作為往屆再往屆的大師兄給2020屆師弟師妹說一句:「別慌,作為曾經榮幸拿到多個OFFER的大師兄,我把我當時畢業的真實面試經驗傳給你們」;1、做好職業規劃(這點非常重要)找工作之前,首先你得確認方向,沒有方向亂投一通的話,最終大部分都是失敗收場的,這點一定要重視;
  • QQ隱藏「表白功能」,秒測出誰在「偷偷喜歡你」,不脫單算我輸!
    我們來分享一下:QQ隱藏「表白功能」,秒測出誰在「偷偷喜歡你」,不脫單算我輸!1.相冊訪問記錄不管是對你有好感還是暗戀你的人,都是希望能更加了解你一下,想要知道你喜歡什麼,厭惡什麼,更想知道你之前的感情狀況是什麼樣,所以才會頻繁的進入你的QQ空間,去你的相冊訪問,太想念你又不好意思說出來,就只能偷偷去你的空間看你的相冊,這樣你要是還不明白的話,那就真是太傻了。
  • 情感測試:第一感覺,哪隻眼睛是畫出來的?測身邊誰在偷偷喜歡你
    情感測試:第一感覺,哪隻眼睛是畫出來的?測身邊誰在偷偷喜歡你 A: 圖片來源於網絡,如有侵權請聯繫作者謝謝~ A:如果這隻眼睛是畫出來的,說明身邊你的同桌在偷偷喜歡你。
  • 塔羅牌佔卜:測誰在偷偷暗戀你!
    因此,每一次測試都是全新的挑戰每一場解牌都是獨一無二的創作過程塔羅牌佔卜|測誰在偷偷暗戀你!請深呼吸,並相信心中的直覺平靜了嗎?選擇一個你最有感覺的牌A從牌面上你身邊還沒有人偷偷愛你,這可能跟你性格有關,你的要求比較高,讓身邊的桃花望而卻步,同時脾氣古怪
  • 微信聊天記錄刪了如何恢復?這樣操作大多數人都找回來了!
    微信聊天記錄刪了如何恢復?微信每天承載著我們的各種數據,不論是工作的還是生活的又或者是朋友間的閒聊啊等,都是通過微信來完成,特別一些群聊信息點據了我們手機更多的內存,時常導致手機內存不夠用,這時候我們就會開始清理我們的微信數據,如果手太快了,我們就會不小心把重要的記錄也給刪了,重要的記錄刪了著急的很,這個時候該怎麼辦呢?
  • 想查看微信好友撤回的消息?Python幫你搞定
    要說微信最讓人噁心的發明,消息撤回絕對能上榜。比如你現在正和女朋友用微信聊著天,或者跟自己喜歡的女孩子聊著天,一個不留神,你沒注意到對方發的消息就被她及時撤回了,這時你很好奇,好奇她到底發了什麼?於是你打算問問她發了什麼,結果她回一句"沒什麼"。
  • 加我時熱情如火,刪我時拜拜都沒有?|22個人刪了我微信,我去問了...
    本文已獲授權 轉載請聯繫原作者    「能麻煩你告訴我,為什麼刪掉我的微信嗎?」    微信最近新出了個功能,幫你篩查不常聯繫的朋友。半年內不聊天、沒回復過朋友圈、沒共同小群的好友,都可以列出來。    就像《植物大戰殭屍》裡的墓碑,佔著好友位置卻不聯繫。滿足以上三項條件的,可以說是朋友圈裡的「墓碑好友」了。