Guide language:

Hello, hello ~ Xiaobian I don’t know if you have experienced, want to contact a friend for a long time, found that the other party has deleted you long ago, and you still know nothing about it. Anyway xiaobian experience!

There are some “zombie fans” in everyone’s wechat contacts list. They lie silently in your contact list, thinking they are still friends, but in fact, they have deleted you from their friends list. How do you screen out these people?

Body:

Before you start writing scripts, you need to do the following

  • A Root Android phone or emulator. If there is no Root device, the NetEase MuMu emulator is recommended

  • Android Development environment, Android Studio

  • Sqlcipher graphic chemical tool

  • Automation tools: Install Pocoui in a Python virtual environment

The whole operation is divided into three steps, namely, cracking wechat database to screen out friends in the address book, simulating the transfer of friends to get zombie powder data, and deleting all zombie powder.

Step 1, we need to crack the database of wechat App.

👉 is just a brief description of the cracking process here. If you want to crack the wechat address book data with one click, you can skip this step and directly use the APK provided at the end of this article.

First, we use Android Studio to create a new project and grant the application administrator with read and write permission to modify the wechat directory when the project is initialized.

/ / WeChat App directory of public static final String WX_ROOT_PATH = "/ data/data/com. Tencent. The mm/"; ** @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 + "\n"; localDataOutputStream.writeBytes((String) localObject); localDataOutputStream.flush(); localDataOutputStream.writeBytes("exit\n"); localDataOutputStream.flush(); localProcess.waitFor(); localObject = localProcess.exitValue(); } catch (Exception localException) { localException.printStackTrace(); ExecRootCmd ("chmod 777-r "+ WX_ROOT_PATH); execRootCmd("chmod 777-r" + WX_ROOT_PATH);Copy the code

Then, get the password of wechat database.

The password of the wechat database is generated by the MD5 algorithm based on the iMEI of the device and the UID of wechat.

/** * Md5 code generated according to iMEI and UIN, * * @param uin * @return */ public static String getDbPassword(String imei, String uin) {if (TextUtils. IsEmpty (imei) | | TextUtils. IsEmpty (uin)) {the d (" trade ", "password database initialization failed: imei or uid is empty"); Return "password error "; } String md5 = MD5Utils.md5(imei + uin); assert md5 ! = null; return md5.substring(0, 7).toLowerCase(); }Copy the code

Then, we can use THE SQLCipher dependency library to query the wechat database. We need to add the following dependencies for the project to facilitate the operation of the database.

Zetetic: Android -database-sqlcipher:3.5.4@aar'Copy the code

Use the password obtained above to open the encrypted database, and then query the “rContact” table to obtain the wechat address book of all friends’ wechat signals, nicknames, user names and other data.

/** * connect to database * <p> * 【rcontact】 Contact list, * * @param dbFile */ private void openWxDb(File dbFile, String db_pwd) {// All contacts 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;" ); // Compatible with 2.0 database}}; Try {/ / open database connection SQLiteDatabase db = SQLiteDatabase openOrCreateDatabase (dbFile, db_pwd, null, hook); VerifyFlag! = 0: public number, service number // Pay attention to blacklist users, Cursor C1 = db.rawQuery("select * from rcontact where verifyFlag =0 and type not in ,4,8,9,33,35,256,258,512,2051,32768,32770,32776,33024,65536,65792,98304 (2) and the username not like \ "% @ app \" and the 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)); } the d (" trade ", "WeChat contacts, contact number:" + contacts. The 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", "failed to read database" + e.tostring ()); Toast.makeText(this, "failed to read wechat record!" , Toast.LENGTH_SHORT).show(); } toast. makeText(this, "read wechat record successfully!" , Toast.LENGTH_SHORT).show(); }Copy the code

It should be noted that the data in the rContact table in the database is rather messy. In addition to normal friend data, blacklisted friends, deleted friends, public accounts, wechat groups and other data are also included, requiring us to filter them through type and verifyFlag fields.

Finally, the queried buddy data is written to a CSV file for Python operations.

@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)); / / add the head name 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(); }}Copy the code

Step 2, we need to simulate the transfer of money to a friend to determine whether the friend relationship is normal.

First, we need to initialize Airtest, and then use ADB to export the data generated in step 1 from the phone to local.

Def __init_airtest(self): """ 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): """ Export directory data from mobile phone :param target_path: :return: "" "# WeChat contacts data wx_db_source_path = "/ data/data/com xingag. Crack_wx/wx_data. CSV" # export to local OS. Popen (' adb pull % s % s' % (wx_db_source_path, target_path))Copy the code

Then there’s the automation.

Open wechat, traverse the list of friends, get the wechat signal of each friend to search friends, jump to the chat interface of friends.

Def __to_friend_chat_page(self, weixin_id): """ def __to_friend_chat_page(self, weixin_id): """ Element_search = self.__wait_for_element_exists(self.id_search) element_search.click() print(' click search ') # 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 Whether a corresponding contact exists, if so, in the first child View layout A list of the most commonly used chats might appear, Index_tips = 0 for index, element_search_result in enumerate(element_search_result_list.children()): Offspring ()[0]. Offspring (self.id_contact_tips).exists(): if element_search_result.offspring(text=self.text_contact_tips).exists(): Element_search_result_list.children ()[index_tips + 1].click()Copy the code

They then try to transfer money to each other, and if they are friends, a payment page pops up asking for a password.

Def __judge_is_friend(self, weixin_id, weixin_name): "" """ # Try to send money to your friends, set a small amount to prevent direct payment via face swiping # If the person is your friend, then you will be asked to enter your password and close the page # If the person is not your friend, it will tell you that they are not your friend, # 5, Click self.poco(self.id_chat_more_button). Click () # 6, click the transfer button Self. Poco (self.id_chat_more_container). Offspring (text=self.text_chat_transfer_account_text) Self.poco (self.id_transfer_account_input).set_text(self.money) # 8, Click transfer button self.poco(self.id_transfer_account_container).offspring(text=self.text_chat_transfer_account_text).click()Copy the code

If you are a zombie fan, a warning dialog box will pop up telling you that you are not a friend of the recipient and cannot complete the transfer operation.

If the warning dialog box exists, you can determine whether the friend relationship is normal. Abnormal friend relationship, including: zombie fans, abnormal account of the other side, etc.

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(' Note! %s has blocked you!! ' % 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, Transfer_account_result_tips: print('%s account received limit!!! ' % 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 friend relationship is abnormal!! ' % weixin_name) write_to_file(self.path_relationship_unnormal, 'id:%s,nickName:%s' % (weixin_id, Element_transfer_account_result_button.click () # return to home self.__back_to_home() else: Print (' friend ') self.__back_to_home()Copy the code

Finally, click the back button of the phone to go back to the main interface of wechat.

Def __back_to_home(self): "" return: "" print(' back_to_home ', 'address book ',' discover ', 'I ') home_tips = ['微信',' address book ', 'discover ',' I '] 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 = True if is_HOME: print(' already back ') breakCopy the code

Loop through the above actions to determine which are zombie fans, which friends’ accounts have been blocked, and which are normal friends.

Step 3, delete the list of zombie fans obtained above.

Given the list of zombie fan data above, you can use the above method to perform a series of automated UI operations to delete those friends.

Def del_friend_black(self, weixin_id): "" __to_friend_chat_page(weixin_id) Click () # click on your friend's avatar self.poco(self.id_person_head_url).click() # Click self.poco(self.id_person_manage_menu). Click () # Find delete action bar Swipe ([0.5, 0.9], [0.5, 0.3], duration=0.2) # Click delete Self.poco (self.id_person_del, Text =self.text_person_del).click() # return to main interface self.poco(self.id_person_del_sure, text=self.text_person_del).click()Copy the code

Step 4, the result of the fruit

You can compile the Android project or directly run APK to save the friends’ data in wechat contacts to the project file directory.

Then, the Python program will traverse the data of friends in the address book, operate the wechat App automatically, and then write all the zombie fans into the local file. Finally, you can choose to delete all the zombie fans.

The end:

At this point, we will complete the search for who secretly deleted your wechat, and finally we like to remember three even oh! Need a complete project source code of the private letter I can yo! Click on this!