解锁并提取Linux客户端微信数据库 (vibe coded)
at 107 lines 4.7 kB view raw
1# -*- coding: utf-8 -*-# 2# ------------------------------------------------------------------------------- 3# Name: OpenIMContact.py 4# Description: 5# Author: xaoyaoo 6# Date: 2024/04/16 7# ------------------------------------------------------------------------------- 8from .db_base import DatabaseBase 9from .utils import db_error 10 11 12class OpenIMContactHandler(DatabaseBase): 13 _class_name = "OpenIMContact" 14 OpenIMContact_required_tables = ["OpenIMContact"] 15 16 def get_im_user_list(self, word=None, wxids=None): 17 """ 18 获取联系人列表 19 [ 注意:如果修改这个函数,要同时修改dbMicro.py中的get_user_list函数 ] 20 :param word: 查询关键字,可以是用户名、昵称、备注、描述,允许拼音 21 :param wxids: 微信id列表 22 :return: 联系人字典 23 """ 24 if not self.tables_exist("OpenIMContact"): 25 return [] 26 if not wxids: 27 wxids = {} 28 if isinstance(wxids, str): 29 wxids = [wxids] 30 sql = ("SELECT UserName,NickName,Type,Remark,BigHeadImgUrl,CustomInfoDetail,CustomInfoDetailVisible," 31 "AntiSpamTicket,AppId,Sex,DescWordingId,ExtraBuf " 32 "FROM OpenIMContact WHERE 1==1 ;") 33 if word: 34 sql = sql.replace(";", 35 f"AND (UserName LIKE '%{word}%' " 36 f"OR NickName LIKE '%{word}%' " 37 f"OR Remark LIKE '%{word}%' " 38 f"OR LOWER(NickNamePYInit) LIKE LOWER('%{word}%') " 39 f"OR LOWER(NickNameQuanPin) LIKE LOWER('%{word}%') " 40 f"OR LOWER(RemarkPYInit) LIKE LOWER('%{word}%') " 41 f"OR LOWER(RemarkQuanPin) LIKE LOWER('%{word}%') " 42 ") ;") 43 if wxids: 44 sql = sql.replace(";", f"AND UserName IN ('" + "','".join(wxids) + "') ;") 45 46 result = self.execute(sql) 47 if not result: 48 return {} 49 50 users = {} 51 for row in result: 52 # 获取用户名、昵称、备注和聊天记录数量 53 (UserName, NickName, Type, Remark, BigHeadImgUrl, CustomInfoDetail, CustomInfoDetailVisible, 54 AntiSpamTicket, AppId, Sex, DescWordingId, ExtraBuf) = row 55 56 users[UserName] = { 57 "wxid": UserName, "nickname": NickName, "remark": Remark, "account": UserName, 58 "describe": '', "headImgUrl": BigHeadImgUrl if BigHeadImgUrl else "", 59 "ExtraBuf": None, "LabelIDList": tuple(), "extra": None} 60 return users 61 62 63@db_error 64def get_ExtraBuf(ExtraBuf: bytes): 65 """ 66 读取ExtraBuf(联系人表) 67 :param ExtraBuf: 68 :return: 69 """ 70 if not ExtraBuf: 71 return None 72 buf_dict = { 73 '74752C06': '性别[1男2女]', '46CF10C4': '个性签名', 'A4D9024A': '', 'E2EAA8D1': '', '1D025BBF': '', 74 'F917BCC0': '公司名称', '759378AD': '手机号', '4EB96D85': '企微属性', '81AE19B4': '朋友圈背景', 75 '0E719F13': '备注图片', '945f3190': '备注图片2', 76 'DDF32683': '0', '88E28FCE': '1', '761A1D2D': '2', '0263A0CB': '3', '0451FF12': '4', '228C66A8': '5', 77 '4D6C4570': '6', '4335DFDD': '7', 'DE4CDAEB': '8', 'A72BC20A': '9', '069FED52': '10', '9B0F4299': '11', 78 '3D641E22': '12', '1249822C': '13', 'B4F73ACB': '14', '0959EB92': '15', '3CF4A315': '16', 79 'C9477AC60201E44CD0E8': '17', 'B7ACF0F5': '18', '57A7B5A8': '19', '695F3170': '20', 'FB083DD9': '21', 80 '0240E37F': '22', '315D02A3': '23', '7DEC0BC3': '24', '16791C90': '25' 81 } 82 rdata = {} 83 for buf_name in buf_dict: 84 rdata_name = buf_dict[buf_name] 85 buf_name = bytes.fromhex(buf_name) 86 offset = ExtraBuf.find(buf_name) 87 if offset == -1: 88 rdata[rdata_name] = "" 89 continue 90 offset += len(buf_name) 91 type_id = ExtraBuf[offset: offset + 1] 92 offset += 1 93 94 if type_id == b"\x04": 95 rdata[rdata_name] = int.from_bytes(ExtraBuf[offset: offset + 4], "little") 96 97 elif type_id == b"\x18": 98 length = int.from_bytes(ExtraBuf[offset: offset + 4], "little") 99 rdata[rdata_name] = ExtraBuf[offset + 4: offset + 4 + length].decode("utf-16").rstrip("\x00") 100 101 elif type_id == b"\x17": 102 length = int.from_bytes(ExtraBuf[offset: offset + 4], "little") 103 rdata[rdata_name] = ExtraBuf[offset + 4: offset + 4 + length].decode("utf-8", errors="ignore").rstrip( 104 "\x00") 105 elif type_id == b"\x05": 106 rdata[rdata_name] = f"0x{ExtraBuf[offset: offset + 8].hex()}" 107 return rdata